Skip to main content
sourceSource: corpus/docs/reference/local-checks.mdModified: 2026-06-23

Local checks and the extension boundary

Works today — plain markdown plus your agent; no corpus tooling required.

corpus ships only generic checks — the ones every spec, task, and review packet should pass regardless of what the code does (checks.md). Teams add their own local checks almost immediately: a script that asserts the migration ran, that the snapshot matches, that the declared scope was touched. This page says where those local checks belong and how to name them so they don't claim more than they prove.

The extension boundary

Four layers own different checks. Keeping them separate is what lets corpus core stay portable while a team's checks grow as specific as they like.

LayerOwnsExamples
corpus core CLI (corpus check)Generic artifact checks — independent of any project's domainspec shape, task scope, review coverage, empty evidence, workspace validity, stale declared evidence (the C catalogue in checks.md)
Workspace / starter kitProject command slots and local policythe Commands table a task's Verify with: resolves against; which checks a team treats as blocking; the high-oversight band
Code repoIts real build/test/lint/typecheck commandsthe gate a task's evidence is produced by — pnpm test:run, cargo build, whatever the repo actually runs
Optional local scriptsProject-specific predicatesa script that emits corpus-shaped evidence (a review row, a Pass/Fail/Unverified result) for something only this project cares about

The rule in one line: corpus core stays generic; product-specific predicates live in the layers a team owns. A local script that emits corpus-shaped evidence is welcome and idiomatic — what is forbidden is implying its predicate is part of corpus core, or that corpus enforces it. corpus deliberately ships no domain-specific check; a team binds its own tool through a Verify with: command or a CONSTRAINT with the static verify method (see Not in the set in the CLI reference).

Writing local checks without overclaiming

A local check is honest about its predicate — the exact proposition it actually establishes — and routes everything outside that predicate to a human, never to a silent Pass.

What a script can establish: that declared artifacts exist, that declared gates ran, that declared snapshots match, that the declared scope was touched, that parseable structure is well-formed.

What a script cannot establish: "no regressions" in the absolute. A check proves no regression across the declared evidence surface — the tests that exist, the scope that was declared — and nothing about behavior outside that surface. Anything outside the declared evidence path is Unverified, a human-attention row, or a follow-up — never silently treated as covered (reviewing output; source authority on why code outside the path never silently amends intent).

So name the check after its predicate, not after the reassurance you wish it gave:

Overclaiming nameHonest nameWhy
no-regressions-checkbaseline-regression-checkIt proves a named baseline held, not the universal absence of regressions.
complete-reviewcoverage-of-declared-scopeIt proves the declared scope was covered, not that the review was complete.
correctness-checkartifact-shape-checkIt proves structure and shape parse, not that the behavior is correct.

And label its honesty level (the honesty legend, ADR-0063). A local script is toolable at best; it becomes enforced only when your gate actually rejects a merge on its failure — that is your team's gate, not corpus's. Until something blocks, it is a checklist or toolable aid, and it says so. A script that cannot run its check returns Unverified or Blocked, never a guessed Pass.

  • Checks — the generic core catalogue and the honesty legend this page extends.
  • Capability matrix — what corpus check ships, and the non-goals a team brings its own tool for.
  • Source authority — why evidence outside the declared path is Unverified, not covered.
  • Reviewing output — where local-check results land as review rows.

Ready to run the loop on your own repo? Get started — copy the kit and write your first spec.