codebase-checkpoints
Codebase Checkpoints (automation contract)
Section titled “Codebase Checkpoints (automation contract)”Opt-in per-project state machine that ties recurring housekeeping checkpoints — project-naming drift, design-doc identity, and (worked example) Cocos playable feel/build-size/parameter passes — to a single inspectable state file, re-evaluated whenever the codebase changes.
Setup (per project, not done by this module)
Section titled “Setup (per project, not done by this module)”- Declare project identity in
project-info.jsonat the REPO ROOT (project.canonicalName,project.client) — see § Identity SSOT below. Do NOT put it in the checkpoints config. - Copy
.claude/data/checkpoints.config.example.jsonto.claude/checkpoints/checkpoints.config.jsonin the consumer project and fill inproject.expected/observed/staleTokens— commit it. - Add
.claude/checkpoints/checkpoints-state.jsonto the project’s own.gitignore(config is committed, runtime status is per-machine and not shipped by any kit mechanism). - Trim or replace the
game-feel/build-size/parameter-auditcheckpoints in the copied config — they are a worked example for a Cocos playable-ad project (theonekit-cocosplayablemodule); a non-Cocos or non-playable project deletes them, or swaps in its own engine’s polish/perf skills.
Identity SSOT — project-info.json, not the checkpoints config
Section titled “Identity SSOT — project-info.json, not the checkpoints config”project.canonicalName and project.client are shipping facts: they outlive this tooling, and
a project that uninstalls this module must not lose its own name with it. They therefore live in
project-info.json at the repo root — NOT inside .claude/, which is kit-managed territory that
t1k modules update may overwrite and which no module.json claims for an instance config.
What stays in .claude/checkpoints/checkpoints.config.json is the audit machinery itself: the
expected vs observed drift fields, staleTokens, protectedTerms, and the checkpoint list.
checkpoints-core.cjs exposes resolveIdentity(), which reads project-info.json first and falls
back to canonicalName/client keys in the checkpoints config so a pre-inversion install keeps
working. That fallback is reported, never silent — loadConfig() records
project._identitySource, and t1k-checkpoints.cjs status prints an
identity LEGACY source=<file> (migrate to project-info.json) line until the declaration moves.
Resolution happens once, inside loadConfig(), so no call site needs to know where the name lives.
Mechanics
Section titled “Mechanics”checkpoints-turn-tracker (PostToolUse, Edit|Write|MultiEdit) queues the mutated path.
checkpoints-stop (Stop) drains the queue once per turn, unions it with a git
working-tree mtime snapshot (so edits made outside Claude’s own tools — an external editor, an
engine editor rewriting a scene/prefab — are not invisible to “whenever the codebase changes”),
re-evaluates every checkpoint in checkpoints.config.json, and reports.
Advisory by design: it prints a frame and exits 0. It never blocks the turn and never writes to
Plane — board writes stay on the guarded t1k-plane path (t1k-plane-binding.cjs); this feature
only reports which items SHOULD exist (t1k-checkpoints.cjs plane-plan) so an agent can create them
through the normal guarded flow. Silent on turns that mutated nothing, so a long-lived red
checkpoint (e.g. naming stays red until the rename actually lands) does not reprint forever.
Two checkpoint modes:
deterministic— a pure text/structure audit or identity probe, run directly by the hook. No LLM judgement (rules/ai-driven-design.md).project-naming(this module’saudit-naming.cjs) is engine-agnostic in its text scan and Cocos-shaped in its structural checks (skipped cleanly when a config omits the Cocos-dir fields — see below);design-docis fully optional, delegating tot1k-cocos-base-system-design’sprobe-design-doc.cjswhen that skill is installed and mapping tounknown(never a falsegreen) when it is not.skill— cannot be run by a hook; staleness is the signal, a reasoning agent invokes the named skill and marks the checkpoint green vianode .claude/scripts/t1k-checkpoints.cjs mark <id> green.
Engine coupling — why this lives in t1k-engine-bridge, not a generic core module
Section titled “Engine coupling — why this lives in t1k-engine-bridge, not a generic core module”The naming audit’s three structural checks (cocos-dir, package-name, script-namespace) assume
a nested engine-project directory holding assets/scripts/<namespace> — a Cocos Creator project
shape. checkpoints-core.cjs also soft-depends on two Cocos-base skill scripts
(t1k-cocos-base-knowledge-sweep/scripts/detect-cocos-project.cjs for directory auto-discovery,
t1k-cocos-base-system-design/scripts/probe-design-doc.cjs for the design-doc checkpoint) — both
resolved via fs.existsSync first and degrading to null/unknown when the Cocos kit is not
installed, exactly like this module’s other Cocos-conditional hooks
(cocos-doc-drift-stop.cjs, cocos-prior-art-reminder.cjs). A config that omits
project.observed.cocosDir skips the three structural checks entirely and runs only the generic
staleTokens text scan — see .claude/data/checkpoints.config.example.json’s _cocosDirComment.
The one hard (not soft) dependency is Plane: checkpoints-core.cjs’s probePlane() shells out to
t1k-plane-binding.cjs status, which ships in core’s always-installed t1k-plane module.
Kill switch
Section titled “Kill switch”T1K_SKIP_CHECKPOINTS=1 disables both hooks for the current invocation.
Related
Section titled “Related”doc-sync-cocos.md(project rule, theonekit-cocos) — the sibling automation contract for this same module’scocos-doc-drift-stop/cocos-doc-turn-trackerpair; same queue-then-drain shape.rules/ai-driven-design.md— the deterministic-vs-skill split this feature follows.rules/green-that-proves-nothing.md— why the naming audit’s structural checks compareobserved !== expectedrather than testingexistsSyncalone (a completed rename must be able to reach green, not report itself as still outstanding under its own new, correct name).t1k-plane-binding.cjs(modulet1k-plane) — the guarded Plane binding/gate CLI this feature reads through, never writes to directly.