by zheref
Hatsu is the local plane of the Akatsuki system — a lead persona, a small roster of focused independents, and the way of working itself, running on your own credentials with no GitHub App and no bot identity. Kurapika (/kurapika) leads, declaring one of six Nen-type work-modes in every reply: Enhancer writes product code; Conjurer authors canon and governance as conjured contracts with conditions; Transmuter shapes machinery; Manipulator drives GitHub-side operations — drives, wakes, labels; Emitter cuts releases and fans out the repin; Specialist takes product intake, his kept Product-Owner canon. Eight independents stand around him, seven ratified and one provisioned: Gon, the mission-scoped trusted delegate who asks what the mission is, which named gates he may cross and under what conditions — and who, until his delegation grammar is ratified, crosses none; Hisoka, UI/UX review and quality measurement before a PR is ever posted; Phinks, adversarial QA under the proven-finding discipline, before a release and, from v0.5.0, on a release-adjacent change set pre-PR; Uvogin, performance testing against the fixed seven metrics with method blocks and baselines; Feitan, security and security only — auth flows, secrets and credential handling, network and storage boundaries, data minimisation — citing SEC-{n} by id, resolved and never remembered; Chrollo, architecture and handbook conformance against the UZF core, exactly one resolved stack handbook and the repository's own architecture notes, who reviews the handbooks and never authors them; Netero, the chairman who observes Hunter execution and files complete issues when constitution, canon or machinery need enhancement; and Illumi, PROVISIONED rather than ratified for En's pre-Ready observation hold and no other loop, read-only, waking Kurapika and acting on nothing. Feitan and Chrollo were activated from the Genei Ryodan bench on 2026-09-09 and their definitions land here at v0.5.0; Killua's role, the rest of Illumi's proposed row and the five remaining bench profiles stay OPEN in docs/ROSTER.md — proposals, not rulings. Hatsu depends hard on the Nen CLI: every deterministic step is a Nen verb, the dependency is checked at warm-up against nen/contract.json (nen's own location and shape, validated by nen schema check), and it fails closed with auto-install — the checksum-verified bootstrap runs itself, and only if that bootstrap fails does the session halt with the exact command. A Nen-owned operation is never improvised in prose. The skill surface is thirty-nine at v0.24.0 (thirty-eight at v0.6.0–v0.7.0, then byakugan). Seventeen answer a request — backlog-state, backlog-board, backlog-loop, backlog-synthesis, bankai-handbooks, bankai-quality, build, file, futon, getsuga, izanagi, izanami, jujisho, pr-state, senkei, sharingan, tensho — each ported under its existing name onto Nen verbs, with drive renamed to sharingan at v0.5.0 (same behaviour; hatsu:drive no longer resolves). Twenty-one ARE the way of working. Ten shipped at v0.4.0: breath warms the effort up, cuts the branch and proves the base tip builds, rasengan AUTHORS the change the request asks for, kokusen verifies the finished tree with the declared iteration checks and refuses a red one before it commits with an ask on every flagged file, amaterasu launches from your own working directory, tsukuyomi runs the tests, rikugan renders the rich HTML report, jutaisho rings the bell, ao pulls from the base, aka pushes when YOU call it, and ren is the per-request loop over them that never pushes. Eight are the PR side, new at v0.5.0: hanten reviews adversarially pre-PR and routes by scope to Hisoka, Feitan, Chrollo, Uvogin or Phinks in one fixed finding shape; gyo is linting; byakugan holds the touched-file coverage ladder and never lowers the bar; kotoamatsukami runs impacted unit, UI and integration suites; shibari composes and opens the one PR; jujutsu pairs a physical device and lands it as a launch target through a PR; murasaki pulls and pushes; mukai is the human-called review-and-PR phase that ends by immediately starting en; and en is the izanagi-capped readiness watch that owns deterministic current-head readiness, with Illumi observing the pre-Ready hold only on surfaces that support an in-session subagent. Three close the release side, new at v0.6.0: susanoo runs the lane's declared archive locally and uploads nothing, kagutsuchi prints a non-production deploy plan always and acts only on your own call naming the target, and mugetsu publishes on your recorded per-target go behind G3 — so four of the five phases only you may call have a skill (aka, mukai, kagutsuchi, mugetsu); the fifth is the merge, which has none because G2 is an action no agent performs. Neither of the last two is ever reached from a composite. Every parameter lives in two files: nen/contract.json's project block says what nen executes, nen/workflow.json says what the workflow decides — branch template, iteration checks, the 80/85/90 coverage ladder, reports, notifications, commit trailers, the monitor cap and the model matrix; docs/WORKFLOW.md is the authority on both. hooks/hooks.json ships two harness hooks: a Stop bell off the gate-stop marker, and a PreToolUse guard that refuses a git commit or git push on the base branch. Five phases are yours alone to call — aka, mukai, the merge, kagutsuchi, mugetsu — and only five G5 conditions ever interrupt you. Two provenance trailers, one per plane, from v0.8.0: Hatsu-Agent is its provenance trailer -- what a local Hatsu session writes, on your own credentials -- and Akatsuki-Agent is the CI plane's, written only by an Akatsuki roster agent there. A local Hatsu actor writes only the first and refuses the second, because a persona is not the CI plane; an autonomous Akatsuki actor writes only the second. nen/workflow.json admits both so one hook can validate either truthful plane, which is not licence to choose one by default. Neither is AI attribution -- each names which agent of which plane did the work -- and no other AI attribution trailer is ever recorded, with includeCoAuthoredBy: false the recommended setting. Existing commits are not rewritten. Per-skill evidence is in docs/ab/. From v0.7.0 Hatsu also runs on two more surfaces: the same skills and personas are generated into Codex and Cursor layouts under surfaces/ by nen surface mirror, placed into the repository you are standing in by the warm-up (.agents/skills/ plus an untracked AGENTS.override.md, or .cursor/skills/ plus .cursor/agents/) and excluded through .git/info/exclude rather than your .gitignore — invoked as $name on Codex and /name on Cursor, hatsu:name on Claude Code. The Codex persona file is an OVERRIDE: it replaces your AGENTS.md in the envelope rather than joining it, so the warm-up copies yours into it verbatim first and never writes the tracked file. Two absences are named rather than assumed: neither of those surfaces has a turn-end hook, so jutaisho rings the bell in-session and says so, and Codex has in-session subagents (spawn_agent); hanten still raises an isolated reviewer as a second codex exec run in its own worktree. The model matrix carries a column per surface — the reviewer tier is deep everywhere, opus / sol / grok — Cursor is Cursor-native only, and the frontier tier never runs a subagent on any surface. docs/SURFACES.md is the authority; scripts/surface_mirror_check.sh fails a mirror that has drifted from its source. At v0.11.0 the pin moves to nen v0.7.0 and nine more residues retire with it. The largest: izanagi's mandatory cap is no longer counted in a skill's prose -- nen loop iterate claims each mutating iteration against the cap its own invocation states and refuses the claim past it, so izanagi and en stop bookkeeping, a cap cannot be widened by re-typing the line, and en's ledger outlives the session so a resumed landing continues the same budget rather than restarting it. stage triage grows the two detectors kokusen, tensho and jujisho were each checking by eye -- local-config (the .local filename infix) and large (--large-bytes, default 1 MiB). pr ready READS nen/gates.json's dependabot_carve_out, inert data until now, and never silently: a satisfied row carries its own note and meta.dependabotCarveOut says whether it fired. Every readiness verdict says which binary decided it, path included, and pr-state, sharingan and shibari relay that line rather than summarising it. Every relative own-path flag resolves against --repo's root instead of the process's directory, which file, build, futon, senkei, shibari and bankai-quality each had to warn about. A missing or malformed --target exits 2 across sixteen verbs and an unreadable input exits 2 on split verify, so an invocation mistake stops reading as a registry finding or an incomplete split. changelog collate's printed manifest agrees with the section it wrote, so getsuga relays it instead of noting a defect; issue attach-sub prints the sub-issues fallback and names nen issue edit-body as the write that performs it; parse izanami accepts a single-quoted --jq on a gh api read; chain-position and effort classify say which of their values can refuse a verdict; and nen bootstrap --help publishes the whole exit-code contract, including the 7 only it can return, while its cache slot is keyed on the source as well as the ref. Four behaviours change in place at this minor with no new flag to notice them by, which is why nen's own compatibility floor is seeded at 0.7 and a pin below it is refused by name. At v0.12.0 the maintainer's ruling of 2026-09-10 re-scopes three of the loop's phases without touching a single authority: rasengan is the AUTHORING phase -- it builds the thing, on the stack nen/contract.json declares, running the iteration checks as the author's own inner-loop feedback rather than as a commit gate; kokusen carries the compile-before-commit, running those same checks over the finished tree and refusing to commit on red with the failing check quoted; and breath's proof is stated for what it always was, a verdict on the BASE tip taken before a line is authored, where a red one is a G5 stop and never this effort's to repair. ren's order is six whole steps again -- breath, rasengan, kokusen, amaterasu, rikugan, jutaisho -- with the interim half-numbered work step folded into rasengan where it belonged, and five load-bearing relations stated: no authoring on an unverified base, nothing committed that was not authored in this turn and verified in it, the launch shows the committed tree, the report quotes the launch that ran, the bell carries the report. The five G5 conditions that interrupt a running loop are unchanged. At v0.13.0 the range stops being computed in this plugin's prose, because nen now decides it: the maintainer's ruling of 2026-09-10 is "exact minor is fine, unless there is a breaking change", and nen v0.8.0 ships COMPATIBLE_MINOR_FLOOR -- the lowest dependency.minimum pin a build satisfies, printed as a 'compat floor:' line on every nen shu tools run and carried in --json as compatibleMinorFloor. The warm-up probes nen --version for presence only and then reads the verdict off the nen row of nen shu tools --repo <the Hatsu checkout>: a satisfied row proceeds to the report, a pin below the build's floor is refused by name with the repin stated, a binary older than the pin re-pins through nen bootstrap, and an absent verb means a binary older than anything this plugin supports. The report line carries the floor beside the version, and says 'floor not reported' on a binary older than 0.8.0 rather than inferring one. dependency.minimum stays "0.7" while pinned_ref moves on its own to v0.8.0 -- two values that no longer travel together, since minimum moves only when nen's CHANGELOG carries a real bullet under Breaking / consumer notes. Left as it was, every warm-up on a host carrying nen 0.8.0 would have read out of range and rebound ~/.local/bin/nen down to v0.7.0, making the floor inert for every Hatsu consumer. Pinned to nen v0.8.0, minimum 0.7. At v0.13.1 the remaining echoes of the literal `nen 0.7.0` outside the dated docs/ab/ transcripts and the version-history prose above are repointed to name the pin by reference -- "the pinned build", or the contract's own pinned_ref -- because a convenience copy that still read v0.7.0 once the contract moved to v0.8.0 was exactly the drift nen/contract.json's own authority clause calls a bug (zheref/hatsu#43). Both generated surfaces are regenerated against nen 0.8.0 to match. At v0.14.0 every path a skill builds from the plugin root is spelled $hatsu_root and resolved in the very shell that uses it: hatsu-warmup's section 0 resolves the root, prints it as one quoted line and reads the contract in one shell; every later block either carries that resolver or sets the variable from the printed line; the manifest is read structurally as the one shape Claude Code's tooling writes, every line validated and any other shape refused; and the captured path is proved to be the candidate's directory, refused if it holds a newline, and taken with CDPATH cleared. So the mirrored skills resolve the plugin root on Codex and Cursor, where $CLAUDE_PLUGIN_ROOT is unset or names another plugin, with the same lines that run on Claude Code (zheref/hatsu#38). At v0.18.0 Hatsu adopts Nen v0.10.0 and its explicit review-round-only policy: Copilot supplies the sole automated round, no separate APPROVED review is required, and the maintainer keeps the human merge decision. At v0.19.0 Mukai ends after opening the PR, rendering its landing report, and immediately starting En; En owns deterministic current-head readiness and uses paced pre-Ready observation without spending cycles on quiet reads, and the human merge remains outside the run. At v0.20.0 aka no longer runs project-wide tests: tsukuyomi is focused tests on every ren turn, kotoamatsukami owns impacted regression at mukai immediately before gyo extracts coverage, and aka is lint/squash/ao/push. At v0.21.0 every Rikugan page opens with This last turn (mukai adds corrections, local-check fallout, and half-run stops) and Architecture delta is a change-highlighted structural diagram rather than a file-line inventory. At v0.22.0 00 stays last-turn only while 01–07 cover the whole session against the base, on every process or product effort. At v0.23.0 gyo is linting on every Ren turn and kotoamatsukami owns coverage capture, extraction and gating at mukai. At v0.24.0 the skill surface is thirty-nine: byakugan captures and measures coverage independently of tests; kotoamatsukami owns unit, UI and integration suites only; gyo remains lint. At v0.25.0 Netero is ratified as process chairman; Breath cuts a fresh branch for every new effort rather than reusing a clean feature branch implicitly; G5 stop reports carry blocker evidence on the turn variant. At v0.26.0 Hanten records per-effort reviewer budgets in `.nen/hanten/<branch-slug>.cycle.json` so remediation cannot re-raise Chrollo twice or Hisoka and Uvogin past their maxima. At v0.27.0 the skill surface is forty: third-hand lands as the wrap-up harvest after En. At v0.28.0 it is a separate phase that starts once En has completed, not En step 8; Codex asks through request_user_input and raises Netero in-session (spawn_agent); Antigravity asks through ask_question (is_multi_select) and raises Netero with invoke_subagent Workspace inherit. The merge stays a human G2 act with no skill. At v0.29.0 Illumi's En watch uses Codex in-session spawn; generated surface inventories are 41 skill files (forty plus warmup) and 9 personas. At v0.30.0 the Hanten cycle ledger is fail-closed: Breath inits it after the branch cut, decide/record/show refuse a missing file, load-mutate-save is locked with a unique temp path, and skipped-exhausted is refused while used is under max. At v0.31.0 the warm-up keeps a consumer plugin checkout current before it refreshes a target: scripts/hatsu_plugin_update.sh --auto fast-forwards trunk or the newest vX.Y.Z tag, skips dirty and authoring trees, never discards, and on Claude Code runs claude plugin update hatsu@hatsu; docs/SURFACES.md is the authority on pointing every surface at a local checkout. Current dependency: nen v0.10.0 with minimum 0.10, required for review-round-only approval policy; Nen compatibility floor 0.7 remains unchanged. At v0.33.0 every skill becomes reachable from a cold checkout: docs/STANDALONE-ENTRY.md is the new authority, carrying the five-step preamble (warm up, orient, establish the delta, elicit, declare) and the four state classes a phase used to inherit from its caller -- the turn boundary, a mandatory argument, a position in an order, and a predecessor's artifact. Twenty skills gain a ## 0. Standalone entry section -- thirteen that derive state cold, seven that add the warm-up, orientation and expectations only -- and the delta default everywhere is the FETCHED origin/<branch.base>, union of committed and uncommitted; the base is the LATEST trunk by the maintainer's ruling of 2026-09-18 -- git fetch origin first, then origin/<branch.base>, with the local ref used only where the fetch has just proved it equal -- and against <base> is the declared delta clause on byakugan, kokusen, tsukuyomi, kotoamatsukami, rikugan and hanten, verified live at nen 0.10.0 including the two-clause and enum-plus-base shapes, while ao and murasaki keep from <base> because a delta is read against a reference and a catch-up pulls from a source. A fetch that fails, an absent origin, or an unresolvable base stops and names the condition rather than falling back to a ref that cannot be known to be latest. Breath runs at most once per session and is never skipped when owed, and it now guarantees an OUTCOME rather than only a verdict: however the checkout looked, a standalone run ends as a branch off a main that was PROVEN green, carrying the maintainer's own commits on that proven tip, with their uncommitted changes still present and still uncommitted. Four steps -- preserve (git stash push --include-untracked, the SHA captured and printed, addressed by SHA and never stash@{0}), prove (every iteration.checks entry against origin/<branch.base> in an isolated worktree holding none of the effort), place (the commits replayed onto the proven tip through ao, which rebases when nothing is published and MERGES when something is, because a published commit is never rewritten), restore (the stash reapplied, still uncommitted, and never dropped on a failure). The win is that a red after the restore is the effort's, mechanically rather than by argument, so a red base is a G5 taken before anything returns and the stash is restored before that stop. Rewriting a commit is confirmed first; stashing is not, being reversible. Hanten routes a missing ledger to breath rather than asking the same question twice. docs/STANDALONE-ENTRY.md joins the plugin-bump guard's surface and the shared-policy preamble, so a runtime-read authority cannot ship edits to nobody. Breath inverts its new-effort default when typed by hand, so work in progress on the current branch reads as the continuation it is; tsukuyomi derives its lane from the delta and offers to have missing focused tests authored rather than refusing; hanten enforces breath when the cycle ledger is absent and asks for scope rather than raising the whole bench; sharingan resolves an omitted PR number from the branch; rikugan recovers turns from the session or from commit history and marks what it cannot recover; third-hand resolves this sitting from the branch or an open PR. kagutsuchi and mugetsu gain orientation and no authority whatsoever -- G3 is unmoved, the invocation is never the go. The second rule is the load-bearing one: no skill is ever indefinitely independent. A standalone run absorbs no later phase, creates no standing authority, crosses no gate the wired run would not cross, and ends with a hand-back line naming its successor; ren, mukai and en state that the phases they call skip ## 0 entirely. murasaki typed alone does its own step 1 and finishes it -- fetch, catch the branch up with origin/<branch.base> through ao, resolve the mechanical conflicts, stop at G5 on a semantic one -- declining only what was never its; rasengan alone stays caller-bound, because the request is its input and no checkout supplies one. At v0.36.0 a tag records a build that LANDED somewhere, by the maintainer's ruling of 2026-09-18 as corrected on 2026-09-19. kagutsuchi section 4a cuts one tag after a --run send that returned exit 0, composing dist/<target>/ from the target it was called with over the IDENTITY in nen/workflow.json's tags.identity; susanoo section 5a reads that same file and merely NAMES the identity the coming tag will carry, cutting nothing and pushing nothing -- one name source, so there is no second name to disagree with. tags.deploy.<target> is read before anything is cut, so a repository declaring only tags.identity gets no tag and an undeclared target is reported rather than tagged; the target is data, quoted and passed as an argument, and the prefix is composed from it rather than pattern-checked. The identity file's second line is the commit the archive was built from, and the tag is cut THERE rather than at HEAD, because the announce and the cut are separate invocations and HEAD can move between them, so its standing property that nothing leaves that machine is literal again. The symmetry is the maintainer's: an upload that succeeds becomes a tag, and a release Apple approves becomes a GitHub release. Both blocks are opt-in and off by default, so a repository declaring neither behaves exactly as before. The NAME is the repository's, read from a declared nameFrom as data -- never templated into shell source, symlinks and out-of-tree paths refused, validated with git check-ref-format before anything is spawned. nen tag cut's refusals stand, including that --at must be an ancestor of origin/<trunk> -- a rule about the COMMIT rather than the branch, so a feature branch at the trunk's tip tags fine; what keeps a tag from attesting the wrong bytes is a separate clean-tree condition, and --trunk comes from branch.base rather than a default. The name carries a dist/<target>/ species prefix because it shares one namespace on origin with getsuga's release tag, which mugetsu proves by name resolution; mugetsu section 3 now says in rule that only the release tag satisfies it. --push is not atomic, and the one sanctioned remedy for a rejected push is deleting and re-cutting a local tag verified absent from origin. mugetsu is still G3 and still cuts no tag.
Claude Code