Inventory a consuming product repo's own backlog — open epics, live integration branches, and open PRs — classify each effort, and drive every open PR to a CON-32/G2-readiness determination. Use when the maintainer asks for the status of a product repo (`<product-repo-A>`, `<product-repo-B>`, or any other Bankai consumer), wants its existing efforts driven forward, or invokes `/senkei`. Kurapika (Manipulator) enumerates the target repo's backlog, classifies each effort (delivering/building/stalled/queued/idle/undecidable), states a Ready/not-Ready call with the reason for every open PR, and reports one status table per pass. Carries no CON-25 delegation and never merges — G2 stays the maintainer's.
Install
npx skillscat add zheref/hatsu/surfaces-antigravity-skills-senkei Install via the SkillsCat registry.
Shared policy location: docs/DISCOVERY.md, docs/WORKFLOW.md,docs/LAUNCH-MIGRATION.md, docs/STANDALONE-ENTRY.md, docs/PROCESS.md and docs/SURFACES.md belong to the resolved Hatsu plugin
root, not the consuming repository. On an installed surface, use the absolute root printed byten to read those files (re-resolve through that skill if unavailable). Relative links
below identify source locations; a missing consumer docs/ copy is not a missing policy and must not
trigger a duplicate filing. Never copy or invent a second policy in the target repository.
Senkei — inventory and drive a product repo's own backlog to G2-readiness
Nature: Manipulator. GitHub-side ops/reporting over a product repo's own backlog. Kurapika
says so when he runs it.
This is the product-repo counterpart of
`backlog-loop`. backlog-loop drives <reference-repo>'s own backlog to
zero as G4-ready PRs; senkei
inventories one consuming product repo's backlog — its open epics, live integration/*
branches, and open PRs — and drives those PRs to CON-32/G2-readiness. It never touches<reference-repo>'s own backlog, and it never mutates the target repo's product code.
The old (<reference-repo>) version of this skill computed every one of §§2–4 below by improvised prose
and raw gh: hand-listing epics and their children over gh issue list, hand-computing
ahead/behind for each integration/* branch, hand-reasoning the five-class taxonomy from labels,
and re-running a dead reviewer job with a bare gh run rerun <id> --failed. This port replaces
those steps with nen repo inventory, nen effort classify and nen run rerun-failed — the three
verbs zheref/hatsu#2 names for this port — plus nen pr ready for readiness (unchanged pointer,
shared with every other ported skill via `pr-state`) andnen parse for the invocation grammar. What remains genuinely un-mechanizable (the five-class
label→input reshape, the Ready/not-Ready narrative, the escalation channel, the closing table)
stays this skill's judgment. See docs/ab/senkei.md for the full mapping, the live evidence
against two real consumer repos, and every finding filed against the binary along the way.
Read the target repo's own backlog only. Never
<reference-repo>'s — that is
`backlog-loop`'s job, and this skill carries no delegation to touch
it, read or write.
In phase-lattice terms, and changing no mechanics below: senkei is an inventory phase, not a
delivery one. It enumerates (§ 2), classifies (§ 3), and drives each open PR to a CON-32
determination through `sharingan`'s own engine — invoked once per open
PR, its first-blocking-condition ordering, its unblock channel and its escalation ladder, exactly
as § 4 already describes them rather than a second implementation of them. It calls none of the
five human-called phases — aka, mukai, the merge, kagutsuchi and mugetsu are the
maintainer's (`docs/WORKFLOW.md` § 4) — and it never prompts for one:
it opens no PR, pushes nothing, merges nothing, uploads nothing and publishes nothing. What it
produces is a table and a Ready/not-Ready call per PR; every gate in that table stays exactly where
it was.
1. Invocation
/senkei <repo><repo> is a product code, a short name, or a full owner/repo — take it from the invocation
(/senkei <product-repo-A>, or /senkei <product-repo-A>); never guess it. Mechanized:
nen parse senkei --grammar "<repo>" --line "<what the maintainer typed>"Verified live (docs/ab/senkei.md § 2.1): a single mandatory slot with no bracketed optional
clause parses correctly both ways (<product-repo-A>, <product-repo-A>) and refuses cleanly with a
corrected line when the slot is empty. This is the same generic --grammar path
`backlog-state` found broken for a bracketed clause — the defect is
specific to [ ... ], not to nen parse as a whole, and senkei's own grammar has no bracket to
trip it.
When no repo is given, resolve the registry and ask:
nen repo resolve all --repo <path to a checkout carrying nen/repos.json — or schemas/repos.json under the fallback nen keeps until v0.4.0>An empty slot (nen parse exit 2) or an unknown repo is the trigger to ask, not the end: the
picker names the token and offers the codes nen repo resolve's own refusal prints — never a guess,
never a prefix match. A missing argument or configuration item is asked for and set up inline
(missing-argument, missing-configuration; `WORKFLOW.md` § 4 Ask, set
up, continue). An unregistered product repo is reported, never written: the registry that would record it is a
foreign one — zheref/bankai-handbooks' (a canon repository at G4, whose public registry names no
private repository) or, at the port, the frozen <reference-repo>'s — so senkei names the missingconsumers entry and the repository that owns the registry, and stops that repo's run (WORKFLOW § 4
What is not a gap).
Product repos do not reliably ship their own registry. Verified live against the real<product-repo-A> at the port: it carried no schemas/ directory at all — no repos.json, nogates.json, no colors.yml, no labels.json (docs/ab/senkei.md § 4.1, three 404s) — and the
check at the current pin is "no nen/ directory" — nothing else. RETIRED at nen 0.5: there is
no schemas/ fallback. It was removed in the release this repository pins, so a target carrying the
four files only under schemas/ is refused exactly like one carrying them nowhere, with the refusal
naming the migration; nen schema check --repo <checkout> answers it in one call, per file, and its--json row now carries legacy — a boolean saying a schemas/<file> copy is on disk, detected,
never read. At the port, the registry that named its product code (RA) and its Nen scenario
(swiftui-tca-uzf-v2) was the frozen <reference-repo>'s own, under consumers, alongside<product-repo-B> (RB). Since 2026-09-28 the canon home is the public zheref/bankai-handbooks, whose
registry records no consumers (private products are not named there), so --repo <path> for
resolution and object notation names whichever registry records the target —
`bankai-handbooks` § 1's order: the canon registry first, then the
product repo's own nen/repos.json when it records itself with a scenario — never a guess, and never
the product repo's checkout as a stand-in for a registry it does not carry. Resolve once, up front, and
carry the resolved owner/repo slug forward:
nen repo resolve RA --repo <registry checkout> # <product-repo-A> (RA) via code
nen repo scenario --repo <registry checkout> --target <product-repo-A> # swiftui-tca-uzf-v2A product repo's own build declaration is a different file, and senkei reads it rather than writes
it. A consumer product repo is, unlike <reference-repo>, one of nen's seven stacks (aswiftui-tca-uzf-v2 scenario is an xcode-ios tree; compose-uzf-v2 a gradle-android one), so with
a local checkout of it in hand:
nen shu detect --repo <product repo checkout> # exit 0: a project block proposed, withheld rows and their reasons; exit 1: no lane detected
nen schema check --repo <product repo checkout> # which taxonomy files it carries, and where nen read each fromReport what detect proposes and withholds (an xcode-ios lane proposes no command row on any
tree — every row names a simulator only the machine knows — and says what it did answer) as part of
the status pass; a product repo with no nen/contract.json is a finding for that repo's maintainer,
and writing the declaration is a PR into that repo at its own gate, never a --write this skill runs.
Driving that repo's PRs to readiness (§ 4) does not depend on it.
The phases this composite calls SKIP their own ## 0. Standalone entry sections. `docs/STANDALONE-ENTRY.md` is the
contract for a phase typed by hand into an arbitrary checkout; a phase reached from here inherits P1–P4
from this run — the warm-up, the orientation, the change set and every derived argument — and
re-deriving them would produce a second answer to a question this composite already settled. Each phase
says which composite is holding it instead.
2. Enumerate the target repo's backlog — nen repo inventory
export GH_TOKEN=$(gh auth token)
nen repo inventory --target <owner/name> --epic-label <label> --integration-prefix <prefix> [--trunk main]This is senkei's own live enumeration, named as such in the verb's own --help: every open issue
carrying --epic-label with its children, every branch under --integration-prefix with its
ahead/behind vs --trunk, and every open PR. Always fetched live — never work from a cached
list; labels, branches and PRs change under you.
--epic-labelis the target repo's own epic marker (bankai:epicon<product-repo-A>/<product-repo-B>—
confirm against the repo's label set rather than assuming the<reference-repo>name matches).--integration-prefixhas no default. The naming convention for a live integration branch
(integration/on<product-repo-A>) is the target repository's own; never hard-code a literal here.--trunkdefaults tomain.
Verified live against the real <product-repo-A> (docs/ab/senkei.md § 3.1):
nen repo inventory --target <product-repo-A> --epic-label "bankai:epic" \
--integration-prefix "integration/" --trunk mainreturned 7 open epics (42 children total — 6+6+6+7+6+5+6 across the seven epics, a mix of
open/closed — verified live, re-run 2026-09-01, docs/ab/senkei.md § 3.1), 4 live integration
branches, 1 open PR. Two of the four integration branches — integration/epic-193 andintegration/epic-213 — belong to epics already closed (confirmed independently against the
live issues, docs/ab/senkei.md § 3.2): exactly the idle class in § 3 below, found on real
data, not constructed. This is the same defect shape <reference-repo>#929
(docs/ab/backlog-state.md § 5) names for a different skill: state that outlives the object it was
opened for, left alive because nothing swept it.
3. Classify each effort — nen effort classify
| Class | Meaning |
|---|---|
| delivering | A delivery PR is open at G2 — the final integration/<epic> → trunk PR, or a shikai-mode child PR. |
| building | A child issue is released (bankai:stage/building) to a builder; no PR yet, or a PR is in review. |
| stalled | Released with no branch/PR ever opened, or a reviewer job that never posted a Verdict: line. |
| queued | G1-approved (a mode label picked) but not yet released with bankai:stage/building. |
| idle | An integration/* branch is still alive but its epic is closed — flag for cleanup. |
The taxonomy is those five. The verb returns SEVEN values, and the other two are answers about
the taxonomy rather than members of it — nen 0.7 settles this in --help itself, where throughv0.6.0 the text called itself "senkei §3's five-class taxonomy", listed six names and returned
seven, so undecidable appeared in neither the count nor the list (zheref/nen#53; verified live,docs/ab/senkei.md § Retired at nen 0.7):
| Not a class | Meaning |
|---|---|
| state-machine-violation | Two stage labels on one object contradict each other. Flagged, never resolved by guessing which is authoritative. |
| undecidable | No stage label, no mode label, no PR and no live branch: nothing here places the object anywhere in the taxonomy. A genuinely untriaged issue, reported rather than silently folded into queued. |
A caller switching on the class must handle both, which is --help's own instruction now — and
this skill's report says undecidable in those words rather than translating it into a class the
issue does not have.
nen effort classify --input <path.json>The input is a JSON array of {kind:"epic"|"child", issueState, stageLabels[], modeLabelPresent, hasPr, prOpen, prIsDelivery, integrationBranchAlive, reviewerVerdictMissing} per effort — reshapenen repo inventory's rows into this shape before calling it (the verb classifies; it does not
fetch). state-machine-violation (two stage labels on one object) is flagged, never resolved by
guessing which is authoritative.
RETIRED at nen
0.7:--input's second baseA relative
--inputresolves against--repo's root, never the process's own directory
(zheref/nen#100). Nothing was inconsistent within a single invocation, which is exactly why it
survived — run from the repository root the two bases are the same path — and it appeared the
moment a caller ran from somewhere else: a worktree, a wrapper script, a step with its own working
directory. Verified live with a decoy of the same relative name in the calling directory
(docs/ab/senkei.md§ Retired at nen 0.7):v0.6.0read the decoy and classified it,0.7.0
reads--repo's copy. An absolute path is still used as-is, and--repostill defaults to the
process's own directory, so a caller standing in the repository sees no change at all.Pass
--repoon this call, therefore, and pass it deliberately: it is what decides whicheffortsfile the verdict is about.
The
stageLabels/modeLabelPresentsplit is load-bearing, and getting it wrong
misclassifies real data.modeLabelPresentis whether a G1 mode label
(bankai:stage/ready-for-bankai/bankai:stage/ready-for-shikai) was picked;stageLabelsis
every otherbankai:stage/*label the object carries. Verified live, three ways
(docs/ab/senkei.md§ 3.3–3.5):
- Feeding the mode label itself into
stageLabels(as it literally appears in GitHub's own
label list — both live under the samebankai:stage/*prefix) makes a G1-approved-but-not-yet-
released epic misclassify asbuilding, because the verb reads any non-emptystageLabels
as "released" — regardless of which label it is. Reproduced against the realRA-IS-#17/RA-IS-#178epics: feeding their realbankai:stage/ready-for-bankailabel intostageLabelsreportsbuilding; excluding it (mode label →modeLabelPresent: true,stageLabels: []) reports the correctqueued— "G1-approved (a mode label was picked) but
not yet released with a stage label" — matching the old skill's own taxonomy exactly.- A pre-G1 label (
bankai:stage/researched,bankai:stage/idea) fed intostageLabels
reportsstalled— "released, but no branch or PR was ever opened" — even though the old
skill's own taxonomy definesqueued/stalledas states an effort reaches only after G1
approval. An issue still atresearched/idea/triagehas not yet entered senkei's
classification universe at all: do not feed it tonen effort classify— report it
separately as "not yet G1-approved," never asstalled.queuedis reachable ONLY whenstageLabelsis empty andmodeLabelPresentistrue—
confirmed true even with an alive integration branch (RA-IS-#17/#178again): an alive
branch does not upgrade aqueuedrow tobuildingon its own; only a genuine (non-mode)
stage label does.Never pass the raw GitHub label list straight through as
stageLabels. Strip the G1 mode
labels intomodeLabelPresentfirst, and exclude pre-G1 labels from the classification pass
entirely — feeding either wrong is a silent misclassification, not a refusal, so there is no
error to catch it for you.
stalled's live-signal half is caller-supplied, not fetched here. A reviewer job that died
mid-run or a builder that burned its turn cap is read from reviewerVerdictMissing — the verb's
own --help says so plainly. The mechanical rule (released, no branch, no PR) still reachesstalled without it; set reviewerVerdictMissing: true only when you have independently confirmed
the dead-reviewer signal (§ 4).
A child carrying two stage labels at once is state-machine-violation — flagged, never
resolved by guessing which one is authoritative (agents/_conventions.md § State machine).
4. Drive every open PR to CON-32, not to "checks green"
For each open PR, state a Ready / not-Ready determination with the reason — never
"required checks are green" alone.
The determination comes from nen pr ready — the same pointer every other ported skill uses
(/pr-state, docs/ab/pr-state.md):
export GH_TOKEN=$(gh auth token)
nen pr ready <ref> --gh-repo <owner/name> [--gates <path> | --reviewers a,b,c --approvers a,b] --explainMost product repos ship no gates file of their own — verified against <product-repo-A>, not
assumed. Without --gates or --reviewers, nen pr ready refuses outright: "no reviewer
identities. This gate never falls back to a built-in reviewer set..." (exit 2; at v0.3.0 the
refusal names nen/gates.json, the one file it looks for) — reproduced
live against the real <product-repo-A>#509 (docs/ab/senkei.md § 4.1). This is the same refusal
`pr-state` documents for <reference-repo>, and the fix is the same shape but a
different file: hatsu's contracts/reference.gates.json is <reference-repo>'s own reviewer
identities and must never be reused for a different repo's PR — that would judge one repo
against another's vocabulary. For a product repo with no --gates file of its own:
- If the repo ships
nen/gates.json, no flag is needed at
all. - Otherwise, pass
--reviewersnaming that repo's own configured reviewer bots and explicit--approversfrom its authoritative approval policy (--approvers ""only for a declaredreview-round-onlypolicy) — derived from its own configuration, read directly, not assumed and not
copied from<reference-repo>'s registry. Verified live, read-only, against<product-repo-A>'s own
workflow files:bankai-review-gates.ymlcallssasuke-review.yml,tenma-review.ymlandbisky-review.ymlas reusable workflows — a genuine review trio, not a pair, and<reference-repo>'s
own registry'sconsumeslist for this repo corroborates the same three (pluscopilot
nowhere in it as a review identity —copilot-sweeper.ymlis a different, non-review workflow).
Never guess a reviewer set and never substitute<reference-repo>'s owncontracts/reference.gates.json. - A disclosed limitation, not routed around: the reduced
--reviewers a,b,c --approvers a,b
CLI path is a flat, static list — it cannot modelbisky's conditional approver behaviour,
which only joins the approval set for a PR it has actually posted a review on at the current
head (approves_when_posted_at_head). This is exactly the dynamic-enrolment shape
`pr-state`'s own gates-contract precedent names for<reference-repo>itself
(docs/ab/pr-state.md§ 1 row 8: "+bisky/+bugbotonly when their check is present at head",
driven byenrolment_check_patternin a realgates.json, never by a flat CLI list) — the same
structural gap, reproduced against a different repo. Verified live (docs/ab/senkei.md
§ 4.2):bisky-bankaihad already posted anAPPROVEDreview on<product-repo-A>#509at the
head evaluated, yet the--reviewers sasuke,tenma,copilot --approvers sasuke,tenmacall this
port actually runs neither namesbiskynor sees that approval — it is invisible to the verdict
computed this way, not merely omitted from the writeup. - Why this set, stated plainly:
sasuke,tenma,copilot(reviewers) /sasuke,tenma(approvers)
is<reference-repo>'s own convention (contracts/reference.gates.json'sbase_reviewers/default_approvers), reused here as the pragmatic fallback — not because<product-repo-A>'s own
workflows call forcopilotas a review-pair identity (they don't;copilot-pull-request-reviewer
shows up only as a PR commenter, pergh pr view --json reviews, never as a reusable-workflow
review-pair job) but because the CLI's flat--reviewers/--approversshape cannot expressbisky's conditional round anyway, so naming it as a plain reviewer would misrepresent it as
unconditional. The gap this leaves: a fullnen/gates.jsonauthored for<product-repo-A>itself, modelingbiskythe way<reference-repo>'s own contract does, is what
would close this fully — until one exists, say so every time this fallback is used, rather than
presentingsasuke,tenma,copilotas<product-repo-A>'s own considered choice. - If neither is available, ask for the identities (the maintainer's word: never derived) and offer
anen/gates.jsonas that repo's own declaration PR at its gate; with no answer the refusal is
the report — surface it verbatim (nen prnever falls back to a guess), never route around it with
an assumed identity set.
Real verdict, verified live against <product-repo-A>#509 with its actual reviewer identities
supplied (docs/ab/senkei.md § 4.2): not-ready: required checks reported but are not all green (CON-32a) — the conjunct table (--explain) shows exactly which check rollup entries are not yet
green, at the current head, short-circuited before any reviewer-round conjunct is evaluated.
Two rules unchanged from `pr-state` and
`backlog-state`: never re-derive readiness from the check rollup by
eye (the current-head rule catches what a glance at the checks page misses), and the
adversarial confirmation pass may only veto a ready verdict, never promote a not-ready one.
Product repos hit failure modes <reference-repo>'s own backlog does not surface as often — check for
these explicitly, by name, in the determination:
A reviewer job that died mid-run, leaving a stale
CHANGES_REQUESTEDon a required check.
Re-run the failed job — mechanized:nen run rerun-failed --target <owner/name> --run-id <n>This is
'gh run rerun <n> --failed', exactly — the verb's own--helpnames it "senkei's
dead-reviewer recovery." Never re-label to force a re-vote. Verified live and safely: run
against a realzheref/hatsuworkflow run whose jobs had all already succeeded — nothing to
rerun, so the call refuses cleanly with no mutation (docs/ab/senkei.md§ 5.1): "run … cannot
be rerun; This workflow run cannot be retried" (exit1). This is the refusal shape a caller
sees when there is nothing dead to recover — the affirmative "actually reran a failed job" path
was not exercised (this verb mutates GitHub with no dry-run mode at all, unlikenen label apply/nen wake fire/nen labels sync), and this port never exercises it against a real
consumer repo's PR — only the refusal shape is confirmed, per the shared brief's mutation
boundary.A builder that burned its turn cap and pushed nothing — the PR looks "in progress" but is
actually stalled; call itstalledin the classify pass (§ 3), notbuilding.A child carrying two
bankai:stage/*labels at once —state-machine-violation(§ 3);
flag it, don't guess which one is authoritative.
Where a PR is stuck for a reason nen run rerun-failed doesn't cover (a swallowed wake, arequest_changes vote substituted for one), use the same unblock channel as
`backlog-loop`/`sharingan`: bankai:wake/iterate,
fired ALONE, never in the same breath as a comment. That mechanization (nen wake fire) is outside this port's own
Scope (zheref/hatsu#2 names only nen repo inventory, nen effort classify, nen run rerun-failed for senkei) and is left as prose here, exactly as the old skill carried it — seedocs/ab/senkei.md § 6 residue.
Verify the wake reached the builder — <agent> / build having run. A probe that iscancelled with no build job is a failed wake, not an attempt, and must be re-fired rather
than counted.
5. Report
One status table per pass, <CODE>-<IS|PR>-#<N> notation (nen ref format), gate named per row:
nen ref format --repo <reference-repo checkout> --code RA --kind IS --number 178 --state open \
--url https://github.com/<product-repo-A>/issues/178
# 📄 RA-IS-#178| Issue | Class | PR | Checks | Reviews | Ready? | Awaiting |
|---|---|---|---|---|---|---|
| RA-IS-#178 | queued | — | — | — | — | Release to a builder — G1-M |
| RA-PR-#509 | building | RA-PR-#509 | not all green | — | ❌ not-Ready | CON-32(a) — checks |
Draw the gate-stop banner (nen stop) only when the maintainer must actually act on something in
the table — a status-only pass reports plainly, no banner.
Explicitly out of scope
- No new authority.
CON-25's third carve-out (run-scoped label delegation) belongs to
`backlog-loop` by name;senkeiapplies nobankai:agent/*orbankai:stage/*label without the maintainer's explicit per-action
confirmation, same as Kurapika outside a named run. - No merging, anywhere. G2 is the target repo's maintainer's, same as it is on
<reference-repo>. - No writes to product code by this skill. It inventories and drives — it never edits the
target repo's product source itself.
Hard limits
- Never merge, on any repo, for any reason.
- Never apply a label without the maintainer's per-action confirmation — this skill carries no
run-scoped delegation. - Never cast a
request_changesreview to move a stuck PR — usebankai:wake/iterate(prose
channel, § 4). - Never guess the target repo when none is given (§ 1).
- Never feed a pre-G1 or mode-carrying label straight into
nen effort classify'sstageLabels
without the reshape § 3 requires — verified live to misclassify. - Never reuse
contracts/reference.gates.json(or any other repo's reviewer identities) for a
different repo'snen pr readycall (§ 4). - Never exercise
nen run rerun-failed's affirmative rerun path against a repo whose PRs you do
not control the consequences of — this port only confirms the refusal shape (§ 4). - The reviewer-round policy is `/sharingan` § 6's, stated there once and
not restated here: one round after/hantensettles; a request only throughnen pr request-reviews, only while requested <round_policy.maxRoundsand resolved <round_policy.minRounds,
never onceminRoundsresolved rounds exist, never after a push that changed nothing reviewable;
either bound reached ends the pass not-ready with the board (zheref/hatsu#102).nen/workflow.json→monitor.maxCyclesis en's acting-cycle cap, a different number.