chaffchaff

Quickstart

Five minutes, ending in a real finding on a file you write yourself, not a canned demo.

1. Clone and build

chaff is pre-release and not on npm yet, so this step builds the workspace-local CLI instead of installing a package.

git clone https://github.com/jamessuuu/chaff
cd chaff
pnpm install
pnpm --filter chaff build

2. Write a small, deliberately imperfect CLAUDE.md

In a scratch directory (not this repo, anywhere is fine), create two files: a CLAUDE.md with one import that points at nothing and one version number in prose, plus the one doc it does import.

mkdir chaff-quickstart && cd chaff-quickstart
mkdir docs

cat > CLAUDE.md <<'EOF'
# Project notes

See @docs/style.md for house style.
See @docs/missing.md for the deploy checklist.

Deployed on build 1.4.2 last night.
EOF

cat > docs/style.md <<'EOF'
Use imperative sentences.
EOF

docs/missing.md is never created. That is the point.

3. Discover a config

node /path/to/chaff/packages/chaff/dist/cli/main.js init

Real output from this exact scenario:

chaff.config.json written · 1 discovered:
  CLAUDE.md

chaff init writes chaff.config.json by discovery. It found one entry point (this directory’s CLAUDE.md) and declared it as the session set, harness claude-code, gate enforced.

4. Analyze

node /path/to/chaff/packages/chaff/dist/cli/main.js analyze --today 2026-08-09

Real output. Nothing here is invented:

chaff · set "session" · o200k_base

RESIDENT   41 ref tok (o200k_base) · 2 files
  CLAUDE.md  41  (@imports 4)
CHAFF      5 / 41 ref tok (o200k_base) = 12.2% · enforced findings only, spans deduped
UNVERIFIED 5 ref tok (o200k_base) flagged by heuristics, excluded from the score above

FINDINGS (2)
  import.broken-target  [enforced · structural · high]  resident  CLAUDE.md:4:5
    @docs/missing.md: import target not found: docs/missing.md
  stale.version-pin  [heuristic · unmeasured · low]  resident  CLAUDE.md:6:19
    pinned version "1.4.2" in prose: build/version pins go stale silently; state the behavior or
    move the pin into tool-owned config

exit code: 1

Exit code 1 because the default gate (--fail-on enforced) blocks on the one enforced finding: import.broken-target. The version-pin finding is tier heuristic, so it is reported and excluded from the chaff% score (the UNVERIFIED line), but it does not fail the build by default.

5. Read the finding, offline

node /path/to/chaff/packages/chaff/dist/cli/main.js explain import.broken-target
import.broken-target · enforced · structural · high

CLAIM
  An @-import names a target file that does not exist, so content the author
  expects to be resident never loads.

RATIONALE
  Claude Code inlines @path/to/import references (relative and absolute) at
  launch, skipping code spans and fenced code blocks
  (code.claude.com/docs/en/memory). A missing target fails silently from the
  author's point of view.

FIX
  Fix the path, or remove the import if the target is gone for good
  (mechanical: remove the dead import line).

STATUS
  structural: a deterministic fact about the artifact that asserts nothing
  about behavior, so it needs no eval (SPEC §6).

Fix it either way and re-run analyze: delete the @docs/missing.md line, or write the file. Either fix drops the finding count to one (the heuristic, non-blocking version pin) and exits 0.

Next

Concepts explains what RESIDENT and the chaff% line actually mean. Rule tiers explains why one finding blocked the build and the other did not. Or skip straight to /analyze to try this in a browser tab instead of a terminal.