Relationship to other pages: this tutorial walks you through writing your first rule step by step. Syntax overview is the compact everyday reference; DSL grammar is the formal appendix.
The simplest meaningful CodeCharter rule is nine lines long. Here it is:
@name "Class must not be named Manager"
@severity warn
@category "Naming"
@description "Classes called *Manager are vague, name them after what they actually do"
@recommendation "Pick a verb-based name: OrderProcessor, EmailDispatcher, PriceCalculator"
from t in Types
where t.Kind == "Class"
where t.Name.EndsWith("Manager")
select t
Save this as rules/no-manager-suffix.ccr in your repo. If you prefer not to
start from scratch, codecharter init creates the rules/ directory with two
example rules for you. Then run the analysis from the repo root — analyze
expects the path to a .sln, .slnx, or .csproj file:
codecharter analyze MySolution.sln
The rules/ directory in the current working directory is picked up
automatically. If you have a class with a Manager suffix, it will appear as a
Finding. When your project does not use platform profiles yet, the CLI also
prints a deprecation note on stderr; it does not stop the analysis and can be
suppressed by setting CODECHARTER_SUPPRESS_DEPRECATION_WARNING=1.
What's Happening Here
Five lines of metadata and four lines of query. Let's walk through it.
Metadata
All directives are optional and have sensible defaults. The rule slug comes from
the file name (no-manager-suffix), not from @name. @name is the
human-readable title shown in the CI log and output formats; when omitted it
defaults to the file name. @severity defaults to warn when omitted —
unrecognized values also fall back to warn, so watch out for typos.
@name "Class must not be named Manager"
@severity warn
@category "Naming"
@description "..."
@recommendation "..."
| Directive | Required | Default | Description |
|---|---|---|---|
@name |
no | filename | Human-readable title |
@severity |
no | warn |
info, warn, or error |
@category |
no | General |
Freely chosen; groups related rules |
@description |
no | — | What the rule checks |
@recommendation |
no | — | How to fix it |
All are optional, but filling in at least @name, @description, and
@recommendation makes findings much more actionable.
Query
The body is a LINQ query against the code model:
from t in Types // all types
where t.Kind == "Class" // classes only
where t.Name.EndsWith("Manager") // with Manager suffix
select t // returns all matches as findings
Comments in .ccr files use //. select t is the required closing clause.
Whatever you select becomes a Finding — t is a TypeModel, so the Finding
will point to the file and line where t is declared.
Variant: Banning Several Suffixes
@name "No vague class suffixes"
@severity warn
from t in Types
where t.Kind == "Class"
where t.Name.EndsWith("Manager")
|| t.Name.EndsWith("Helper")
|| t.Name.EndsWith("Util")
select t
Conditions combine with && and ||. The query language supports a fixed set
of LINQ-style methods such as Where, Any, OrderBy, and Count; the
Syntax overview lists what is available.
Variant: Combining Multiple Conditions
A rule that finds only classes that are too large AND have too many fields:
@name "Large class with many fields, split candidate"
@severity warn
@category "Design"
from t in Types
where t.Kind == "Class"
where t.LinesOfCode > 400
where t.Fields.Count > 15
select t
Testing Your Rule
codecharter test rules/no-manager-suffix.ccr --scaffold writes a starter spec
file rules/no-manager-suffix.spec.md next to the rule. Fill in code snippets
the rule should and should not flag, then run codecharter test rules/ to verify
the rule against them.
More Complete Examples
The Rule examples page has a gallery of ready-to-copy rules by category, including the full Manager-suffix and async/CancellationToken patterns. Refer there once you are comfortable with the basics above.
Where to Go Next
- File Structure — how the
rules/directory is organized - Syntax Overview — collections overview and query forms
- Predicate catalog — full property catalog for all model types
- Best Practices — what separates good rules from bad ones