Checkwright v0.27.0
2026-09-28
Checkwright is the verification layer under agent orchestration, and this release fits the prose profile to spec trees that Spec Kit or OpenSpec writes, and adds a static Linux gate binary beside the glibc one so the installer serves any Linux.
In brief
- If Spec Kit or OpenSpec writes your specs, each now has a tested recipe for the
proseprofile, and Spec Kit gets an extension attached to this release ascheckwright-companion-0.27.0.zip. The Spec Kit and OpenSpec page walks both. - Alpine, and any Linux whose glibc is older than 2.39, is now served: a static build ships beside the glibc one, and the installer takes the glibc build wherever it runs and the static one everywhere else. An install that runs today keeps its binary.
- Installs now check the minimum versions of the tools they rely on, such as git 2.15, and name the floor a host is below instead of failing later.
- New gates ship for docs pages, catching a repeated sentence or link, a section citation left unlinked, and a collapsible region the Pages parser would print raw. Each arms only where you register it.
- You have one step to take after upgrading. Register each new gate your kits carry, or declare it unregistered; your first battery names them. Then regenerate the pages it reports stale.
Tightened gates
check-survey-record— a survey block’scorpusmust now be the literalnoneor space-separated git pathspecs, single-quoted where one carries a quote, a shell metacharacter, a glob character or pathspec magic, and in bare mode each pathspec must match a path at the block’srev. A block whose corpus is prose, carries an unquoted glob, or names nothing reds; rewrite its corpus to the pathspecs the survey read (scoping prose moves tofinding), ornonefor a survey over no tree corpus.check-docs-page-repeat— new canon-kit gate: no page declared inCANON_KIT_PAGE_REPEAT_PAGESstates a relative link target, or a sentence ofCANON_KIT_PAGE_REPEAT_MIN_WORDSwords or more, twice. It arms only where you set the corpus knob; register it and set the knob to hold your docs pages, then make each later repeat plain text or an in-page anchor.check-gate-substrate-parity— reds after upgrading through assertion I, which holds every gate the binary carries for a kit you vendor to be registered in yourgates.listor declared# unregistered:there. If you vendor canon-kit, the newcheck-docs-page-repeatandcheck-citation-linkare such gates, and if you vendor site-kit, the newcheck-docs-collapsibleis: register each, or declare# unregistered: <gate> — <reason>.check-citation-link— new canon-kit gate: on a page declared inCANON_KIT_CITATION_LINK_PAGES, every section citation (<path> §<heading>, or a bare§<heading>) sits in a link’s text whose target carries that section’s anchor; a later mention of a section the page already linked stays plain text. It arms only where you set the corpus knob; register it, set the knob to your hand-authored pages, and turn each unlinked citation into a link to its section.check-docs-collapsible— new site-kit gate: every<details>region on a tracked docs page opens withmarkdown="1", carries a<summary>, hides no heading and closes. Register it where your docs site builds with the Pages parser, and addmarkdown="1"to any region the Pages parser was printing raw.
Renamed knobs
None. Knobs were added this cycle, and none was renamed or removed.
Behavior changes
--emit file-survey— the arm now refuses at exit 2, filing nothing, a corpus outside the grammar above or naming a pathspec that matches no path tracked at HEAD, and names each unmatched pathspec. File the pathspecs the survey read, single-quoted where needed, ornone; anonecorpus’s witness hint prints the oracle re-run alone.--emit file-gapand--emit file-survey— both now refuse at exit 2, writing nothing, when run in a linked worktree, where the tracked line would be lost with an uncommitted worktree. An isolated child hands the finding back to its dispatcher, who files it from the main checkout; a session that works and commits in a linked worktree appends the line by hand in the record’s grammar.--hook workflow-state-guard— withLIFECYCLE_KIT_STAGE_SESSION_TYPESset, a dispatched stage session whose stage the cursor has left is now refusedWriteandEditoutside the scratch dirGATE_SDK_TMP_DIRnames; its resume journal there stays writable. Such a session answers through its report and the live stage session lands the change. With the knob empty, nothing changes.--enter-stageand--install queue-source— on native Windows, the iteration-boundary wipe report (boundary-wiped from <tmpdir>: …, and each residue path it could not remove) and thequeue-sourcerecord now join each name onto its directory with/, the declared dialect, where they joined with\. Nothing to do; a reader splitting these lines on/now reads them.--emit enforcement-map— a harness settings file at the default path that does not parse now drops the hook sections, as for an absent file, where it refused at exit 2 and reddenedcheck-enforcement-fresh. An explicitly setCONTEXT_KIT_SETTINGS_FILEthat does not parse still refuses. Nothing to do.--emit enforcement-mapand--emit footprint— the generated pages’ prose changed: the enforcement map names the repository it is generated from where it said “this repo” and states what the(consumer)group holds, and the footprint page states what earns a row.check-enforcement-freshandcheck-footprint-freshred on your committed pages until you regenerate them with the command each prints.CANON_KIT_COMMENT_ACTIONS— new knob,offoron; set toon, it extendscheck-comment-tier,check-spec-pointer,check-todo-task-livenessandcheck-deprecation-taskto every actions-shaped YAML file (a top-leveljobs:orruns:key), so your CI workflows’ comments are governed like a script’s. It defaults tooff, so nothing changes until you set it; set it in yourcanon-config.knobsonce your workflows’ comments are directives.check-comment-tier— thegh-repo-exempt:andaction-permissions-exempt:valves and theenforce:monitor marker are now blessed directives, so a governed workflow may carry them. Nothing to do.init— a re-run now writes the hooks and the coupling graph where yourGATE_SDK_HOOKS_DIRandGATE_SDK_GRAPH_ARTIFACTput them, and records those paths, where it wrote the graph to the default<gates-dir>/CHECK-GRAPH.htmland recorded both at the default layout whatever the knobs said. Nothing to do; delete a default-path graph an earlier run left behind if your knob moved it.uninstall— now removes the installed gate binary even when it no longer matches the hashinitrecorded, where it kept it and reported it as yours. Nothing to do.doctor, and soinit— now holdgit≥ 2.15 on every profile,curl≥ 5.9 where delegation-kit is selected andshellcheck≥ 0.6.0 where a registered gate needs it. A host below refuses atdoctorand names the floor, and--emit env-proberenders the same floors (jq≥ 1.5 among them, contributor-only); upgrade the tool.- The Linux gate binary — now published twice per architecture: the glibc build,
x86_64-unknown-linux-gnuandaarch64-unknown-linux-gnu, and beside it a build statically linked against musl,x86_64-unknown-linux-muslandaarch64-unknown-linux-musl, which runs on any Linux kernel 3.2 or later (4.1 on arm64) whatever the host’s C library. The installer takes the glibc build where it runs and the musl build everywhere else, and asks no question about the host’s C library. A musl host such as Alpine, or a glibc below 2.39, where the glibc build alone could not run, is now served. An install on a host where the glibc build runs keeps it. Nothing to do. - The per-target Release archives — gain the two
*-linux-muslarchives beside the*-linux-gnuones, whose names are unchanged. lifecycle-kit/templates/lead.md— the lead now writes nothing into the checkout or a linked worktree while a dispatched stage session is live, gitignored scratch included, keeping only its resume journal, its session-role marker and what the arms it runs write for it; a probe that must write runs after the stage or in a clone outside the checkout. It also reads a linked worktree’s provenance (branch and lock, dirtiness, commits the main checkout lacks, the journal or dispatch naming it) before calling it stale. Nothing to do.- The gate scratch directory —
.tmpunlessGATE_SDK_TMP_DIRsays otherwise, now carries a.gitignoreholding*, written byinitand by the battery when absent, so a battery run no longer leaves an untracked file; an existing.gitignorethere is never rewritten, and the iteration-boundary wipe and the session-start scratch sweep spare it. An adopter who already added a root ignore line may keep it. If you copied context-kit’ssession-context.shtemplate, add! -name .gitignorebeside! -name .gitkeepin your copy’s step-6 scratch sweep, which otherwise deletes the file once it is a day old. LIFECYCLE_KIT_AMENDMENT_GLOB— a value carrying/now matches a file’s repo-relative path component by component,*inside one component and**across any number, so a tree can mark its in-flight specs by location;check-stage-entryandcheck-reads-couplesboth read it so. A value with no/matches the basename as before. Nothing to do.
Upgrading
Replace the vendored kit directories wholesale at v0.27.0, or run checkwright update. Regenerate your generated artifacts: the enforcement map and the footprint page red until you do, and each freshness gate prints its own regen command. If you copied context-kit’s session-context.sh template, add the scratch-sweep exclusion the scratch-directory change above names. Then run the full battery.
The allowed reds. Each is a gate named above, and each clears differently:
check-gate-substrate-parity— reds once for each new gate your vendored kits carry and yourgates.listdoes not name. Register it, or declare it# unregistered:with a reason.check-survey-record— reds on a survey block whose corpus is prose, an unquoted glob, or nothing. Rewrite the corpus to the pathspecs the survey read, ornone.check-docs-page-repeat,check-citation-linkandcheck-docs-collapsible— red only once registered, and the first two only once their corpus knob is set. Each red names the line to fix.
The behavior changes above are declared for reading, not a mechanical scan. If a gate reds that this note does not name, the upgrade smoke was supposed to catch it first — open an issue, because that is a defect in the release rather than work for you.