Author: Ahmed Gaper, a contributor to Google Summer of Code 2025
GSoC project link
- Project overview
- Usage guide
- Default ruleset
- Contributions & Merged PRs, Challenges & how I solved them
- Conclusion & future work
- Acknowledgments
The Accord Project uses concerto models as human-readable schemas that drive the logic in smart legal contracts. This project delivered a concerto Linter: a modular tool that statically analyzes .cto model files and reports issues (naming, structural problems, reserved keywords, etc.) so models are high-quality before they are consumed.
Solution. A configurable linter that: 1) provides a sensible default ruleset, 2) lets teams supply or extend rulesets, and 3) integrates via a straightforward API and a CLI command so checks can run locally or in CI.
Goals. Catch common model issues early, reduce human review overhead, and provide actionable guidance rather than opaque errors.
Quick highlights
- ✅ Modular
@accordproject/concerto-linterpackage - ✅ Portable default ruleset package
@accordproject/concerto-linter-default-ruleset - ✅ Programmatic API (
lintModel) andconcerto lintCLI
Install
Basic usage (CTO string)
Parsed AST (ModelManager)
Options (most useful)
ruleset: path to a custom Spectral ruleset or'default'to force the built-in ruleset.excludeNamespaces: override default exclusions (e.g.concerto.*,org.accordproject.*).
For comprehensive details, including additional examples and usage patterns, see the concerto-linter README
Syntax
Key options
--model <file>– path to .cto model(s)--exclude <namespace>– exclude a namespace--json– JSON output--ruleset <file|'default'>
Examples
@accordproject/concerto-linter-default-ruleset provides a curated set of Spectral rules tuned to concerto ASTs. It ships as a separate npm package so teams can consume or extend it.
Available rule categories:
namespace-version– ensure namespace includes a versionno-reserved-keywords– prevent use of reserved identifierspascal-case-declarations– declaration names must be PascalCasecamel-case-properties– property names must be camelCaseupper-snake-case-enum-constants– enum constants in UPPER_SNAKE_CASEpascal-case-decorators– decorator names in PascalCasestring-length-validator– string properties should have length validatorsno-empty-declarations– disallow empty declarationsabstract-must-subclassed– require concrete subclasses for abstract types
How to customize (summary)
- Extend the default ruleset with
extends: '@accordproject/concerto-linter-default-ruleset'. - Disable specific rules by setting their ID to
off. - Set severity levels (
error,warn,info,hint). - Create custom rules using Spectral’s
given/thenconstructs or custom functions when needed.
For more configuration examples, and extension guidance are available in the default ruleset README
Challenge 1 – Understanding the existing architecture, defining the linter shape with configurable behavior
Problem. The concerto repository is large and feature-rich; I needed to identify stable extension points and design a simple, maintainable configurable linter architecture that fits the existing ecosystem.
How I solved it. First, I defined a high-level architecture up front: a small, focused linter runtime, a separate default-ruleset package. I exposed a simple programmatic API (lintModel) with configuration and built-in support for loading rulesets. Through iterative development, we incrementally refined the solution until it reached the full set of required features.. Finally, I delivered thorough README usage examples, configuration guides, and a comprehensive unit/integration test suite so the linter is reliable, easy to extend, and simple for other contributors to use.
Merged PRs:
- feat: Add concert-linter package structure and naming convention rules #1027
- feat(linter): Add configurable linter support #1036
- feat(linter): Introduce default-ruleset package for extensibility #1038
- Fix: Resolve default-ruleset Publish Failure #1039
- docs(linter): update READMEs and add unit tests for all rules #1060
Problem: A default ruleset must be practical and relevant; it cannot be a collection of arbitrary checks. Finding and implementing rules that actually improve model quality required research and careful design.
How I solved it: I reviewed common modeling mistakes from real-world examples, prioritized rules that give actionable fixes, and implemented them using Spectral constructs (and custom functions where needed).
Merged PRs:
- feat: add new default ruleset #1045
- feat(linter): Add string length, PascalCase decorator name rules #1054
- fix(linter): add reserved-keywords rule and enhance decorator-name rule #1056
Problem: Consumers (API users and CLI users) expect a predictable output shape and filtering options (namespaces, JSON output, severity levels). Designing the output and CLI UX required coordination between the linter library and the CLI tooling.
How I solved it: I refactored the linter output to a stable shape, added namespace filtering, and implemented the concerto lint command so both programmatic and CLI consumers get consistent results.
Merged PRs:
- feat(linter): refactor lintModel output shape & add namespace filtering #1057
- feat(linter): add lint command #78
The concerto Linter lays the foundation for improved model quality across the Accord ecosystem. It ships a default ruleset, a programmatic API, a CLI, and configuration discovery, enabling teams to adopt the tool in local development and CI.
Next steps / future work
- Expand the ruleset with community-driven rules (advanced inheritance checks, template-specific hints).
- Tune severity and default rule choices based on ecosystem feedback.
- Integrate lint annotations into the Accord VSCode extension so
.ctofiles show inline diagnostics.
One of the greatest benefits of this project was the weekly Working Group (WG) meetings. They showed me how a professional team and organizational workflow operate and elevated my software career to a new level of professionalism. The routine of proposing what I would do and receiving feedback from the entire WG helped me iterate toward the best and most useful solutions. The 1:1 sessions with Jamie were also incredibly valuable, Jamie provided a clear plan and guidance that I followed throughout the project, which made a big difference in both my progress and learning.
The development of the concerto Linter was guided by the Accord Project community. Special thanks to all my mentors for technical mentorship and advice on rules design and configuration. Thanks to contributors to Spectral and the open-source community for tools that made this possible. This work was completed as part of Google Summer of Code 2025 with the support of the Accord Project (a Linux Foundation initiative) and is released under the Apache 2.0 License.