canon-kit

Spec discipline for agent-authored components: one canonical spec per component, deltas as short-lived amendment files, and a star topology across the prose surfaces — every fact has exactly one owning surface, and every other surface cites it rather than restating it. Gates hold the copy-shaped failure modes; the irreducibly semantic judgment stays a review tripwire, not a gate.

Why: when a coding agent authors the specs, design rationale gets re-derived under build pressure unless it is captured up front, and a parallel copy of any gated fact is an un-gateable second source that drifts silently. The remedy is a lifecycle (amendments authored up front, merged and deleted at build) plus gates over the mechanically-decidable copy failures — a doubled Definition-of-Done, a banned-heading code dump, a fenced block that verbatim-copies a source file, a glossary definition restated on another surface, a feature task with no amendment. See SPEC.md for the full contracts.

Install

Vendor the kit beside gate-sdk (required); the queue-facing gate reads the tag syntax queue-kit defines.

  1. Register the gates — add to your gates.list, each where its surface exists:

    check-amendment-queue        # needs a task queue
    check-amendment-update-target # every update target cites a delta the amendment defines
    check-spec-dod-singleton     # needs canonical specs
    check-spec-derivable-section # needs canonical specs
    check-spec-embedded-source   # needs canonical specs + tracked source
    check-surface-duplication    # needs a glossary (exits 2 without one)
    check-comment-tier           # classifies comments on shell/config sources
    check-spec-pointer           # resolves spec:/contract: pointer targets
    check-todo-task-liveness     # resolves TODO(task:) slugs against the queue
    check-docs-cmd               # invoked paths + kit knobs in docs resolve
    check-knob-citation          # knob values stated only in the owning SPEC
    check-knob-default-coupling  # source knob defaults agree with the owning SPEC
    check-manifest-count         # no bare cardinal over a governed collection
    check-measured-claim         # needs a measured-claim oracle (marked claims re-measured)
    check-unmarked-claim         # needs a claim-class roster (a declared class carries a marker)
    check-manifest-temporal      # no temporal narration in manifest prose
    check-tracking-claim         # a path's tracking status in prose agrees with git
    check-prose-enum             # partial enumeration of a governed set
    check-md-refs                # internal markdown links resolve
    check-install-claim          # one declared primary install transport, led with everywhere
    check-payload-claim          # one declared payload-disclosure class, asserted nowhere else
    check-spec-fence-balance     # even fence counts, parsers never desync
    check-docs-link-convention   # needs a docs site (cite-downward links)
    check-prose-tells            # needs prose surfaces (mechanical AI-prose tells)
    check-deprecation-task       # needs a deprecation-marker vocabulary
    

    They resolve through gate-sdk’s registry path (your gates dir first, then each kit’s checks/), and their # graph: manifests put the precommit-tier ones in the generated hook: bash gate-sdk/bin/gen-pre-commit.sh --write.

  2. Adopt the amendment lifecycle — copy templates/SPEC-amendment.md when a designed-but-unimplemented change needs a home. Name it after the feature (SPEC-<feature>.md), place it in the owning component’s directory (a governance ruling with no component lives at the repo root), and pair it with a queue entry tagged [spec: SPEC-<feature>.md]. Merge it into the canonical spec and delete it when the work completes.

  3. Optional — reshape the config: copy templates/canon-config.sh into your gates dir and override the spec/amendment names, section set, the Definition-of-Done mode (exactly-one / at-most-one), the banned-heading set and density budget, the embedded-source language map, or the glossary surface list. Defaults are this repo’s layout.

Use

The lifecycle is prose discipline the gates enforce; there is no runtime tool. Author a spec so it (1) owns semantics, (2) names every contract and couples it to code by a gate, and (3) never copies a structural definition — reference the code instead. Author amendments up front; merge and delete them at build.

Test

bash gate-sdk/bin/run-gate-tests.sh canon-kit/gate-tests canon-kit/checks