File one well-formed, correctly-labelled, non-duplicate issue — reconciling it against the open backlog first. Use when the maintainer invokes hatsu:file <problem> <repo> or a bare hatsu:file (which files what the session has just been discussing), or asks to file, open, log or raise an issue. **Also execute the shared discovery protocol when authorized work exposes a durable workflow, machinery, or owner gap.** Process-chairman findings — constitution, canon prose, machinery enhancement, duration, redundancy, autonomy gaps, deterministic jobs still done by hand, missing toolchain — are **Netero's** completeness contract (`claude/agents/netero.md`; Codex: the Netero section of `AGENTS.md`): every declared classifying label, observable acceptance criteria, and cross-references for deployment, fan-out and provisioning. Kurapika searches for duplicates to amend, near-neighbours to fold into, and issues this supersedes before writing.
Install
npx skillscat add zheref/hatsu/file 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 by ten 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.
File — one issue, reconciled against the backlog before it is written
Nature: Manipulator. The filing itself is GitHub-side reconciliation and label
application, the same discipline as a drive or a wake. Name a second mode alongside it when
the underlying problem is squarely governance (Conjurer), machinery (Transmuter), or
product code (Enhancer) — say which leads, per the identity header's rule against blending
modes silently.
The default failure this skill exists to prevent is not a badly-written issue. It is a backlog
that grows faster than it is worked, because every new finding is filed as if the backlog were
empty. So filing is the last of five steps, and four of them are about what is already there:
Amend a duplicate · fold into a neighbour · supersede what this obsoletes · then file · then
label so a loop can triage it without reading it.
0. In-flight discovery — standing authority
All Hatsu phases, composites, reviewers, and resumed sessions use the common protocol in
`docs/DISCOVERY.md` when authorized work exposes a concrete,
reproducible defect, missing capability, or ambiguous durable rule. file is the execution
route for that protocol; it is not permission to start an unrelated build.
The maintainer's standing authority covers capture, four-pass reconciliation, and the narrow
GitHub write selected by the protocol: create a distinct issue, add material evidence to a
duplicate, or fold compatible scope into a neighbour. It needs no second confirmation per
discovery. The normal explicit hatsu:file invocation still uses the reviewed plan in §4.
Standing authority never covers a stage/release label, closing or superseding an active effort,
merging, publishing, changing canon, or implementing the discovered owner work. Preserve the
original objective, continue it when safe, and report the canonical URL or pending record.
1. Invocation
hatsu:file <problem to file> <repo_token>
hatsu:file <problem to file>
hatsu:fileParsing. The last whitespace-delimited token is taken as the repo only if it
resolves:
nen repo resolve <token>against the current checkout's nen/repos.json
— the only location nen reads it from at this pin; --repo <path> names another checkout's registry) — aproduct_code, an owner/name slug, or a repository's short name, matched exactly and
case-insensitively, never as a prefix, and since nen v0.2.0 resolved from everything the registry
records — consumers, product_codes keys and values, maintained_tools, pending_onboarding
(verified live at v0.3.0: nen repo resolve BC --repo <path> exits 0 with the resolved slug;nen repo resolve notarealtoken --repo <path> exits 1 and its own refusal text names every valid
code and repository — that refusal text is the candidate list, never re-derived by hand). Exit 0 → the token is the repo;
everything before it is the problem. Exit 1 → the token is part of the problem text,
not a typo'd repo — never silently repoint a filing at a repo the maintainer did not name.
RETIRED at nen
0.5: exit2is a THIRD answer, and it means something else entirely. A target
carrying no registry at all — neithernen/repos.jsonnor the removed legacyschemas/repos.json—
now refuses at exit2naming the file, where throughv0.4.0it fell through to a generic exit1
indistinguishable from an unresolved token. Verified live at the pin, exit2: "<path>/nen/repos.json:
no such file. Nen reads this repository's taxonomy from 'nen/repos.json' in the TARGET repo and has no
built-in copy to fall back on." So the branch above must be read three ways, not two:0the token
resolved,1the registry opened fine and the token is not in it,2there is no registry to read — a
precondition, not a data problem, and the trigger to set the registry up (below), not the end. A registry that is present but malformed is unaffected and stays1.
The repo, when omitted: run nen repo resolve with no token — it resolves the current
working directory's origin remote against the same registry. If the cwd is not a registry
repo, it refuses (verified live) and the refusal text already lists the registry's codes and
repositories — ask, quoting that list, rather than reconstructing it. Filing into the wrong
repo is worse than a round-trip: it routes the work to the wrong lane, wakes the wrong agent,
and hides from the sweep that would have caught it.
A missing argument or configuration item is asked for and set up inline (missing-argument,missing-configuration; `WORKFLOW.md` § 4 Ask, set up, continue); a
missing registry is set up through nen scaffold init, a missing entry through nen/repos.json's own key.
The problem, when omitted (bare hatsu:file): the subject is the problem this session has
just been discussing — the defect just diagnosed, the gap just hit, the thing that just went
wrong. State the problem back in one line before doing anything else and let the plan carry
it; the maintainer's confirmation of the plan is the confirmation of that reading. If the session
has discussed several distinct problems, do not merge them — say so and ask which, or file
them as separate issues (one issue per distinct problem).
2. Before the plan — elicit what is missing
Ask for missing data before presenting the plan, never after. A plan the maintainer must
amend three times is a plan that was presented too early.
Every issue owes: the problem in one sentence · the evidence (a run link, a diff, a paste, a
repro) · why it matters and to whom · observable acceptance criteria · explicit scope
boundaries · the cross-references it touches (constitution/handbook clause IDs, rule IDs, files,
sibling issues, in the target repo's own object notation — § 5's nen ref note).
A product defect additionally owes: repro steps, expected vs actual, platform and build,
frequency. A performance finding owes its method block — an unqualified number is void
(nen quality method-check validates one, if the target repo scenario carries method-block
rules). A machinery defect owes the failing run link and what the guard should have done
instead. A canon/governance gap owes the rule that is missing or wrong, and what a reader did
instead because of it.
Never invent an acceptance criterion to fill the shape. An issue whose acceptance criteria
were guessed will be built to the guess. If a criterion is genuinely the maintainer's call, name
it as an open question inside the issue rather than resolving it silently.
3. Reconcile against the backlog — the four searches
Export a token first — nen never picks one up ambiently, unlike gh:
export GH_TOKEN=$(gh auth token)Then run the whole reconciliation in one call:
nen issue search --target <owner/name> --subject "<text>" \
[--files a,b] [--rule-ids X-1,X-2] [--lane-labels l1,l2]This is the four duplicate searches, run in order and reported with what each pass was
for — never reconstructed by hand: subject/open, subject/recently-closed (the verb picks
its own lookback window), files+rule-ids, lane. A pass with no terms to search on is
reported skipped, never silently omitted (verified live: an invocation with no --files,--rule-ids or --lane-labels prints skipped -- this pass had no terms to search with for
both of those passes rather than staying quiet about them). Exits 1 when any pass could
not run at all — "found nothing" and "could not look" must never read the same; a non-zero exit
here is itself a finding to report, not a clean empty search.
(a) Duplicates — amend, do not file. Same problem, same scope, same lane. Comment on the
existing issue with the new evidence:
nen issue comment --target <owner/name> --issue <n> --body-file <path> --dry-run # the exact gh call and the exact bytes
nen issue comment --target <owner/name> --issue <n> --body-file <path> # post itnen issue comment is new in nen v0.2.0 and retires the residue this port carried (the A/B doc's
"no nen verb owns posting a plain issue comment" is history): exactly one of --body/--body-file,
an empty or whitespace-only body refused at exit 2, --issue held to digits only (1e3 is refused,
not read as 1000), and --dry-run fully offline — it prints would run: gh issue comment … and the
body fenced between --- body as it would be posted --- markers, stating whether it ends in a newline
(verified live at v0.3.0). --body-file resolves against --repo's root from nen 0.7, where through v0.6.0 it
resolved against the process's cwd (zheref/nen#100); the RESOLVED path is what travels onward togh, so nen and gh cannot disagree about which file it is. An absolute path is still used as-is.
For an explicit request, post the comment only once the plan is confirmed (§ 4). For standing
discovery authority, post only after the completed protocol has found material evidence absent from
the existing issue and its comments. A discovery write does not authorize a severity change;
leave that separate action for explicit authority. Where explicitly authorized, raise severity only
when new evidence justifies it, via:
nen label apply <CODE>-IS-#<n> --label <severity-label> --repo-slug <owner/name> \
--repo <path to the target's own checkout> \
--reason "<what changed the assessment>" --run--repo is not optional: nen label reads the taxonomy from nen/labels.json in the checkout--repo points at, not in whatever directory the
skill happens to be invoked from, and has no built-in copy to fall back on — omit it and the call
refuses with nen/labels.json: no such file naming both locations the moment it is run from a
checkout that doesn't carry that file itself (e.g. this skill's own hatsu checkout; verified live
against v0.1.0 in docs/ab/file.md § 2.7, and the refusal shape re-verified at v0.3.0 throughnen schema check --repo <hatsu checkout>). Point it at the target repo's own checkout — the one
named by --repo-slug — never at the checkout file happens to be running from.
For an explicit plan, raise the severity only once confirmed — say what changed the assessment
(broader blast radius, a second occurrence, a consumer now affected). One open issue per distinct
problem.
(b) Fold — near, not same. A different problem whose scope and authority level are close
enough that one PR would sanely deliver both: same lane, same files or same clause, same
severity band. Folding adds the new requirement to that issue as a checklist item plus a comment
explaining the addition — the comment through nen issue comment, exactly as in (a); the checklist
edit replaces the whole prepared body through:
nen issue edit-body --target <owner/name> --issue <n> --body-file <path>edit-body certifies that <n> is an issue before it writes and replaces the body byte-for-byte;
prepare the current body plus the added checklist, never just the new lines. Do not fold
across lanes — a governance change and the machinery that implements it are a dependency chain,
not one issue; cross-link distinct owners instead.
(c) Supersede — this obsoletes those. Where the new requirement makes an existing issue's
approach or scope moot, propose closing the former with a comment naming this issue and why.
Guard every candidate first:
nen issue open-pr-check --target <owner/name> --issues <n1,n2,...>Exits 1 when any candidate carries an open PR (verified live against <reference-repo>:
scanned every open PR, matched by both closingIssuesReferences and body mentions, and flagged
every issue either one touches — cross-checked by hand against gh pr view <n> --json closingIssuesReferences,body, byte-identical). Exit 0 clears every candidate.
⚠️ An issue with an OPEN PR is never quietly closed.
open-pr-check's exit code is the
guard, but the decision is still the plan's: flag it prominently with a recommendation —
usually exclude it from the supersede set and let its PR land first — and let the
maintainer's approval cover whatever the plan states. Closing the issue itself is two acts: the
comment naming this issue and why goes throughnen issue comment --target <owner/name> --issue <n> --body-file <path>(never a rawgh issue comment), and the close isgh issue close <n> --repo <owner/name>— residue, narrowed: nonenverb closes a single issue outside the multi-childconsolidate-closechoreography in (d), which is the one verb that closes, and it takes two or more
children and a parent. Comment first, then close, so the close never points at a comment that does
not exist yet.
(d) Umbrella check. If three or more open issues would be folded or superseded, this is not a
filing — it is a consolidation, and nen issue attach-sub / nen issue consolidate-close
exist for exactly that shape (attach as sub-issues, compute the label union and severity maximum,
guard every child with the same open-PR check, then close — never the first failure, the whole
table). Say so and stop short of folding/superseding piecemeal here; hand the consolidation to
whatever skill owns it in this checkout (hatsu:backlog-synthesis, once ported) rather than
improvising the choreography inside file.
4. The plan, and the one confirmation
Present one plan covering everything that will be written, and take one confirmation for
all of it. The plan states, in this order:
- What is being filed — the drafted title and body, in full. Not a summary of a body you
will write afterwards; the actual text. - The labels that will be applied, each with its one-line basis (§ 5).
- Duplicates found — which issue is being amended, with what comment, and any severity bump.
- Fold candidates — which issue absorbs which requirement, or none, and why not.
- Supersede candidates — which issues close, with the comment text, and any excluded for an
open PR (open-pr-check's own verdict, quoted). - What was searched —
nen issue search's own report, § 3, pasted in full. A reconciliation
nobody can audit is a claim, not a check.
The stop is a G5 gate event. Render it with the shared verb rather than reconstructing the
banner by hand:
nen stop --who Kurapika --gate G5 efforts.md(or - to pipe a one-row efforts table through stdin) and put the DECIDE ask to the
maintainer with the options lettered — typically file as planned / file, but skip the closes
/ amend the duplicate only / do not file — the ⭐ recommendation, and what would tip it.
Nothing is written before that answer for an explicit hatsu:file request. Not the issue,
not a comment, not a label, not a close. Under §0's standing discovery authority, the completed
four-pass record and the selected narrow action replace this per-finding confirmation; the
report must say created, updated, folded, unchanged, or pending, never merely
"filed". A `hatsu:third-hand` harvest pick replaces this banner for
those drafts — do not render a second G5 DECIDE, and do not file unselected proposals.
5. Labels — so the loop can triage without reading it
Applied in the create call, never as a follow-up edit:
nen issue file --target <owner/name> --repo <path to a checkout carrying nen/labels.json — or schemas/labels.json under the fallback nen keeps until v0.4.0> \
--title "<title>" --body-file <path> --label <a,b,...> --assignee <user> \
[--forbid-family <a real, declared target stage-label family>](--body-file resolves against --repo's root from nen 0.7 — zheref/nen#100; throughv0.6.0 it was handed to gh unresolved and resolved against the process's cwd instead. An absolute
path is still used as-is.) nen issue file checks every label against the target repository's nen/labels.json
before attempting anything (verified live: an unknown label refuses with is not in this repository's taxonomy … GitHub would CREATE it rather than refuse, so a typo becomes a permanent undocumented label — GitHub itself never catches this, only the taxonomy check does) and enforces--forbid-family as a hard, machine-checked guard when the target taxonomy declares that
family (verified live: a label in a forbidden family
refuses with is in the '<family>' family, which this invocation declared off-limits with --forbid-family — before any GitHub call is made). Pass the target repo's stage-label
family only when it is actually declared. Hatsu's current flat nen/labels.json declares none,
so do not invent a family name or add the flag here. A stage label remains excluded from this
skill's create labels; where a real family exists, the flag makes that exclusion a call refusal.
| Class | What to apply | Basis |
|---|---|---|
| Lane / agent | Whichever labels route this problem to its owning discipline in the target repo's own taxonomy — several when it spans lanes | Read from nen/labels.json at run time, never from memory; a label this port hasn't seen before is still a real one if the taxonomy carries it |
| Severity | Exactly one severity label from the target repo's own severity vocabulary | Propose with one line of reasoning; the plan carries it |
| Kind | Bug / handbook-question / epic / QA / observation-fix, as the target repo's taxonomy names them | What the issue is |
| Stage | None | Zero stage labels before release; the stage-that-is-the-release-trigger is the human's. Use --forbid-family only when the target's declared taxonomy supplies that family. |
Assign the human maintainer — a specific user, never an org login — so the issue reaches
them by notification rather than at the next local session.
Process-chairman filings additionally owe Netero's completeness
(claude/agents/netero.md; Codex: the Netero section of AGENTS.md): every declared classifying label that is
true of the issue (kind, and severity or routing when the target taxonomy has those families),
observable acceptance criteria, and cross-references for deployment, fan-out and provisioning.
Do not invent a family the target does not declare. An incomplete chairman issue is refused, not
shipped thin.
Severity is proposed, not decreed. The plan says why, so it can be overruled in the same
answer that approves the filing.
Cite every cross-reference in the target repo's own object notation (<CODE>-<IS|PR>-#<N>),
formatted with nen ref format --code <CODE> --kind IS --number <n> [--state <s>] rather than
hand-typed — codes come from that repo's registry at run time (§ 1's nen repo resolve), never
from a fixed list carried in this file.
6. After filing — offer the build
Report the issue in object notation with its number linked, then offer the next verb in one
line:
hatsu:build <CODE>#<N>Offer it; never start it. Releasing work into an agent's autonomous build is a separate
go-signal, given by a separate invocation. An offer that starts itself is not an offer.
A filing from `hatsu:third-hand` does not offer it — that sitting is
over, and starting a build would open the next one.
7. Authority
file carries routing delegation only: for an explicit request, only what the approved plan
named; for an in-flight discovery, only the §0/DISCOVERY.md reconciliation outcome.
- Permitted: the lane/agent labels on the issue it files and on the neighbours the plan
names; the severity and kind labels; the comments (nen issue comment) and closes the plan states;nen label apply --runfor a severity bump the plan named, logged in its ledger. - Not permitted: any stage label (and, where the target declares its family,
--forbid-family
makes this a refusal), any
G1 mode label, any merge, any review vote, any close the plan did not name. - Log every application — object, label, time — in the report.
nen label applywrites its
own ledger entry (outcome: "applied"or"failed", written after the call resolves) whether
or not this report also restates it — restate it anyway, so the report is self-contained.
8. Hard limits
- Never files without the confirmation for an explicit request, and never files anything the
plan did not show. A discovery write needs the standing authority plus the recorded protocol
outcome; it is not an exception to reconciliation and never carries a severity change. - Never closes an issue that has an open PR unless
open-pr-checkwas run, the plan named it
and the maintainer approved it with that fact stated. - Never files a duplicate. If
nen issue searchcould not run a pass (exit1), recordpendingwith the failed pass and recovery check; do not create or update an issue while the
reconciliation result is incomplete. - Never applies a stage label (use
--forbid-familyonly when the target declares the relevant
family — see § 5), and never releases work into build. - Never merges several distinct problems into one issue to save a round-trip.
- Never fabricates evidence, a repro, a number, or an acceptance criterion.
- Never files into a repo it resolved by guess —
nen repo resolve's exit code is the only
basis for treating a token as a repo (§ 1); never fall back to inferring one when it refuses. - Never hand-roll
attach-sub/consolidate-close's choreography for a 1-or-2-candidate
supersede that doesn't need it, and never invoke the umbrella verbs on fewer than three
candidates just because they exist. - Never posts a comment with a raw
gh issue comment.nen issue commentowns that step, andnen issue edit-bodyowns a whole-body replacement. The only rawghthis skill still carries
is the single-issue close named as residue above.