A rule directory runs when it is declared under rules: in
.codecharter/config.yml (codecharter config add rules rules), resolved
against the repository root, or passed with --rules <dir>. A folder is never
picked up just because it exists.
Declared directories run alongside the
platform profiles in the same file: the
profiles first, then the rules: directories, then any --rules directory. A
later source wins on a duplicate rule id, and the run names each shadowed id.
The layout below applies to every rule directory you keep in the repo,
whether you declare it, pass it with --rules, or bundle it into a profile.
Recommended Layout in the Repo
rules/
├── architecture/
│ ├── domain-must-not-reference-web.ccr
│ └── repository-naming.ccr
├── naming/
│ ├── no-manager-suffix.ccr
│ ├── no-manager-suffix.spec.md
│ └── async-suffix.ccr
└── team-conventions/
└── controller-action-limit.ccr
.codecharter/config.yml
Subdirectories under rules/ are freely chosen. CodeCharter reads all .ccr
files recursively. Older .cgr files from before the rename from CodeGuard
to CodeCharter are still read for backward compatibility, so existing
repositories keep working without changes.
The rule ID is the file name without the .ccr extension; subdirectory names
carry no meaning. These IDs are what .codecharter/config.yml entries and
suppression comments reference, so avoid using the same file name in different
folders.
Spec tests live as <rule-name>.spec.md next to the .ccr file and are
discovered recursively by codecharter test.
Initializing rules/
codecharter init
Creates a rules/ directory with two example rules that you can grow from.
.codecharter/config.yml
The repository configuration lives at .codecharter/config.yml. Among other
sections, ignore switches rules off (optionally limited to a namespace or
matching entity names) and exclude removes whole paths from analysis:
version: 1
ignore:
- rule: namespace-distance
in: Acme.Generated
- rule: async-suffix
exclude:
- "**/tests/**"
- "**/obj/**"
See Configuration file for all sections (profiles, parameters, severities, rule activation, and path scopes).
Inline Suppressions
Per location in code:
// codecharter-disable-next-line datetime-direct-usage
var migrationTimestamp = DateTime.UtcNow;
The rule ID in the comment must match the rule's file name exactly, including casing. See Suppressions for all variants.
Platform Profiles in the Repo
When you use platform profiles, you list them in .codecharter/config.yml;
codecharter.lock.json (pinning each profile by content hash) and the
downloaded rule bundles both live under .codecharter/:
.codecharter/
├── config.yml
├── codecharter.lock.json
└── cache/
Commit config.yml and codecharter.lock.json; cache/ is a local download
cache and should stay out of version control (see
Configuration file).
Multi-Repo and Monorepo
In a monorepo you can have rules/ directories per sub-project and point to
them with --rules. CodeCharter finds .codecharter/config.yml by walking up from
the file being analysed, so a config at the repository root applies everywhere
beneath it.