CodeCharter lets you track requirements right next to the code that implements
them. Each requirement is one Markdown file with a YAML frontmatter block under
.codecharter/req (the legacy .codeguard/req location is still read). There is
no database and no external tool: the requirement corpus is just files in your
repository, so it reviews, diffs, and merges like everything else.
The .req.md file
A requirement file has YAML frontmatter between --- fences, followed by a
Markdown body:
---
id: REQ-1
title: Users can reset their password
priority: must
contractual: true
status: implemented
kind: functional
section: Account management
source: spec.md#3.2
relations:
refines:
- REQ-0
conflicts:
- REQ-9
criteria:
- id: C1-1
rule: some.dsl.expression()
status: open
blocked_by:
- C1-2
confidence: needs-predicate
- id: C1-2
test: Tests.Auth.PasswordReset_Should_SendEmail
anchors:
- symbol_id: MyApp.Auth.PasswordResetService
---
Describe the requirement in prose here. Full sentences, not bullet fragments —
this is what a reviewer or auditor reads to understand the "why".
## Out of Scope
Single sign-on providers are not covered by this requirement.
All keys are snake_case. Value tokens (priority, status, kind, and the
criterion/anchor keys below) are English and kebab-case, so a requirement file
reads the same regardless of the team's spoken language.
Frontmatter fields
| Key | Required | Value | Meaning |
|---|---|---|---|
id |
yes | <Prefix>-<Number>, e.g. REQ-1 |
Stable identifier. Referenced by refines, conflicts, and documents.yml. |
title |
yes | free text | Short, human-readable summary. |
priority |
yes | must / should / could |
MoSCoW priority. |
contractual |
yes | true / false |
Whether this requirement is part of a binding agreement (a contract, an SLA) rather than an internal goal. |
status |
yes | open / in-progress / implemented / partial |
Current delivery state. |
kind |
yes | functional / security / legal / performance / usability / infrastructure |
Category. |
section |
no | free text | Where this requirement lives in a source specification document. |
source |
no | free text | A pointer back to that source, e.g. a file and section reference. |
relations.refines |
no | list of ids | Requirements this one narrows or specializes. |
relations.conflicts |
no | list of ids | Requirements this one is documented to be in tension with. |
criteria |
no | list | See below. |
anchors |
no | list | See below. |
Every top-level key not in this table is rejected — but only with a warning,
not an error, because an unknown key is more likely a field from a newer
CodeCharter version than a typo. codecharter req check still tells you about
it, though, so it does not pass unnoticed.
Criteria
A criterion is one acceptance check for the requirement. Each needs an id and
exactly one of five carrier keys, which say how the criterion is verified:
| Carrier | Meaning |
|---|---|
rule: |
A CodeGuard rule DSL expression that must hold. |
test: |
A specific automated test that exercises this criterion. |
manual: |
A step a human verifies (e.g. in a manual QA pass). |
integration: |
An integration or contract test suite. |
external: |
Verified by something outside this repository (an audit, a third party). |
A criterion with zero carriers, more than one carrier, or an empty carrier
value is invalid — codecharter req check reports it.
Optional criterion keys:
status: openmarks a criterion not yet satisfied. Omit the key for a satisfied criterion — there is no explicit "closed" token.blocked_by:lists the ids of other criteria (in this or another requirement) that must land first.confidence: needs-predicateflags a criterion whoserule:expression is a placeholder, not yet backed by a real, checkable predicate.
A requirement marked status: implemented while one of its criteria is still
status: open is a contradiction codecharter req check catches — you cannot
claim a requirement is done while its own acceptance check says otherwise.
Anchors
An anchor links a requirement to the code that satisfies it. Three kinds exist today, all declaration-only (no runtime verification yet):
| Anchor | Keys | Meaning |
|---|---|---|
| Attribute-expected | attribute_expected: |
Names a fully-qualified type; the requirement is satisfied by any symbol carrying [Satisfies("REQ-1")] from the CodeCharter.Annotations package on a member assignable to that type. |
| File selector | file: + selector: |
Points at a file path and a textual selector (e.g. a class declaration) inside it. |
| Symbol id | symbol_id: |
Names a fully-qualified symbol directly. |
A requirement with status: implemented or status: partial and no anchor at
all is an error — an "implemented" requirement with nothing pointing at the
code that implements it cannot be traced. The same gap on an open or
in-progress requirement is only a warning: it is normal for work not yet
started to have no anchor yet.
## Out of Scope
A ## Out of Scope heading in the body (case-insensitive, any amount of
whitespace) starts a delimitation section: everything after it is read as the
boundary of the requirement — what it deliberately does not cover. Keeping
this in the same file as the requirement itself means the boundary travels
with the requirement instead of living in a separate, easily-forgotten note.
documents.yml: organizing requirements into documents
Alongside the .req.md files, an optional .codecharter/req/documents.yml
groups requirements into documents and chapters — a requirements
specification, a functional specification, an acceptance protocol:
title_page:
title: Sample Product — Requirements
subtitle: Volume 1
customer: ACME Corp
project: Sample Product
version: "1.0"
issued_on: "2026-01-01"
documents:
- slug: requirements-specification
kind: requirements-specification
title: Requirements Specification
chapters:
- slug: account-management
title: Account management
requirements:
- REQ-1
- REQ-2
kind is one of requirements-specification, functional-specification, or
acceptance-protocol. codecharter req check cross-references the chapter
requirements lists against the corpus: an id that does not exist anywhere is
an error, and a requirement that exists but appears in no chapter is a
warning, so nothing quietly falls out of the published document set.
Checking the corpus
Run codecharter req check to validate everything described on this page —
duplicate ids, dangling refines/conflicts references, criteria without a
usable carrier, the implemented-with-open-criteria contradiction, missing
anchors, and the documents.yml cross-references. See
codecharter req check for the full list of codes, exit
codes, and output formats.
Reading requirements from an AI coding tool
An agent working in your codebase can read this same corpus over MCP without
ever touching a .req.md file directly: see
Requirements over MCP for the three
read-only tools (req_context, req_search, req_justify).