Skip to content

Latest commit

 

History

History
914 lines (667 loc) · 51.5 KB

cli-reference.md

File metadata and controls

914 lines (667 loc) · 51.5 KB

CLI Reference

Use npx charter ... if Charter is installed as a local dev dependency. Use charter ... if installed globally.

Governance Commands

charter validate

Checks commit trailers for governance compliance. Every commit should carry a Governed-By: trailer linking it to an ADR or governance decision.

npx charter validate                       # check recent commits
npx charter validate --ci                  # CI mode — exits 1 on violations
npx charter validate --ci --format json    # machine-readable output
npx charter validate --range HEAD~5..HEAD  # specific commit range

Default range detection: When --range is omitted, Charter tries main..HEAD or master..HEAD first, then falls back to the most recent 5 commits.

JSON output includes policyOffenders (missing required trailers) and riskOffenders (high-risk paths without governance), plus effectiveRangeSource and defaultCommitRange for agent transparency.

When git.requireTrailers is enabled, trailer presence is evaluated per commit. A trailer on one commit does not satisfy other commits in the selected range. validation.citationStrictness controls whether missing per-commit trailers fail or warn.

charter drift

Scans the codebase for deviations from your blessed stack patterns. Detects unapproved dependencies, frameworks, and patterns defined in .charter/patterns/*.json.

npx charter drift                         # scan + print report
npx charter drift --ci --format json      # CI mode
npx charter drift --path ./packages       # scan a specific directory

charter audit

Generates a governance posture report: risk score, governed commit ratio, recent violations, and trend data. Policy score uses configurable section coverage.

npx charter audit
npx charter audit --format json
npx charter audit --range HEAD~10..HEAD

charter classify

Classifies a subject or change request into a governance scope.

Scope Meaning
SURFACE UI/copy only, low risk
LOCAL Contained to one module
CROSS_CUTTING Touches multiple systems, requires ADR
npx charter classify "add OAuth callback flow"
npx charter classify "migrate auth provider" --format json

charter hook

Installs git hooks for commit-time governance enforcement.

npx charter hook install --commit-msg                # trailer gate + normalization hook
npx charter hook install --pre-commit                # ADF evidence gate hook
npx charter hook install --commit-msg --pre-commit   # both hooks
npx charter hook install --commit-msg --force        # overwrite existing hooks
  • --commit-msg — normalizes Governed-By and Resolves-Request trailers via git interpret-trailers; rejects a message with neither trailer in its final trailer block whenever charter validate --ci would fail it, reading .charter/config.json with validate's defaults (requireTrailers on unless falsy, citationStrictness FAIL, an unparseable file treated as the defaults). It blocks under FAIL/STRICT or ci.failOnWarn and warns under advisory strictness. No .charter/config.json at all, or no node on PATH, skips the gate with a warning. # lines are stripped before the check, as the default editor cleanup does, so under -m or --cleanup=verbatim a trailer followed by a #... line can pass locally and fail CI.
  • --pre-commit — runs ADF evidence checks (LOC ceiling validation) before each commit. Only gates when .ai/manifest.adf exists.
  • --force — overwrite existing non-Charter hooks

Must specify at least one of --commit-msg or --pre-commit.

charter bootstrap

One-command repo onboarding. Orchestrates detect + setup + ADF init + install + doctor in a single flow.

npx charter bootstrap                                         # interactive
npx charter bootstrap --preset worker --ci github --yes       # fully automated
npx charter bootstrap --preset worker --security-sensitive     # security posture baseline
npx charter bootstrap --skip-install --skip-doctor            # minimal
  • --ci github — generate GitHub Actions governance workflow
  • --preset <worker|frontend|backend|fullstack|docs|rust-wasm> — stack preset
  • --security-sensitive — generate SECURITY.md, seed hard-fail drift denies in .charter/patterns/security-deny.json, and warn in doctor when no security* or l4* test file exists
  • --skip-install — skip dependency installation phase
  • --skip-doctor — skip health check phase
  • -y, --yes — accept all prompts

charter setup

Bootstraps .charter/ config and optionally writes CI workflow scaffolding. For full onboarding, prefer charter bootstrap which orchestrates setup + ADF init + install + doctor.

npx charter setup --detect-only --format json
npx charter setup --ci github --yes
npx charter setup --preset fullstack --ci github --yes
npx charter setup --preset rust-wasm --ci github --yes

Setup-specific options:

  • --ci github — generate GitHub Actions governance workflow
  • --preset <worker|frontend|backend|fullstack|docs|rust-wasm> — stack preset
  • --detect-only — preview detection results without writing files
  • --no-dependency-sync — skip rewriting @stackbilt/cli devDependency

charter init

Scaffolds the .charter/ config directory without running the full setup workflow.

npx charter init
npx charter init --preset worker

This writes .charter/.gitignore, which marks the local-only parts of .charter/ — .cache/, context.md, and telemetry/. Everything else under .charter/ (config, patterns, policies) is meant to be committed.

Upgrading: untracking already-committed telemetry

.charter/telemetry/events.ndjson is per-machine usage data. Releases before the telemetry/ ignore rule did not exclude it, so repos bootstrapped with an older CLI may already have it committed — where it grows with every command and conflicts on every merge between machines.

Adding the ignore rule does not untrack a file that is already in the index. Re-running charter init or charter bootstrap updates .charter/.gitignore, but existing repos must also untrack the file once:

git rm -r --cached .charter/telemetry
git commit -m "chore: stop tracking local charter telemetry"

This removes it from version control while leaving it on disk, so charter telemetry report keeps working.

charter doctor

Checks CLI installation and repository config health. Validates ADF readiness: manifest existence, manifest parse, default-load module presence, sync lock status, and agent config file migration status. When trailers are required with FAIL/STRICT citation validation, doctor also warns unless an active git hook or GitHub Actions workflow invokes charter validate --ci. It additionally reports when <configPath>/telemetry is tracked in the git index — see Tracked telemetry below.

npx charter doctor                    # full diagnostics
npx charter doctor --adf-only         # ADF checks only (skip Charter config)
npx charter doctor --ci --format json # CI mode: exit 1 on warnings
  • --adf-only — run only ADF readiness checks, skip Charter config validation
  • --ci — non-interactive, exits with policy violation code on warnings

The hook installed by charter hook install --commit-msg counts as a local trailer gate: it rejects a commit with no trailer under a strict policy. A commit-msg hook installed before the gate existed only normalizes trailers that are present; doctor names it and asks for a re-install. The local hook checks only the commit being written, so CI should still run charter validate --ci; the workflow generated by charter setup --ci github includes that step.

Tracked telemetry

Charter appends to <configPath>/telemetry/events.ndjson on every run. In a repo bootstrapped before that path was added to the generated <configPath>/.gitignore, nothing stopped the log from being staged, so it may already be tracked — and once it is, every git add -A stages it again, because an ignore entry alone never untracks a file already in the index.

doctor reads the git index for <configPath>/telemetry and, when anything there is tracked, names the files and the two-step remedy: ensure telemetry/ is ignored, then git rm -r --cached "<configPath>/telemetry". In that order, because after the untrack the file is still on disk and a reflexive git add -A would otherwise re-stage it. The log is never deleted, so charter telemetry report keeps working.

This is advisory (INFO) and never fails CI — the condition is state Charter's own bootstrap created, not something you opted into, so it cannot break an existing repo's build on upgrade. The check reads only the git index (never the filesystem), so it behaves identically on case-sensitive and case-insensitive checkouts, and it is skipped under --adf-only and outside a git repository.

Source LOC budgets (god-object drift)

The ADF entry_loc metric only caps the single entry file. To stop other runtime source files from quietly growing into god-objects, declare per-path LOC budgets in .charter/config.json. charter doctor then measures matching files and reports them:

{
  "locBudgets": {
    "defaultWarn": 300,
    "defaultFail": 600,
    "paths": [
      { "pattern": "src/index.ts", "warn": 200, "fail": 500, "reason": "entry should stay thin" },
      { "pattern": "src/**", "warn": 300, "fail": 600 }
    ]
  }
}
  • Patterns match repo-relative paths: * within a single path segment, ** across segments, everything else literal. The first matching rule wins, so list more specific patterns first. Per-rule warn/fail fall back to defaultWarn/defaultFail.
  • Enforcement is opt-in and graduated. A file over its fail ceiling is a WARN doctor check — under --ci this exits non-zero, failing the build. A file over warn but within fail is advisory (INFO) and never fails CI. Set "enabled": false to keep a config block without enforcing it.
  • No budgets configured? doctor emits a soft, non-blocking INFO nudge so teams know entry_loc alone leaves other files uncovered — it never fails an existing repo's CI on upgrade.

charter why

Prints a quick explanation of Charter's governance value and adoption ROI.

npx charter why

charter score

Deterministic local AI-readiness audit. Grades the repo across agent config, grounding, architecture, testing, governance and freshness, and prints a letter grade out of 100. No network calls and no model inference — the same repo scores the same every run.

npx charter score                     # full report
npx charter score --format json       # machine-readable
npx charter score --ci                # exit 1 when the score is below 60
npx charter score --badge             # shields.io endpoint JSON on stdout
npx charter score --badge --write     # also write .charter/badge.json
  • --ai-dir <dir> — override the ADF directory (default: .ai)
  • --ci — exit 1 when the score is below 60
  • --badge — print shields.io endpoint JSON instead of the full report
  • --badge --write — additionally write the badge JSON to .charter/badge.json

Grounding and path references. The grounding dimension counts how many file paths referenced in your docs actually resolve. A reference that does not exist at its literal path is retried by filename: if exactly one file in the repository has that basename and the referenced path's trailing segments match that file's, it counts as resolved. This is what stops a fenced directory tree — where the prefix is carried by indentation rather than written out — from scoring as dozens of broken references. Ambiguous basenames, and paths whose directories disagree with the match, stay broken, so a genuinely stale reference is still reported (#293).

The file inventory comes from git ls-files --cached --others --exclude-standard where available, so dependencies and build output cannot resolve a reference.

charter telemetry

Reports local command telemetry. Reads <configPath>/telemetry/events.ndjson, which Charter appends to on every run. Command metadata only — no prompt text and no code content.

npx charter telemetry report                  # default: last 7d
npx charter telemetry report --period 24h     # 30m | 24h | 7d

The log is local and is not uploaded anywhere. It should not be committed: charter doctor reports when it is tracked in the git index and names the fix — see Tracked telemetry.

charter stamp-policies

Stamps the policy-repo reference into the repo's governance config so policy citations resolve to a pinned commit rather than a moving branch.

npx charter stamp-policies                              # resolve the ref automatically
npx charter stamp-policies --dry-run                    # preview without writing
npx charter stamp-policies --policy-repo-ref <sha>      # pin explicitly
npx charter stamp-policies --no-fix-pins                # stamp without rewriting existing pins
npx charter stamp-policies --path <dir>                 # target another checkout
  • --policy-repo-ref <sha> — explicit ref; otherwise CHARTER_POLICY_REPO_REF is used, and failing that the ref is resolved automatically
  • --dry-run — report what would change without writing
  • --no-fix-pins — leave existing pins untouched
  • --path <dir> — operate on a different repository (default: .)

ADF Commands

ADF (Attention-Directed Format) is Charter's modular AI context compiler. These commands manage the .ai/ directory.

charter adf init

Scaffolds .ai/ directory with preset-aware modules. The scaffolded core.adf includes a [load-bearing] CONSTRAINTS section and a METRICS [load-bearing] section with starter LOC ceilings.

npx charter adf init
npx charter adf init --ai-dir ./context       # custom directory
npx charter adf init --force                  # overwrite existing
npx charter adf init --emit-pointers          # generate thin pointer files
npx charter adf init --module testing         # add a single module to existing .ai/
  • --ai-dir <dir> — custom directory path (default: .ai). Resolved to an absolute path at runtime.
  • --force — overwrite existing files. Without this flag, existing .adf files are skipped and reported; only the missing manifest.adf is written.
  • --emit-pointers — generate thin pointer files (CLAUDE.md, .cursorrules, AGENTS.md). The generated CLAUDE.md includes a ## Session Start section with guidance to call the charter_context MCP tool at session start, giving agents the live constraint surface before any other action.
  • --module <name> — add a single module to existing .ai/ (delegates to adf create)

Default scaffolding (worker/frontend/backend/fullstack presets):

File Purpose
manifest.adf Module registry with default-load and on-demand routing
core.adf Universal constraints, metrics, and project context
state.adf Current session state
frontend.adf Frontend module scaffold (triggers: React, CSS, UI)
backend.adf Backend module scaffold (triggers: API, Node, DB)

Docs preset (--preset docs):

File Purpose
manifest.adf Docs-specific module routing
core.adf Universal constraints and metrics
state.adf Current session state
decisions.adf ADR and decision tracking (triggers: ADR, decision, rationale)
planning.adf Roadmap and milestone tracking (triggers: plan, milestone, phase, roadmap)

Rust/WASM preset (--preset rust-wasm):

File Purpose
manifest.adf Rust/WASM-specific module routing (triggers: Cargo, WASM, wasm-pack, wasm-bindgen, cdylib, wasm32)
core.adf Universal constraints and metrics
state.adf Current session state
rust-wasm.adf Library constraints: pure exports, dual crate-type, wasm-pack build/test gates, pkg/ publish boundary

charter bootstrap --preset rust-wasm also scaffolds: Cargo.toml (cdylib + rlib), src/lib.rs, tests/integration.rs, root package.json (private, wasm-pack scripts), .gitignore (excludes pkg/, target/), and .github/workflows/ci.yml (Rust toolchain + wasm32 target + wasm-pack test + wasm-pack build steps).

charter adf create

Creates a new ADF module file and registers it in the manifest under DEFAULT_LOAD or ON_DEMAND.

npx charter adf create api-patterns                           # on-demand module (default)
npx charter adf create core-rules --load default              # default-load module
npx charter adf create react --triggers "react,jsx,component" # on-demand with triggers
npx charter adf create api-patterns --force                   # overwrite existing
  • --load <default|on-demand> — loading policy (default: on-demand)
  • --triggers "a,b,c" — comma-separated trigger keywords (for on-demand modules)
  • --ai-dir <dir> — path to ADF directory (default: .ai)
  • --force — overwrite existing module file

charter adf migrate

Scans existing agent config files (CLAUDE.md, .cursorrules, agents.md, GEMINI.md, copilot-instructions.md), classifies their content, and migrates structured blocks into ADF modules. Replaces originals with thin pointers.

npx charter adf migrate --dry-run                # preview migration plan
npx charter adf migrate --yes                    # execute migration
npx charter adf migrate --source CLAUDE.md       # migrate a single file
npx charter adf migrate --merge-strategy replace # overwrite existing sections
npx charter adf migrate --no-backup              # skip .pre-adf-migrate.bak files
  • --dry-run — preview changes without writing files
  • --source <file> — migrate a specific file instead of scanning all
  • --merge-strategy <append|dedupe|replace> — how to handle duplicates (default: dedupe)
  • --no-backup — skip creating backup files
  • --ai-dir <dir> — path to ADF directory (default: .ai)

Every module that receives content is registered in manifest.adf, after the module merge and before the pointer is written, so the CLAUDE.md module index lists it. core.adf and state.adf go to DEFAULT_LOAD. Other modules go to ON_DEMAND, with up to 6 triggers inferred from the headings routed there. The heading word the router matched (e.g. deployment) counts double, and words that already trigger another module are left out. When nothing usable is left, the module's lowercase file stem is the trigger. Registration is append-only: an existing entry is never rewritten or moved, and its triggers are never merged. New bullets are inserted as text after the section's last item. Every other byte of the manifest is left as it was, including comments, section order and line endings. Already-registered modules are reported with their existing section and triggers. When core.adf is listed under ON_DEMAND, migrate warns instead of moving it. When manifest.adf is missing, registration is skipped with a warning to run charter adf init. The plan shows one REGISTER line per module, for example REGISTER .ai/manifest.adf (infra.adf → ON_DEMAND: deployment, docker [planned]), and --format json adds sources[].registrations[] with module, loadPolicy, triggers, triggerSources, reason, status (planned, added, already-registered or skipped) and, when skipped, skipReason. A --dry-run across several sources reports each module once. It does not simulate an earlier source's new triggers when routing a later source, though a real run does.

charter adf fmt

Parses and reformats ADF files to canonical form. Enforces emoji decorations, canonical section ordering, and 2-space indent.

npx charter adf fmt .ai/core.adf --write   # reformat in-place
npx charter adf fmt .ai/core.adf --check   # CI: exit 1 if not canonical

charter adf patch

Applies typed delta operations to ADF files. Agents issue patches instead of rewriting entire files — preventing silent memory corruption.

npx charter adf patch .ai/state.adf --ops '[{"op":"ADD_BULLET","section":"STATE","value":"Reviewing PR #42"}]'
npx charter adf patch .ai/state.adf --ops-file patches.json

Operations: ADD_BULLET, REPLACE_BULLET, REMOVE_BULLET, ADD_SECTION, REPLACE_SECTION, REMOVE_SECTION, UPDATE_METRIC.

With --format json, the output includes a changes[] array showing per-op before/after values:

{
  "file": ".ai/core.adf",
  "patched": true,
  "opsApplied": 1,
  "changes": [
    { "op": "UPDATE_METRIC", "section": "METRICS", "key": "total_loc", "before": 280, "after": 312 }
  ]
}

For bullet ops, before is the original item text (or null for ADD_BULLET); after is null for REMOVE_BULLET.

charter adf bundle

Resolves manifest modules for a given task and outputs merged context with token estimate. Only loads modules whose trigger keywords match the task.

npx charter adf bundle --task "Fix the React login component"
npx charter adf bundle --task "Add REST endpoint" --format json

JSON output includes triggerMatches (with matchedKeywords and loadReason), unmatchedModules, tokenEstimate, tokenBudget, tokenUtilization, and perModuleTokens.

charter adf sync

Verifies source .adf files match locked hashes, or updates the lock file.

npx charter adf sync --check               # CI: exit 1 on drift
npx charter adf sync --write               # update .adf.lock
npx charter adf sync --check --format json

Sync tracks only manifest SYNC sources. With none declared, it says so and points to charter adf vendor status (also in JSON nextActions), since a stale adf compile --check is about vendor modes, not SYNC.

charter adf evidence

Validates metric constraints and produces a structured evidence report. The core of Charter's ADF governance pipeline.

npx charter adf evidence --auto-measure                     # full report
npx charter adf evidence --auto-measure --ci --format json  # CI gating
npx charter adf evidence --task "auth module" --auto-measure
npx charter adf evidence --context '{"entry_loc": 142}'
npx charter adf evidence --context-file metrics.json

--auto-measure counts lines in source files referenced by the manifest METRICS section and injects them as context overrides.

Constraint semantics: value < ceiling = pass, value === ceiling = warn, value > ceiling = fail.

CI mode: exits 1 on any constraint failure. Warnings (at boundary) surface in the report but do not fail the build.

Output includes constraint results, weight summary (load-bearing / advisory / unweighted), sync status, advisory-only warnings, and a nextActions array.

charter adf metrics recalibrate

Recalibrates metric baselines and ceilings from current measured LOC. Requires a rationale for every recalibration to maintain audit trail.

npx charter adf metrics recalibrate --auto-rationale                   # auto-generate rationale
npx charter adf metrics recalibrate --reason "post-refactor baseline"  # custom rationale
npx charter adf metrics recalibrate --headroom 20 --dry-run            # preview with 20% headroom
npx charter adf metrics recalibrate --auto-rationale --format json     # machine-readable
  • --headroom <percent> — percentage above current LOC for ceiling calculation (default: 15, range: 1–200)
  • --reason "<text>" — required rationale text (mutually exclusive with --auto-rationale)
  • --auto-rationale — auto-generate rationale from headroom and metric count
  • --dry-run — preview recalibration without writing files
  • --ai-dir <dir> — custom .ai/ directory (default: .ai)

Behavior: Parses all METRICS sections across manifest modules, measures current source file line counts, calculates new ceilings as ceil(current × (1 + headroom / 100)), and appends entries to the BUDGET_RATIONALES section with format:

{metric}_{ISO_DATE}: {old} -> {new}, ceiling {oldCeiling} -> {newCeiling}; {rationale}

One of --reason or --auto-rationale is required.

charter adf compile

Outbound compiler: renders the .ai/*.adf source tree into flat vendor agent-config files. The inverse of charter adf migrate and charter adf tidy, which fold vendor content back into .ai/.

npx charter adf compile --target claude                 # print to stdout
npx charter adf compile --target all --write            # re-render targets in compiled mode (or absent)
npx charter adf compile --target all --write --mode compiled # also switch pointer/unmanaged files to compiled
npx charter adf compile --target all --check            # CI drift gate, by each file's mode
npx charter adf compile --target claude --write --force # overwrite hand-authored content (never changes mode)
  • --target <claude|agents|cursor|gemini|all> — vendor target: claude→CLAUDE.md, agents→AGENTS.md, cursor→.cursorrules, gemini→GEMINI.md. all requires --write or --check.
  • --write — write output to the repo root for each target in compiled mode or absent, subject to the overwrite guard below
  • --mode compiled — with --write, also convert targets in pointer or unmanaged mode. The VENDORS record is set to compiled before the file is written; if it cannot be recorded, nothing is written (refused-record, exit 1). If the file write itself fails, that target's record is restored, the target is reported as refused-record with writeError, and the remaining targets are still processed (exit 1). compiled is the only accepted value: to make a file a pointer, run charter adf vendor set <file> pointer. --mode without --write, or another value, exits 2.
  • --check — verify each target by its mode; exit 1 on drift (see below)
  • --force — with --write, bypass the overwrite guard. It never changes a file's mode: a pointer or unmanaged target still needs --mode compiled.
  • --ai-dir <dir> — custom .ai/ directory (default: .ai)

Default with no --write or --check prints to stdout, single target only.

Modes. Each target's mode comes from the VENDORS record in manifest.adf (see charter adf vendor). A file with no entry is classified by its markers: the compile banner means compiled, a pointer marker means pointer, anything else is unmanaged. A missing file with no entry is compiled as before.

--write per target:

Mode --target all single --target with --mode compiled
compiled, or absent and unrecorded written written written
pointer skipped (its [skip] line names the command), exit 0 refused, exit 1 record set to compiled, then written as Written CLAUDE.md (mode: pointer -> compiled)
unmanaged skipped, exit 0 refused, exit 1 as pointer, but an existing hand-authored file also needs --force

When every target is skipped, compile says that nothing was written and how to switch. JSON output keeps written, refused and nextActions, and adds skipped and targets (one row per target: state, source, status, recordedMode, previousMode, remedy, writeError).

--check per target:

Status When Exit
fresh / stale compiled: bytes equal / differ (remedy: compile --target <t> --write) 0 / 1
missing no file on disk (a recorded pointer suggests git checkout -- <file> or adf vendor set <file> unmanaged) 1
pointer-ok pointer with nothing adf tidy would extract 0
pointer-bloated pointer carrying content that belongs in .ai/ (remedy: adf tidy --source <file>) 1
mode-drift recorded compiled or pointer, but the file looks like another mode. Both fixes are printed, the content-preserving one first; regenerating says how many items it would discard 1
skipped-unmanaged unmanaged: not checked 0

No --check remedy suggests compile --write for a pointer or unmanaged file. JSON output keeps stale (stale, bloated and drifted files), current, missing, upToDate and nextActions, and adds skipped and targets.

Overwrite guard. With --write and no --force, compile writes an existing file only when it recognises it as Charter-owned — either compiler output (carrying the compile banner) or a Charter thin pointer. It refuses in two cases:

  • the file is hand-authored and carries no Charter marker
  • the file is a pointer carrying your own content under a retained heading (## Environment and the other headings adf tidy retains) that the pointer template does not have

The second case matters because compiled output has no ## Environment section and .ai/ does not hold that content, so overwriting would lose it with no way back except git. Move such content into a .ai/ module first, or pass --force to discard it.

Both refusals happen before the record is touched, so a refused target never changes VENDORS.

charter adf tidy

Scans vendor config files for content added beyond the thin pointer, classifies it, routes it into ADF modules, and restores the pointer. Runs automatically in the generated pre-commit hook.

npx charter adf tidy                        # classify and route, restore pointers
npx charter adf tidy --dry-run              # preview without modifying files
npx charter adf tidy --dry-run --ci         # exit 1 if bloat found (pre-commit gating)
npx charter adf tidy --source CLAUDE.md     # single file
  • --dry-run — preview without modifying files
  • --ci — exit 1 if bloat is found; combine with --dry-run for gating
  • --source <file> — tidy a single file instead of scanning all vendor configs
  • --ai-dir <dir> — custom .ai/ directory (default: .ai)

Retained headings (## Environment, ## Module Index, ## Session*, and operational protocol headings) are kept in the vendor file verbatim rather than routed into .ai/.

Tidy reads each vendor file's mode from the VENDORS record and processes only pointers. Compiler output is skipped. A file carrying the GENERATED by charter adf compile banner is not a thin pointer — it is the full ruleset rendered from .ai/ — so tidy reports it and leaves it alone rather than folding .ai/ back into itself (#296). Edit the .ai/ modules and re-run charter adf compile --write instead. The banner wins whatever the record says. A file recorded compiled without a banner is also skipped (status compiled); its warning names the content-preserving fix first (adf vendor set <file> pointer, then adf tidy --source <file>) and says how many items regenerating would discard, and an unmanaged file (recorded, or hand-authored with no Charter marker; it used to report not-found) gets status unmanaged. A file recorded pointer that has no pointer marker is skipped rather than guessed at. JSON rows add vendorFile, mode, source and skipReason. A --source path that is not a repo-root vendor name keeps the marker logic. AGENTS.md and agents.md that are one file on disk are tidied once. Tidy never writes the record.

charter adf populate

Auto-fills ADF files from codebase signals — package.json, README, and stack detection. Populates CONTEXT in core.adf, backend.adf and frontend.adf, and STATE in state.adf.

npx charter adf populate --dry-run   # preview
npx charter adf populate             # fill empty sections
npx charter adf populate --force     # overwrite existing custom content
  • --dry-run — preview without writing
  • --force — overwrite sections that already hold custom content
  • --ai-dir <dir> — custom .ai/ directory (default: .ai)

Files with existing custom content are skipped unless --force is passed.

charter adf context

Resolves which ADF modules apply to a set of file paths and/or explicit keywords, deriving keywords from file extensions and directory names (for example src/components/*.tsx → react, ui, frontend).

npx charter adf context --files "src/api/routes.ts,src/db/schema.sql"
npx charter adf context --keywords "auth,migration"
npx charter adf context --files "src/ui/Button.tsx" --bundle
  • --files <paths> — comma-separated file paths to derive keywords from
  • --keywords <text> — additional keywords, in addition to any derived. Accepts a comma-separated list or free text: the value is split on whitespace and ,;:()[]{}, and single characters are dropped.
  • --bundle — emit the merged ADF document instead of the resolution summary
  • --ai-dir <dir> — custom .ai/ directory (default: .ai)

Reports the derived keywords and each resolved module as DEFAULT or ON_DEMAND.

charter adf suggest

Diagnostics over .charter/telemetry/events.ndjson: dead modules, recurring unmatched keywords, and modules that load while a downstream command still fails. Report-only — no module attribution is guessed and nothing is applied automatically.

npx charter adf suggest
npx charter adf suggest --min-occurrences 5
npx charter adf suggest --emit-ops /tmp/ops.json
  • --min-occurrences <n> — threshold before a signal is reported (default: 3)
  • --window-minutes <n> — time-window fallback for joining a resolution to a later command outcome when no sessionId is set (default: 60)
  • --emit-ops <file> — write non-ambiguous candidates as REPLACE_BULLET ops for review, then apply with charter adf patch --ops-file <file>
  • --ai-dir <dir> — custom .ai/ directory (default: .ai)

Also reports co-occurrence trigger candidates — a weaker, non-failure-backed heuristic where a keyword often appears alongside one that already triggers a module.

charter adf vendor

Show or record each vendor file's mode: a thin pointer to .ai/, compiled output of charter adf compile, or unmanaged (hand-authored, left alone). The record is a VENDORS list in <ai-dir>/manifest.adf. Vendor files are read from the repository root.

npx charter adf vendor status                       # recorded or inferred mode of each vendor file
npx charter adf vendor status --all --format json   # include absent names
npx charter adf vendor set CLAUDE.md compiled       # record one file's mode
npx charter adf vendor set CLAUDE.md pointer --dry-run
npx charter adf vendor init                         # record inferred modes for unrecorded files
🏷 VENDORS:
  - CLAUDE.md: pointer
  - AGENTS.md: compiled
  • status: read-only. A file with a valid entry shows its recorded mode, plus (recorded; file looks compiled) when the markers on disk disagree. A file without one shows the mode inferred from its markers, the way adf tidy classifies it: the compile banner means compiled, a pointer marker means pointer, and anything else is unmanaged. Malformed, duplicate (the last entry wins), unknown-file and not-allowed entries are reported and ignored. A missing manifest exits 0 with a warning.
  • set <file> <mode>: records or replaces one entry, editing only that line. Only CLAUDE.md, AGENTS.md, .cursorrules and GEMINI.md may be compiled. agents.md and copilot-instructions.md have no compile target, so compiled is refused with exit 1. An unknown file or mode, or a missing manifest, exits 2. The file does not have to exist yet.
  • init: records the inferred mode of every vendor file on disk that has no entry. It never changes an existing entry, and a second run writes nothing.

One physical file has one entry. When two vendor names are the same file (AGENTS.md and agents.md on a case-insensitive filesystem, or a hard link), every writer records it under the spelling already recorded, or AGENTS.md when neither is. status shows it once. set names the spelling it used.

  • --dry-run: with set or init, report the change without writing
  • --all: with status, also list vendor names that are absent and unrecorded
  • --ai-dir <dir>: custom .ai/ directory (default: .ai)

bootstrap and adf init --emit-pointers record pointer for each pointer file they write. adf migrate records pointer for each source it replaces with a pointer, and adf compile --write records compiled for each target it writes (with --mode compiled, replacing the entry). The other writers only add missing entries. If a file is already recorded with another mode, the entry is kept and a warning names adf vendor set as the way to change it. Nothing is recorded under --dry-run, and a failed record write is only a warning, except under adf compile --write --mode compiled, where the target is refused (refused-record) and its file is not written. Every manifest edit is text-level and keeps line endings and every other byte, and the block it writes is already in adf fmt canonical form. It is re-parsed before writing, and if the result would change anything else, nothing is written.

adf compile (--check and --write) and adf tidy act on the record; see their sections. doctor and the pre-commit hook still decide from the markers in each file, and score skips the section when it checks manifest path references. Later changes under #318 make them read it.

charter blast

Compute the blast radius of a change: which files transitively depend on the given seed files?

npx charter blast src/kernel/dispatch.ts                    # default depth 3
npx charter blast src/a.ts src/b.ts --depth 4               # multi-seed, custom depth
npx charter blast src/foo.ts --format json                  # structured output
npx charter blast src/foo.ts --root ./packages/server       # scan a subdirectory
  • <file> — one or more seed file paths (required, positional)
  • --depth <n> — max BFS depth through the reverse dependency graph (default: 3)
  • --root <dir> — project root to scan (default: .)
  • --format json — emit structured JSON instead of the text summary

How it works: Walks the source tree under --root, extracts imports from every TS/JS file (ES modules, CommonJS, dynamic import(), re-exports; comments stripped), builds forward and reverse adjacency maps, and BFS-traverses the reverse graph from each seed up to --depth. Auto-detects tsconfig path aliases (including extends chains) so monorepo @scope/package imports resolve correctly.

Output includes:

  • affected — relative paths of files that transitively import the seeds (excludes seeds themselves)
  • hotFiles — top 20 most-imported files in the graph (architectural hubs)
  • summary.totalAffected, summary.seedCount, summary.depthHistogram

Governance signal: blast radius ≥20 files triggers a CROSS_CUTTING warning in text mode. Use this as a gate to escalate wide-reaching changes to architectural review.

Semantics: zero runtime dependencies, no LLM calls, no TypeScript compiler API. Regex-based import extraction — trades some precision for universality across JavaScript/TypeScript/ESM/CommonJS projects.

charter serve

Expose ADF project context as an MCP server over stdio, for use with Claude Code, Codex, and Cursor.

npx charter serve                             # stdio MCP server (default)
npx charter serve --ai-dir /abs/path/.ai      # explicit ADF directory
npx charter serve --name "my-project"         # override the server name shown in MCP clients
  • --ai-dir <dir> — path to the .ai/ ADF directory (default: .ai). Always resolved to an absolute path at startup, relative to the working directory the server was spawned in. When wiring in .mcp.json, use the repo-relative .ai — .mcp.json is a committed, shared file, so an absolute path breaks it for every other clone and for CI.
  • --name <name> — override the MCP server name (default: inferred from core.adf PROJECT section or directory name).

Wiring in .mcp.json

{
  "mcpServers": {
    "charter": {
      "command": "npx",
      "args": ["@stackbilt/cli", "serve", "--ai-dir", ".ai"]
    }
  }
}

Use the repo-relative .ai — this is what charter bootstrap generates. .mcp.json is committed and shared, so an absolute path here leaks your local directory layout and breaks the server for every other clone and for CI.

.ai resolves against the working directory the MCP client spawns the server in, which is normally the project root. If your client spawns it somewhere else, set the client's cwd, or pass an absolute --ai-dir and keep the whole file out of version control — add .mcp.json to .gitignore (and git rm --cached .mcp.json if it is already tracked). An absolute path is only a problem in a file other people clone. A wrong working directory fails loudly rather than silently: charter serve emits a startup error naming the path it resolved (see Startup errors).

charter bootstrap warns about an absolute --ai-dir only when git actually tracks .mcp.json, so a deliberately machine-local config stays quiet.

Startup errors

If startup validation fails (missing .ai/ directory or manifest.adf), charter serve emits a structured JSON-RPC error to stdout before exiting so MCP clients can surface a human-readable message:

Condition Error message Fix
.ai/ directory missing No .ai/ directory found. charter init
manifest.adf missing .ai/manifest.adf not found. charter adf init

Registered MCP tools

Tool Description
charter_brief Call first. Pre-digested repo brief — routes, hotspots, governance.
charter_context Session continuity snapshot reader/refresher (.ai/context.snapshot.json). Use refresh=true to run context-refresh before reading.
getProjectContext ADF bundle resolved for a given task or trigger keywords.
getProjectState Constraint validation results across all loaded modules.
getArchitecturalDecisions Load-bearing constraints from core.adf.
getRecentChanges Recent git commits classified by type.
charter_blast Blast radius for one or more source files.
charter_surface API surface — HTTP routes and D1/SQLite schema tables.
updateEvidence Write-back. Measures metric source files, patches ADF with current values, returns before/after diff + live constraint status.
updateEvidence — keeping ADF metrics accurate

Call after code changes that affect tracked metrics (e.g. after adding files to a module that has a LOC ceiling):

// MCP call — no args needed for a full refresh
{ "tool": "updateEvidence" }

// Preview first without writing
{ "tool": "updateEvidence", "dryRun": true }

// Update specific metrics only
{ "tool": "updateEvidence", "metrics": ["total_loc", "test_count"] }

Returns:

{
  "measured": [{ "metricKey": "total_loc", "sourcePath": "src/core.ts", "measured": 312 }],
  "changes": [{ "file": "core.adf", "metricKey": "total_loc", "section": "METRICS", "before": 280, "after": 312 }],
  "skipped": [],
  "written": ["core.adf"],
  "constraints": { "allPassing": true, "failCount": 0, "warnCount": 1, "items": [...] },
  "hint": "Run `charter adf sync --write` to update .adf.lock"
}

updateEvidence does not update .adf.lock. Run charter adf sync --write separately if you need lock hygiene (this preserves the drift-detection signal for CI).

charter context

Pre-digested repo brief for AI agents. Composes routes (surface), hotspots (blast), sensitivity tags, and governance posture into a single bounded markdown document.

The fastest way to orient an AI agent in a Charter-governed repo. Reading the brief replaces 15-30 cold-boot discovery tool calls.

Usage

npx charter context                   # print brief + write .charter/context.md
npx charter context --stdout-only     # print only, no file write
npx charter context --verbose         # no token ceiling (for human reading)
npx charter context --write           # write .charter/context.md only (for hooks)

Brief sections

Section Source Always present
Identity .charter/config.json, manifest.adf (PRESET/STACK), and package.json Yes
Surface charter surface (routes + D1 tables) Yes
Hotspots charter blast (top hot files by importer count) Yes
Sensitivity .charter/config.json tags + ADF SENSITIVITY sections (manifest + referenced modules) Yes
Governance .ai/manifest.adf module routing Yes

Token budget

The brief is capped at 2000 tokens (~8000 characters). When content exceeds the budget, sections are truncated in this order: hotspots tail → D1 tables → routes → governance ON_DEMAND entries. A ## Truncated section is appended listing what was reduced.

Use --verbose to remove the ceiling for interactive sessions.

MCP tool

charter serve registers charter_brief. Agents should call this first:

"CALL THIS FIRST when entering a Charter-governed repo. Returns routes, hotspots, sensitivity tags, and governance in a single pre-digested brief — replaces 15-30 discovery tool calls."

Post-commit hook (keep brief fresh)

echo 'charter context --write' >> .git/hooks/post-commit
chmod +x .git/hooks/post-commit

Or use charter bootstrap — it adds this as a suggested next step.

Blast seed strategy

Seeds for hotspot analysis are chosen by resolved preset (from .charter/config.json when set, otherwise ADF PRESET fallback):

Preset Seeds
worker src/index.*, route files, wrangler entry
frontend src/App.*, src/main.*, src/index.*
backend src/index.*, src/server.*, src/app.*
fullstack worker + frontend seeds
cli bin/ entries, src/commands/*.ts
docs README.md, docs/*.md
rust-wasm src/lib.rs, src/**/*.rs, Cargo.toml
unknown src/index.*, src/main.*

charter context-refresh

Generates a live session snapshot and writes it to .ai/context.adf plus .ai/context.snapshot.json.

Supports git, github, and repo-intel sources with fail-closed behavior for missing GitHub credentials and graceful skip when the gh CLI is unavailable.

npx charter context-refresh
npx charter context-refresh --sources git
npx charter context-refresh --sources git,github
npx charter context-refresh --sources repo-intel
npx charter context-refresh --output CONTEXT.md
npx charter context-refresh --ai-dir .ai
npx charter context-refresh --once --ttl-minutes 30
npx charter context-refresh --format json

Flags

  • --sources <csv> — context sources to include. Supported: git, github, repo-intel.
  • --output <path> — optionally mirror a markdown snapshot to a file (for session briefs/docs).
  • --ai-dir <dir> — target ADF directory (default: .ai), output file is <dir>/context.adf.
  • --once — skip refresh when an existing snapshot is newer than TTL.
  • --ttl-minutes <n> — TTL window used by --once (default from config or 30).
  • --force — bypass TTL skip and refresh immediately.

Output

  • Always writes:
    • .ai/context.adf (or <ai-dir>/context.adf)
    • .ai/context.snapshot.json (or <ai-dir>/context.snapshot.json)
  • Context payload includes:
    • STATE metadata (GENERATED_AT, source set)
    • OPEN_WORK (branch + working tree status)
    • RECENT_ACTIVITY (recent commits / issue updates)
    • PENDING_DECISIONS (derived issue prompts)
  • In --format json, prints a machine-readable summary including status, reason, generatedAt, expiresAt, files, warnings, and errors.

Config file

Optional config path: .charter/context-sources.json

  • defaults.sources — default sources when --sources is omitted
  • defaults.ttlMinutes — default TTL for --once
  • defaults.maxItems — source-specific result caps
  • sources.github — repo + strict label filter setup

If github is enabled but GITHUB_TOKEN is missing, refresh continues without hard failure and records sources.github.available = false plus warnings.

If repo-intel is enabled but the gh CLI is not installed or has no GitHub remote, refresh continues without hard failure and records a warning. When available, repo-intel writes a full payload to .charter/repo-intel/snapshot.json.

Sources reference

Source Description
git Local git branch, working tree, and recent commit log.
github Open issues from the GitHub API (requires GITHUB_TOKEN).
repo-intel GitHub history via the gh CLI — open/closed issues, PRs, releases, and a computed summary (openIssueCount, mergeVelocity, stalledIssues, recurringLabels, releaseCadence). Writes .charter/repo-intel/snapshot.json. Skips gracefully when gh is unavailable.

For active implementation status and next-session handoff details, see Context Refresh Resume Guide.

charter surface

Extract the API surface of a project: HTTP routes and database schema tables.

npx charter surface                                 # text summary
npx charter surface --format json                   # machine-readable
npx charter surface --markdown                      # for .ai/surface.adf injection
npx charter surface --root ./packages/worker        # scan a subdirectory
npx charter surface --schema db/schema.sql          # explicit schema path
  • --root <dir> — project root to scan (default: .)
  • --schema <path> — explicit schema SQL file (default: auto-detect *schema*.sql under root)
  • --markdown / --md — emit markdown suitable for .ai/surface.adf or AI mission brief injection
  • --format json — emit structured JSON

Detects:

  • Routes — Hono, Express, itty-router via regex. Requires path arguments to start with / to avoid false positives from unrelated method calls. Strips block and line comments before scanning so jsdoc examples don't match.
  • Schema — D1/SQLite CREATE TABLE statements, column types (including parameterized like VARCHAR(255)), column flags: PRIMARY KEY, NOT NULL, UNIQUE, DEFAULT. Skips table-level constraints (FOREIGN KEY, CHECK).
  • Prefixes — .basePath('/api/v1') annotations on Hono routers

Ignores: __tests__/, __mocks__/, __fixtures__/, and any *.test.* / *.spec.* files — test fixtures contain route-like strings that aren't real routes.

Exit codes: returns 2 with a usage error if no routes or schema tables are detected (surface is designed for Cloudflare Worker / Hono / Express projects with a schema.sql file; falling through silently on a non-Worker project would be misleading).

Use cases:

  • Breaking-change detection — diff the JSON output before and after a PR to identify removed endpoints or dropped columns. Feeds into version-bump automation.
  • Auto-generated AI context — pipe --markdown output into .ai/surface.adf so LLM agents always know the API shape.
  • Mission brief fingerprinting — inject the markdown output into autonomous task runner prompts so agents don't burn turns exploring project layout.

Global Flags

Flag Effect
--config <path> Path to .charter/ directory (default: .charter/)
--format json Machine-readable output with stable schemas
--ci Non-interactive, deterministic exit codes
--yes Accept all prompts (for automation)
--preset <name> Stack preset (worker, frontend, backend, fullstack, docs)
--detect-only Setup mode: detect stack/preset and exit
--no-dependency-sync Setup mode: do not rewrite @stackbilt/cli devDependency
--force Overwrite existing files (hooks, ADF modules, config)

Exit Codes

Code Meaning
0 Success / pass
1 Policy violation (CI mode: governance threshold breached)
2 Runtime / config / usage error