What this is. A CLI that writes the git commit message from your staged diff. Zero
runtime dependencies, Python ≥3.8, shipped both as a package and as one auditable file.
Its one genuinely differentiated idea: it refuses to describe documentation prose as
work that was implemented — a CHANGELOG.md edit never becomes a fake feat:.
The rule every design question comes back to. The tool never writes history that did not happen. A message that describes an earlier commit, an instruction's own example, or a file the diff does not contain is the product failing at the thing it exists to do — which is why §T60 is the top of the queue and why the evaluation harness (§T51) scores "did the output contain a phrase that appears only in the rules" as a regression.
commitclerk/ the package — cli, gitio, diffing, files, history, prompt, providers
dist/commitclerk.py the standalone build; scripts/build_single_file.py --check gates it
tests/ unittest (not pytest); COMMITCLERK_SOURCE=dist runs them against the build
docs/ROADMAP.md active backlog, one line per task (T<n>)
docs/CHANGELOG.md the task ledger, indexed by block — written by `roadkeep ship`
docs/IMPROVEMENTS.md design rationale, one §T<n> section per UNSHIPPED task
docs/STRATEGY.md positioning, distribution, licensing — never a backlog
CHANGELOG.md the published release notes (Keep a Changelog), grouped by version
README.md, README.pt-BR.md, docs/llms.txt, docs/index.html the user-facing surfaces
roadkeep.toml this project's prefix, paths, limits, markers and budgets
The four docs/ files above are governed: an Edit on one is denied and names the
command instead. Ids, the → §T<n> pointer, the (deps: …) annotations and every
length limit are derived or refused at insertion, so a line is correct before it is
written. The write path — which command, what it derives, how work is picked — is the
roadkeep skill, loaded on the turns that touch a governed file and costing nothing on
the turns that do not. Nothing here repeats it; a rule in two files is a rule two files
can disagree about.
Start a task with roadkeep brief (or the mcp__roadkeep__brief tool): it picks, and it
prints the line, its rationale, the deps and the binding non-goals in one call.
docs/last-task.md is gone — roadkeep next-id derives the answer from the files.
roadkeep lint must pass on docs/, and it exits 1 on any violation, dangling
pointer, orphan section, unsatisfiable dep or over-budget always-loaded file. CI runs it.
docs/ROADMAP.md → "Non-goals", which brief prints with every task.
The hardest of them: zero runtime dependencies in the core path. A task that needs a
package is a task that needs a redesign, or a STRATEGY.md decision first. Positioning,
naming, distribution and licensing are STRATEGY.md prose and never a numbered task.
python -m unittest discover -s testsfrom the repo root. No install step, no pytest.python scripts/build_single_file.pyafter touchingcommitclerk/, and--checkis what CI runs — a staledist/commitclerk.pyfails the build.python -m unittest discover -s testswithCOMMITCLERK_SOURCE=distruns the same suite against the built artifact. Both paths ship, so both are tested.ruff checkwith the config inpyproject.toml. The floor is 3.8: notomllib, nomatch, noX | Yannotations at runtime.- Every string that can reach a terminal must be ASCII (§T57). Prose files may use
typography freely;
--help, errors and notices may not.
One task → one commit, the instant it is validated. What ship wrote goes in the
same commit as the code, so the docs never describe a state that did not ship, and a
batch of ≥2 tasks is not permission to batch: /loop, one task per iteration. Use
run-commit.cmd -m "<conventional-commits title>" from the repo root, -m always and
ASCII — this repo's product is the commit tool, so every task is also the dogfood run.
run-commit.cmd stages everything, so a tree holding unrelated work wants the task's
paths staged and python -m commitclerk -m … instead.
A flag that lands in the code and never reaches README.md, README.pt-BR.md and
docs/llms.txt is a bug — six surfaces are updated by hand per flag today, which is what
§T58 exists to test. The decision procedure (is it user-facing, which surfaces, the
translation, SECURITY.md when the data flow changes) is
.claude/skills/commitclerk-user-docs,
loaded on the turns that ship one.
What stays here is only what a turn touching no governed file needs: the product's one
rule, where the code is, how to build it and how to commit it. Its budget is [budgets]
in roadkeep.toml, held by lint and not by this sentence.