Changelog
The latest sections of each repository's CHANGELOG.md, read at build time.
Read from the repositories at commit: hatsu 3c582c18a4 (v0.159.0) · nen d7a720ddcd (v0.29.0) · handbooks 39b8e06d3c (v0.13) · 2026-11-04
Hatsu
v0.152.2
v0.152.2 — GPT idle batch: evidence, bootstrap boundaries and trusted workflow retries
- Prepare the first landing of #496: the trusted workflow validator admits the current Node canon lint and the exact Nen form with trusted pin, bootstrap and digest steps. Both installed forms pass the full trusted self-test entrypoint. The new Nen form checks the downloaded bootstrap script against the trusted script digest before execution, then checks the binary independently. The live workflow stays on Node until this validator merges; the workflow flip and old guard retirement remain step two.
- Prepare Direct's dated price steps, task-cost methods, served-product warnings and quota-only in-pool evidence behind
snapshot.evidenceVersion(default off). Preserve the live registry and generated page byte for byte; fixtures prove the enabled report and expired-price CI refusal. Activation requires a follow-up after this compatible trusted renderer merges on main. (Part of HA#341) - Reject an explicit null evidence version, clear inherited Node settings in the documented evidence command, and keep successful CLI fixtures valid as the UTC date advances. (HA#341 review fixes)
- Add exact-source capture and extraction to eight remaining focused shell lanes, including both publish integrity targets. Move report-time assertions into a dedicated fixture while preserving and verifying its --self-test forwarding path. Preserve strict absent-ignore redaction behavior. Live tree capture remains held for an explicit maintainer naming/policy decision under #149, and trusted preflight stays unsupported for its Ruby implementation and archived historical guard copies. Delivers part of #148; the issue remains open and the 80/85/90 ladder is unchanged.
- Wire the report-time companion into the trusted CI runner, refusing a missing companion and propagating fixture failures. Automatic workflow selection begins after the updated runner is adopted by the PR base.
- Getsuga § 4 records the maintainer's reviewed-head cut when a later delivery races the release
- Activate bounded API retries in the plugin-bump workflow (zheref/hatsu#381). The live changed-files and base-manifest step now invokes the already-shipped typed reader from the trusted workflow revision on pinned Node 24. Transient non-JSON, server and transport failures retry at most three times with backoff and bounded request timeouts; persistent failures refuse with HTTP status and a sanitized body prefix. A missing base manifest still writes the sentinel only after confirming the base commit. The
editedtrigger, rename paths, read-only API token boundary and deterministic body-only reruns remain covered by the focused fixtures. Plugin 0.152.2; generated mirrors refreshed.
v0.152.0
v0.152.0 — The kazaana claude batch: bounded delegate waits, the host workload budget, the wrap-up's two prerequisites, parks on observed blockers only, and the durable ledger slice
- Every Futon-based batch drives every delivery to Ready, or holds it and names why (zheref/hatsu#488).
docs/WORKFLOW.md§ Batch delivery states the maintainer's instruction of 2026-10-25 once.enis started behind every delivery a batch opens and keeps acting on pending checks, owed review rounds, findings and catch-up. Every delivery stands in exactly one state —driving,ready(thenen pr readyverdict quoted at the current head),merged,closed, orheld-<cause>(approval, gate — en's sixth stop and hanten prompt included —, credential, cap, handback, stranded), parked durably withnen run park(a later merged or closed read wins over the append-only park) and carrying three facts: the prerequisite or bound, the last verdict and its judged head, the resume line. A batch with any held delivery ends incomplete, never as a success,registernotfinal; an attended run stays open while a delivery stands Ready at its prompt; the wrap-up picker waits for the run's end. Under--idlea run has one integration branch and one integration-to-main PR, no per-effort PR and no stack; an effort that cannot join parks and is listed not included; separate integration deliveries come only from separate runs.hatsu:futon§§ 1, 10, 12,hatsu:kazaana§§ 1, 3, 7,hatsu:en§ 7,hatsu:dowsing-chain§ 9 andhatsu:backlog-loop§ 10 cite it; no batch ends on "blocked" any more, and WORKFLOW's stacking default and idle overlap rule now say attended. scripts/futon_effort_record.mtsgainsresume— the newest real, unended, end-tracked run whose line nen parses alike (never the spelling), or--run <id>, continued under its own id with the launch answers nen stored (re-checked against the idle floor), its recorded terminal and integration branch; exit3alone means no open run, start one, every refusal is exit1; it refuses before calling nen when the manifest is absent (nen would write an empty one that opens thethengate), and a moved committed profile is reported, never obeyed —end, which futon § 10 records so a finished run is never resumed, andintegrate, which records the run's one integration branch and refuses a second one, the default branch in any spelling and a namegit check-ref-formatrejects. A malformed or forged sibling record never refuses a start and never is picked.bindrefuses an idle run,verifyrefuses a claim on an idle or dry run, andstartnames an earlier run typed as the same line. The fixture's stub nen now keeps manifests as nen 0.28 does, and it asserts that the batch endings in futon, kazaana and backlog-loop cite § Batch delivery; it is red against the previous script and the previous futon prose.- Part of #475: define bootstrap gate verdicts and make the exact Hanten review block, settled checklist evidence, and tracked deferred issues part of every resolved PR body. SC-1's real consumer-validator and fresh-adoption execution remains owed; this tree proves Hatsu's section guard and the recorded compatibility contract, not execution of that consumer-owned validator.
- Document Cursor Cloud's checksum-verified Nen bootstrap, durable install path, per-session PATH binding, required GitHub egress, and fail-closed PR proof so a missing cloud binary cannot be replaced with raw git or
gh. - Hanten now validates the complete findings record and canonical HR citations, then checks HR-cited findings against each roster row's live status before settlement advances, keeping ruled findings critical and fixed or deferred while admitting cited push-backs for reading, reversed, and superseded rows. Closes #466.
- The generated mirrors take nen 0.28.0's shape (regenerated at 0.144.0 with the released pin): every Antigravity persona's
tools:is a list of Antigravity names (view_file,run_command; the other Claude tool names have no documented Antigravity name and are dropped, zheref/nen#505 OQ-1), so personas that agy 1.4.3 silently skipped under the old comma string now load (measured on the mirrors of 0.143.0 and 0.144.0, 2026-10-25); and the Cursor mirrors of the seven read-only personas (bisky, buhara, illumi, leorio, lippo, satotz, shizuku) carryreadonly: true. Part of #449. - Repin nen to v0.28.0 (
dependency.minimum0.28, the compatibility floor nen moved for six exit and output changes), with the release's three checksums; declarecanon.lint(the canon prose lint's rules, baseline and skill paths),review.excludedPersonas(the four intake examiners, never a code reviewer) andprecedenceRestatedIn(WORKFLOW's prose restatement, held to the contract'sprecedence). Part of #449. - Attribute Hanten reviewer spend for numbered rounds and bounded delta passes, including historical bare-delta sources. Refuse malformed Hanten usage with the record and expected forms; document each source form without changing review budgets or ledger history.
- Capture the Delivery parser with Node’s existing exact-source coverage pattern alongside shell coverage in one focused fixture run.
- Select the Delivery lane in the trusted CI runner and require both fixtures. Automatic PR selection starts after the updated runner reaches the trusted base; this initial PR does not prove live CI adoption.
- Keep the bump guard and contributor list current with the composed adoption, history, refresh and publisher runtime helpers; prove each helper-only edit refuses an unchanged plugin version (#439).
- Plugin bump checks now cover every helper that skills execute or read from the installed Hatsu root, preventing fixes to those shipped paths from being omitted from installed copies. Closes #439.
- PR section validation now executes through installed Hatsu directory and file symlinks, compares real filesystem paths, and reports a failed CLI entry resolution instead of silently succeeding. Library imports stay inert. Closes #417.
- The Node toolchain now checks for
import.meta.mainas well as the>=22.18floor. Node 23 and 24.0–24.1 lack this capability and are refused; supported Node 22.18+ and 24.2+ retain inert library imports. The section checker also refuses unsupported hosts directly, including when its CLI entry path cannot be resolved.
… more in CHANGELOG.md
v0.142.0
v0.142.0 — The SDD-100 delivery and the first idle kazaana batch
- The canon prose ratchet lint (HR-13, HR-4).
scripts/prose_ambiguity_check.mts(lanecanon-lint) readsclaude/skills//SKILL.md,claude/agents/.md,claude/rules/.mdanddocs/*/.md, neversurfaces/*, against the twelve rules ofcontracts/prose.lint.json(PL-01…PL-12) and the shrink-onlycontracts/prose.lint.baseline.json, whosePL-03(stale nen pin) andPL-04(dangling citation) rows are always empty. Exits0clean,1findings (a stale row, including one whose file the walk no longer reads, and a row grown over the base revision's baseline, summed per key),2wiring (a rule id paired with another class than its handler's or missing a key it reads, a repeated baseline key, a marker row that is not ask-once-per-run, a link through a symlink leaving the root); never green over a file it could not read. Rule ids are fixed; the RETIRED exemption is the contract'sretired.rules; quotes pair within one line and never across a code span; anchors keep_; bracket and clause spans are bounded. Its TypeScript fixture,scripts/prose_ambiguity_check_fixture.mts, carries the hostile cases (CRLF, a heading inside a fence, folded frontmatter, a symlink leaving the root, a marker naming a human-gate row, an unparseable contract). Owed tonen canon lint(zheref/nen#481) andnen ref resolve --citation(zheref/nen#482). Page:docs/config/prose.lint.json.md. - The advisory
canon-lintcheck, step one.templates/prose-ambiguity-check.yml, cloned fromprose-size-check.yml's hardening, is registered ahead of its file inscripts/workflow_runner_policy_check.rbwith its guard step frozen and its node pinned; the guard passes the trusted base revision's baseline as--base-baseline, so the check refuses growth. Installing it is step two (docs/GATE-CONFIGURATION.md). Thecanon-lintfixture runs inunit-tests.ymlthroughscripts/unit_tests_ci.mts, andscripts/trusted_guard_preflight.rbderives.mtsguards (the canon lint and the direct-matrix check run; the readiness verdict is named as not run before a PR exists). - Three conventions.
docs/PROCESS.md§ An unresolved question in prose (the one marker shape, the contract's ask-once-per-runmarkerRowsonly, every human-gate row refused, at most three per skill, a ledger reference, no default); § Residue and owned dependencies: every Residue item citeszheref/<repo>#Norunfiled;docs/ROSTER.md§ The ruling template. - Stale pin claims and dangling citations on the tree.
futon,pr-state,tenkai,limbo,docs/WORKFLOW.md,docs/PROCESS.mdanddocs/config/plugin-registries.mdstop restating a nen pin;kazaana,kotoamatsukami,mukai,ren,docs/WORKFLOW.md,docs/PROCESS.md,docs/STANDALONE-ENTRY.md,docs/config/plugin-registries.md,docs/ab/hatsu-plugin-update.mdanddocs/history/v0.42.0-prose-diet.mdre-aim citations that resolved to nothing.docs/WORKFLOW.md's Report titles and Where the effort is anddocs/PROCESS.md's AI reviewers per consumer become headings. (landed by #402, through #412.) - Handbook canon repinned from
zheref/bankai-handbooksv0.6.0tov0.11.0.nen/repos.json→maintained_tools→zheref/bankai-handbooks→pinnedreadsv0.11.0, moved bynen canon pin --write(tag first,CON-13).hatsu:bankai-handbooksandhatsu:bankai-qualityquote the tag their prose was re-read against on 2026-10-22: the always-load set is the same five files;handbooks/spec/authoring.md(SP-{n}) and thehandbooks/ports/family (PT-{n}:INDEX.mdplus the six directed pair files of the three product stacks, zero rulings each) load beside the set; each product stack handbook ends in an Appendix — capture reader mapping its file suffixes to the spec row kinds;UZF-21carries clauses (a)–(f),UX-13governs cross-platform adaptation,SEC-15binds every lane that reads content it did not author, andQA-26is reserved. The review preamble's prefix list admitsSP-andPT-. Both skills record that nen0.24.0answersnen repo scenariofor amaintained_toolsrow that declares ascenario, and quote its refusal for one that does not. No canon mirror to regenerate (Hatsu carries none); the three surface mirrors are regenerated at0.134.0. Five stale rows leavecontracts/prose.lint.baseline.json. (landed by #421.) - Acceptance-criterion coverage is
nen pr converge's verdict alone (HR-11; zheref/hatsu#413). The interimscripts/pr_criteria_check.mtsand its fixture retire at the nen0.26pin:hatsu:shibari§ 4 runsnen pr converge --target <owner/name> --pr <n> --requirements-from "$hatsu_root/contracts/issue-sections.json"after open and edit,hatsu:en§§ 4–5 hold its exit0as a readiness conjunct besidenen pr readyandbody-check, andhatsu:rikugan§ 3 quotes it beside the verdict. Closing issues now come from GitHub's closing references (or, off the default branch, the body's closing keywords) rather than the Associated issues table. The catalogue declares nocoverageblock, so nen's defaults apply, andtemplates/pr-body/verify.md,docs/PR-SECTIONS.md,docs/config/plugin-registries.mdanddocs/config/spec-repo.mdname the verb instead of restating its rules. Thecriterialane stays, on a new fixturescripts/pr_criteria_fixture.mts: every reader cites the verb with Hatsu's catalogue, no canon file restates the coverage rule, the catalogue is read throughnen issue criteria --body-file, the verify template andverify-contentwiring, andcontracts/hanten-findings.schema.json's disposition invariants;scripts/unit_tests_ci.mtsgates it as its own fixture. Cloud tier'sAC-{epic}-{nnn}rows (zheref/hatsu#411) are unrecognised by nen0.26.0, pinned in the fixture as a documented miss owed to nen. Installed copies get the change by updating to0.140.0. - Settle round (hanten on HA-PR-#456).
hatsu:en§§ 4–5 word the conjunct once (converge's exit1is not ready, whatever it blocks on) and carry one G4 reading:closingSourcenone-on-non-default-basewhile the Development guard's--bodyform exits0(no closing row, as a stacked delivers part PR) is not applicable, ruled by the maintainer as HR-357 (record R-2026-10-24-01, zheref/hatsu#450): reported as such withclosingSourcequoted, never as a pass, and readiness and en § 5's recorded delivery merge proceed on the other conjuncts.hatsu:shibari§ 4 says when converge runs and what exit1asks. Thecriterialane runs unconditionally inunit-tests.yml, catches the restatement shapes it retires in each file's joined text, so a hard-wrapped one too (ROSTER's HR-11 row cut out by its id as the ruling), pins nen0.26.0's raw U+202E inissue criteria --jsonas a miss owed to nen, and cleans its temp directory.docs/NEN-CONTRACT.mdanddocs/history/nen-repins.mdrecord the adoption. (landed by #467.) - Acceptance-criterion coverage is a readiness conjunct, and a constitution-cited finding is critical by shape (HR-11, HR-10).
templates/pr-body/verify.mdgains, for every repository kind, one| Criterion | Coverage | Evidence |row per AC id of each closing issue:<CODE>#<N>/AC-<k>, the closed vocabulary satisfied · partial · missing · contradicts · unrequested, and a test name, path:line or scenario. Theverifycatalogue row declarescontent: true, socontracts/pr-body.requirements.jsongains averify-contentrow and an empty verify heading failsnen pr body-checkandscripts/pr_body_sections_check.shalike.scripts/pr_criteria_check.mts(--bodyor--pr,--json) derives each closing issue from the Associated issues table, resolves its code throughnen repo resolve, reads its- AC-{n}:rows throughscripts/gh_token_env.sh, and exits1on a criterion with no row, amissingorcontradictsrow, or a closing issue with no criteria (not-verifiable, never a pass); its fixture runs on the newcriterialane.hatsu:shibari§ 4 runs it beside the evidence and Development guards,hatsu:en§§ 4–5 hold it as a readiness conjunct besidenen pr readyandbody-check, andhatsu:rikugan§ 3 quotes it beside the verdict.hatsu:hanten§ 4's reviewer prompt carries the closing issue refs quoted; the review preamble § 3 and hanten § 5 admit<CODE>#<N>/AC-<k>,CON-{n}andHR-{n}as rule values; hanten § 6 never pushes back aCON-/HR-finding, only fixes it or defers it to a named amendment PR.contracts/hanten-findings.schema.json(hatsu.hanten.findings/v0.1) states the disposition enum, the required detail and the tracked ref; its registration withnen schema checkis owed to nen. The guard is owed to nen as part ofnen pr converge(zheref/nen#483). hanten, the preamble, shibari and rikugan pay their bytes by deleting restated links and restatements. (landed by #402, through #401.) scripts/pr_body_delivery_check.shrenders the Delivery expectation from Hatsu's owntemplates/pr-delivery.md, resolved beside the script, instead of<--repo>/templates/pr-delivery.md. A consumer carries no such file, so on any non-Hatsu target (zheref/nen's NN-PR-#507 the first seen) the guard exited 2 withcould not read '<target>/templates/pr-delivery.md' (ENOENT)and could never pass; a target that did carry one would have had its own text checked as the expectation.shibari§ 3's manual Delivery render now names"$hatsu_root/scripts/pr_delivery.ts"and"$hatsu_root/templates/pr-delivery.md"for the same reason. The guard resolves its own directory physically (cd -P,CDPATHcleared), andscripts/pr_delivery.tscompares real paths before running, so a call through a symlinked plugin root (~/.claude/skills/hatsuis one) no longer exits 0 having written nothing.- The guard and its engine are plugin-shipped paths.
scripts/pr_body_delivery_check.shandscripts/pr_delivery.tsjoinPLUGIN_SURFACE_GLOBSbeside the evidence and Development guards, so a change to either needs a version bump and reaches cached installs; this release is0.138.1.CONTRIBUTING.md's copy of the list is re-synced, picking upscripts/issue_body_check.mtsandscripts/pr_criteria_check.mtsit had missed. Installed copies get the fix by updating to0.138.1. - The delivery fixture runs the guard against a target with no
templates/, with a planted template it must ignore, from a plugin root with no template (refused, naming the plugin's path), and through a symlinked plugin root; each fails againstmain's guard or engine. (landed by #438.) hatsu:dowsing-chain, the capture skill, wave 1 (HR-12, HR-16). A product family's sibling repositories read through their build-system membership into evidence rows and written once as a private, livinggithub/spec-kitcanon in the family's spec repository: the constitution merged first, one folder per capability in waves at G2, every statement ending in[src: <CODE>:<path>:<l1>-<l2> @ <sha> · <tier>]or exactly one marker, one bounded clarify sitting, the intake examiners' uncounted challenge (HR-23 … HR-41); thendispatchfiles only what the never-starred picker names at a pinned spec sha,wavebuilds filed marker-free issues throughfutonon the typed call,recaptureappends a convergence diff, andresumecontinues from${XDG_STATE_HOME}/hatsu/specs/<run-id>.json.docs/config/spec-repo.mdstates the five-template grammar, the id, citation and marker grammars, the living-spec model, the pickers, the issue and PR Spec shapes and the run recordhatsu.spec.run/v0.1once, and cites the SP family's confidence tiers and vocabulary rule (SP-2, SP-3, SP-5) with Hatsu's deltas;nen/decisions.jsongains eight rows (spec-capture-scope,spec-slice,spec-clarify,spec-claim-unverified,spec-dispatch,spec-coverage,spec-conflict,spec-converge-filing); offline fixtures underscripts/fixtures/spec-family/. The nen spec verb family is owed (zheref/nen#493), so the inventory is prose-made and unverified until it lands;--dry-runruns end to end today. The skill joins the dieted list and its three surface mirrors. (landed by #402, through #408.)- An intake examiner can no longer be configured as a hanten reviewer (HR-23).
config_values.sh set --id workflow.review.scopesrefuses, exit2and nothing written, any scope whosepersonaissatotz,lippo,buharaorbisky— the set read from the catalogue'sintake.challengeroptions, never a second copy — in the TypeScript adapterscripts/config_values.ts(BC-11). The adapter now reads the engine's mode after--hatsu-root, sofillanddiagnosekeep their enrichment when that flag comes first.hatsu:hanten§ 3 names the four and treats one raised by a hand-written scope as a gap; nen's own refusal for hand edits is zheref/nen#472, and running this lane in CI is zheref/hatsu#397. Theconfig-values-guardlane now runsscripts/config_values_fixture.sh: the frozen engine's self-test, thenscripts/config_values_examiner_fixture.ts(the examiner set checked against the agent files and the two prose copies; refusals by name, case, whitespace, zero-width and full-width forms, a path,.mdorhatsu:form, in any scope, under a repeated--idor--value, a flag's value that looks like a flag,--hatsu-rootbefore the mode, and aNaNliteral the strict parser cannot read — refused, never passed through; a hanten reviewer still written; red on 0.131.0).docs/config/workflow.json.mdand the catalogue row say so. Plugin bumped to 0.133.1. (landed by #398.) - futon runs on nen's run manifest (zheref/hatsu#423).
scripts/futon_effort_record.mts startopens the manifest throughnen run start --id <run id> --target --repo [--idle-answers]and only then writes its ownership record, contracthatsu.futon.run/v0.3(id, repo, invocation, selector,startedAt,dry, and the idle profile'sterminal,budget,source; no PRs, no parks, no answers). Every opened PR isnen run append, every parknen run park, thethengate and the registernen run verify, the budgetnen run budget --max-minutes --max-tokenswith the committed profile's values, and futon § 6's slotsnen loop slots --from-run <run id> --target— no typed efforts file. The record'sappend,parkandstatusare retired and refuse by name; a newprofileprints the ownership record. A run started before this release has no nen manifest, so itsthengate is held. Park rows are[a-z0-9-]+:g5-<class>andresidue-<skill>replace the colon forms nen refuses.
… more in CHANGELOG.md
v0.130.0
v0.130.0 — Port rulings numbered PT-{n} from one global counter, and the SDD assessment's rulings recorded as HR-1 … HR-34
- #355 Port rulings are
PT-{n}from one global counter (#355). The maintainer ruled on 2026-10-21, recorded indocs/ROSTER.md§ Rulings of 2026-10-21 — the port rule prefix (HA#355): the ports rule prefix isPT, and one counter runs across every pair file of the rulings directory. The answer is HR-34, re-confirming HR-9.templates/ports/pair.mdcarriesprefix: PT · numbering: global. Citations keep the ruled form<from>--<to> PT-<n> (branch <ref>, unmerged). (landed by #392, #355.) scripts/port_rule_reserve.shreads every<rulingsDir>/.md(the--pair-file's own directory) at the tip, at the run's HEAD and working tree, on every siblingports-branch, and in every open same-repository PR touching one. The next id is one past the highest anywhere.--checkrefuses one id in two pair files, including a tip row in a different file.- Exit 2: a
--pair-filewith an empty,.or..segment, a leading./or a trailing/; a--prefixother thanPT; a--targetwhose name is not a segment (acme/.,acme/..). - Exit 3: any header line (
<!--namingprefix:ornumbering:, keys in any case, at any indent, in a file or in an open PR's added lines) that is not exactly oneprefix: PT · numbering: global, withglobalfollowed by whitespace,),·or-->; a headerless file is counted. A pair file named out of shape, its path printed. A first cell carrying another prefix (SW-3), orPT-<digits>that is not a row. Every GFM row form is counted: a pipe-less row, up to three leading spaces,**/*/backtick emphasis. A row in a fenced example is counted too, a safe over-count. - Exit 1, nothing reserved: a failed git listing, blob or working-tree read.
- Never read, or not others: a fork PR is never read and is listed by number only. The run's own push and own PR are not "others" to
--checkwhen, and only when, they are ancestors of HEAD (the PR by itsheadRefOid); a same-named branch or PR of another run is counted.--checkalso flags one id in two rows of one pair file. A local head trackingrefs/pull/*, or a remote whose URL is not origin's, is skipped and reported by count, never by name; a remote unset or.is read.--jsonescapes every control character. - Every earlier refusal keeps its exit code, except the fork-PR reads, which are never made (exit 1 → 0). The
port-rule-guardfixture proves each case (77 checks, at bash 5.3 and at/bin/bash3.2). hatsu:bankai-rule§§ 2–3 state the rulings-path grammar and the prefix and header refusals. § 3 drops the G5 stop that held the global case.hatsu:kamuiandhatsu:bankai-handbookslose stale "not landed" and "ruled on its adoption PR" wording.- The reservation stays linear in rows and costs no more than the one-file read it replaced: one listing per place, one blob batch and one judging pass for every place, whatever the number of pair files.
- The open-PR reads stay residue until zheref/nen#456.
- Plugin bumped to 0.130.0.
- The SDD assessment's rulings are recorded as HR-1 … HR-33, and the HR id space starts.
docs/ROSTER.mdgains § Rulings of 2026-10-20 — the SDD assessment sitting: the maintainer's sixteen picker answers to Part 9 of the SDD assessment report, each question, the options shown and the pick recorded as the label the picker returned (private repository names placeheld), under stable anchors HR-1 … HR-16, every rowruledat the sitting. A second section, § Rulings of 2026-10-21 — the SDD sitting's follow-up questions, records HR-17 … HR-33: the six questions the sitting left open (HRis Hatsu Ruling; OPEN-4's contract and cap; the 2026-10-19 delegated-publication reading ratified as written;intake.challengeras a map; Hidan kept per consumer), then the intake cast they led to — in the maintainer's own words a dedicated cast that only challenges at capture intake, isolated from code review (HR-23), the Hunter Exam examiners Satotz, Lippo, Buhara and Menchi (HR-24), every matching examiner, Satotz for anything unmapped and for challenging the Design Direction Menchi drafts, shared machinery, and challenge rounds never counted but run until the brief is fulfilled, its criteria ideally testable, stalled examiners dropping out until none remains and the maintainer is asked, a decline filing the open questions (HR-25 … HR-33). HR-14's challengers, HR-19's cap, HR-21's values and HR-28's ledger are marked reversed or superseded, their wording unchanged; How HR ids are read gains the partial and ratified-by cases. OPEN-4 is closed, and § Sources notes that HR-1 retires its upstream fallback. Rulings only: every change the rows settle is owed to its own PR, the intake cast's definitions, ROSTER section,intake.challengermap andemperor-timechanges among them. Plugin bumped to 0.129.1 (overtaken by #392's 0.130.0;mainreads0.130.0at this cut). (landed by #391.)
v0.129.0
v0.129.0 — Gemini 3.1 Pro as the hallucination-shaped fallback, read-only GitHub API access restored, the canon guard names no stale version, and Shizuku's second cleanup pass runs on every surface
- Defined Shizuku cleanup pass 2 consent channel, fixed local branch deletion against fetched base, and anchored cleanup markers (#319).
cleanuppreviously failed to run pass 2 on Claude Code because Shizuku declares no question tool (tools: Read, Grep, Glob, Bash) and subagents cannot receive user turns, while her canon correctly refuses a relayed prompt string as maintainer consent. Under candidate (b), uniform across Claude Code, Codex, Cursor, and Antigravity, Shizuku inventories on pass 1 and writes an initial marker (plan[], emptypicked[],done[],result: "pending"), the main session presents the picker through the surface's native question tool (AskUserQuestion,request_user_input,AskQuestion,ask_question) and recordspicked[]and rawpickerAnswerin the marker, the main session executes the picked rows fromplan[]in pass 2, and Shizuku returns to verify read-backs against the marker, update freed bytes, and close the marker. Local branch deletion incleanup§ 5 now runs the ancestry check against fetchedorigin/<branch.base>before non-force deletion (git merge-base --is-ancestor -- '<branch>' 'origin/<branch.base>' && git branch -d -- '<branch>'), and explicitly classifies a branch that passes ancestry but thatgit branch -drefuses against a stale local trunk (deterministic once the core trunk is fast-forwarded, or proposed with that reason), never retrying with-D. The cleanup marker path is explicitly specified as<core>/.nen/cleanup/<slug>.json(with session worktree fallback where isolation blocks core writes),<slug>is defined for all scopes, markers are read from both locations, cache removal prints literal absolute paths, and detached release worktrees are classified explicitly via commit reachability fromorigin/<branch.base>. Plugin bumped to 0.120.0 and mirrors restamped (the bump that fragment names was overtaken by later merges;mainreads0.129.0at this cut). (landed by #387, #319.) - #317 Canon guard output (#317). The canon contracts guard now describes Nen's current invariants without repeating an obsolete version in its header or pass line. (landed by #384, #317.)
- #326 Read-only GitHub API access (#326). Claude Code's permission pack now grants a named TypeScript reader for audited REST GETs and a fixed GraphQL query. The reader rejects caller-supplied methods, endpoints, bodies, and mutation text before invoking
gh. Installing the pack removes the retiredgh api *allow rule from older local settings while preserving unrelated entries. Local trusted-guard preflight also runs the newly required private-name fixture. (landed by #383, #326.) - #342 Gemini 3.1 Pro is the fallback on the hallucination-shaped reading cells (#342). Under the maintainer's four rulings of 2026-10-20, recorded in
docs/ROSTER.md,contracts/direct.registry.jsonmoves the fallback of 21 Opus-primary cells from GPT-6.1 Sol on Codex to Gemini 3.1 Pro on Antigravity (VISUAL_ORCHESTRATOR): requirements, analysis, triage, deprecation, prose-authoring, evals, drift-review and parity. The other 19 reading cells and the 24 execution-adjacent Opus cells keep Sol, and Opus stays primary on the four discovery/backlog cells Pro already backed.VISUAL_ORCHESTRATOR's selection text states the measured profile with its source and date, and the standing terminal-cell rule: never an execution-side primary or fallback, never the fallback on an execution-adjacent Opus cell. Four older cells where Pro already backs Sol are named there as open for the maintainer (ruled grandfathered at the merge prompt of 2026-10-20).VISUAL_FALLBACK(Flash) is kept for a later in-pool role.docs/DIRECT-MATRIX.mdis regenerated; a consumer's directed issues change their fallback only on their nexthatsu:directsweep. Plugin bumped to 0.129.0. (landed by #388, #342.)
v0.128.4
v0.128.4 — the redaction fixture runs in CI, file stages drafts safely, PR bodies resolve from a section catalogue with a Delivery preamble, the porting trio lands, readiness reads Nen's JSON and unit tests run on pull requests
classify.publish(label|label+comment, catalogue idworkflow.classify.publish): underlabel+comment,hatsu:classify§ 5b posts one marker-keyed<!-- hatsu:classify -->comment per labelled issue carrying the appliedlang//job/keys with confidence and cited signals, the low keys and any undecidable axis, idempotent on the poster's own marker, never underrenor for an inline effort.fileandbuildname it besidedirect.publish. Hatsu's own value islabel+commentfor both keys, on the maintainer's request of 2026-10-20 (ROSTER § Rulings of 2026-10-20 — classify and direct always write back); the family and consumer repositories set both through their own PRs. Plugin bumped to 0.127.0. (landed by #369.)- The classify criteria comment is specified in data and carries no issue text (hanten round 1 on #369, landed after #369 merged at its pre-review head). The whole contract moves to
contracts/classify.taxonomy.json→publish—classify.publishread at the default branch's tip (a PR cannot opt itself in), one comment per classified issue with unapplied keys marked not applied and their reason, signals posted as category ids (signalIds) and never as issue text, an injection-suspect row posting keys only, idempotence on the poster's own trailer, amktempbody file outside the checkout, the private-names ignore file, failure never a stop, the sweep picker naming the comments, keys decided against the taxonomy alone (the target'snen/labels.jsonbounds what is applied), a trailer carryingapplied=and a-form so a status change re-posts and an undecidable issue's comment parses, a paginated marker read keeping id, author and last line only, every body line checked against the closed grammar before posting, and a private-name refusal stopping the remaining posts — and classify § 5b points at it, so no marker literal reaches the mirror generator's prefix rewrite (which turned it into$classify//classifyon Codex, Cursor and Antigravity). The ROSTER rows are marked as this run's reading, row 3 agrees with the skill, the rollout names the sibling PRs and bankai-handbooks as owed; WORKFLOW § 2 gains theclassifyblock;build,emperor-time,file, DISCOVERY, PROCESS, the READMEs and the config docs name the key. Plugin bumped to 0.127.2. (landed by #372.) hatsu:direct§ 7 no longer quotes its comment marker as a literal. The mirror generator rewrites thehatsu:invocation prefix everywhere, so the Codex, Cursor and Antigravity mirrors told those sessions to look for$direct//directmarkers that nobody posts, which could lead to a duplicate public comment. § 7 now points atcontracts/direct.registry.json→publish.comment(marker,idempotent,shape,versionPattern,bodyFile,verb), the same fix zheref/hatsu#372 made for classify, and the mirrors carry no marker literal. A sweep ofclaude/(hanten round 1 on this PR) found three more spans the rewrite bent:hatsu:neterointhird-hand's Claude Code raise row andhatsu:shalnarkinblack-voicenow name the plugin's agent, andmugetsu§ 0's slash-prefixed/hatsu:mugetsu(mirrored as/$mugetsuand//mugetsu) drops the slash; every otherhatsu:code span is an invocation and is meant to be rewritten. The generator-side fix is zheref/nen#465. Plugin bumped to 0.127.3. (landed by #373.)- Publish the readiness check from Nen's structured JSON verdict in Hatsu and Tenkai-rendered workflows, with the reader installed from the trusted base checkout. (landed by #328, #131.)
- #131: Admit a trusted, head-pinned TypeScript reader for
nen pr ready --jsonbeside the current frozen readiness step. The workflow and Tenkai template move to the JSON form in the follow-up installation PR. (landed by #327, #131.) - Add the ledger-rendered Delivery metadata preamble to PR bodies, with observed surfaces, model tokens and registry aliases, effort dials and session identity; retain explicit unread values for unavailable facts. Require the Delivery guard before every body write while keeping commit trailers and the final Agent attribution ledger persona-only. Adopt published Nen v0.24.0 for its phase, usage and session ledger APIs. (HA-IS-#321) (landed by #374.)
- Run the redaction-guard fixture as a frozen
Redaction guard fixturestep ofsurface-mirror-check.yml, on the trusted checkout with no secret, no private list and no token, so a guard regression goes red in CI; the workflow-policy validator now requires the step, completing the two-step landing. (HA-IS-#337) (landed by #377, step one #376.) hatsu:file§ 4 no longer stages the title through a quoted heredoc. It told the filer to writetitle.txtwithcat > title.txt <<'EOF', the constructiondocs/PROCESS.md§ Escaping the maintainer's words forbids, since a quoted heredoc's delimiter is in-band. § 4 now says to write every draft (title, body, comment) with the surface's own file-writing tool and points at that PROCESS section rather than restating it (zheref/hatsu#345). A title-file flag is still owed to nen (zheref/nen#444); until it lands the title is typed single-quoted, as § 4 and § 5 now both show. Plugin bumped to 0.128.3. (landed by #375.)- PR bodies resolve from one section catalogue by repository kind and work family, with a seven-reader cap, glyph headings, kind-specific verification tables and a warning above 150 prose words per section (#351). Templates now live per section; footer blocks remain outside the cap and Delivery remains reserved for #321.
- Configuration fill writes every default matrix cell and its section-purpose annotation while preserving consumer edits. Interim resolver and body-section guards have a hermetic focused lane; source skills and all surface mirrors use the same catalogue. Release rows retain the written matrix as the maintainer clarified on 2026-10-20.
- The mirror fixture now verifies that CI calls the shared regeneration script and refuses a copied hook-root table. Its prior assertion expected the retired YAML copy and failed on unchanged main; per-surface generation parity remains covered by the regeneration fixture.
- New interim branching logic and fixtures are TypeScript (
BC-11); existing configuration Python is moved unchanged behind a catalogue adapter, and the old composition Python only loses its migrated section checks. Adversarial review also covers literal/escaped comment openers, thematic breaks, dangling declarations, terminal-safe diagnostics and the three-dot PR path range. (landed by #364.) hatsu:bankai-rule(#355, child 1 of the porting epic #354). A port ruling — what a source stack's rule or concept becomes on the target:mirror·map·drop with note·target-only addition— recorded once as a stable-id row in a directed pair file ofzheref/bankai-handbooks'handbooks/ports/family (rendered fromtemplates/ports/), the id reserved against the tip, the run's own branch, every pushed or local sibling rulings branch and every open same-repository PR, with a--checkduplicate pass at every catch-up (scripts/port_rule_reserve.sh, theport-rule-guardlane's fixture with aghstub), one rulings PR per port run throughaka → mukai → ento the G4 prompt. The pair is parsed with scenario slots enumerated fromhandbooks/stack-matrix.mdand the ruling split off before the parse (the probe, refusal included, indocs/ab/bankai-rule.md). Shared pieces the later children use:file§ 4's one clause (a composite's typed call or a ruled picker answer stands as the confirmation), theport-driftdecision row (one batched picker call per run), the catalogue rowsworkflow.port.handbooksRepoandworkflow.port.rulingsDirunder the newportdomain,bankai-handbooks§ 2 reading a pair file through--always-loaduntil nen resolves it (limbomirrors none at 0.22.0). Owed to nen and filed: zheref/nen#456 (an open-PR id-reservation read), zheref/nen#457 (pair resolution and mirroring — no mirror carries a pair file at 0.22.0, so the limbo half of criterion 5 is owed there) and zheref/nen#458 (a first-anchored trailing clause for the ruling split). The rule prefix stays unnamed (<prefix>in the template) until zheref/bankai-handbooks#4 rules it. README counts corrected to fifty-four skills; plugin bumped to 0.125.0 (both manifests); the mirrors regenerated. Incidental:nen/contract.json's duplicatetoolchain.nodekey is folded into one whose reason names its three consumers (the effective value is unchanged). (landed by #367.)hatsu:kamui— one feature written once as the product's spec, then ported to the siblings you pick (plugin0.125.0; zheref/hatsu#356, child 2 of the cross-platform porting epic zheref/hatsu#354).hatsu:kamui <CODE>-IS-#<N> | <CODE>-PR-#<N> [--dry-run]writes the source issue (or a merged PR and its closing issues) as agithub/spec-kitset in the product family's spec repository. The set is pinned atv1.2.2, read live on 2026-10-20:specs/<nnn>-<slug>/withspec.md,plan.md,research.md,data-model.md,quickstart.md,contracts/,tasks.mdandchecklists/requirements.md, plus.specify/memory/constitution.mdonce, which citesCON-{n}and never overrides it. The spec repository is searched first for the source and its linked objects, each matched as a fixed string on word boundaries, so a later port of the same feature amends its folder. The spec PR runsren → aka → mukai → ento the G2 merge prompt, and nothing is built before it merges: the wait isnen watch untilon the PR's state;CLOSEDends the run spec declined, and an observation-error streak is a G5. Then the sibling picker asks which configured siblings get a port issue (newnen/decisions.jsonrowport-siblings). It is never starred, pages in fours, and asks even for a lone sibling. Its answer is the G1 for one port issue per pick throughfile§§ 3–5, written bynen issue file --assigneeand read back explicitly. Next, a start picker runs the picks ashatsu:buildone after another. Kamui holds build's register and wrap-up, and a build's G5 stops the chain. Missing setup is asked per item, in order; creating the spec repository is a G5 hand-over line, given only when gh says the repository does not resolve. A member whose visibility reads public never receives the family.
… more in CHANGELOG.md
v0.124.0
v0.124.0 — hatsu:file routes every filing, emperor-time intake, CI reviewer lanes, and nen's gate path sets
hatsu:filenow runshatsu:directon every new filing, right afterhatsu:classify: the three picks, resolved from the target's own checkout, kind and role, join the one plan and confirmation; once the issue has a confirmed number and its classification keys travelled in the create call,direct§ 7 publishes under the target'sdirect.publish, else routing is reported owed. A missing verb, an empty job axis or an undeclaredmodel/label is said and never stops the filing (the maintainer's request of 2026-10-19). (landed by #335.)- The private-name guard says
no ignore filewhen none was read (#149).scripts/private_name_check.shused to report an absent default ignore file as0 ignored by the maintainer's ignore file, indistinguishable from a file that was read and ignored nothing; every ok line (--allow-emptyincluded) and every refusal now sayno ignore file, so nothing ignoredwhen none was read, and a dangling default ignore-file link is a wiring fault (exit2) rather than a silent absence, and a host with neitherXDG_CONFIG_HOMEnorHOMEset refuses at exit2naming why, where bash's unbound-variable exit1read as a finding. The other exit codes are unchanged, and theredaction-guardfixture proves each state (188 cases).docs/PUBLIC-REDACTION.md§ How it is guarded records that theredaction-treelane is red by design without the file and that a session hands that refusal to the maintainer, never judging it no leak; the 2026-10-13 #149 row indocs/ROSTER.mdcarries a dated pointer to the #289 item 10 row that spent its 2(b) deferral. Plugin bumped to 0.117.0 and the three surface mirrors restamped. (landed by #343.) - #154 Futon delivery merges (#154). Futon records its invocation before a PR opens and binds stacked delivery PRs to that run. En may merge only a recorded PR with a pinned Ready verdict through Nen's bounded non-main delivery guard. Main-bound PRs remain at the maintainer gate. The Claude Code permission pack admits only the bounded
nen pr merge … --delivery … --require-head … --runpattern — Nen's delivery guard, not the pattern, refuses protected bases, a non-Ready verdict and a moved head; the Futon record is checked by en § 5'sfuton_effort_record.mts verify, not by Nen or the pattern — keeps directgh pr mergedenied, and removes broadgh api *access that could bypass the guard. Node 22.18 or newer is required for the TypeScript record helper. Live classifier proof awaits a later eligible Ready Futon stack. (landed by #325.) - Add narrow Claude Code permission-pack forms for Hatsu's declared plugin release plan and publication, with a fixture and explicit host-denial handling. The publication pattern admits any
--repo(Claude Code patterns carry no root syntax —contracts/permissions.json→scope.enforced_by); the maintainer's go is mugetsu § 3's recorded go, a rule nothing enforces (§ 5a), and the host may still deny the command. (landed by #322, #156.) - Add a conservative version-reference helper that lists every tracked old-version mention, rewrites only unambiguous authored lines, and leaves generated mirrors and PR bodies for their owning steps. (landed by #320, #158.)
- Warn authors when a dieted skill has fewer than 512 bytes of prose headroom, and require a changed changelog fragment when a version-bumped PR changes a declared spec path. The new decisions run in trusted TypeScript sources. (landed by #318 via #311, #166.)
- Use the shared mirror-regeneration script in the GitHub builder and retire its duplicated command loop after the trusted policy accepts the script form. (landed by #311, #209.)
- #234 trusted direct-matrix CI policy (#234). The workflow validator now admits the exact TypeScript-backed matrix drift step, while preserving the current no-step workflow during the staged landing. The adapter fences untrusted renderer output and reports its verdict; a focused fixture proves hostile output stays fenced. Plugin bumped to 0.114.6 and mirrors restamped. #324, below, installs the CI step. (landed by #323.)
- #234 direct matrix check (#234).
surface-mirror-checknow runs the trusted TypeScript matrix adapter against every PR checkout, so data-only registry, taxonomy and model changes fail on a staledocs/DIRECT-MATRIX.md. Nen repin PRs must run--verifyat the new pin and quote its agreement line. Plugin bumped to 0.114.7 and the three surface mirrors restamped. (landed by #324.) - The report data document's derivable defaults and the
--registerdesk's shape rules are written down once (#291). A newdocs/PROCESS.md§ The report data document, verified live against nen0.22.0, says whatnen report dataalready fills (repo,gate,effortStage,stageClass,worktree,generatedAtLocal,generatedDateLocal,timeZone,turnNumber), what--graphand--variantinject, a table of every extension key with a mechanical default and how it is derived (launchis total and never"": arenturn takes the lineamaterasu§§ 1, 1a or 3 recorded, and a landing — launch is never a mukai step — or any turn amaterasu did not run in takes the last call's line on the effort, elseno launch target declared; skippedwhere no target is declared, elseno launch in this session;deskClearedis""beside an ask;architectureCaptionis""only onturn-fast, sinceturnandlandingrefuse without--graph;mukaiLastTurnis the examples' boolean, counting En's first landing only when mukai started En in the same sitting and no newer request came; every row with no live source marked new canon for the maintainer to confirm), the judgement remainder the caller writes, the two call rules (a--targetread throughscripts/gh_token_env.sh; the desk passed by absolute path), therepofallback whennen repo resolvealso fails (the--targetslug, elsenullwith a blank masthead slot and the missing repo named innotDelivered[]andfooterNote, new canon), and the three desk rules the refusals used to teach, each with nen's refusal text and a minimal valid desk carrying ageneratedAtLocalplaceholder.docs/WORKFLOW.md§reportsReport time now says the plainnen report datafills the clock from0.22.0and only a hand-built document or a--registerdesk callsscripts/report_time.sh --at <generatedAt>, and Where the effort is derivesturnLabelfromturnNumber;PROCESS.mdcites both rather than restating them.spiritual-message§ 4 citesPROCESS.mdandWORKFLOW.mdReport time for the verb-filled keys and the clock instead of restating them, and drops from its extension list the keys the verb now fills;backlog-board§ 3 citesnen report data --helpfor the desk's shape instead of an inline copy, andrikugan§ 3 citesbacklog-board§ 3 for the desk's judgement andPROCESS.mdfor its shape and clock.PROCESS.md§ Residue and owned dependencies names the defaults derivation and the register pass's clock lag as owed to nen (not yet filed). The checked report examples'turnLabelnow readsTurn 3andLanding · after turn 3, and theirlaunchis the line a repository with noproject.launchrecords (turn-fast: the profile deferral) rather than a render command, and the report-markdown fixture's fence case injects its own entity-bearinglaunch. All three skills stay inside the 12288-byte ceiling. Plugin bumped to 0.123.0 and the three surface mirrors restamped. (landed by #358.) - The provenance guard no longer calls a failed merge proof an old Git, and no longer needs the object store writable (#314).
scripts/branch_authorship_check.sh --trunkused to self-merge the trunk withgit merge-tree --write-treebefore judging anything and report every nonzero exit as--trunk needs git >= 2.38, so a supported Git whose object store the sandbox would not let it write was sent toward a Git upgrade. The capability is now read offgit merge-tree -h, which writes nothing; the merge proof runs only for a trailer-less merge whose exemption must be proved, and it writes its tree into a throwaway object directory under${TMPDIR:-/tmp}(named by a template, so macOS honoursTMPDIR; the repository's objects as its alternate; removed on exit), so it adds no object to the repository's store — Git may refresh the mtime of an object the store already holds, and where that is refused the tree is written to the throwaway directory — and a read-only store proves the same merge. Every Git read runs withGIT_NO_REPLACE_OBJECTS=1and aGIT_GRAFT_FILEthat cannot exist, so arefs/replaceentry cannot pass an evil merge off as the clean one andinfo/graftscannot hide a commit from the range: the guard judges the objects a push sends. The proof runs withGIT_NO_LAZY_FETCH=1, so a partial clone missing a blob it needs fails closed rather than fetching on the caller's credentials (Git 2.44 or later; an older Git ignores the variable and may still fetch). A proof Git still cannot complete — any exit but0clean or1conflicted (unrelated histories, a shallow clone, a partial clone that would need a fetch, a signal), or exit0with no tree id — is exit2naming the commit and Git's exit, quoting at most three lines and 300 characters of Git's sanitised stderr asgit said (untrusted):, read apart from the stdout the tree id comes from; it points at the harness's approval path only when the quoted lines themselves report a permission refusal, naming the directory actually used, and never at replacing Git. Findings are held until the range is through, so that exit2prints none. Thepublish-integrity-guardfixture now holds 138 cases (88 onmain; #314 adds 50): 25 of the 50 fail againstmain's guard and the other 25 pin verdicts it already gave. Plugin bumped to 0.119.0 and the three surface mirrors restamped. (landed by #348.) - Register
AK(zheref/cloud-tier, the Cloud tier CI plane) innen/repos.json, soAK#<n>resolves from a Hatsu checkout. Under the maintainer's ruling of 2026-10-19 it is the one private repository whose name may be public; its code stays private (zheref/hatsu#329). (landed by #338.) - Add a committed named list,
scripts/private_name_named.txt. The private-name guard reads it by default and drops exactly theowner/nameit carries. A bare name is refused, and a same-named repository under another owner is still a hit. The fixture covers it and pins the list's entry set (173 cases). (#338.) hatsu:file§ 4 joins the named list with the maintainer's ignore file into the one file nen's guard takes, until zheref/nen#441.hatsu:file,backlog-synthesis,mugetsuandsharingannow always pass that file to nen's issue writers.hatsu:build§ 1 resolves a code against the checkout it stands in, asclassifydoes. The private-name guard is BC-11 debt: it is frozen to fixes only until nen ports it (zheref/nen#441).docs/PUBLIC-REDACTION.mdanddocs/ROSTER.mdrecord the exception. (#338.)
… more in CHANGELOG.md
v0.114.0
v0.114.0 — the backlog selector grammar on nen 0.22, the trusted canon preflight, and Cursor for Grok
- The shared mirror-regeneration script is admitted as the workflow's next frozen form, with its stamp-only behaviour proved, and it is named in Ao's catch-up path (#310 via #306, #209). #209 stays open: #311 installs the workflow step, and it is not in this release.
- Cursor is the official coding surface for Grok models. Grok Build remains a documented headless CI option, not a fifth interactive Hatsu surface (#308 via #306, #236, 0.113.1).
- Focused fixture lanes report silent failures by name, and failure probes under
set -ereach their own expected/actual assertions (#307 via #306, #243, 0.113.0). - En continuations route a published PR's updates through Murasaki's guarded fast-forward push, reserving Aka for first publication (#309 via #306, #292).
- The trusted canon contracts guard runs during local PR preflight, naming broken candidate contracts before a PR opens (#306, #293).
backlog-stateandbacklog-boardtakecontext, gate lists, severity bands and label selectors (#315, #297; the maintainer's rulings of 2026-10-17, recorded there).- The grammar is
<repo|all|context>[@<gate>[+<gate>…] | <severity>[+] | <label>][#<label>[&<label>…]], plusevery …on the board.+between gates is OR,&between labels is AND, and every filter combines as AND. - It parses through
nen parse's list slots and three-way alternation, read byalternativeanditems. - Labels and severity bands filter through
nen backlog fetch/nen report data--label/--severityagainst the target's ownnen/labels.json. A label containing&is unsupported, and a target with nobankai:severity/*family has no bands. Follow-ups are tracked in zheref/nen#427. contextcovers only the objects named in the conversation, echoed as a per-repository list before a fresh read.- backlog-board's § 1 defers to backlog-state's, so the two cannot diverge.
- nen repinned to
v0.22.0(minimum "0.22") (#315; zheref/nen#410, released by NN-PR-#423). - The list slots and the backlog filters are 0.22's, and the release raises nen's compatibility floor to 0.22.
nen/contract.jsoncarries the three release digests, and every convenience copy names the new pin.
… more in CHANGELOG.md
v0.112.32026-10-13
v0.112.3 — the 2026-10-13 rulings built, pickers and hand-overs, the redaction tree
reports.sectionsis required for a render, and canon no longer promises a default nen refuses (#253, #108).spiritual-message§ 3's parameter row reads required, no default and citesdocs/WORKFLOW.md§ 2 →reports, which now states once what nen 0.21.0 does — an undeclared variant or a file with nosectionsis exit2; a variant withouttemplateor a non-emptyblocksmakes nen refuse the whole file, exit1(verified three times by hanten) — and the one adoption sentence: a repository that has never declaredsectionssets up the five-variant blockdocs/config/workflow.json.md§reportsdocuments asmissing-configurationat the first phase that will render, landing as WORKFLOW § 4 step 3 says. The false claim that a variant declaring no blocks renders every block is gone from WORKFLOW § 2,docs/config/workflow.json.mdand the skill;en's parameter table no longer gives.sectionsa default either. § 6, § 7, § 8 and two hard limits were shortened to carry the row under the 12288-byte ceiling, the Antigravity write permission keeping itsbrain/<conversation-id>/scope. Plugin bumped to 0.94.4; mirrors regenerated at that stamp.- Step one of the prose-diet guard in CI:
prose-size-check.ymlis registered in the workflow-policy validator and ships inert attemplates/(#270, #135). The validator judges every pull request from the base, so the workflow's job, trigger, draft-skip guard, check creation and frozen guard step are learned one PR before the file moves under.github/workflows/(#80's order); a workflow pending inPENDING_HOSTED_WORKFLOWSis judged fromtemplates/as if installed. The frozen guard step refuses to measure without a fresh fence token, and reads any exit but0and1as a wiring refusal. The exact-head check each guard workflow creates and finishes is now frozen at both ends inplugin-bump-check.yml,surface-mirror-check.ymlandprose-size-check.ymlalike, so its conclusion mapping cannot be edited into a green (QA-18). Every per-workflow table of the validator is checked at load to cover exactly its workflows, so a registration that misses one fails loudly.scripts/prose_size_check.shresolves a symlink's whole chain before its root check, so a link to an in-root link that leaves the root is refused, with a fixture case. Plugin bumped to 0.107.0 (templates/and a shipped runtime script); mirrors restamped. prose-size-check.ymlruns the trustedscripts/prose_size_check.shagainst every pull request's checkout (#271, #135). A file over its ceiling fails theprose-size-checkcheck, the guard'sOVERrow naming the file, its size and its ceiling, andnen pr readyreads the pull request not-ready. It is a check of its own becausepr-readiness.ymlconcludessuccessby construction. The guard used to run only by hand and in its focused lane, sohanten/SKILL.mdreachedmainover its ceiling with #129; it is under again on main (12286 bytes), and this effort leaves it untouched. The workflow landed in the #80 order (registered in the validator while it shipped inert attemplates/, then installed), now stated once as the new-workflow rule indocs/GATE-CONFIGURATION.md, withPENDING_HOSTED_WORKFLOWSkept as a permanent tier, empty when nothing is pending. Its guard step is frozen (PROSE_FROZEN_GUARD), and its exact-head check is frozen at both ends, as in the other guard workflows. The check is advisory and ready to be required, which is the maintainer's ruleset edit. Plugin bumped to 0.106.0; mirrors restamped.- A comment can no longer disarm a hostile fixture in
scripts/workflow_runner_policy_check.rb(#266, #136). The self-test built its fixtures withString#sub, which edits the first occurrence of a literal, so on #134 a comment spelling the trusted contract path took the edit meant forsurface-mirror-check.yml's pin read, and a trailing comment could take it while the suite stayed green. Every edit of a real workflow now goes throughfixture_sub: it tries each occurrence and keeps the first that changes what the parser and the shell see (YAML comments are not in the parse;fixture_codedrops a run's comment text, trailing comments included, reading'…',"…"and ANSI-C$'…'quotes and passing heredoc bodies over as data), inside the one step the fixture names or outside every step when it names none.fixture_codeis a reader, not a parser, and its comment names what it still misreads: a<<shift inside$(( )), acasepattern's)inside$( ), a heredoc delimiter quoted in part or starting with a digit, and backquotes; no workflow here uses any of them. A fixture no occurrence satisfies, or one whose scratch tree is refused before its edit, stops the self-test as a BROKEN FIXTURE naming the case. The two property cases (a sibling.trusteddirectory and a traversal out of it) also assert the refusal's reason, not only a refusal. The hand-built fixture tables check throughfixture_changed!. Every existing case is still refused for the same reason, andsurface-mirror-check.ymlno longer warns authors against spelling the path. No shipped surface changes. - Codex installs from a committed, clean marketplace snapshot (#273, #147, 0.108.1)
hatsu_surface_link.sh --surface codexarchives the served commit before registering its marketplace. Codex's copied plugin slot excludes.git, ignored settings, worktrees,.nen/andReports/. An existing direct-checkout marketplace is migrated to the snapshot.hatsu_plugin_update.sh --codexresolves the source checkout from the snapshot's adjacent record, updates it, re-registers the new committed snapshot and reads back the installed version. A changed snapshot refuses installation; the fixture suites cover migration, excluded local files and tampering.- The Codex guides explain what is copied and how to remove an old marketplace registration, snapshot and cache slot.
- #149's ruling of 2026-10-13 is recorded: the listed issue bodies were rewritten to the legend's placeholders on the maintainer's go per edit (#287, #149;
docs/ROSTER.md§ Rulings of 2026-10-13). Twelve closed issues (and #102's title) now carry<product-repo-A>,<product-repo-B>,<reference-repo>,<ci-plane-repo>and theRAproduct code where they named a private repository; three were left as they are on the maintainer's word; #57 was already clean. Two of the twelve still trip the guard on one dictionary-word name until the maintainer's ignore file carries it, every rewritten issue's pre-rewrite revisions stay in GitHub's public edit history until the maintainer deletes them, and #102's rename event keeps its old title: the row records each as the maintainer's own. The guard (v0.81.0) andnen's exit-4 refusals delivered criteria 2(a) and 3 before this ruling; criterion 2(b), the tree check, stays deferred and the issue stays open. The nen request (the pre-filing check honouring the same ignore file, and nothing wider) goes through the harvest. Plugin bumped to 0.107.10 (a shipped doc changed); the mirrors restamped. - Preflight trusted pull request guards before opening a PR (#274, #157, 0.108.5)
- **
claude/agents/kurapika.md§ The exit codes, and what you do on each now says that$?after a pipeline is the last stage's status, never the verb's**, with the exact remedy — redirect to a file and read$?after the verb alone — and the two approximations,${PIPESTATUS[0]}(bash) or$pipestatus[1](zsh) on the very next command in the same shell, orset -o pipefail, each answering141(SIGPIPE, not the verb failing) under a reader that closes early (docs/GATE-CONFIGURATION.md§ 5), with one of the three wrong readings recorded on #161 as the evidence.tenkai§ 2 anddocs/GATE-CONFIGURATION.mdare unchanged and named inkurapika.mdas instances of the general statement;akaandao's two-stream rule is named as a different rule. Plugin bumped to 0.94.2 (Claude manifest and Codex overlay); the mirrors regenerated at that stamp, since the agent file is mirrored. (#250) - The ruling of 2026-10-13 on #165 is amended to option (b), toggle only, and #165 closes (#296, #165;
docs/ROSTER.md§ Rulings of 2026-10-17). The maintainer answered the register's DECIDE through the picker on 2026-10-17: the preflight read is not built and no secret is held; criteria 1 and 2 are withdrawn by the amendment, 3 and 4 were delivered earlier; the 2026-10-13 row opens with the amendment. The same section records the three readings of that sitting (#176, #223, #149) as accepted. Plugin bumped to 0.111.2 (a shipped doc changed); the mirrors restamped. - #165's ruling of 2026-10-13 is recorded as partly delivered; the issue stayed open until the amendment of 2026-10-17 (HA-PR-#296, the next entry) (#284, #165;
docs/ROSTER.md§ Rulings of 2026-10-13). The picker's option (a) asked for the repository toggle plus an in-job preflight; the build found the toggle already on, the header note and the docs line delivered by HA-PR-#193 and HA-PR-#211 (moved by HA-PR-#241), the cleanup step by HA-PR-#211, criterion 2 not met (the toggle is named after the push, not before, with no fixture), and the preflight read needing an Administration (read) permissionGITHUB_TOKENcannot carry — the 2026-10-02 ruling that kept #165 open. The row returns the remainder to the maintainer: a scoped token and the preflight, an amendment to option (b) and a close, or the issue kept open. Plugin bumped to 0.107.6 (a shipped doc changed); the mirrors restamped. - The three inputs every Hatsu PR hands nen are declared once, in
contracts/pr-composition.json(#262, #171; the nen half is zheref/nen#239). Until now each run retyped them from prose. Body check:contracts/pr-body.requirements.jsonis the{name, pattern}arraynen pr body-check --requirements-fromreads, derived fromtemplates/pr-body.md— eight required headings,The flowandEconomicsoptional,## Agent attributionrequired last — andshibari§ 4 passes it from$hatsu_root. Gate sets:gateDerive."zheref/hatsu"holds the twonen gate derivepath sets, its process set now carryingcontracts/andtemplates/so the declaration, the array and the template deriveG4asdocs/WORKFLOW.mddid when it held the sets (this run's reading, the maintainer's to confirm at theG4merge); a canon repository with no row has none declared, the run asks, and the row is written by a Hatsu PR at Hatsu'sG4. Fragment inputs:changelogFragmentholdsfragment-required'sspecPaths,fragmentDirandheadChangelog; a PR that adds itschangelog.d/fragment readsfragment-presentwith no opt-out line, anddirectSection.optOutis the one opt-out, carried only by a PR whose own diff changesCHANGELOG.md. That condition is unenforced by nen, which honours the phrase anywhere, over any diff, inside an HTML comment or a code fence too: a Hatsu-side raw-body check is owed, and the nen half is zheref/nen#239's scope. Citations:docs/WORKFLOW.md§ Gate derivation,shibari,tensho,jujisho, the template andCONTRIBUTING.mdcite the file and carry no copy. Drift guard:scripts/pr_composition_check.sh, the newpr-composition-guardlane (35 fixture cases), fails on a literal set copied into the canon prose (a leading/included), a Gate derivation section naming a directory prefix of any depth that no declared set carries or a file path no set covers (the section cut with fenced lines masked), a requirements array that drifts from the template, the fragment opt-out phrase anywhere in the template, a reader that does not cite the declaration, a declared path that escapes the root, and a scanned file that is not UTF-8. Template hazard: the template's top comment no longer spells out the fragment opt-out phrase, which nen honours anywhere in a body.
… more in CHANGELOG.md
v0.94.0
v0.94.0 — nen v0.21.0, the gates keys retired, prompt on hanten, per-consumer AI reviewers, opt-in direct publishing and the README redesign
- nen is pinned at
v0.21.0(minimum0.21), and Hatsu'snen/gates.jsoncarries only keys nen reads — the maintainer's ruling of 2026-10-04, retire 2, adopt 2 (zheref/nen#310; #227; #245). nenv0.21.0refuses every gates key it does not read, so the repin and the cleanup land together: check_exclusions→ nen'schecks.excluded({name, match, reason, ruled, until}, zheref/nen#249). Hatsu's list was empty and is declared empty in nen's form.nen pr readyreads it at the pull request's base and applies it itself, sopr-state§ 2,sharingan§ 4 anden§ 6 pass no--exclude-checkfor a declared ruling and quote the verdict as printed.jusshin§ 8 edits the new key.reviewer_fallbackdeleted, superseded byround_quorumand zheref/nen#361 (a met quorum fulfils an exhausted member's round). Unavailability is now observed, never declared:nen pr request-reviewsexit9, the bot inunrecordedBots(zheref/nen#277), stated once insharingan§ 6. When every quorum member is unavailable at the judged head — the five-part predicate stated once indocs/PROCESS.md§ Reviewer rounds and review threads, The sixth stop: a declared quorum,rounds-owedthe only failing row, every member at exit9or with a round-check run at the judged head that completed without a round (never "no run at head"), each exit9bound to its head and recorded verbatim, and no reviewer outsideany_ofowed — reachable only wherereviewers[]⊆any_of, since nen 0.21's--jsonlists no owed reviewers — the PR goes toen§ 5's merge prompt on hanten's rounds with the not-ready verdict quoted verbatim, never calledready— the maintainer's ruling of 2026-10-11, Prompt on hanten, recorded indocs/ROSTER.md. That isen§ 6's sixth stop andnen/decisions.jsonrowreviewer-exhausted's default; PROCESS, WORKFLOW and the decisions guide say the same.round_policy.minRounds/.maxRoundsstay, now nen's keys (zheref/nen#240).nen pr request-reviewsrefuses a bot's request pastmaxRoundsat exit2, andpr ready --explainprints requested and posted counts. nen countsminRoundsagainst posted rounds, whilesharingan§ 6 counts resolved ones. The$comment,sharingan§ 6,cap-reachedanddocs/GATE-CONFIGURATION.md§ 3 say so.scripts/tenkai_adopt.sh: one observation item,gates/retired-keys, replacesgates/check-exclusionsandgates/reviewer-fallback. It names the move for either retired key and leaves nen's keys tonen schema check. Its self-test covers it.cap-reachedreads exit2with arefused:line as the bound and any other exit2as usage.- The rest of v0.21.0's consumer notes, checked against Hatsu.
pr open's new exit1for a PRghcreated before failing is covered byshibari's existing rule (exit1names a PR; it opens once).jusshinnames thepool-<id>label every pool now ends in, andscripts/runner_preflight_fixture_check.shexpects it in a renderedruns-onunder nen 0.21+ (the declared set alone under an older binary).deploy.defaultTargetneedsproject.targets.<name>.nonProduction: truefrom nen 0.21:scripts/config_values.sh setnow refuses a default target without it (self-test added), andkagutsuchi, PROCESS, the contract and workflow guides and the catalogue name the typed mark. Hatsu declares no runners and noselectblock, and its callers pass--requirements-from. nen/contract.jsonrepinned:minimum0.21,pinned_refv0.21.0, the bootstrap URL, and the three release digests from v0.21.0'sSHA256SUMS. The bootstrap commands ininstall_paths.nen_absentand the halt template pass--source zheref/nen, as doesfetch_must_be_two_step.right. The convenience copies follow it (docs/NEN-CONTRACT.md,docs/WORKFLOW.md,docs/config/contract.json.md, the marketplace descriptions,surface-mirror-check.yml,futon,classify,templates/runner-preflight.yml). Theround_policydefault file and its guide say the caps are nen's keys now. The base-read claim forchecks.excludedis qualified for stacked and integration bases (SEC-6).- The plugin is bumped to 0.94.0 (Claude manifest and Codex overlay). The mirrors are regenerated at that stamp with nen
v0.21.0. aiReviewers— AI reviewers per consumer (#245, the maintainer's rulings of 2026-10-11). A top-levelnen/workflow.jsonkey,required | optional | off, for every automated reviewer innen/gates.json→reviewers[], gating both their use and their expectation. Absent readsrequired, today's behaviour.optionalrequests within the caps and never waits;offnever requests, so there is zero AI-reviewer spend. Under both, a PR failing only onrounds-owed, with hanten settled, goes to the merge prompt on hanten's rounds with the not-ready verdict quoted verbatim. This returns the off switch that deletingreviewer_fallbackremoved. The rule is stated once indocs/PROCESS.md(AI reviewers per consumer);sharingan,en,pr-state, WORKFLOW, the newnen/decisions.jsonrowai-reviewersand ROSTER cite it. It is catalogued asworkflow.aiReviewers(enum, defaultrequired, asked at adoption), andconfig_values.shsets, diagnoses and refuses it, with self-tests. Hatsu's own value isoptional. The value is read at the PR's base and the default branch's tip, the stricter applying and never the PR's own head (SEC-6), so a change takes effect once merged. The hanten prompt needs everyreviewers[]entry to be inround_quorum.any_ofwith an anchoredlogin_pattern, since nen exposes no reviewer kind.round_policy.maxRounds: 0was never an off switch.- Hatsu's own
direct.publishislabel+comment, on the maintainer's request of 2026-10-11 ("Open a PR setting direct.publish to label and comment"), written withconfig_values.sh set: ahatsu:directrun here — underbuild, standalone on an issue, or thebacklogsweep — now applies the primary pick'smodel/<line>label throughnen label applyand posts one marker-keyed issue comment with the three picks, tier, surface, effort dial and the live-read version, closing with theDirect:trailer;renstays report-only. The default in the catalogue,docs/WORKFLOW.md§ 2 anddocs/config/workflow.json.mdis unchanged (none); the config page records Hatsu's own value beside it, asmukai.autoEnis. The first sweep ran the same day with the key stillnoneand, on the maintainer's word, applied its seven labels as if it were already set (model/gpton #243, #238, #236, #235, #234;model/claudeon #242, #240), ledgered under.nen/direct/label-ledger.jsonl; the comments wait for this value. (#244) - The README is a cheatsheet, and the surface and configuration prose moved where a reader expands into it.
README.md(399 lines, from 1,266) carries a start-here table, a per-surface quickstart, the request flow and the skill composition graph as Mermaid, a Workflows section (each with its prerequisites, its prompt per surface and the chain that runs), the roster, every skill with the skills it calls, the model tiers per surface withdocs/DIRECT-MATRIX.mdlinked, the gates and the Nen contract in six lines. New:docs/using/(the surface hub, one guide per surface in the same order, requirements → setup → usage → maintenance → uninstall → caveats, andmirrors.mdfor the generated-mirror mechanics),docs/config/(one page per expected configuration file, key by key, plus the plugin-owned registries),docs/NEN-CONTRACT.md(the D10 section whole),docs/history/release-highlights.md(the README's former release notes, verbatim) andCONTRIBUTING.md.docs/SURFACES.mdis superseded bydocs/using/README.mdanddocs/using/mirrors.mdand remains as a redirect stub whose§ 3and§ 4anchors still land, so every path citing it in the skills, the mirrors and the evidence keeps resolving. Plugin bumped to 0.93.1 (Claude manifest and Codex overlay) for the stub; mirrors regenerated at that stamp, bodies unchanged. (#241)
v0.93.0
v0.93.0 — the registry rebalanced for cost, three picks per cell, Grok on Cursor, and the model matrix as a readable page
contracts/direct.registry.json— the registry rebalance of 2026-10-05. The execution default moves from the frontier tier (GPT Astra) to the deep tier (GPT Sol) asEXECUTION_FRONTIER; Astra becomes theEXECUTION_MAXescalation, mirroringSEMANTIC_MAX; Terra becomesEXECUTION_VALUEon the fast tier. Grok on Cursor enters asEDITOR_FRONTIER(Cursor's deep tier): the primary on the eight editor-shaped TypeScript cells and the cross-provider fallback for execution work. Every cell now yields three picks — primary (cost-aligned best), fallback (on another provider or surface in every cell; 66 cells moved in all, 60 of them to satisfypicks.fallbackRule) and recommended (cost-agnostic, bypicks.recommended). Each alias carries its model line (claude | gpt | gemini | grok | composer) and escalation; the snapshot is re-read live with list prices and served ids per surface; Codex's dial gainsmax, Cursor'sxhigh; Grok Build and Copilot are listed as non-actionable surfaces. Standalonereviewcells route to the semantic reader. The realised saving lags the price sheet where a surface still serves an older id: Codex servesgpt-5.6-solat $4 / $20 today, recorded insnapshot.served. (the maintainer's rulings of 2026-10-05,docs/ROSTER.md; #237)hatsu:directreports three picks on five axes — line, tier, version and effort dial (read live), surface — compares the session against the whole set (within the registry's set, one line, never asked), keeps companion jobs (review,delivery-ops, flagged incontracts/classify.taxonomy.json) out of the verb call that decides and reports them from a second call, names the other-pool aggregate fallback where the verb's runner-up shares the primary's pool (zheref/nen#389), and publishes only wherenen/workflow.json→direct.publishopts in:labelapplies onemodel/<line>label throughnen label apply;label+commentadds one marker-keyed issue comment with aDirect:trailer;hatsu:direct backlog [<repo>]sweeps every open classified issue — one table, one confirmation, then label and comment per issue (never underren, which cannot leave the machine). The fivemodel/labels are declared innen/labels.json(sync after this lands).build§ 2b andren§ 2 run the compare;nen/decisions.jsonrowdirect-mismatchreads the set.docs/DIRECT-MATRIX.mdre-rendered: the alias table gains line, escalation and list price, a Primary, fallback, recommended section, served ids, the non-actionable surfaces and the live effort-dial column;scripts/direct_matrix_doc.sh --self-testnow checks the registry's own invariants over every cell;--verifyagrees on 2,019 printed claims at nenv0.20.0.docs/surfaces/cursor.md: the livegrokresolve matchesgrok-4.7-as well ascursor-grok-(the served 4.7 ids carry no prefix, read 2026-10-05); Cursor's model sheet quoted.contracts/config-catalogue.jsongainsworkflow.direct.publish;docs/WORKFLOW.md§ 2 gains thedirectkey block and its consequence paragraph. The plugin is bumped to 0.93.0 (Claude manifest and Codex overlay) and the mirrors regenerated at that stamp.docs/DIRECT-MATRIX.md— the model matrix, readable without runninghatsu:direct. One page answers which model, surface and effortdirectwill recommend for any work:- the ten aliases, each with its provider, family, surface, the name you type and the dated snapshot model;
- a grid of all 39 jobs × 5 domains naming each winner, with per-language winners inline, fallback routes marked, and the two cells no issue can reach (
parityin feature and maintenance) shown as—; - five job × language matrices, one per domain as the registry routes them, each cell giving that pair's winner, runner-up, phase and interactive tool;
- the domain rules, the fallback sentence and the aggregation rule, quoted from the data; the effort rule with job weights and each surface's dial;
- seven worked examples with their restart lines. (#233)
- Rendered, never hand-written.
scripts/direct_matrix_doc.shbuilds the page fromcontracts/direct.registry.json,contracts/classify.taxonomy.jsonandnen/workflow.json→models, the filesnen direct resolvereads. --checkfails on a stale or missing page.--self-testproves the guard's negative paths on hermetic fixtures, then runs--check. It is the argv of the new focused lanedirect-matrix-guardinnen/contract.json.
… more in CHANGELOG.md
v0.92.0
v0.92.0 — classify and direct route every issue, one bot reviewer suffices, and nen v0.20.0 is the pin
- nen repinned to v0.20.0, and the classify, direct and round-quorum canon now runs on the pinned build (zheref/hatsu#168).
nen/contract.json→dependency.minimummoves0.19→0.20, andpinned_refmovesv0.19.0→v0.20.0(zheref/nen v0.20.0, released by zheref/nen#384, published 2026-10-05 UTC).- The minimum moves for a feature and for the floor. Hatsu adopts the
nen classifyandnen directfamilies (zheref/nen#370, #371, carried tomainby #380) thathatsu:classifyandhatsu:directexecute, andround_quorumfulfilling its members' rounds (zheref/nen#359). v0.20.0 raises the compatibility floor to0.20for breaking consumer notes, so every 0.20+ build refuses a0.19pin at exit 5. pinned_ref_semanticsrecords the release and its darwin-arm64, linux-x64 and windows-x64 checksums, andbootstrap.sha256carries the same three.- The top
$comment, the bootstrapurlandfetch, the two-stepwrong/right, bothinstall_pathsand the halt message point atv0.20.0. - The convenience copies follow: the pin line in the README's § The range,
docs/WORKFLOW.md, the marketplace descriptions,futon's pin line andsurface-mirror-check.yml's comment. - The canon that waited on this pin no longer does:
classifyanddirectresidue, PROCESS § Residue and owned dependencies and the round-quorum paragraph namev0.20.0as the release that ships them; ROSTER's dated note of 2026-10-04 is marked superseded;classifyreads bodies throughstatus --with-bodyand syncs withclassify install --sync. - v0.20.0's breaking consumer notes are absorbed:
- ten § 1 and § 2c —
nen shu toolsreports a host nen that meets the minimum but sits belowpinned_refasBEHIND, exit7(zheref/nen#354). § 1 routes it to § 2's install; § 2c reads it as installed, not reachable, never as a failed shell.nen_global.shreads onlysatisfiedon a strictly newer host and is unchanged. - ao § 3 —
nen wc catch-upexits3when every conflicted path is in a declaredmechanicalset, printing the commands and running none (zheref/nen#368). The table carries the row; § 4 takes over with nen's classes quoted. Hatsu declares nomechanicalblock, so its own catch-ups still stop at1. - file § 4 —
nen issue file,commentandedit-bodyrefuse a private repository's name bound for a public target at exit4, writing nothing (zheref/nen#367, closing #329). nen reads no default ignore file, so every such write passes the guard's own with--private-names-ignore-filewhere it exists;private_name_check.shstays the first guard, and a nen4after the guard read0is the two guards disagreeing — stopped and reported, never redacted around. nen's exit1is read by what it shows: its guard's refusal,issue file's label or title refusal, or an uncertainedit-bodywrite read back through--json'soutcome.--body-fileresolves against--repo's root.mugetsu§ 7,sharingan§ 7 andbacklog-synthesispoint at it; PROCESS § Residue and PUBLIC-REDACTION no longer call #329 owed. - murasaki § 6 routes catch-up exit
3to ao; ao § 4 readsconflicted[]at exit1or3. breath § 2c and the kurapika persona'sshuexit table readshu tools' exit7as a host behind the pin, not a red build. - direct passes
--repotonen direct answer, which refuses without it;classifyanddirectname ten § 2's install, not a repin, when the verbs are absent.nen/gates.json'sround_quorumcomment, GATE-CONFIGURATION and ROSTER's quorum ruling namev0.20.0as the release that ships the fulfils half. - WORKFLOW §
reportsand PROCESS § Residue —nen report dataderivesrepo(the hostedowner/name, ornull),worktree,effortStage,gateandstageClass(zheref/nen#375); the caller fills only what staysnullandturnLabel/generatedAtLocal.
… more in CHANGELOG.md
Showing the latest 12 sections. The full history is CHANGELOG.md.
Nen
v0.29.02026-10-29
v0.29.0 — 2026-10-29
- Repin:
"0.28"→"0.29", andv0.28.0→v0.29.0. The compatibility floor moves to0.29: this release changes verdicts, exits and outputs consumers already read (the bullets below), so a pin below0.29is refused by this build. Hatsu (minimum0.28,pinned_refv0.28.0) owes the repin. nen pr readyno longer reads a readiness placeholder as green. A check whose record only says the verdict did not report used to count as passed; it now reads undetermined, the output names undetermined and failed checks, and a pull request that readreadyon such a placeholder readsnot-readyon the same bytes. Caller-supplied gates on a base without gate configuration are reported as non-authoritative judgements (#557).nen parse izanamiclassifies barenen run verifyandnen run budgetas mutating. Only their new--dry-runforms read as read-only, because the bare forms can move a legacy manifest. A surface allowlist built on the old read-only reading prompts on the bare forms;run verify --dry-runandrun budget --dry-runare the forms to allow. The run verbs also refuse at exit 1 a manifest path, legacy manifest or runs directory that is a symbolic link, where they used to read, move andchmodthrough the link, and the--dry-runofrun start|append|park|importno longer moves a legacy manifest (#549).- The criterion id grammar is one grammar, and it blocks where it used to clear.
pr converge,pr body-check --criteria*andpr merge --deliverynow block on a closing issue that states one criterion id on two rows, and a verify row's prefix is the catalogue's acceptance prefix, so under a catalogue whose prefix is notACa| AC-1 |row that used to coverCR-1is malformed. Ahatsu.issue-sections/v1catalogue whoserows.acceptance.patternopens no group right after<ID>-is refused at exit 2;--criteria AC-01is read asAC-1where it was refused; a- AC-1-2:row that used to blockpr convergeas unrecognised is now the criterionAC-1-2(#548). - The private-name guard's hits change shape, and a bare ordinary word is no longer one. Every hit in
--json'sprivateNameCheckgainsformandclass, so a caller comparing a hit or the verdict by exact equality must add them; a bare use of a policed name that is an ordinary word is reported on stderr and listed underruled, not refused (#541). - Committed Antigravity hook mirrors read stale under
surface mirror checkuntil regenerated.surface mirror generatenow writes Antigravity hooks in their native named-definition format and reads an older hook file as stale, so a consumer that committed the old form fails the check until it regenerates (#560). - Generate Antigravity hooks in its native named-definition format, retain lifecycle handlers and tool matchers, and recognize older hook files as stale while preserving ownership and stamp checks (#543).
- New verb
nen audit deps(zheref/nen#508): a directory's exact dependency pins, read from its lockfile and never by running its package manager, and with--queryasked about at the OSVquerybatchendpoint the caller's declaring contract names.--contractis an absolute path to a JSON file with adependencyAuditobject and--rownames the row; Hatsu'scontracts/scans.jsonnoderow is read unchanged. The row'secosystemselects the reader:npmreadspnpm-lock.yaml(lockfileVersion 5, 6, 9),yarn.lock(berry and classic) andpackage-lock.json/npm-shrinkwrap.json(lockfileVersion 1, 2, 3);SwiftURLreads everyPackage.resolvedat the root and inside an.xcodeprojor.xcworkspacebundle (formats 1, 2, 3), so the Swift procedure is now a verb, which can retire the hand procedure once Hatsu'sswiftrow declares the four keys below. It is a port of Hatsu's interimscripts/dependency_audit_resolve.mts, and every lockfile case of that script's fixture but the one run on Hatsu's own tree passes here with the same exit code and verdict (theaudit-config:lines now read "evidence for review"). Four exits:0clean (or resolved, without--query),1a finding at or above the row'sseverityFloor, an UNRATED id or an unqueried entry,2wiring (nen exits auditlists its own meaning of 2),3not scanned with the reason. A symbolic link, a truncated or unrecognised lockfile, a file overmaxLockfileBytes(new, default 268435456), more thanmaxEntriesentries or npm v1 nesting pastmaxDepthis not scanned. An entry from git,file:, a host offregistryHosts, or a Swift pin on a branch or revision is unqueried and never clean.pnpm-lock.yamlis parsed as strict YAML (bounded first by size, bracket depth and indentation depth), and a pnpm entry is local or unqueried only by the keys of its own parsedresolutionmap; a repeated key, an alias, an anchor, an explicit tag or a merge key is not scanned. A registry entry whoseresolvedortarballURL names another name or version than the entry claims is unqueried, the name read from the path segments just before/-/, so a registry mounted under a path prefix is read correctly. A malformed, non-JSON, oversized, failing, slow or unreachable OSV answer is not scanned, and so is a redirect, which is never followed or retried; a severity outsideseverityLevelscounts as a finding.vulnEndpointmust end in/. It reads no environment variable of its own and forces certificate verification; the runtime'sfetchhonours the host's proxy variables andNODE_EXTRA_CA_CERTS, which USAGE documents as the host's network configuration.--jsonisnen.audit.deps/v0.1. - Behaviour changes:
nen --helplists 48 families, andnen exitsgains twoaudit depsrows (2wiring,3not scanned). Hatsu'sswiftrow as it stands names onlyendpointandecosystem, so--row swiftagainst it is refused at exit 2 namingseverityLevelsuntil Hatsu addsvulnEndpoint,severityLevels,severityFloorandtimeoutSecondsto it. Those values are Hatsu's policy to set, in the repin that retires the interim script.nen/workflow.json's security review scope now claimssrc/audit/**, under a new criterion recorded inreview.$commentfor the maintainer's ruling: egress of the audited tree's dependency pins to a contract-named host. - Epic-scoped criterion ids (zheref/nen#519):
nen issue criteria,nen issue body-checkandnen pr converge(andpr body-check --criteria/--criteria-from,pr merge --delivery) now share one criterion id grammar, and Cloud tier's- AC-12-001: …rows are criteria with their whole id --AC-12-001, never truncated toAC-12-- where they used to be listed as unrecognised and the issue read not verifiable. A verify row<CODE>#<N>/AC-12-001matches that criterion and<CODE>#<N>/AC-12does not. With no catalogue the id is one number or several joined by hyphens; with a catalogue (--requirements-from/--catalogue) the shape is the group itsrows.acceptance.patternopens right after the prefix, never a binary default, so Hatsu's^- AC-([0-9]+): …keeps readingAC-{n}only. The bold- AC-1:form,AC-01read asAC-1, and theSC-,AS-,OQ-rows are unchanged. - Behaviour changes: a
hatsu.issue-sections/v1catalogue whoserows.acceptance.patternopens no group right after<ID>-is now refused at exit 2 naming that field, where its acceptance id used to be read as<ID>-<n>regardless. A list row such as- AC-1-2: …that used to be unrecognised (blockingpr converge) is now the criterionAC-1-2when no catalogue is given. A criterion's--jsonnumberis its id's last number (AC-12-001is 1); rows are matched byid.--criteria AC-01is now read asAC-1where it used to be refused at exit 2. A single-run id is read by value as text (leading zeros dropped, never through a float); a row whose last digit run passes nine digits is unrecognised. A closing issue stating one criterion id on two rows now blockspr converge,pr body-check --criteria*andpr merge --delivery(<issue>: duplicate criterion id <id> at lines …, orat positions …for a--criterialist) where one verify row used to clear both. The verify rows' prefix is now the catalogue's acceptance prefix: under a catalogue whose prefix is notAC, a row| AC-1 | … |that used to coverCR-1is reported malformed; a verify cell whose id (after any<owner/name>#<N>/qualifier) passes 64 characters is never matched, and an issue row whose id span passes 64 characters is unrecognised. A catalogue's acceptance id group must keep to the safe subset USAGE names (digit classes,-, bounded quantifiers; a variable digit run ends at a-or the end; a nested quantifier only in a--led or--ended group; no named group or backreference), else exit 2.issue criteria's summary saysduplicate id(s)where it saidduplicate number(s), and an epic-scopedrow-ordermiss names the expected id within its leading group. - Run manifest modes and dry forms (zheref/nen#522): every write of the
nen.run/v0.1manifest --nen run start,append,park,importand the one-time move from the legacy<git-common-dir>/hatsu/runs/-- now lands it at0600in a0700directory (the directory created at0700, the document written to a temp file created exclusively at0600and renamed over), and the modes are read back and printed:mode: file 0600, directory 0700, with(narrowed: ...)when a write narrowed a wider one, andmode{ verdict, file, directory, repaired, reason }in--json(null when neither the plan nor a legacy move writes). Where a mode cannot be set -- awin32host, a failingchmod, a read-back that is not0600/0700-- the write stands and the verb saysmode: not set (<reason>), verdictnot-set, rather than claiming the mode.nen run verifyandnen run budgettake--dry-run: a manifest still at the legacy path is read in place and the move printed on stderr (would move run manifest ...), nothing moved. The--dry-runofstart,append,parkandimportcreates no directory and moves no legacy manifest, and printsmode: would set file 0600, directory 0700. - Behaviour changes: manifest modes are now set and repaired -- a manifest an earlier build left at the umask's
0644under0755is narrowed to0600under0700on its next write, and said so.--jsonofrun start,append,parkandimportgains a trailingmodekey, and their text output a trailingmode:line when they write or would write.--dry-runofstart,append,parkandimportno longer moves a legacy-path manifest (it used to, before planning the dry write).nen run verify --dry-runandnen run budget --dry-runare accepted where they used to be refused at exit 2 as another subcommand's flag.nen loop slots --from-runno longer moves a legacy-path manifest: it reads it in place and names thenen run verify --id <id> --target <owner/name>line that moves it on stderr. A manifest path, a legacy manifest or a runs directory -- or any component of it below the git common dir, such as.nen-- that is a symbolic link (or not a regular file) is now refused at exit 1, naming it, by every run verb that reads or writes the manifest and byloop slots --from-run, where it used to be read, moved andchmod-ed through the link;nen run record readlikewise answerscould-not-readfor a record directory that is a link, asrecord writealready refused one, and both now check every component of the record directory below the state home (hatsuas well ashatsu/specs). When a verb moves a legacy manifest,--jsonmodecarries the move's modes -- alone when its plan then writes nothing (existing,unchanged), combined with the plan's when it writes too -- instead of null or the second write's alone. izanami (nen parse izanami) now classifies barenen run verifyandnen run budgetmutating and only their--dry-runforms read-only, since the bare forms can make the legacy move. - Readiness placeholders that say the verdict did not report no longer count as green; readiness output names undetermined and failed checks. Caller-supplied gates on a base without gate configuration are explicitly reported as non-authoritative judgements.
… more in CHANGELOG.md
v0.28.02026-10-25
v0.28.0 — 2026-10-25
- Repin:
"0.26"→"0.28", andv0.26.0→v0.28.0. The compatibility floor moves to0.28: this release changes the meaning of exit codes and outputs consumers already read (the bullets below), so a pin below0.28is refused by this build. Hatsu (minimum0.26,pinned_refv0.26.0) owes the repin. nen issue questionsexits 1 when a question is still open or an issue could not be read; v0.26.0 exited 0 whatever the counts. A caller that read exit 0 as "the body was read" reads exit 1 with a non-empty stdout as "read, and a question is open".nen wc overlapretires theoverlap(<paths>)verdict. Efforts that share a path and do not chain readstack(...)at the same exit 1, and--jsonaddsstacks[]; a caller that branched onverdict == "overlap"readsstackwithstacks[].source: "given".- One effort-id grammar (
src/ledger/effort.ts):directandstop answernow refuse at exit 2 ids they admitted (a space, a leading., a-start, a character outside the alphabet), with a new refusal text;phaseandusageadmit#and:ids they refused. - The phase, usage, session and direct ledgers move to
<git-common-dir>/.nen/. A ledger an older build left at<checkout>/.nen/<family>/is read in place through the 0.28 line and moved by the next write; the fallback is removed in 0.29.0. These verbs, andstop --mark,stop listand everystop clear, now spawn git and exit 2 on a git refusal other than "not a git repository".nen report datawithout--effortreads every effort of the repository. pr convergeandissue criteriablocking lines quote the row and name the id a missing row lacks, so a caller matching the old strings exactly must match the prefix.pr convergeon a non-default base whose body names no closing issue exits 0 where v0.26.0 exited 1, and--compositeadds exit 3 (a read that did not finish, or was at another head).- Changed reads and outputs:
nen spec checkreads the spec repository'snen/workflow.jsonand refuses one that does not parse, where it ignored it;issue body-check,issue questionsandissue criteriarefuse a non-UTF-8--body-fileat exit 2;surface mirror generaterewrites every Antigravity persona with atoolskey, so a committed Antigravity mirror reads stale undersurface mirror checkuntil regenerated. nen run import --id <run-id> [--from <file>]reads Hatsu's futon run manifest (hatsu.futon.run/v0.2, or v0.1) from<git-common-dir>/hatsu/futon/run-<id>.jsoninto nen'snen.run/v0.1manifest (zheref/nen#486 AC-5), so one manifest owns a batch run and Hatsu can retire its second one. It reuses therun start,appendandparkplans: every PR is read live, issue numbers become<owner/name>#<N>, and the idle decisions becomeidleAnswers. It is idempotent (unchangedon a re-import) and never writes the Hatsu file. An unread PR, a PR older than the run, or a contradiction with the manifest nen holds refuses the whole import at exit 1, with nothing written.run start|append|park|verify(AC-1 to AC-4) shipped in #484/#498 and are otherwise unchanged; the next entry changes howappend --issueandpark --issuespell an issue.run append --issueandrun park --issuenow record one spelling,<owner/name>#<N>. A<CODE>#<N>is resolved through--repo'snen/repos.json, so an append after an import names the same issue. An import first normalises the rows nen already holds and dedupes parked rows that collapse to one issue and row. A code the registry does not resolve to oneowner/nameis exit 2. Behaviour change: a manifest that already holds code-form issues conflicts with a re-append in either form. Re-import, or edit the manifest once.nen run record read|write --schema <id> --id <run-id> [--from <file>] [--dry-run](zheref/nen#493, AC-11): a caller's resumable run record, validated against a schema shipped as data (hatsu.spec.run/v0.1, Hatsu'sdowsing-chainrecord) and kept at${XDG_STATE_HOME:-$HOME/.local/state}/hatsu/specs/<run-id>.json. The run id is matched whole against the schema's pattern before any path is built; the record'sschema,callerandrunIdare checked before its fields; every row value is typed (codes, shas, statuses, counters); a relativeXDG_STATE_HOMEis ignored for$HOME/.local/state; a write is the whole document through a temp file created exclusively at0600in a0700directory that is never a link or another user's, then a rename, and a failed write or an unreadable--fromiscould-not-read. Verdictsvalid·written·would-write·absent·invalid·could-not-read. It sits beside the batch manifest (run start|append|…), which stays under the git common dir.nen spec converge --repo <spec> --folder <dir> --inventory <file> --code <CODE> --checkouts <file>(zheref/nen#493, AC-6, SC-3): a merged folder's citations of one member re-read at a newer inventory's sha in the member checkout, each rangecurrent,moved,changed,vanishedorunreadable, and each requirement's gap classedmissing·partial·contradicts(a candidate for the spec-conflict ruling, never decided by nen) ·unrequested(rows new sincecapture/<CODE>/inventory.json, in a directory the folder cites). A ticked task naming a requirement with a gap is aclaim, never evidence.--write(behind--dry-run) only appends: a[STALE @ <cited sha>]companion beside each moved, changed or vanished citation, and one## Phase N: Convergence <date>totasks.md(SP-9's heading;Inventory: <CODE> @ <sha12>as its first body line), one task per gap tagged with its story and the member's platform, ending· supersedes T<nnn>when the requirement's gap class changed since its last recorded finding; it never renumbers or deletes, and a second run on the same inputs changes zero bytes. Verdictconverged·gaps·could-not-read; exit 1 on either of the last two.src/spec/citecheck.tsexports the member-checkout chain (resolveMember) soconvergereads members exactly ascite-checkdoes.nen spec coverage(zheref/nen#493, AC-7, AC-12), each number with its denominator (SP-14). Capture form (--repo <spec> --inventory <file>[,…]): per member (its code resolved from the spec repository'snen/repos.json) and per row kind,covered/total— a row covered when one of the member's citations overlaps it,total: nullwhere the inventory could not count the kind — plus requirement↔task/test traceability both ways (requirementsCited,requirementsTested,requirementsTasked,testsCited,tasksTraced) and the open markers per folder. Delivery form (--issue-body <file> --pr-body <file> [--test-report <file>]): everyF<nnn>-SC-###the issue carries needs exactly one## Specrow in the PR body,— satisfied — test <id>(in the report and passing, when one is given) or— deferred — <reason> · <follow-up object>; a missing or empty section, an unaccounted, duplicated or malformed row, or an issue with no criterion is exit 1, and an id the issue does not carry is exit 2. Verdictsmeasured·partial·accounted·unaccounted·could-not-read; the test report is read throughshu test-report's parsers.nen spec diff --from <inventory> --to <inventory>(zheref/nen#493, AC-5): the added, removed and changed rows between two inventories of one member, by stable row id, each changed field with itsfromandto. A differentshaalone is not a change, so identical inputs — or inputs differing only in their commit — give an empty diff. Two differentorigins exit 2; an input that is not a readablenen.spec.inventory/v0.1document (or recordedcould-not-read) is verdictcould-not-read, exit 1. The verb reads no checkout and refuses--repo.
… more in CHANGELOG.md
v0.27.02026-10-22
v0.27.0 — 2026-10-22
- No repin: the compatibility floor stays
0.26. Existing pins keep working and no exit code changes meaning. The one behaviour change is generated output: a consumer that commits Cursor mirrors of read-only personas regenerates them after adopting this release, orsurface mirror checkreads the committed mirror as hand-edited (the last bullet under Added). nen surface mirror generatecarries a persona's read-only intent onto the surfaces that lost it (zheref/nen#473). A persona is read-only when itstools:list names none ofEdit,Write,MultiEditorNotebookEditand nomcp__*tool, a YAML comment ignored and a list it cannot read as tool names treated as not read-only (notoolskey means every tool, so not read-only). Cursor: its mirror gainsreadonly: true, the documented key ("no file edits, no state-changing shell commands"), unless the source setsreadonlyitself;checkreads a hand-removed line as hand-edited. A persona whose only routable keys would be the derived one is still refused. Codex: nothing is written, because a custom agent file cannot override the parent sandbox (sandbox_mode"don't override the parent configuration"); each read-only persona is a reportnote:(codex: <name> is read-only at source; Codex documents no per-agent read-only control …), with or without--models. Antigravity and claude-code output is unchanged.nen surface capabilitiesaddsreadOnly: { control, source }per surface and the text lineread-only persona:: honoured on claude-code; honoured at project placement on cursor, with plugin placement unverified (forum.cursor.com/t/173787); unverified on antigravity, whose page documents its own tool names rather than the Claude Code names the mirror carries; none documented on codex.- Behaviour changes: the cursor mirror of every read-only persona gains one frontmatter line, so a consumer's committed mirror reads hand-edited until it is regenerated.
generate'snotesgain one codex line per read-only persona.
v0.26.02026-10-22
v0.26.0 — 2026-10-22
- Repin:
"0.24"→"0.26", andv0.25.0→v0.26.0. The compatibility floor moves to0.26: this release changes the meaning of exit codes and outputs consumers already read (the bullets below), so a pin below0.26is refused by this build. pr openadopts an existing pull request at exit 0 (existing: true) when the head and base match; consumers that read exit 1 as "already open" (Hatsushibari) must readexistinginstead.- Refusals under
--jsononissue file,idea file,canon resolveandcommit formatarrive as onenen.refusal/v0.1envelope on stdout, with no refusal prose on stderr. pr readyandpr merge --release-unitreadaiReviewersat the pinned PR base and the default-branch tip, the stricter winning; absent or unreadable meansrequired.- Ledger homes move to the git common directory: the loop ledger to
<git-common-dir>/.nen/loop/, stop answers to.nen/stops/and run manifests to.nen/runs/; older spellings (<common>/nen/loop/,<repo>/.nen/loop/,<common>/hatsu/runs/) are migrated once on read.review ledgeradopts a declared roster and its own mutex: stop legacy writers of the hanten cycle ledger before adopting it. nen parse <skill> --grammarrefuses a later slot no literal introduces, at exit 2; re-check every grammar at the repin.pr convergeexits 1 on the rows listed under Changed.repo classifyreads a family's spec repository as rolespecat gateG2(nen repo familyreports the family's statedspec.gate).- Add
review ledger init|ensure|decide|record|show|recover-firstto own Hatsu's v0.1 review-cycle history, declared persona budgets, PR keys, durable lost-ledger traces and concurrent updates. Migration retains existing history; ambiguous unstamped missing reviewers require restoration rather than a built-in persona exception. (#346) - Reviewer identities declare
wake: request|event. Request routing skips event lanes, and readiness reports their live, absent, completed-without-review or posted state without counting a successful job as a formal review. Live lanes remain owed across met quorums and stall against their run start. - Warmup sweeps a consumer’s
ci.pinnedagainst its provider registry’s latest, with--ci-registryoverrides and explicit NOT CHECKED when no CI block is declared. nen pr readyandpr merge --release-unitnow readaiReviewersat the pinned PR base and default-branch tip, taking the stricter policy and defaulting unreadable or absent declarations torequired. Optional/off waive only consistently declared bot rounds and bot quorum contributions; human/unknown obligations and every other gate remain binding. Reports retain raw evidence and name policy provenance and waivers.pr request-reviewsexit 9 now says an accepted bot request was absent from the response and that the response cannot distinguish allowance exhaustion from an otherwise unrecorded request, including itsfirst:100pagination limit.nen/contract.jsongains an optional top-levelprecedencelist (Hatsu ruling HR-1): ordered canon sources, first wins, each from a closed vocabulary:skill.hardLimit,roster.ruling,nen/decisions.json,docs/WORKFLOW.md,docs/PROCESS.md,handbooks, and<plane>.CON(e.g.cloud-tier.CON), whose plane name is checked by shape only because nen ships no system's name.nen schema checkrefuses an empty list, an unknown or repeated source and a near-miss root key, by pointer; nen never applies the order.nen/workflow.jsonmodelsmonitor.localSlotFrees(ready+prompted|merged|stacked-open, HR-5), whichnen loop slotsreads from--repoto decide when a local slot frees, and validates an optionalidleprofile (decisionsper ask-once row →default|hold|refuse,terminal,budget: {minutes, tokens}). A newnen/workflow.json#idlerow innen schema checkcross-checks each row id againstnen/decisions.json.nen/repos.jsongainsfamilies[](HR-16):name,spec.repo,spec.gateexactlyG2, andmembers[]whose codes must be exactproduct_codeskeys — a typo'd member code, a code in two families or a non-G2 gate failsnen schema checkby pointer.nen repo classifyreports rolespecat gateG2for a family's spec repository, and the newnen repo family <name>(contractnen.repo.family/v0.1) resolves the spec and each member to<code> <owner/name> <platform>; an unknown family exits 2 listing the declared ones. (Closes #453)
… more in CHANGELOG.md
v0.25.02026-10-20
v0.25.0 — 2026-10-20
- No repin: the compatibility floor stays
0.24. Both additions are compatible with existing pins and flat PR-section overrides remain supported. pr sections resolve --overridesreads Hatsu'spr.sectionsenvelope (max,variants,$canon), honors a consumer cap within the catalogue cap, and reports invalid nested cells at their actual pointers. Existing flat cell maps remain supported; metadata does not affect resolution. (NN-IS-#464)shu tools --installaddsgem-useralongside the existing lane-local Bashcov-onlygeminstaller. It installs any declared unscoped Ruby gem with an exact stable pin into the current user’s gem home on macOS/Linux, checks Ruby >=3.2, bypasses.gemrc, reports prerequisites separately from the consumer reason, and verifies the declared version after installation. Presence-only probes, incompatible pins and unsupported hosts refuse before installation. Nen never installs a runtime, edits PATH/profiles, or installs project dependencies.
v0.24.02026-10-20
v0.24.0 — 2026-10-20
pr body-check --exact [--max <n>]refuses undeclared, repeated, ambiguous orpr sections resolvereads caller-owned section catalogues, conditional facts- Record caller-reported effort levels with
phase begin --dialandusage record --dial, verbatim or null; existing v0.1 ledgers with no dial read null. Addsession record|showand the atomicnen.session.ledger/v0.1ledger, requiring a meaningful title or id and deriving no identity from the harness. (Refs #437) - Breaking-consumer notes: additive
dialfields on phase and usage entries and report rows, plussessions[]onnen.report.data/v0.1carrying caller-reported identity and dial. Existing keys and contract versions retain their meaning; consumers may render delivery attribution from the ledgers after repinning. No breaking migration or provisioning; the compatibility floor remains 0.22. Hatsu template/guard changes belong to HA-IS-#321. - Preserve the full existing report key prefix by appending
sessions[]after context/register fields and before the final optionalobjectsFilter. Refuse dangling session ledger links without replacing them, reject stray session arguments before any operation, and warn when an existing sessions directory cannot be read. - Session ledger reads refuse non-regular entries without waiting for FIFO writers; report ingestion warns and skips them.
- Refuse stray positionals in
backlog fetchandreport dataat exit 2, naming each token and explaining that a value with spaces is one quoted argument. Consumer note for the next minor: quote spaced--labelvalues; previously ignored trailing tokens now fail. The same opt-in guard rejects ignoredwc prunepassthrough arguments without changing deletion safeguards. - Declare
workflow.severitywith a family and highest-first order, optionally mapping short severity names to full label names for flat taxonomies. Fetch/report filters read omitted flag values from it; explicit flags override independently. Schema checks validate all labels. Nen declares its existing priority labels without creating or syncing labels; consumers such as Hatsu can declare their own vocabulary on repin. - Correct two severity values joined by
+to the lower band with+, retaining #416's complete-line round-trip validation and guarded gate/label relocation. Refusals still exit 2 and JSON exposescorrected. - Parse exact GitHub issue/pull URLs and
owner/name#Nthroughref parse, returning slug, optional registry code, kind (null for short refs), and number without network access. Other hosts, authorities and path shapes fail closed. Hatsu's URL restriction and selector workarounds can retire when it repins this minor. Provisioning: none. (Refs #427) - Harden GitHub subject diagnostics against userinfo disclosure on malformed authorities and schemes, require the literal ASCII
github.comhost, and enrich codes only from exact recorded slug identity (including consumer-only codes). Legacy repository token resolution remains unchanged. - Check optional GitHub subject codes against the existing resolver’s canonical code identity, so two recorded owners sharing a repository basename cannot borrow each other’s code.
- Refuse
$-prefixed severity order names before mapping lookup, keeping all mapping metadata untyped and inactive. Clarifyref parserefusal and output documentation separately for object notation, GitHub URLs and short subjects. - Repin:
"0.23"→"0.24", andv0.23.0→v0.24.0. The compatibility floor moves to0.24. The isolated ledger fragment’s earlier floor-0.22note is superseded by this combined release: the previous released floor was0.23, and this release refuses stray selector and prune arguments older builds ignored. Quote spaced label values as one argument.
… more in CHANGELOG.md
v0.23.02026-10-19
v0.23.0 — 2026-10-19
- the deliveries: #415 (closes #160), #416 (refs #410), #417 (refs #216), #418 (refs #391), #420 (closes #383), #429 (closes #382), #430 (closes #351), #431 (closes #373), #432 (closes #372), #433 (closes #363), #434 (closes #262), #435 (closes #426), #436 (closes #350).
- direct —
nen direct matrix --registry <path> --taxonomy <path> --repo <path> [--job <c,d>] [--domain <e,f>] [--json]enumerates every (job, domain, language) answernen direct resolvegives, so a consumer can render the whole routing table without re-implementing the resolver. Each cell is that one job and that one language (or none, the*column) in that domain, answered byresolve's own functions — the route, phase fallback and stand-ins, the aggregate, both sides resolved (surface, spelled alias, restart line, interactive tools, snapshot quote, live lookup) and the effort; nothing is re-derived. Which domains a job can be in isresolve's domain derivation asked about bounded witness issues (the job alone or with up to two other jobs; a kind no rule names, then each named kind; no role, then each named role; no label, then one per pattern). The first witness per domain is printed and passes toresolveas typed.witnessIsCellsays whether it is the job alone: then oneresolvecall on it reproduces every cell, while a witness that needed companions shares only the domain and the job's own pair with the cell (the cell's winner, aggregate and effort stay that one job's). A domain no witness derives isunreachable, and a cell a reviewer wins with no stand-in isskipped.--jsonisnen.direct.matrix/v0.1, grouped job → domain → language. Invalid or unroutable input refuses byresolve's own names at exit 1, an unknown or empty filter at exit 2 (#435, closes #426) - parse — Retain concrete structured invocation corrections on the merged list/alternation grammar, preserving string values with list items and canonical slot names. Ambiguous or incomplete structured repairs return
corrected: nullwithout a pasteable-line heading; legacy scalar refusals keep their placeholders. It validates the meaning of the complete correction in a separate parser pass; it refuses boundary-changing relocations and incomplete required structured positions, and normalizes malformed free-list alternatives without changing the chosen alternative. (#416, refs #410) - labels, classify — Label syncing now reads all remote pages once, skips identical labels, updates only differences, and prints incremental counts. Label apply accepts a validated JSON batch file with one result and after-the-fact ledger entry per pair. Label and classify apply share a preflighted
.nen/label-ledger.jsonldefault, creating its state directory before mutations. Non-regular ledgers are refused without blocking, including a FIFO swapped in during preflight; regular-file symlinks remain supported. The existing loop release behavior is unchanged; Claude default-harness permission validation remains outstanding (#418, refs #391) - pr —
pr readyaccepts additive--target/--praliases and consistent mixed forms, refusing new conflicting declarations before API access while preserving legacy reference overrides. Its unevaluated token remedy now names--token-envbesideGH_TOKEN, and the reference lists authentication for every PR verb. Gate predicates, policy sources and explicit-token authentication are unchanged (#420, closes #383) - review scopes — nen's own
nen/workflow.jsonroutessrc/runner/to thesecurityreview scope (Feitan), so a runner change raises the security reviewer as NN-PR-#334 and NN-PR-#336 should have. A survey of every othersrc/family, against one test (does it run elevated, or read, mint or copy a host credential's value?), adds three exact files and rules out the rest;src/review/scopes.test.tspins both halves against the repository's own file (#429, closes #382) - Ruled in:
src/runner/**(it writes the elevated host scripts that install, stop and delete runner services and mint registration tokens withgh, insrc/runner/script.ts);src/github/client.ts(tokenFromEnvreads the named token variable and sends it as the Authorization token);src/wc/worktree.ts(--copy-from-corecopies gitignored credential files from core into a worktree);src/shadow/run.ts(dev-only; it mintsGH_TOKENfromgh auth tokeninto its own process). - Ruled out:
src/shu/(requiresEnvasserts variable names and never reads a value, and host installs never rendersudoorRunAs);src/surface/(no elevation, and it only redacts credentials in output);src/seam/exec.tsandsrc/stage/(they redact or detect credential shapes and read no credential);src/supply/(checksum verification, no credential);src/scaffold/(itstokenis a{{token}}template placeholder);src/canon/checkout.ts(it expands only the variables a checkout template names into a path, never a credential by design); the families that callghorgiton gh's own stored credential without reading it (for examplebacklog,canon,classify,dev,idea,issue,label,labels,repo,report,run,tag,wake). Every othersrc/path neither runs elevated nor reads, mints or copies a host credential's value, and is thecodescope's alone. - Already covered:
src/pr/,src/release/andsrc/verbs/pr_ready.tsby path, andsrc/security/secrets.tsby**/secret. - pr —
pr readyreads everynen/gates.jsoninput at the pull request's BASE commit, not onlychecks.excluded: everyreviewers[]key (name,login_pattern,review_check_pattern,round_check_pattern,enrolment_check_pattern,bounded_policy_exempt,delivery_holistic_pass,approves_when_posted_at_head),default_approvers,approval_policy,base_reviewers,round_quorum,round_policy(the stall bound and the round caps),deliveryanddependabot_carve_out. One base read serves the identities and the exclusions, through the route #249 built. A head that loosens its ownlogin_patternorround_quorumno longer changes its own verdict. The checkout's own file applies only when the base could not be READ (a 403, the network, no base commit), with ameta.warningsline on every output. A base that declares nonen/gates.jsonnever applies the checkout's file:--reviewers' own identities do when given, and otherwise there is no verdict (unevaluated, exit 1). A base file this build refuses gives no verdict either.checks.excludedis never taken from the checkout. An explicit--gatesnaming a file outside the checkout is the caller's word and supplies everything butchecks.excluded, which stays the base's. A--gatesnaming the checkout's ownnen/gates.jsonis read at the base, under any spelling or hard link. Any other--gatesfile inside the checkout is applied as possible head content, with a warning.--reviewerswith nonen/gates.jsonin the checkout (a head that deleted it) reads the base all the same: a base file applies,--reviewersonly narrowing it; none at the base, the flags are the gate (null); a base that could not be read leaves themflags-unverified.watch until --prandpr mergeshare the read.--require-base-gates(onpr readyandwatch until --pr) turns every route butbase,gates-flagandnullintounevaluated, exit 1, for callers that act on the exit code.pr merge(both forms, allowing onlybase) andwatch until --until ready(allowingbase,gates-flag,null) refuse areadyon any other route, andpr merge --deliveryrefuses a pull request that changesnen/gates.jsonornen/workflow.json; both merge forms compare those paths case-insensitively.pr next-blockerapplies the same rule throughgh: exit 2 wherepr readygives no verdict, and--jsonaddsidentities { path, read }.pr ready --jsonaddsmeta.identities.read:base,local-fallback,gates-flag,local-unverified,flags-unverified, ornullwhen--reviewerssupplied the identities on a base that was read and declares none.--explainnames the route on its identities line (#432, closes #372) - issue, idea, pr, wake, release — the private-name guard #329 put on
issue file,issue commentandissue edit-bodynow runs before every write of caller text to a GitHub API text field:issue consolidate-close(each child's--close-comment/--close-comment-maptext, before the attach),idea file(title and body),pr open(title and body, before any other call),pr edit-body(body, after the certifying read),pr threads replyandpr threads settle(every reply body, before the walk),wake fire(--comment, before the label is touched),wake verify(--nowand the two markers, before the first read) and nen's ownsrc/dev/release-publish.ts(release title and notes, before the create; not on its offline--dry-run). Each takes the same opt-out, ignore file and--allow-all-ignored, prints the same index-only lines prefixed with its own name, and addsprivateNameCheckto--json.pr openandpr edit-bodynow handghthe checked bytes on stdin (--body-file -) rather than the path. For every guarded verb, #329's included: an internal target is now checked like a public one; a credential whosegh api -i useranswers noX-OAuth-Scopesheader, or one withoutrepo, is refused as a list that may be partial; and an ignore file whose real path lies inside the--repoworking tree is refused.wake verify --nowmust be an ISO-8601 instant. The shared adapter issrc/issue/privacyguard.ts, andGUARDED_VERBSis held both ways to the table in docs/USAGE.md's guard section. Not guarded, out of #363's scope rather than exempt: declared taxonomy data reviewed as its own change (labels syncdescriptions,labels renamenames), and git objects that reach GitHub by push rather than through an API text field (commit messages fromcommit write/wc publish, the tag message oftag cut --message --push) — follow-ups: label descriptions,tag cut --message --push, push-side commit messages. Writers with no caller prose (label apply,classify apply,issue attach-sub,pr request-reviews|retarget|mark-ready|merge,pr threads resolve,run rerun), the read-onlyissue reconcileand therunnerverbs (a variable and labels the public cannot read) are named there too (#433, closes #363) - pr — every
prsubcommand now refuses, at exit 2 and before anyghcall, each flag it does not read, naming the subcommands that do read it (--fromnamespr threads settle;--reviewersnamespr readyandpr next-blocker). One per-subcommand table insrc/pr/command.tsreplaces the family's spread ofpr ready's flags and the one-flag-at-a-time refusals, and the parser's flag set is derived from it. A--token-envrefusal says which credential that subcommand actually runs on.pr --helpand the reference say an unknown flag is unknown per subcommand (#430, closes #351) - docs —
docs/USAGE.md's list of contract ids is now every versioned id the binary carries, writing or reading (70 shapes, 73 ids; it named 35 and had gone stale, among others missingnen.pr.open,nen.pr.threads,nen.pr.merge-unit,nen.release.unit-check,nen.wc.publish,nen.wc.catch-up,nen.commit.write,nen.usage.ledgerandnen.canon.pin, and namingnen.issue.edit-body/v0.2where the code writesv0.3).src/cli/usage-contracts.test.tsholds the list to the code. It collects everynen.<name>/v<n>[.<n>]literal from the non-test, non-fixture files undersrc/andtemplates/after blanking comments (single, double or backtick quotes, underscores and major-only versions included, plus any template literal with an interpolation such asnen.shu.${verb}/v0.1), and fails with its file:line on id-shaped text no rule collected rather than skipping it. It fails when the USAGE list is missing a carried id, names one that is not carried, lists one twice, or states a shape or id count that disagrees with it The command-family count stayssrc/cli/surface.test.ts's:COMMANDSplus the two pre-registry commands, which README and USAGE already state correctly. Adding a contract id to the binary now means adding it to the USAGE list and moving the two stated counts in the same change. (#436, closes #350) - schema —
schema checkgains a.claude/rules/row, afternen/decisions.json, comparing a consumer's canon mirror as written bynen canon mirror generatewith the bindings in.claude/canon-values.yml, without a canon checkout. The values each token held in earlier committed revisions (the most recent 100 that did not delete the file) are read from git, raw, throughgit cat-file blob, offline (GIT_NO_LAZY_FETCH=1). The row FAILs, naming the token, both values and the files, when a token's bound value is nowhere in the mirror while an earlier value of it is (SNAPSHOT_OS is bound to '27.0' but 3 file(s) still carry '26.5': …), or when an earlier value is a table cell or code span on a line beside the bound value or the token's name, the hardcoded-column case a drift check accepts. Each FAIL endsRegenerate the mirror (nen canon mirror generate); never hand-edit it (CON-13).An earlier value in prose elsewhere in a mirror that carries the bound value is not a finding, nor is a value that is any token's current binding, or a consumer's own unmarked rule. No.claude/canon-values.yml, or an empty.claude/rules/, readsok. Every comparison that could not be made is awarnrow readingNOT CHECKED:.mdfiles none of which carries nen's marker (a mirror the oldersync-canonwrote is not read), a shallow clone, a history or a revision git cannot read, or no committed revision (#434, closes #262)
… more in CHANGELOG.md
v0.22.02026-10-18
v0.22.0 — 2026-10-18
- the deliveries: #411 (closes #341), #412 (closes #348), #413 (closes #410), #414 (closes #404), #422 (closes #405).
- parse —
nen parsegains list slots (<slot>{+},<slot>{&}; every item of an enumerated list is checked) and alternations (<a:..>{+}|<b:..>[+]|<c>; the free alternative is taken only when no piece of the value is an enumerated value, so@g4+model/gptis refused rather than read as free text).--jsonaddsalternativeanditemsonly where they apply (#413, closes #410). - backlog, report —
nen backlog fetchandnen report datagain a repeatable--label(AND over an effort's issue and PR labels) and a--severity <name>[+]band, read from--severity-familyand--severity-order. An undeclared label, or a piece of a declared label containing&, is refused at exit 2 before any read; a filter that keeps nothing is an explicit zero at exit 0; an unfiltered document is unchanged. A filtered fetch keepsissueCount/prCountas fetched (before the filter) and adds afilterkey; a filteredreport datakeeps every object of a kept effort, appendsobjectsFilteras its last key (with or without--register), refuses a filter given no objects source, and refuses at exit 2 a--registerdesk naming an object the filter removed.backlog orderandreport renderrefuse the filter flags (#413). - release, pr —
release.unitPathsaccepts{ "path": "<exact text file>", "lines": ["<whole-line regex>"] }entries.release unit-checkandpr merge --release-unitcheck every removed and added line against complete merge-base/head blobs, failing closed on unreadable text or a diff beyond the stated work bounds. Existing JSON-key bounds keep their report shape;linedPathsandlineScopedViolationsare additive fields (#412, closes #348). - schema —
schema checkreportsnen/workflow.json#release, including exact, prefix/glob, key-bound and line-bound counts (#412). - release — an
=pathstring claims one exact path, so=README.mdcannot admitREADME.md/**. Nen's own release unit bounds changed lines insrc/version.ts,README.mdanddocs/USAGE.mdto version/floor and declared install/example forms, and names=CHANGELOG.mdexactly. Both removed and added lines are checked independently; allowed lines may be deleted, moved or replaced by another allowed form, including optional fixed command fragments. The bound does not preserve presence, position, pairing or consistent versions (#412). - release — line bounds use a release-only bounded state matcher, preserving legacy identity-regex consumers. Unsupported syntax fails schema loading by pointer. Matching never backtracks through PR text; source, nesting, state, class and pattern-count limits bound compilation, and changed-line length plus per-line/per-file operation budgets fail closed with a distinct exhaustion reason. The limits and supported expression subset are documented in USAGE (#412).
- schema, report — exact markers in review scopes and report tiers are validated at their read seams, so an empty
=or malformed repo-relative exact path cannot silently claim nothing. Bare prefixes and globs retain their existing meaning (#412). - schema — lane cwd paths share stdoutTo's repository-relative validation, including Windows absolute, drive-relative and traversal spellings on every host. Dependabot review exemptions name one anchored literal bot account rather than a catch-all or human-shaped regex (#414, closes #404).
- pr — threads settle scans every inline and file body before any GitHub call for GitHub/URL credentials, AWS access keys, Google API keys, Azure account keys, private-key headers and high-entropy tokens. Refusals name the shape and redact the value. A URL authority's numeric port followed by an @ in its path, query or fragment no longer reads as a password (#414).
- gates — NEXT_RELEASE is derived as VERSION's next minor; release proposals need no separate edit to gates.ts (#414).
- reports — Nen declares final/register sections for Hatsu's Rikugan template (#414).
- wc —
wc squash --message-filerefuses a message missing every agent trailer admitted bycommits.allowedAttributionTrailers, at exit 2 before reset or commit, naming the keys and policy source (#422, closes #405). - runner — the runner preflight fixture and Nen's Windows workflow are refreshed from Hatsu 0.111.2: branch-only pushes stop release tags waking the pool, and Windows tool resolution uses the runner service's recorded PATH. Each pool keeps its own label and SHA-pinned checkout (#411, closes #341).
… more in CHANGELOG.md
v0.21.02026-10-11
v0.21.0 — 2026-10-11
- the deliveries: #381, #385, #386, #387, #388, #392, #393, #394, #395, #396, #397, #398, #399, #400, #401.
- shu —
--streamrelays each step's stdout and stderr live, one whole line at a time, onbuild,test,ui-test,lint,archive,release,deploy,coverageandtest-report(under--jsonthe child's stdout goes to stderr); a step still running after 30 s prints a heartbeat on stderr every 30 s,--heartbeat <s>sets the interval and--heartbeat 0without--streamrestores the old captured path (#381, closes #244). On the apple lane a growing log now proves nen is alive, not the child: use--stream, or declare astallguard. - shu —
nen shu test --select <id>[,<id>…]runs the lane's one declared focused form,project.verbs.<lane>.test.selectinnen/contract.json(exe,argv,eachwith{id},pattern, a requiredresults: { path, format }under.nen/focused/) (#393, closes #207). A bad selection, or a lane with noselect, is refused at exit 2 before anything spawns, never a fallback to full regression; a selection that executed zero tests is exit 6 withselection.executed: 0andzeroMatch: true. Old results are moved aside into.nen/focused/.previous/<run-id>/under a lock, never deleted in place, and the last 2 runs are kept. - pr —
pr body-checkwith no--requirements-fromderives the requirement set from the repository's pull-request template, naming the source on the verdict line and in--jsonsource, or refuses at exit 2 with a bootstrap pointer;--base <ref>reads the template at a commit, so a PR cannot loosen its own requirements (#385, closes #239). A derived section with no real content isEMPTY, distinct fromMISSING. - pr —
nen pr threads settle --target <owner/name> --pr <n> --from <file.json>(nen.pr.threads-settle/v0.1) settles a reviewer round in one walk plus one reply and one resolve per entry (2N + 1calls, where a loop cost4N); the whole file is checked before any write, analready-resolvedthread exits 3, a refused mutation stops the batch, and abodyFileis confined to the batch file's directory, refused on dot-segments, hard links and credential shapes (#398, closes #230). - pr —
nen pr open --assignee <login>[,…]:@meresolves throughGET /userand is printed, every login is checked assignable before anything opens, and the assignees are read back;nen.pr.open/v0.1appendsassignees,meandassigned(#398, closes #293). - pr — under
--explainand--json,pr readydiagnoses each queued required check against the runners that could take it:meta.runnerAvailability[]with a determination (online,offline-only,no-runner,github-hosted,started,environment-wait,undetermined),infrastructureStallafter 10 minutes queued, and the missing grant named when the token cannot read runners (#394, closes #224). The verdict, rows, exit codes and default output are unchanged, and the default path makes no extra read. - gates —
round_policy.minRoundsandround_policy.maxRoundsbecome nen keys, adopted under the consumer's names by the maintainer's ruling of 2026-10-04 (#388, closes #240):pr request-reviewsrefuses a bot's request pastmaxRoundsat exit 2, reading it at the PR's base and at the default branch's tip and applying the lower;pr ready --explainprints per-reviewer requested/posted counts (meta.roundCounts), never a conjunct; and the CON-32(b) rounds-owed row tells "no round at any head yet" from "pending request only" (plus "own-request"), with the verdict unchanged. - canon —
nen canon checkout --repo <consumer>(nen.canon.checkout/v0.1) resolves the canon checkout from--canon-checkout, then the row'scheckout_envvariable, then itscheckouttemplate (two new optionalnen/repos.jsonmaintained_toolsfields), and verifies it read-only: top of its work tree, origin on the consumer's host, HEAD at the pinned tag, a clean tree whatever the checkout's own configuration hides (#386, closes #294).canon mirror generate|checkaccept--stack-dir <dir> --leaf <name>in place of--rules-dir, so a mirror check is portable literal argv. - canon —
nen canon pin --repo <consumer> --write <tag>(nen.canon.pin.write/v0.1) moves exactly one value, thepinnedon the row the read path answers from, byte-preserving and atomically, after the tag resolves through the canon checkout; it reads the pin back and says the mirror must be regenerated in the same commit (#396, closes #291). It moves an existing pin only. - schema —
nen schema set --repo <path> --file <nen/…json> --pointer <ptr> --value <json>(nen.schema.set/v0.1) writes one declaration value in place, every other byte kept,$notes included, and validates the result with the file's own loader before writing (#400, closes #338). Gate changes fail closed: every pointer ingates.json/decisions.jsonand the gate scopes ofcontract.jsonandworkflow.jsonneed--gate-change, the flag on a non-gate pointer is exit 2, and a canonpinnedis refused in favour ofcanon pin --write. The$-metadata rule is now published inschema --helpand USAGE, and a fixture over all seven declaration files guards it. - schema —
nen/workflow.json→deploy.defaultTarget(nullor a target name) andproject.targets.<name>.nonProductioninnen/contract.json;schema checkgains anen/workflow.json#deploy.defaultTargetrow, andshu detectproposestestflightforxcode-ioswhen the repository declares it markednonProductionand runnable (#399, closes #300).shu deploystill requires--target. - runner —
nen runner relabel --target <o/n> --pool <id> [--runner <names>] [--run]adds a pool's ownpool-<id>label to runners named one by one, a dry run by default, refusing a misfit, a desktop runner for a plain pool and a twin-pool runner, and reading back every write;verify --poolandinventory'spools[].unlabelledreport what is still unlabelled (#395, closes #340). - surface —
nen surface installandnen surface status(nen.surface.install/v0.1,nen.surface.status/v0.1) install and report a first-party plugin on Claude Code, Codex and Antigravity, plugin-agnostic (--plugin <name> --root <checkout>), replacing only a link it owns, never writing settings (owed actions exit 4 with the command that clears each), and reading every surface back (#392, closes #298).status --treesjudges only the copy Claude Code serves.claude,codexandagyare optional dependencies of these two verbs only.
… more in CHANGELOG.md
v0.20.02026-10-05
v0.20.0 — 2026-10-05
- the deliveries: #352, #353, #354, #356, #359, #364, #365, #367, #368, #369, #370, #371, #375, #376, #377, #378, #379;
- #380, which carries #371's commits to
main: #371 was merged into its base branch after that branch had already landed through #370, somainnever received thedirectfamily until #380. nen classify— a new family over a consumer'scontracts/classify.taxonomy.json(hatsu.classify-taxonomy/v1: thelang/andjob/label axes zheref/hatsu#224 introduced) (#370):classify labelsrenders the taxonomy's label set;classify install --writedeclares it into the consumer'snen/labels.json, and--sync --targetrefuses until that declaration has landed;classify status [--with-body]reports which axes each open issue still lacks;classify apply --plan [--run] [--include-low]applies a confidence-graded plan, refusing a plan with any invalid row, applying high and medium rows only unless told otherwise, and refusing to edit an issue whose ledger cannot be appended to before the first edit — a directory named as the ledger is refused by its own stat on every platform (#380).nen direct— a new family over a consumer'scontracts/direct.registry.json(hatsu.direct-registry/v1, zheref/hatsu#225) (#371, #380):direct registryvalidates the registry and prints its snapshot, aliases, surfaces and live-lookup sources, refusing by pointer a cell whose surface differs from its alias's, a reviewer runner-up withoutalso, non-contiguous effort bands and a phase name the phases do not carry;direct resolvederives the domain from the taxonomy's structured rules, collects one routing pair per job and language (a non-code language always reads the shared cell), aggregates a winner and a runner-up, scores the effort and compares the session's surface, model alias and effort in dial space —unreadis never a mismatch — and--record <effort-id>files the verdict under.nen/direct/<percent-encoded id>.jsonwith symlink-real containment;direct answer --record <id> --answer continue|stopwrites the picker's decision into that same record, under the ledger lock and by rename, refusing a record that is not anen.direct.resolve/v0.1document for that effort.round_quorumfulfils its members' rounds (#359; the maintainer's ruling of 2026-10-04, #361): once at leastminimumofany_ofhave a round,pr readyrow 4 no longer fails on a member that is unavailable — no round-check run at head, a run that completed without a round, or a pending review request with no round check — and names each excused member in the row's note; a member whose round-check run is still in flight stays owed, a reviewer outsideany_ofis owed as before, andpr next-blockeragrees. A file with noround_quorumgets byte-identical output.- Declared check exclusions —
nen/gates.json→checks.excluded[](name,matchexact or glob,reason,ruled,untila date or{ "condition" }), validated by pointer at load (#359).pr ready,pr next-blockerandpr merge --release-unitread the list fromnen/gates.jsonat the PR's base, so a PR can never exempt its own failing check, and every honoured exclusion is printed once, in--explain, inmeta.warningsand in the merge transcript. The CLI's--exclude-checkstill applies on top. nen pr merge --delivery— the one merge a run performs into a non-main base (#377; contractnen.pr.merge-delivery/v0.1): the base must not be the default branch,branch.base, a protected or ruleset-bound branch, or the head of an auto-merging PR into one; thenpr ready, the head pin,pr body-check, and whose PR, every verdict quoted; without--runit prints the plan only.nen watch until --pr <ref> --until checks-settled|review-posted|ready|settled-and-reviewed— compound wake predicates over the same readpr readymakes (#376). Only--until readyis a merge signal; the others are wakes, and--jsoncarriesreadyAtWake. Polls are paced bymonitor.pollSeconds, bounded bymonitor.maxCycles, never under 30 s, and stop after two hours with no bound.nen stage triage --range <base>..<head>triages a committed range with the working-copy detectors, exit codes and--jsonshape (#379): names from every path any commit in the range touched, sizes from every blob it introduced,in-historyon a finding the net change no longer carries, and undecodable names flagged rather than guessed.nen stage listemits the exact add list a checkpoint should stage, through the same pass asstage triage(#364): newline,--nulor--json; exit 3 on an empty tree, exit 1 with the list withheld when anything needs a human.nen shu coverage --touched --from-capturemeasures touched-file coverage from an existing capture a producing run wrote, provenance-checked by a tree fingerprint and the reports' digests, and never re-runs the lane (#369).nen surface mirror check --surface claude-code --plugin <name> --installed <dir|auto>judges a Claude Code plugin install in its own layout (nen.surface.mirror.check-plugin/v0.1), the worst copy winning underauto, with the six verdicts Hatsu'splugin_cache_check.shgave (#378).nen report dataderives the effort's context —repo,worktree,effortStage,gate,stageClass— from facts, or null with its reason on stderr (#375); and--register <desk>emits the backlog register document, every fact nen's and the desk file carrying judgement only (#365): on the live path every verdict ispr ready's ownreadiness.reason, quoted; on the--objects-frompath verdicts come from the caller's file, and each such row and the footer say so (verdict read from <file>, not from GitHub) — an offline register is file evidence, never a fresh readiness assessment.nen issue edit-body --expect-body-sha256 <hex>refuses at exit 3, writing nothing, when the live body no longer hashes as the caller read it;--current-body-outwrites the certifying read's exact bytes; every report saysbodyCheck.atomic: false(#356).
… more in CHANGELOG.md
v0.19.02026-10-04
v0.19.0 — 2026-10-04
- the deliveries: #334, #335, #336, #342, #343, #355 and #357;
- #358, the release proposal, and #362, which folds in #355 and #357. Those two merged while #358 was open, ahead of its merge.
- runner (#335, closes #333) — interactive Windows runners, which run inside a signed-in desktop session for jobs that drive a real UI. A service runs in session 0, where such a job times out.
- Declaration:
nen/workflow.json→runners.pools[].modeisserviceorinteractive. - Absent means
serviceon Windows and Linux, andinteractiveon macOS, whose runner is a LaunchAgent. macOS+serviceandLinux+interactiveare refused.- An interactive Windows pool's labels are exactly
["self-hosted", "Windows", <arch>, "desktop"]. runner plan: its contract is nownen.runner.plan/v0.2, which addsmodeanddailyAccount; a v0.1 plan still reads, as a service plan.- An interactive identity must be a local account; the built-in service identities are refused.
- Every rendering says the runner is online only while that account is signed in, with an active, unlocked session.
- It also says such a runner takes every job aimed at the plain
[self-hosted, Windows, <arch>]set, not onlydesktopjobs. - When the identity is the Windows account computing the plan, the plan warns and records
dailyAccount: true. runner script: adailyAccountplan renders only with the new--accept-daily-account, and the verb repeats that check itself on Windows.- For an interactive pool the script installs no service and asks no password.
… more in CHANGELOG.md
v0.18.32026-10-01
v0.18.3 — 2026-10-01
- the deliveries: #320, #321, #323 and #324.
- #325, the release proposal.
- gates (#321) — this repository's own
nen/gates.jsondeclares the reviewer-round caps Hatsu reads:round_policy.stallMinutes30 (nen's, equal to the built-in default, so nopr readyverdict changes),minRounds1 andmaxRounds3 (Hatsu's, read bysharingan§ 6). Without them a Hatsu run driving a nen pull request had no ceiling and re-requested Copilot past Hatsu's own cap (four rounds on #316). - ci (#320) —
.github/workflows/runner-preflight-windows-x64.ymlre-rendered from Hatsu's fixed template (zheref/hatsu#177, zheref/hatsu#178, zheref/hatsu#179): the Windows step classifies each tool's firstwhere.exematch, searched on PATH only ($PATH:<tool>, never the fresh checkout's directory), fails anything under the service user's profile or anAppDatasegment, prints verdicts and never a path, and its remedy names no install location. The push ran it green on the pool (run 36802460051,NZ-NNR2);nen runner enablethen setNEN_WINDOWS_RUNNER=onlineon the run dispatched frommain(36802783501). - ci (#323) —
check-windowsruns itsrun:steps under bash, job-wide (defaults.run.shell). On the leg's first live run (ci run 36802734735, runnerNZ-NNR1) the shell-less steps were written to.ps1files and executed under Windows PowerShell as the runner's service account, which refused them ("running scripts is disabled on this system") beforebun install; the pool's declared toolchain (nen/workflow.json→runners.pools[windows-x64].tools:git bash gh) never included PowerShell, and its preflight proves bash.src/ci/runner-policy.test.tspins the default. - surface (#324) —
surface mirror generateandsurface mirror checkread file modes for what NTFS can hold of them. Node and Bun on win32 report0o666for a writable file and0o444for a read-only one whatever mode was declared, so on Windows everygeneratere-chmodded every hook script and reported itwritten, and everycheckreported every hook scripthand-editedat exit 1 (the false red zheref/hatsu saw on this pool). A newhostMode(declared, platform)maps a declared mode to the host's at the two comparison sites: a fresh mirror now checksokon Windows; a script made read-only by hand still readshand-edited, and a regenerate repairs it. POSIX is unchanged. Where the executable bit matters, git records it (git update-index --chmod=+x); USAGE says so undersurface mirror generateand in the drift table'shand-editedrow. - test (#324) — the suite is green on Windows under Git Bash (ci run 36810142678:
Test Files 225 passed,Tests 6638 passed | 7 skipped): eightcommit format/commit writetests accept the host's own path spelling (nen[\\/]workflow\.json, both backslashes as the source has them), the--hooks-rootround-trip test passes a forward-slash drive path on win32 (rebaseCommandrefuses a backslash by design), and the mode tests take their expected and "wrong" modes from the platform. Noit.skipwas added. - docs (#324) — README § Platform parity and § CI runner boundary, and USAGE § Platform parity, say what is true: the suite runs on Linux and macOS on every change, and on Windows while
NEN_WINDOWS_RUNNERisonline(skipped otherwise); the two host-wide Windows rules (native path spelling, no executable bit) are defined once, with links to the verbs that also behave differently (shu tools --install,watch until,shu detect'sdotnet-winui). - No repin: the compatibility floor stays
0.18. A repository pinnedminimum: "0.18"needs no change to read this build.pinned_refSHOULD move tov0.18.3on a repository whosesurface mirror checkruns on a Windows host: that is how the falsehand-editedred on hook scripts goes away.
Showing the latest 12 sections. The full history is CHANGELOG.md.
Bankai-Handbooks
Unreleased
Unreleased
v0.12.0
v0.12.0 — the Electron desktop shell
- The Electron desktop shell is a render target of
react-uzf-v1, not a scenario (handbooks/VERSIONv0.12, MINOR under the pre-1.0 carve-out; BH-IS-#15). Scaffold scenario 2A already mapped toreact-uzf-v1, but no rule covered its Electron desktop shell. The decision — a third render target beside Next.js and Expo, becausereact-uzf-v1already spans several platforms as render targets over one ui-architecture and one shared core, and 2A adds one more — is recorded inhandbooks/stacks/react-uzf-v1/rules/README.md(Reconciliation decisions) and inhandbooks/stack-matrix.md, for the canon owner's G4 ruling.handbooks/stacks/react-uzf-v1/rules/14-electron-desktop-shell.mdis new and carriesRC-64–RC-69, appended afterRC-63with nothing renumbered: the main/preload/renderer process boundary and where Feature, Store and Service live across it, a desktop-owned Chakra UI (v3) Page layer over the shared core — the maintainer's ruling of 2026-10-22: never the Tamagui{{APP_PACKAGE}}Page, noreact-native-webalias, desktop Service bindings injected by name into aThunkExtra-typeddesktopExtraatrenderer/main.tsx(never resolved by extension; a missing forked binding is a typecheck failure), every target-neutral Page rule (RC-61,RC-37,RC-10,RC-15,RC-14,RC-5,RC-3,RC-18,RC-11,RC-31,RC-63) and theUX-{n}baseline binding it — one store in one window, desktop navigation throughNavigationServiceonly, and ≥3 scenario tests per main-process handler and migration (RC-64); IPC as a Service behind a context-isolated, typed preload bridge, the channel map a real module,nodeIntegrationoff andsandboxon for every window (RC-65); packaging and signing through electron-builder, in CI, from secrets, with an unsigned artifact failing the release (RC-66); auto-update through electron-updater as a main-process Repository, surfaced to the renderer as anUpdateService(RC-67); local storage in the main process through one better-sqlite3Databaseheld by a Repository, secrets throughsafeStorage(RC-68); and the desktop performance budget for a Chromium shell, floored on 2A's own trade-off line (RC-69).11-forbidden-patterns.mdgains the matching reject section and09-testing.md's toolbox the desktop row.RC-49's meaning changes: its member set is now per scaffold scenario (1: core, app, web, mobile; 2A: core, app, mobile, desktop — desktop being the member 2A adds — plus web if added later; scenario 5's set is not asserted, since the matrix's 5 names Tailwind + shadcn/ui rather than Tamagui or Solito and the separate canon issue on web styling settles it), stated in08,10and the registry — carried as MINOR under the pre-1.0 carve-out and flagged for the reviewer.RC-52andRC-53are qualified to "every render target present",RC-46andRC-51scope{{APP_PACKAGE}}to the Tamagui targets ({{WEB_APP}},{{MOBILE_APP}}) — the 2A desktop shell does not consume it and depends on{{CORE_PACKAGE}}only — andarchitecture.md§ H is retitled accordingly.stack-matrix.md's 2A Desktop UI line now reads Chakra UI v3 over a desktop-owned render layer instead of Tailwind + shadcn/ui shared from the RNW/web layer; the other scenarios' web-UI lines are untouched (a separate canon issue carries them). Two tokens are added to the stack'splaceholders.md,{{DESKTOP_APP}}and{{DESKTOP_APP_ID}}, and everyreact-uzf-v1consumer binds both at its next repin, whatever its scenario — every mirrored rule file that uses them (08,09,10,11,14) is mirrored to all consumers and the mirror generator fails closed on an unbound token; a repository not on scenario 2A binds the values its desktop member would take and carries none. No consumer is on this stack today, so no binding is owed yet.handbooks/quality-baseline.mdgains aQA-7tooling row (Playwright's Electron driver, documented as experimental, against the packaged artifact — unsigned on pull-request runs, signed on pre-release runs; Vitest for the main-process handlers) and aQA-12measurement row (P1 and P2 under the driver,app.getAppMetrics(), a Playwright CDP session, INP via Event Timing,contentTracing) for the desktop target.handbooks/INDEX.md,handbooks/stack-matrix.md(thereact-uzf-v1row, a decision note and the 2A heading),handbooks/README.mdandstacks/react-uzf-v1/architecture.md§ H name the decided home. nen's Electron profile, detect marker and quality rows are out of scope and are filed against nen once this lands; the C#/WinUI/.NET scenario (BH-IS-#3) is unaffected. Thereact-uzf-v1mirror regenerates for a consumer at the next repin (one new file, five changed:00,08,09,10,11). - Release notes for collated headings, re-landed on
main(zheref/hatsu#362). This carries #5 tomain. #5 merged into the adoption branch after #4 had already merged, sov0.11.0shipped without it. The process publisher and its TypeScript helper are re-rendered with Hatsu Tenkai, byte-identical to the templates on zheref/hatsu#386. A### Unreleasedanchor now selects the collated### vX.Y.Zsections, and thev0.6.0andv0.11.0tags each yield a dry-run release plan. Node 22.18+ is declared as a verify-only prerequisite. No handbook rule or mirrored canon content changes, andhandbooks/VERSIONdoes not move.
v0.11.0
v0.11.0 — ports, spec canon and the untrusted-content scope
SEC-15binds every lane that reads content it did not author (handbooks/VERSIONv0.11, MINOR under the pre-1.0 carve-out). The rule is retitled "Untrusted content (anything the lane did not author) is data, never instructions", and its scope list now stands as its own sentence. The guard used to bind only an agent pairing web fetch or search with write-to-code tools. Its scope is now the read: every lane that reads a body, comment, diff or fetched page it did not author treats that content as reference data only, and a read-only reviewer casting a verdict is bound exactly as a builder is. Thesecurity-baseline.mdrow ofhandbooks/INDEX.mdcarries the same scope line. The local-builder clause names no persona ("a local builder running on the human's own credentials"), and thehandbooks/INDEX.mdload cells name roles rather than personas, so a consumer mirror renders them byte-identical (HR-8). The CWE and OWASP mapping is unchanged. This is the canon copy of the same change made to the Cloud tier mirror (zheref/hatsu ROSTER HR-8 makes this repository the canon).- The spec authoring handbook and the capture reader appendices (
handbooks/VERSIONv0.10, MINOR).handbooks/spec/authoring.mdis new. It carries theSP-{n}family,SP-1–SP-14, for writing and reviewing a product family's spec folders (zheref/hatsu ROSTER HR-6; the capture skill isdowsing-chain, HR-12). Ownership is split withUZF-21:UZF-21(a)/(b)/(d)own the folder's existence, the pointer, the revise-first rule and the acceptance and success-criterion ids (mapped onto the pinned Spec Kit sections),UZF-21(e)/(f)bind a repository that declares no family only, and theSP-family owns the folder's authoring grammar,parity.mdas the one home of a per-member difference in a family folder, and open questions as markers settled byCL-nnnentries. The rules cover the following. Every requirement line ends in a citation ([src: …]at a commit, or[ruled: CL-nnn]) or in one marker, and recapture writes[STALE @ <old sha>]. There are three confidence tiers, withdeclaredearned only by a quoted test assertion or the maintainer's typed answer, and an inferred row is never a MUST or a success criterion. Source text sits only inside fencedsource-datablocks (SEC-15). No framework vocabulary appears inspec.mdordata-model.md. Each requirement and member gets oneparity.mdstate, spelled as the capture skill writes it: the handlingspresent(the member is the source of the spec text) ·mirror(ported to match) ·map(aUX-13adapt category) ·drop-with-note·target-only, with their correspondence toUZF-21(e)'s dispositions and the ports family's spellings stated once, and the open sub-statesabsentanddiffers, which block dispatch until aCL-nnnruling. A build cites the spec at a pinned commit, citingUZF-21(b)for revise-first. Convergence appends, ids never renumber (the id forms areUZF-21(d)'s, andPT-{n}is cited, never minted), and a reversal is a supersedes line. During capture neither a hand-written spec nor the code wins: a contradiction stays a marker until aCL-nnnruling. AnobservedSC-###carries its threshold as[ruled: CL-nnn]. Clarification is bounded at one round of five questions per run and three successive runs unless the spec repository declaresspec.clarify.maxQuestions/maxRoundsotherwise, and answers are kept verbatim under a dated session. Checklists are ticked by the reviewer, never the author. Completeness iscovered/totalper kind for a spec folder or a capture (SP-14). An informative table names the 14 capture row kinds.QA-26is reserved and was never in force: the completeness rule drafted there becameSP-14. The SwiftUI, Compose and React stack handbooks each gain an Appendix — capture reader mapping file suffix → UZF concept → row kind, with no new stack id. The Compose appendix cites therules/README.mdKT registry, and the pre-existing numbering collision is #11. No rule id was renumbered and no token was added. Flow impact: a family spec repository loadsSP-{n}, and a product repository loads it when one of its issues, PRs or tests quotes a spec id (SP-8,SP-10), resolved live from a checkout at the pin; no consumer mirror regenerates. - The family spec is the canon, and the feature spec gains acceptance (
handbooks/VERSIONv0.9, MINOR under the pre-1.0 carve-out;UZF-21's meaning changes). For a repository that declares a product family (families[]in itsnen/repos.json, owned and read by the planes; zheref/hatsu ROSTER HR-16), the canon for a feature is the family's private spec repository,specs/<nnn>-<slug>/spec.mdat a tag, anddocs/Features/<Name>.mdbecomes a generated pointer carrying only that folder path and the tag (zheref/hatsu ROSTER HR-6). A repository with no family keeps its feature docs as canon.UZF-21gains clauses (a)–(f) for every repository ((e) and (f) for a repository that declares no family): the spec decides over the code, and the "if the spec disagrees with the code, the spec is wrong" line is retired in the three stack feature-documentation rule files; a port reads the spec, never another platform's code; the skeleton gains## Acceptance(AC-{n}, Given / When / Then) and## Success criteria(SC-{n}, measurable), so issues and PRs can cite the ids (HR-11); a multi-platform feature's platform notes become a## Platform notestable with one row perAC-{n}/FR-{n}id and aport·adapt·n/adisposition per platform and theUX-13category of each row, where an unported requirement is ann/arow with its rationale, never a missing row,adaptis admitted only in aUX-13adapt category and anAC-{n}outcome always mirrors; and every open question is anOQ-{n}row with its owner and a date (HR-4). Clauses (e) and (f) binddocs/Featurescanon in a repository that declares no family; in a familyspec.md, (d)'s ids map onto the pinned Spec Kit layout (anAC-{n}is a numbered acceptance scenario under aUS-n, the success criteria sit under## Success Criteria), a per-member difference lives inparity.md(SP-6), and an open question is anSP-1marker settled by anSP-12CL-nnn. A mirror category outsideUX-13's lists, such as business rules, is a valid Category value. The new findings' severities sit inuzf-core.md's Severity guidance table, not in the rule bodies. The SwiftUI, Compose and React session checklists check all of this.UX-13is new: navigation pattern, back behaviour, sheets and dialogs, haptics, permission prompts and typography scale adapt to the platform, while copy and the acceptance outcome as the user sees it are mirrored from the spec; business-rule and data-lifecycle divergence stays withUZF-21(b)/(e)in the architecture reviewer's lane. No rule id was renumbered and no token was added. - The port rulings family (
handbooks/VERSIONv0.8, MINOR).handbooks/ports/is new: a manifest,ports/INDEX.md, and one directed pair file for each of the six ordered pairs of product stacks Hatsu'sbankai-rulecan target (swiftui-tca-uzf-v2,compose-uzf-v2,react-uzf-v1, both directions; neverbankai-machinery, never a stack to itself). Each file is rendered from Hatsu'stemplates/ports/with itsCanonical sourcemarker, and its Equivalence and Drift tables are empty: no ruling exists yet. A ruling's id isPT-{n}from one counter across every pair file (zheref/hatsu ROSTER HR-9; the global counter zheref/hatsu#392 landed, re-confirmed by HR-34). The family is registered inhandbooks/INDEX.md,handbooks/README.mdand the top-level README, with its reading rule: a pair file is read beside the always-load set and the target's stack handbook, never alone.CON-13gains a Port rulings clause: the family is read beside the one stack handbook (beside the target stack; source-stack ids are cited, never loaded as a second stack folder), and until zheref/nen#457 lands no consumer mirror carries it and it is read live from a checkout at the pin. When #457 lands, the pair files a consumer's scenario is the target of enter its mirror. A pair file exists for each directed pair that has rulings, created on first use byhatsu:bankai-rule.stack-matrix.mdgains a Cross-cutting row and that resolution note. Pair files for a new product stack are created on first use byhatsu:bankai-rule, not in the stack's PR (§ Adding a stack, AGENTS.md § 2 rule 4,01-canon-authoringstep 4). No existing rule id changed, and which stack folder a review loads is unchanged. The redaction guard now admits thebankai-ruleskill name, which the rendered files carry, and its self-test gains a passing and a refused case for it. - The design reviewer is named by its role (
handbooks/VERSIONv0.7, MINOR). The handbooks, the constitution and the shared conventions no longer call the reviewer-tier design gate Bisky. That name now belongs to Hatsu's intake examiner for rendered surfaces (zheref/hatsu ROSTER HR-41), which never reviews code. Every mention reads the design reviewer, and its role, phasing, severity table andUX-{n}duty are unchanged. The literalbisky / reviewcheck name and thebisky-review.ymlhistorical record are kept, because they name machinery, not a persona. - Hatsu adoption (
hatsu:tenkai, 2026-10-20). The repository now carries the two declarations every Hatsu phase reads:nen/contract.json(the nen dependency pin carried from the canon sibling, and one hand-authoredcanonlane whoselintisscripts/canon_check.shand whosereleaseis the renderedscripts/release-publish.sh) andnen/workflow.json(branch shape, the singlelintiteration check, four review scopes — Nobunaga, Chrollo, Feitan, Phinks — reports, notifications, trailers,mukai.autoEn, the release unit);nen/gates.jsongains theround_quorumthe optional AI-reviewer reading needs. With themhatsu:aka,hatsu:mukaiandhatsu:enrun here, so a canon PR can be driven to its G4 merge prompt by the local plane;nen/colors.ymlis seeded,Reports/and.claude/worktrees/are ignored. The three CI checks incanon.ymlnow run the same script the local loop runs over the committable set, with a self-test job (the focusedcanon-check-guardlane, 34 assertions) and a digest check on the bootstrapped nen against the trusted contract, and the taxonomy job reads the nen pin from the contract instead of carrying its own. Two limits are declared rather than hidden: the readiness workflow is withheld until the process-repository guard is portable (zheref/hatsu#361), and the rendered publisher cannot yet read this changelog's###sections (zheref/hatsu#362). No rule changed andhandbooks/VERSIONstays atv0.6: nothing a consumer mirrors moved.
v0.6.0
v0.6.0 — the canonical home
- The handbooks, the constitution and the shared agent conventions now live here.
CON-13re-stated: the doctrine now names this repository as that source, and- The machinery self-review stack is now
bankai-machinery. ItsBC-rule-ID CON-51added: gates, no green-at-any-cost, spec as source of truth, and- The shared agent conventions are carried as
CONVENTIONS.mdbeside the - Release machinery stood up, because the repository was seeded by direct push
- The four
bankai:severity/*bands are declared and provisioned. They are - CI gates what this repository can silently get wrong, since there is no build:
Showing the latest 4 sections. The full history is CHANGELOG.md.