Without --rules, the CLI looks for a rules/ directory in the current
working directory. Use the --rules <dir> option to point to any other
directory.
A local rules/ directory is the legacy path. The recommended way to
manage a rule set is platform profiles
declared in .codecharter/config.yml. Profiles and an auto-discovered
rules/ folder are mutually exclusive: once profiles are configured, the run
uses only the profile rules and any local rules/ directory is ignored,
unless you pass an explicit --rules <dir>, which always wins. Running with
only built-in or local rules and no profiles configured prints a deprecation
notice pointing you to platform profiles. The layout below still applies to
custom rules you keep in the repo, whether you load them via --rules or
bundle them into a local 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.