Skip to content

Hello-World DSL

The smallest possible CodeCharter rule of your own. Explained step by step.

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