Verstakify
Bring the current repo to the verstak agent standard: a dense, AI-first
AGENTS.md (read every session, not by a human once) + a CLAUDE.md pointing
at it, the NKS session rituals wired as hooks, and a quality gate. You generate the
config from the skeleton — nothing is copied by hand and the user pastes no
template.
The real deliverable is a trust interface: a doc the agent can believe every
session — not a pretty dense file. AGENTS.md is a derived view, a projection
of sources that already hold the truth (code, package.json, CI config, the
filesystem, NKS) plus a thin layer of authored judgment (gotchas, why-clauses)
that lives nowhere else. So the contract has two co-equal halves: density
(every line changes behavior) and accuracy (every derived line re-checked
against its source this run). A dense false line is worse than a verbose one —
short and confident, the agent swallows it without resistance. Verify with the
same rigor you compress with.
The body skeleton lives in references/agents-template.md (relative to this
skill). Read it; it is the set of ## sections your finished AGENTS.md must
have, with <…> slots and a few <!-- … --> notes. Fill the slots, drop
optional rows/sections that don't apply, strip every <!-- … --> note, never
leave an angle bracket. The skeleton is what to produce; this file is how.
Contract: 1. Step 7 stamps this number into every AGENTS.md it writes.
Increment it by one only when a change here or in the skeleton makes an
already-generated file wrong — a section added, renamed or retired, a ritual
changed, a tool name dropped; never for wording. A repo whose stamp is lower
gets the full arc, and you name the contract its config came from.
It is a plain counter, and deliberately neither a date nor the plugin's
version. A date cannot express two changes in one day — it happened, and the
second change had no way to announce itself. The release version moves on every
release, including ones that touch no skill here, so stamping it would mark
every generated config stale after any release at all; a staleness signal that
fires constantly stops being read. This counter is the template's own and moves
only when the template's output goes wrong. A config stamped with a date
predates this scheme — treat it as lower than any number and run the full arc.
The skeleton deliberately inlines repo-agnostic agent-discipline (Working
principles, parts of Session lifecycle) into every generated AGENTS.md so the
file stands alone for agents with no NKS access. Keep it inline — don't replace
it with a pointer to the methodology realm even though it duplicates content
there.
Audit → classify → act (not fresh-vs-existing)
A repo is never simply fresh or configured — it's a spectrum, and the trap is
"a file exists, therefore its facts are true." Don't branch on whether
AGENTS.md / CLAUDE.md / .claude/ exists. Instead audit every concern
against its source of truth and classify it:
- absent — no claim yet → derive it from the source (or, for an authored
slot with no checkable source, ask the user).
- stale — a claim exists but disagrees with its source → re-project from the
source, overwriting the stale text. Do not carry it forward just because it was
written down.
- correct — claim matches source → leave it.
Run this per concern using the source map below. "Fresh repo" is just
everything absent; a mature repo is a mix — and most dangerous when
mostly-correct, because the few stale lines hide among trusted ones (this is
why the verify pass is whole-artifact, Step 7). For authored slots with no
checkable source, absent → ask the user; never invent.
Source of truth per concern
Each claim class has one authority. Verify there — don't recall:
| Concern |
Source of truth |
How to check |
| Versions, dependencies |
package.json / pyproject.toml / go.mod / Cargo.toml + lockfile |
read |
| Build/test/lint/dev commands |
package.json scripts, Makefile/Justfile, CI workflow |
read; run --help/dry-run where cheap |
| Quality gate (strictness, max-warnings) |
linter config, tsconfig, CI yaml |
read |
| Project structure, path aliases |
filesystem + tsconfig/bundler config |
glob / list |
| Nature, production statement, relaxations |
the user (authored) |
confirm in conversation |
| Reality carriers + how to observe them |
the user (authored) |
confirm in conversation — never derive |
| Design decisions, why-clauses, open questions |
NKS |
nks_orient / nks_search |
| Branch state, what's runnable |
git + HANDOVER.md |
git status / log |
| Gotchas |
authored (past pain) |
sanity-check only — don't auto-derive |
Two kinds of line, handled differently: derived facts (upper rows) are
re-projected from source every run — never preserved when stale; authored
judgment (lower rows — gotchas, why-clauses, nature) lives nowhere else —
preserve it, only sanity-check it against the code.
The output contract — density and accuracy
AGENTS.md is read every session, so it must be both dense and true —
co-equal, not form-first. Accuracy is operationalized above (audit/classify each
concern against the source map) and below (verify pass, Step 7). The density half
is these five rules:
- Imperative, addressed to the agent. "Orient before coding," not "the
agent should orient."
- Density rule. Every line must change what the agent does. If deleting a
line wouldn't change behavior, delete it. Reads like a checklist, not an
essay — no motivation, no aphorisms, no victory laps.
- No design rationale, no duplication of NKS. The why behind a decision
lives in NKS (vimarshas) — link, don't restate.
AGENTS.md is a reference
artifact (shabda); narrative in it sets up a second source of truth that
drifts from NKS and misleads future agents. Keep a terse (why: …) clause
only for an invariant a future agent would otherwise violate — a code-level
gotcha or non-obvious constraint, never a design justification.
- Tables and bullets over paragraphs. One directive per bullet.
- No length target — but a section that runs to paragraphs is almost always
carrying rationale that belongs in NKS. Move it there.
Out of scope — orchestration mechanics. AGENTS.md addresses one agent in
one session. Build-gating chains, sub-agent push verification, model-routing,
multi-lane coordination don't belong here — inlining them violates the density
rule for the solo reader. Home: a dedicated orchestration/scheduler skill or the
methodology realm — except the sub-agent delegation slice, which this skill
projects as role files (Step 6, references/delegation.md), never as AGENTS.md
prose. Link if needed, don't inline.
Worked example — same ## Code conventions entry, bad (narrative) vs good
(AI-first):
- ❌ "We try to be careful about state because this is a demo and the store is
the only place data lives, so it's important that components read it correctly
when the persona changes, otherwise the demo can look broken."
- ✅ "Persona-scoped UI reads role via
use-acting-context; re-check render on
persona switch. (why: store is the only data source — a stale read shows
wrong-role data.)"
The good version is a directive + one invariant clause. The bad version is three
sentences of rationale that belong in an NKS vimarsha.
Procedure
Idempotent throughout: in a mature repo, run each self-check and act only on
failures; report what's still outstanding.
Quick mode — first contact only. The full run is a heavy first thing to meet
after a restart, before the newcomer has seen anything worth the cost. On a repo's
first verstakify, unless the user asked for the full pass: run Step 2 (realm,
focus holon, agent karta) plus a skeleton AGENTS.md of the slots you can
derive without asking, then hand over to the roadmap teaser (Step 7's baton).
Defer Steps 1, 3, 4, 6 in one line — "gate, hooks and the interview are deferred —
say verstakify again for the full pass." Two rules keep it honest: never write a
derived line you haven't checked (an unasked authored slot stays absent, never
guessed), and always name what was deferred. Every later run is the full arc.
A deferred authored section is declared, not dropped — Reality and Shared
surfaces especially, because other sections point at them. Keep the heading and
write one real line under it — "Not settled yet: run the interview (say
verstakify) before accepting any behavioral claim here." — not a slot, so the
no-angle-brackets check still passes. An absent section reads as "nothing to
check here", the opposite of true, and leaves the pointers in Session lifecycle
and Working principles 4 and 6 aimed at nothing.
Step 1 — Settle with the user (do first)
Don't silently pick defaults. Confirm in conversation, then write into What this
project is: Nature (and, if not production, which principles are relaxed +
why), NKS realm name (create if missing), Stack, Quality gate
(propose strictest — Step 3). For an existing repo, infer these from the repo and
the old config first, then confirm only what's ambiguous.
Also settle who owns direction: the realm's owner as a svatantra (主)
karta — created in Step 2 if missing. Out-of-mandate questions will be posed to
it as graph vimarshas (posed_to), not chat-only asks.
Also settle shared mutable build/test state: does build or test read or
mutate a shared resource — a database, a fixed port, a dev server, a global
cache, a cloud sandbox? If yes, capture per-lane isolation (per-branch
DB/schema, per-lane port, per-lane temp dir) as a gotcha: agents run branches
concurrently in separate worktrees, and a shared resource corrupts across lanes.
Skip when build/test has no shared mutable state.
Also settle shared surfaces: which components, schemas, contracts or rules
have more than one consumer, and which consumers. Authored slot — a silently
forked component looks like two ordinary files, so the repo can't be grepped for
it. Fills Shared surfaces; omit the section only if the answer is genuinely
nothing.
Also settle reality — what a claim here is verified against; fills the
Reality table. A code repo, a data repo and an infrastructure repo answer this
differently, so derive nothing, ask: where a change lands, what effects it
produces, which of them are observable and with exactly what command / URL /
query, and what the agent reaches alone versus what needs the user. Press for
the canonical carrier of each claim class — the built artifact, not the
sources; the live endpoint, not the handler; a clean install, not a warm cache.
A class with no reachable observation goes under Ceiling with its reason,
never left as an aspirational row.
Also settle cross-project memory — ask once per user, not per repo (a
previous verstakification's answer is reusable): does the user want what
outlives any single repo to persist — the personal realm @<handle>/mind for
user facts, and a globally injected preferences file ("how to act with me":
~/.claude/CLAUDE.md, ~/.config/opencode/AGENTS.md) for standing
instructions? Yes → establish the layer: bootstrap the realm (minding
§3) and the preferences file (create if absent, one source linked across the
harnesses the user runs); the generated routing keeps its personal-realm
branches, and the memory-guard message keeps its minding route. No → the
routing is repo-scoped: project facts to this repo and its realm, everything
else stays session-local — the personal-realm branches, the preferences
clause, and the minding route in the guard message are omitted. Never assume
the layer exists because the harness has a slot for it.
Also settle workflow-suite coexistence (only when a coercive workflow suite
is detected — its skills appear in the skills list, or its dir exists in the
plugin cache, e.g. ~/.claude/plugins/; today that means superpowers): tell
the user what was found and settle the mode:
- Full interop (recommended) — AGENTS.md gets the interop subsection
(from this skill's
references/superpowers-interop.md) + the spec-write
hook (Step 4);
- Prose-only — the subsection, no spec-write hook;
- Skip — no coexistence text (not recommended; note the risk: design
sessions led by the suite won't persist to the realm by default).
Step 2 — NKS bootstrap
- Realm exists? If not: agree a name, then
nks_realm(action="create").
- If the project has structure beyond the realm itself, a focus holon exists
(named after the project's boundary,
contains-linked from the realm root),
and its #seq goes into What this project is. Design the boundary with the
design skill, create with nks_add_holon.
- The doer becomes a steward. Create the repo's agent karta
(
nks_add_karta, manifested_as=adhikarin, motivation distilled from the
Production statement) and draw its steward edge to the focus holon — an
adhikarin without a steward edge is a live warning ("acts but answers for
nothing"). Create the owner's svatantra karta if Step 1 found none, and bind
it to the human it stands for — user="me" when the owner is the person
running this, otherwise their sub from nks_admin(action="list_members").
That binding is what makes the owner findable across every repo they own
(minding §4); without it their roles stay unlinked per realm. Record both
seqs in What this project is — the doc slot is the only path an agent can
rely on.
Step 3 — Quality gate (propose strictest, user confirms)
For each: propose the strictest sensible option for the stack, a one-line
trade-off, await confirmation. Default strict; relaxations need an explicit ask,
calibrated to cost-of-breakage from What this project is and recorded there
per-tool.
Tightening an existing gate is not free. On a mature repo whose gate is
already relaxed, max-warnings 0 is not a checkbox — it commits the user to a
refactor. Before proposing to tighten, measure: run the linter/typechecker at
the proposed strictness, count the failures, and show that cost. Tightening an
already-relaxed gate needs the same explicit ask as a relaxation — and may belong
in a follow-up branch, not the bootstrap.
- Linter, max strict (e.g.
@typescript-eslint/strict; Ruff
E,F,B,I,N,UP,RUF; golangci-lint broad; clippy -- -D clippy::pedantic).
- Formatter, auto-fix on save + pre-commit (Prettier,
ruff format,
gofumpt, rustfmt).
- Type checker, strict, if the stack has one (
tsc --strict, mypy --strict / pyright --strict).
- Pre-commit hook: linter + formatter + typecheck on staged files.
- Test framework + discipline (unit for libraries; +integration for
services; +e2e for UI; coverage threshold for production). Record in Code
conventions.
- CI: lint + typecheck + tests on every push, fails on warnings. Mandatory
for
production.
- CI parity: any check that can fail must gate PRs, not just post-merge.
Audit the workflows for jobs scoped to push-
main/release only (codegen,
schema/API-spec/docs generation, image or bundle build, migration check) — a
post-merge-only check lets two individually-green PRs break main after merge.
Tighten it to also run on PRs; record any gap you can't close now as a gotcha.
Write commands into Commands, discipline into Code conventions.
Step 4 — Hooks
The deliverable is the rituals, not the file. Detect which harness the repo
uses and wire its surface — Claude Code's hooks file, Codex's [hooks] in
config.toml, OpenCode's plugin dir — from references/harness-surfaces.md,
which carries the verified paths, event names and per-ritual mapping for each.
More than one may be present; wire each. Where a harness has no surface for a
ritual, say which one you couldn't automate — it still binds through the AGENTS.md
Session lifecycle prose, which the skeleton inlines for exactly this reason.
Never write a config for a format you're guessing.
The rest of this step is Claude Code's shape. Three hooks in .claude/settings.json (committed — project-wide rituals, every
agent on every clone needs them), plus a conditional fourth — the spec-write
hook — only when the Step-1 coexistence settle chose full interop (the
settled mode is recorded in the AGENTS.md interop stamp, Step 7; no subsection
= no settle = three hooks). Merge, never overwrite: other suites may
already own entries in this file — add yours alongside theirs in the same
arrays; deleting another suite's hooks breaks its rituals. Generate the JSON for
this project — write it yourself:
SessionStart → reminder to orient in NKS before acting (skill entry),
naming this realm slug, focus holon and agent karta: open the doer's
agenda (nks_orient(realm, focus="<agent-karta-seq>")) — incoming posed_to
vimarshas are the session's inbox; pick up or explicitly defer each.
PostToolUse with "matcher": "Bash" → when the command contains git push, reminder to ask which kind of push this was — where done means
merged, a push that only opens or updates a PR ships nothing, so it records
an answer where one genuinely stands and leaves bodies and modes describing
what the trunk carries (a model written ahead of the merge describes what the
repo does not have, and a withdrawn PR leaves it lying). After a merge:
update NKS only from fresh artifact evidence — confirm
the canonical changed path and the exposed old requirements were actually
exercised — then advance the bianhua map and end what the merge settled by axis
(addressed_by records the answer, release is its own act), sweep the
shipped contour (walk the whole designed contour, not only the nodes you
touched; but a mode flip is itself a claim, so flip what the evidence covers
and leave the rest as it stands rather than advancing it ceremonially), work
the inbox (the posed_to questions the work answered), run the
after-green-push self-review, re-read the diff and the nodes for borrowed
project-management words — ticket, backlog, sprint, epic, story, done,
blocker, committed — naming each to the user and asking what this project
calls it instead of swapping it yourself, and: uningested design/spec docs on
this branch → intake them (intake skill, then design) before closing.
Two things this hook is the natural place for. Check freshness rather than
trust it: branch on the push having actually run, and where the branch no
longer descends from the trunk — git merge-base --is-ancestor origin/main HEAD exits nonzero — say so in the same breath. Stale discovered at push
costs a fetch; discovered at merge it costs whoever integrates. And phrase
the merge half as an event: the reminder fires on a push, but the post-merge
sequence is owed to the merge signal itself, never to a quiet stretch after it
— an agent on a live channel never gets one, so a ritual conditioned on calm
reads as a rule and behaves as none.
The vocabulary re-read rides this hook on purpose: it is the prose ban's
mechanism, and a ban that lives only in AGENTS.md is the one an agent skates
past.
PreToolUse with "matcher": "Write|Edit|MultiEdit" → the memory-guard
hook: when the target path is inside the local project-memory dir, block
the write (exit 2, routing message on stderr) — state lives in the repo,
the graph, or the user's personal realm, never in local agent memory, and the
prohibition is by dir rather than by category; the dir stays frozen at its
prohibition stub (Step 5). Blocking is safe here: the path is unambiguous and
legitimate writes there are zero by policy. It fires at the exact moment the
save-instinct does, when AGENTS.md is far behind in the context. Exact JSON
below.
PostToolUse with "matcher": "Write|Edit" → the spec-write hook
(full-interop mode only): when the written file path looks like a design/spec
doc, reminder that the file is a draft view — the graph is the design record.
Same envelope style, gated on .tool_input.file_path the way the push hook
gates on the command text; exact JSON below.
Stop → the turn-without-a-change guard. A turn that ends having
announced what the agent is about to do — "I'll start with this one, if
you don't mind" — ends the agent: no input is due, and it sits dead until
someone pings it. The norm against this is written and gets violated
anyway, which is the same shape as the memory rule: what a norm cannot
catch, a hook fires at the exact moment the instinct does. So this one
blocks, and the exemption is what makes it safe — a turn passes if it
produced a change (an edit, a command, a node) or carries a question
written where its addressee will find it. Announcing an intention is
neither. Wire the announcement into the occupation line instead, which is
where "what I am on" belongs.
Each hook runs a shell command that echoes the hook envelope to stdout. The
nesting (event → array → {"hooks":[{"type":"command","command":…}]}) is the
easy part to get wrong:
{ "hooks": { "SessionStart": [ { "hooks": [ { "type": "command",
"command": "echo '{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"<orient reminder: realm + focus holon>\"}}'" } ] } ] } }
The PostToolUse entry adds "matcher": "Bash" and gates the echo on the
command: jq -r '.tool_input.command // ""' | grep -q 'git push' && echo '<envelope>' || true.
This matches the command text, so it will also fire on commands that merely
mention git push (an echo, a PR-body heredoc, this very hook's own
validation) — a known false-positive. Harmless for a non-blocking reminder, so
ship it as-is; just never promote this text-match to anything that gates work. To
cut the noise, also branch on .tool_response so the reminder fires only when
the push actually ran.
The memory-guard hook — unlike the reminders it blocks: a PreToolUse
command that exits 2 stops the tool call and hands Claude the stderr message.
The path is unambiguous (.claude/projects/<encoded>/memory/), so false
positives are near zero. The message's last route follows the Step 1
cross-project-memory answer — under no, drop the personal-realm sentence:
{ "matcher": "Write|Edit|MultiEdit", "hooks": [ { "type": "command",
"command": "jq -r '.tool_input.file_path // \"\"' | grep -Eq '\\.claude/projects/.*/memory/' && { echo 'BLOCKED: local agent memory is forbidden entirely, not by category (AGENTS.md, Persistence rules). Route the fact: repo conventions / code facts → AGENTS.md; project state, this project's servers and dated duties → the project realm; a user-scoped fact no project owns → the personal realm @<handle>/mind (minding skill) — drop this route under cross-project-memory=no. This dir stays frozen at its prohibition stub.' >&2; exit 2; } || exit 0" } ] }
This entry goes under "PreToolUse" — its own event array, not the
PostToolUse one.
The spec-write hook (full-interop only), same gating style — a wide behavioral
glob; false positives are harmless for a non-blocking reminder, never promote
it to anything that gates work:
{ "matcher": "Write|Edit", "hooks": [ { "type": "command",
"command": "jq -r '.tool_input.file_path // \"\"' | grep -qE '(^|/)specs/[^/]+\\.md$|(^|/)docs/.*design[^/]*\\.md$' && echo '{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"A design draft was written; per AGENTS.md this file is a draft view — the graph is the design record. Intake it (intake skill, then design skill) in this session — do not defer to a push.\"}}' || true" } ] }
The spec-write entry merges into the same PostToolUse array as the git-push
hook — sibling objects, not replacements; the memory guard lives in its own
PreToolUse array.
Self-check: all three base hooks present, and the spec-write hook present
iff the AGENTS.md interop stamp says full (absent stamp or prose-only →
it must NOT be wired — don't re-add it on refresh); SessionStart names the
real realm slug, focus holon and agent-karta seq, not placeholders; no
pre-existing hook entry from another suite was dropped by the merge.
Heads-up: writing .claude/settings.json may be flagged by the harness as
self-modification and require explicit approval — surface the write for
confirmation rather than assuming it lands silently.
Step 5 — Repo hygiene
- Commit
.claude/settings.json; ignore .claude/settings.local.json via
.gitignore. If .claude/ is broadly ignored, add an explicit un-ignore:
!.claude/settings.json. Verify with git check-ignore -v .claude/settings.json .claude/settings.local.json.
- Tracked secret/env files: run
git ls-files '.env*' '*secret*' '*local*'.
If a real env/secret file is tracked (not just an .example), warn in Code
conventions: never stage local edits — git update-index --skip-worktree <file>, never git add -A / commit -a (an agent editing a tracked env file
otherwise leaks it into the PR).
- Local project-memory dir (
~/.claude/projects/<encoded-path>/memory/):
audit and evacuate it, then freeze it. Nothing keeps a place there —
the prohibition is by dir, not by category. Project state (decisions,
constraints, branch state, gotchas) → AGENTS.md / HANDOVER.md / NKS; this
project's servers and dated duties → its realm; the user's own holdings
(personal machines, expiries, people, cross-project findings) → the user's
personal realm (minding) — but only under the Step 1 cross-project-memory
answer yes; under no they stay in the repo's AGENTS.md if this repo
must keep them, otherwise they are dropped with the user's knowledge.
Working-style preferences are instructions, not facts: → the globally
injected instruction file (minding §3 establishes it), never a node. Then
freeze: MEMORY.md becomes a one-line
prohibition stub («project state lives in the repo or the graph — see
AGENTS.md, Persistence rules»), and the memory-guard hook (Step 4) blocks
any further write at the moment the save-instinct fires. Evacuate before you
freeze — a stub over unread content destroys what it was meant to relocate.
Reason: reproducibility + multi-machine, multi-agent work — local memory is
invisible to every other agent and machine.
- The forge and its CLI — derive it, never assume GitHub. Read
git remote -v; the host decides the tool (gh GitHub, fj Forgejo/Codeberg, glab
GitLab, tea Gitea). Check it is installed and authenticated, then name it in
Git workflow together with its watch command. This is not cosmetic: opening
the PR is the one hand-off step the agent owns outright, and an agent that
can't name the tool turns it back into a question for the user. An
unrecognized self-hosted host → ask which CLI they use; never guess gh
because it is the one you know.
- Stack, Commands, Project structure, Code conventions hold real content
proportional to maturity. Empty is fine day one;
TBD is not.
HANDOVER.md exists only if feature-branch work is in flight.
README.md is short, human-facing, and doesn't duplicate AGENTS.md.
Step 6 — Subagent delegation roles
Project the delegation doctrine as named role agents, not as AGENTS.md
prose (orchestration mechanics stay out of AGENTS.md — the output contract
above). Doctrine + file templates: references/delegation.md (relative to
this skill).
- Always:
.claude/agents/reader.md (cheap-tier recon),
.claude/agents/worker.md (mid-tier brief execution), and
.claude/agents/verifier.md (cold falsification-first acceptance audit).
Use stable aliases for reader/worker (haiku/sonnet); resolve a supported
top/session model for verifier rather than inheriting a cheap tier. The
verifier is projected even where the repo has no runtime yet — it is what
makes the Reality table actionable, and a repo that gains a carrier later
should not need a re-run to gain its acceptor.
- When the repo shows OpenCode use (
opencode.json / .opencode/ present, or
the user says so): .opencode/agents/reader.md + worker.md + verifier.md,
mode: subagent, model pinned per file — an unpinned OpenCode subagent
inherits the invoking primary's model, so the pin is the point, and on the
verifier it decides whether acceptance is real. Resolve
current provider/model-ids from the user's setup (ask, or read
opencode.json / the global config); never hardcode from the reference.
- The
description fields are the delivery channel — they sit in the
agent/task tool list every session, so the routing trigger fires without any
skill load. Keep them trigger-shaped: when to use, what comes back, what NOT
to trust it with.
- Open-ended judgment (design, synthesis, exploratory review) gets no role
file — it stays with the session model or a per-call top-tier override.
verifier is the narrow exception: frozen claims and a falsification-first
return contract make acceptance review delegable without delegating judgment
about what the product should mean. It is also an expensive role: use it
only for load-bearing claims where independent falsification can change
acceptance.
- Merge, never overwrite: a same-named
reader / worker / verifier
agent file from another suite may already exist — fold your body/description
in or rename yours (verstak-reader); the same rule the hooks merge follows.
- Self-check: role files parse (frontmatter); pinned models exist in the
user's setup; AGENTS.md carries no inlined delegation doctrine (a
pointer at most); no pre-existing agent file was overwritten.
Step 7 — Finalize
- Write the filled body to
AGENTS.md — the vendor-neutral canonical name,
which Codex and OpenCode read natively. A pointer file is Claude Code's
requirement alone (it reads CLAUDE.md, not AGENTS.md); don't create one
for a harness that doesn't need it. Two isomorphic forms, chosen by whether
symlinks survive the checkout — decide by git config core.symlinks plus the
platform, don't assume:
- Symlinks work (POSIX default):
ln -s AGENTS.md CLAUDE.md. One file,
two names — nothing to keep in sync, and any tool reading CLAUDE.md
literally gets the real content, not an import directive.
- Symlinks don't (Windows,
core.symlinks=false): copy AGENTS.md to
CLAUDE.md byte-for-byte. A copy is a second source of truth, so it is
regenerated on every verstakify run and listed in What to update when;
edits go to AGENTS.md and never to the copy. A third form exists — a
one-line CLAUDE.md containing @AGENTS.md, Claude Code's import (no
backticks, a code span suppresses it) — use it where a copy would be worse
than an import that only Claude Code understands.
Don't churn a pointer that already works, whichever of the three it is.
Per-harness specifics, including Codex's root→cwd merge and its
AGENTS.override.md local override, are in references/harness-surfaces.md.
- Legacy config already present (the common case): use the skeleton as the
frame and fold existing content in by line kind — re-project derived facts
from their source (don't carry a stale version, command, or path forward just
because it was written down) but preserve authored judgment (gotchas,
why-clauses, nature) that has no checkable source, sanity-checking it against
the code. Project-specific content with no slot moves to Code conventions or a
new section. End with
AGENTS.md as the one file + CLAUDE.md as the pointer
(whichever of the three forms above the checkout supports) — if a content-bearing
CLAUDE.md exists, fold its content into AGENTS.md and replace the file
with the pointer. One source per concern — no duplicate sections.
- If Step 1 settled full interop or prose-only: render the
### Workflow-suite interop (superpowers) subsection at the end of
## Session lifecycle, taking the section text from this skill's
references/superpowers-interop.md (deployable part only — the maintainers'
re-verify checklist stays in the reference). Stamp it with the plain trailing
line *(interop: <full|prose-only> — verified against superpowers@<version> — re-check on suite upgrade)* — the stamp records the settled mode; Step 4 and
refresh runs read it. On refresh runs, audit the subsection like any other AGENTS.md
concern: source of truth = the reference file + the installed suite version.
- Verify pass (co-equal with the density pass): re-check every derived line
against its source from the map — whole-artifact, not just the lines you
touched. The most dangerous errors sit in untouched, settled-looking lines
that drift silently because nothing challenges them. A claim you can't tie to a
source is either authored judgment (keep it, recognize it as such) or a guess
(cut it).
- Density pass: for every body line ask "does this change what the agent
does?" Cut narrative, motivation, design rationale (rationale → NKS).
- Drift between runs is guaranteed — the doc goes stale the moment code changes.
verstakify re-verifies only when re-run; an automatic "claimed vs actual" check
hook (e.g. doc versions vs
package.json) is a settled non-default —
generic prose-vs-source parsing is brittle, throws false positives, and the
checker drifts alongside the doc it guards. Re-running verstakify is the
discipline. A narrow per-repo checker on named lines is the only shape worth
building; never a generic one.
- Stamp the contract. Trailing line of
AGENTS.md: *(verstakify: contract <the number from the top of this file> — re-run when the installed contract is higher, or when the sources this file derives from have moved since.)* On a
refresh, overwrite the old stamp; never leave two. A config carrying no
stamp, or one carrying a date from the scheme this counter replaced,
predates the contract — treat it as lower than any number and run the full arc.
- Confirm no
<…> slot and no <!-- … --> note survived into AGENTS.md.
- Every skill name written into
AGENTS.md must resolve as written. Check
each against the live registry you can actually see, the same way tool names
are checked — never from memory, and never in a form a previous generation
used. Addressing depends on the install channel (a plugin namespaces its
skills; a flat unpack leaves them bare), so write the form that resolves on
the channel this repo declares. A name that cannot be invoked is a defect of
the projection, not a typo: it raises no error, only a shrug, and the hook
that pointed at a method keeps firing while the method never runs.
- On the bootstrap push, NKS reflects the change (vimarshas opened/closed,
the bianhua map advanced).
- Pass the baton — name the next step, never let the user guess it. End by
offering the first visible value: a quick roadmap teaser (
product-roadmap
skill, quick mode) over the freshly bootstrapped repo. Say its name, don't
allude to it. After a quick-mode run the baton is two items in order: the
teaser, then "say verstakify again for the gate, hooks and the interview".
The chain from setup to first wow breaks wherever the user is expected to
remember a word across a session restart.
1---2name: verstakify3description: Use when the user asks to verstakify a repo — bootstrap or refresh its AGENTS.md / CLAUDE.md to the verstak standard, apply the NKS methodology conventions, or wire the session-lifecycle rituals (orient-in-NKS on start, push→update-NKS hooks, quality gate, memory guard, CLAUDE.md pointer — @AGENTS.md import, Windows-safe). Triggers: "verstakify", "verstakify this repo", "привести проект к стандарту", "завести/обновить AGENTS.md", "set up AGENTS.md", "bootstrap AGENTS", "apply the meta template", "наведи порядок в конфиге агента". AGENTS.md is a derived view, not hand-written prose: each concern is audited against its source of truth and re-projected when stale, preserving authored judgment; fresh repos ask the user for the authored slots. Needs the nks_* MCP tools for the NKS steps.4---56# Verstakify78Bring the **current repo** to the verstak agent standard: a dense, AI-first9`AGENTS.md` (read every session, not by a human once) + a `CLAUDE.md` pointing10at it, the NKS session rituals wired as hooks, and a quality gate. You **generate** the11config from the skeleton — nothing is copied by hand and the user pastes no12template.1314The real deliverable is **a trust interface**: a doc the agent can believe every15session — not a pretty dense file. `AGENTS.md` is a *derived view*, a projection16of sources that already hold the truth (code, `package.json`, CI config, the17filesystem, NKS) plus a thin layer of authored judgment (gotchas, why-clauses)18that lives nowhere else. So the contract has two co-equal halves: **density**19(every line changes behavior) and **accuracy** (every derived line re-checked20against its source *this run*). A dense false line is worse than a verbose one —21short and confident, the agent swallows it without resistance. Verify with the22same rigor you compress with.2324The body skeleton lives in `references/agents-template.md` (relative to this25skill). Read it; it is the set of `##` sections your finished `AGENTS.md` must26have, with `<…>` slots and a few `<!-- … -->` notes. Fill the slots, drop27optional rows/sections that don't apply, strip every `<!-- … -->` note, never28leave an angle bracket. The skeleton is *what to produce*; this file is *how*.2930**Contract: `1`.** Step 7 stamps this number into every `AGENTS.md` it writes.31Increment it by one only when a change here or in the skeleton makes an32already-generated file *wrong* — a section added, renamed or retired, a ritual33changed, a tool name dropped; never for wording. A repo whose stamp is lower34gets the full arc, and you name the contract its config came from.3536It is a plain counter, and deliberately neither a date nor the plugin's37version. A date cannot express two changes in one day — it happened, and the38second change had no way to announce itself. The release version moves on every39release, including ones that touch no skill here, so stamping it would mark40every generated config stale after any release at all; a staleness signal that41fires constantly stops being read. This counter is the template's own and moves42only when the template's output goes wrong. **A config stamped with a date43predates this scheme** — treat it as lower than any number and run the full arc.4445The skeleton deliberately *inlines* repo-agnostic agent-discipline (Working46principles, parts of Session lifecycle) into every generated `AGENTS.md` so the47file stands alone for agents with no NKS access. Keep it inline — don't replace48it with a pointer to the methodology realm even though it duplicates content49there.5051## Audit → classify → act (not fresh-vs-existing)5253A repo is never simply *fresh* or *configured* — it's a spectrum, and the trap is54"a file exists, therefore its facts are true." Don't branch on whether55`AGENTS.md` / `CLAUDE.md` / `.claude/` exists. Instead **audit every concern56against its source of truth and classify it**:5758- **absent** — no claim yet → derive it from the source (or, for an authored59 slot with no checkable source, ask the user).60- **stale** — a claim exists but disagrees with its source → re-project from the61 source, overwriting the stale text. Do not carry it forward just because it was62 written down.63- **correct** — claim matches source → leave it.6465Run this per concern using the source map below. "Fresh repo" is just66*everything absent*; a mature repo is a mix — and most dangerous when67*mostly-correct*, because the few stale lines hide among trusted ones (this is68why the verify pass is whole-artifact, Step 7). For authored slots with no69checkable source, *absent* → ask the user; never invent.7071### Source of truth per concern72Each claim class has one authority. Verify there — don't recall:7374| Concern | Source of truth | How to check |75|---|---|---|76| Versions, dependencies | `package.json` / `pyproject.toml` / `go.mod` / `Cargo.toml` + lockfile | read |77| Build/test/lint/dev commands | `package.json` scripts, `Makefile`/`Justfile`, CI workflow | read; run `--help`/dry-run where cheap |78| Quality gate (strictness, max-warnings) | linter config, `tsconfig`, CI yaml | read |79| Project structure, path aliases | filesystem + `tsconfig`/bundler config | glob / list |80| Nature, production statement, relaxations | the user (authored) | confirm in conversation |81| Reality carriers + how to observe them | the user (authored) | confirm in conversation — never derive |82| Design decisions, why-clauses, open questions | NKS | `nks_orient` / `nks_search` |83| Branch state, what's runnable | git + `HANDOVER.md` | `git status` / `log` |84| Gotchas | authored (past pain) | sanity-check only — don't auto-derive |8586Two kinds of line, handled differently: **derived facts** (upper rows) are87re-projected from source every run — never preserved when stale; **authored88judgment** (lower rows — gotchas, why-clauses, nature) lives nowhere else —89preserve it, only sanity-check it against the code.9091## The output contract — density and accuracy9293`AGENTS.md` is read *every session*, so it must be both **dense** and **true** —94co-equal, not form-first. Accuracy is operationalized above (audit/classify each95concern against the source map) and below (verify pass, Step 7). The density half96is these five rules:971. **Imperative, addressed to the agent.** "Orient before coding," not "the98 agent should orient."992. **Density rule.** Every line must change what the agent *does*. If deleting a100 line wouldn't change behavior, delete it. Reads like a checklist, not an101 essay — no motivation, no aphorisms, no victory laps.1023. **No design rationale, no duplication of NKS.** The *why* behind a decision103 lives in NKS (vimarshas) — link, don't restate. `AGENTS.md` is a `reference`104 artifact (shabda); narrative in it sets up a second source of truth that105 drifts from NKS and misleads future agents. Keep a terse `(why: …)` clause106 *only* for an invariant a future agent would otherwise violate — a code-level107 gotcha or non-obvious constraint, never a design justification.1084. **Tables and bullets over paragraphs.** One directive per bullet.1095. **No length target** — but a section that runs to paragraphs is almost always110 carrying rationale that belongs in NKS. Move it there.111112**Out of scope — orchestration mechanics.** `AGENTS.md` addresses one agent in113one session. Build-gating chains, sub-agent push verification, model-routing,114multi-lane coordination don't belong here — inlining them violates the density115rule for the solo reader. Home: a dedicated orchestration/scheduler skill or the116methodology realm — except the sub-agent delegation slice, which this skill117projects as role files (Step 6, `references/delegation.md`), never as AGENTS.md118prose. Link if needed, don't inline.119120Worked example — same `## Code conventions` entry, bad (narrative) vs good121(AI-first):122- ❌ "We try to be careful about state because this is a demo and the store is123 the only place data lives, so it's important that components read it correctly124 when the persona changes, otherwise the demo can look broken."125- ✅ "Persona-scoped UI reads role via `use-acting-context`; re-check render on126 persona switch. (why: store is the only data source — a stale read shows127 wrong-role data.)"128129The good version is a directive + one invariant clause. The bad version is three130sentences of rationale that belong in an NKS vimarsha.131132## Procedure133134Idempotent throughout: in a mature repo, run each self-check and act only on135failures; report what's still outstanding.136137**Quick mode — first contact only.** The full run is a heavy first thing to meet138after a restart, before the newcomer has seen anything worth the cost. On a repo's139*first* verstakify, unless the user asked for the full pass: run **Step 2** (realm,140focus holon, agent karta) plus a **skeleton `AGENTS.md`** of the slots you can141derive without asking, then hand over to the roadmap teaser (Step 7's baton).142Defer Steps 1, 3, 4, 6 in one line — "gate, hooks and the interview are deferred —143say `verstakify` again for the full pass." Two rules keep it honest: never write a144*derived* line you haven't checked (an unasked authored slot stays absent, never145guessed), and always name what was deferred. Every later run is the full arc.146147**A deferred authored section is declared, not dropped** — *Reality* and *Shared148surfaces* especially, because other sections point at them. Keep the heading and149write one real line under it — *"Not settled yet: run the interview (say150verstakify) before accepting any behavioral claim here."* — not a slot, so the151no-angle-brackets check still passes. An absent section reads as "nothing to152check here", the opposite of true, and leaves the pointers in *Session lifecycle*153and Working principles 4 and 6 aimed at nothing.154155### Step 1 — Settle with the user (do first)156Don't silently pick defaults. Confirm in conversation, then write into *What this157project is*: **Nature** (and, if not `production`, which principles are relaxed +158why), **NKS realm name** (create if missing), **Stack**, **Quality gate**159(propose strictest — Step 3). For an existing repo, infer these from the repo and160the old config first, then confirm only what's ambiguous.161162Also settle **who owns direction**: the realm's owner as a svatantra (主)163karta — created in Step 2 if missing. Out-of-mandate questions will be posed to164it as graph vimarshas (`posed_to`), not chat-only asks.165166Also settle **shared mutable build/test state**: does build or test read or167mutate a shared resource — a database, a fixed port, a dev server, a global168cache, a cloud sandbox? If yes, capture per-lane isolation (per-branch169DB/schema, per-lane port, per-lane temp dir) as a gotcha: agents run branches170concurrently in separate worktrees, and a shared resource corrupts across lanes.171Skip when build/test has no shared mutable state.172173Also settle **shared surfaces**: which components, schemas, contracts or rules174have more than one consumer, and which consumers. Authored slot — a silently175forked component looks like two ordinary files, so the repo can't be grepped for176it. Fills *Shared surfaces*; omit the section only if the answer is genuinely177nothing.178179Also settle **reality** — what a claim here is verified *against*; fills the180*Reality* table. A code repo, a data repo and an infrastructure repo answer this181differently, so derive nothing, ask: where a change lands, what effects it182produces, which of them are observable and with exactly what command / URL /183query, and what the agent reaches alone versus what needs the user. Press for184the *canonical carrier* of each claim class — the built artifact, not the185sources; the live endpoint, not the handler; a clean install, not a warm cache.186A class with no reachable observation goes under *Ceiling* with its reason,187never left as an aspirational row.188189Also settle **cross-project memory** — ask once per *user*, not per repo (a190previous verstakification's answer is reusable): does the user want what191outlives any single repo to persist — the personal realm `@<handle>/mind` for192user facts, and a globally injected preferences file ("how to act with me":193`~/.claude/CLAUDE.md`, `~/.config/opencode/AGENTS.md`) for standing194instructions? **Yes** → establish the layer: bootstrap the realm (**minding**195§3) and the preferences file (create if absent, one source linked across the196harnesses the user runs); the generated routing keeps its personal-realm197branches, and the memory-guard message keeps its minding route. **No** → the198routing is repo-scoped: project facts to this repo and its realm, everything199else stays session-local — the personal-realm branches, the preferences200clause, and the minding route in the guard message are omitted. Never assume201the layer exists because the harness has a slot for it.202203Also settle **workflow-suite coexistence** (only when a coercive workflow suite204is detected — its skills appear in the skills list, or its dir exists in the205plugin cache, e.g. `~/.claude/plugins/`; today that means superpowers): tell206the user what was found and settle the mode:2071. **Full interop** (recommended) — AGENTS.md gets the interop subsection208 (from this skill's `references/superpowers-interop.md`) + the spec-write209 hook (Step 4);2102. **Prose-only** — the subsection, no spec-write hook;2113. **Skip** — no coexistence text (not recommended; note the risk: design212 sessions led by the suite won't persist to the realm by default).213214### Step 2 — NKS bootstrap215- Realm exists? If not: agree a name, then `nks_realm(action="create")`.216- If the project has structure beyond the realm itself, a focus holon exists217 (named after the project's boundary, `contains`-linked from the realm root),218 and its `#seq` goes into *What this project is*. Design the boundary with the219 `design` skill, create with `nks_add_holon`.220- **The doer becomes a steward.** Create the repo's agent karta221 (`nks_add_karta`, `manifested_as=adhikarin`, motivation distilled from the222 Production statement) and draw its `steward` edge to the focus holon — an223 adhikarin without a steward edge is a live warning ("acts but answers for224 nothing"). Create the owner's svatantra karta if Step 1 found none, and bind225 it to the human it stands for — `user="me"` when the owner is the person226 running this, otherwise their `sub` from `nks_admin(action="list_members")`.227 That binding is what makes the owner findable across every repo they own228 (**minding** §4); without it their roles stay unlinked per realm. Record both229 seqs in *What this project is* — the doc slot is the only path an agent can230 rely on.231232### Step 3 — Quality gate (propose strictest, user confirms)233For each: propose the strictest sensible option for the stack, a one-line234trade-off, await confirmation. Default strict; relaxations need an explicit ask,235calibrated to cost-of-breakage from *What this project is* and recorded there236per-tool.237238**Tightening an existing gate is not free.** On a mature repo whose gate is239already relaxed, `max-warnings 0` is not a checkbox — it commits the user to a240refactor. Before proposing to tighten, *measure*: run the linter/typechecker at241the proposed strictness, count the failures, and show that cost. Tightening an242already-relaxed gate needs the same explicit ask as a relaxation — and may belong243in a follow-up branch, not the bootstrap.244- **Linter**, max strict (e.g. `@typescript-eslint/strict`; Ruff245 `E,F,B,I,N,UP,RUF`; `golangci-lint` broad; `clippy -- -D clippy::pedantic`).246- **Formatter**, auto-fix on save + pre-commit (Prettier, `ruff format`,247 `gofumpt`, `rustfmt`).248- **Type checker**, strict, if the stack has one (`tsc --strict`, `mypy249 --strict` / `pyright --strict`).250- **Pre-commit hook**: linter + formatter + typecheck on staged files.251- **Test framework + discipline** (unit for libraries; +integration for252 services; +e2e for UI; coverage threshold for production). Record in *Code253 conventions*.254- **CI**: lint + typecheck + tests on every push, fails on warnings. Mandatory255 for `production`.256- **CI parity**: any check that can *fail* must gate PRs, not just post-merge.257 Audit the workflows for jobs scoped to push-`main`/release only (codegen,258 schema/API-spec/docs generation, image or bundle build, migration check) — a259 post-merge-only check lets two individually-green PRs break `main` after merge.260 Tighten it to also run on PRs; record any gap you can't close now as a gotcha.261262Write commands into *Commands*, discipline into *Code conventions*.263264### Step 4 — Hooks265**The deliverable is the rituals, not the file.** Detect which harness the repo266uses and wire *its* surface — Claude Code's hooks file, Codex's `[hooks]` in267`config.toml`, OpenCode's plugin dir — from `references/harness-surfaces.md`,268which carries the verified paths, event names and per-ritual mapping for each.269More than one may be present; wire each. Where a harness has no surface for a270ritual, say which one you couldn't automate — it still binds through the AGENTS.md271*Session lifecycle* prose, which the skeleton inlines for exactly this reason.272Never write a config for a format you're guessing.273274The rest of this step is Claude Code's shape. Three hooks in `.claude/settings.json` (committed — project-wide rituals, every275agent on every clone needs them), plus a conditional fourth — the spec-write276hook — **only when the Step-1 coexistence settle chose full interop** (the277settled mode is recorded in the AGENTS.md interop stamp, Step 7; no subsection278= no settle = three hooks). **Merge, never overwrite:** other suites may279already own entries in this file — add yours alongside theirs in the same280arrays; deleting another suite's hooks breaks its rituals. Generate the JSON for281*this* project — write it yourself:282- **`SessionStart`** → reminder to orient in NKS before acting (skill `entry`),283 naming *this* realm slug, focus holon **and agent karta**: open the doer's284 agenda (`nks_orient(realm, focus="<agent-karta-seq>")`) — incoming `posed_to`285 vimarshas are the session's inbox; pick up or explicitly defer each.286- **`PostToolUse`** with `"matcher": "Bash"` → when the command contains `git287 push`, reminder to **ask which kind of push this was** — where done means288 merged, a push that only opens or updates a PR ships nothing, so it records289 an answer where one genuinely stands and leaves bodies and modes describing290 what the trunk carries (a model written ahead of the merge describes what the291 repo does not have, and a withdrawn PR leaves it lying). After a *merge*:292 update NKS **only from fresh artifact evidence** — confirm293 the canonical changed path and the exposed old requirements were actually294 exercised — then advance the bianhua map and end what the merge settled by axis295 (`addressed_by` records the answer, release is its own act), **sweep the296 shipped contour** (walk the whole designed contour, not only the nodes you297 touched; but a mode flip is itself a claim, so flip what the evidence covers298 and leave the rest as it stands rather than advancing it ceremonially), **work299 the inbox** (the `posed_to` questions the work answered), run the300 after-green-push self-review, **re-read the diff and the nodes for borrowed301 project-management words** — ticket, backlog, sprint, epic, story, done,302 blocker, committed — naming each to the user and asking what this project303 calls it instead of swapping it yourself, and: uningested design/spec docs on304 this branch → intake them (`intake` skill, then `design`) before closing.305 Two things this hook is the natural place for. **Check freshness rather than306 trust it**: branch on the push having actually run, and where the branch no307 longer descends from the trunk — `git merge-base --is-ancestor origin/main308 HEAD` exits nonzero — say so in the same breath. Stale discovered at push309 costs a fetch; discovered at merge it costs whoever integrates. And **phrase310 the merge half as an event**: the reminder fires on a push, but the post-merge311 sequence is owed to the merge signal itself, never to a quiet stretch after it312 — an agent on a live channel never gets one, so a ritual conditioned on calm313 reads as a rule and behaves as none.314 The vocabulary re-read rides *this hook* on purpose: it is the prose ban's315 mechanism, and a ban that lives only in AGENTS.md is the one an agent skates316 past.317- **`PreToolUse`** with `"matcher": "Write|Edit|MultiEdit"` → the **memory-guard318 hook**: when the target path is inside the local project-memory dir, **block319 the write** (exit 2, routing message on stderr) — state lives in the repo,320 the graph, or the user's personal realm, never in local agent memory, and the321 prohibition is by dir rather than by category; the dir stays frozen at its322 prohibition stub (Step 5). Blocking is safe here: the path is unambiguous and323 legitimate writes there are zero by policy. It fires at the exact moment the324 save-instinct does, when AGENTS.md is far behind in the context. Exact JSON325 below.326- **`PostToolUse`** with `"matcher": "Write|Edit"` → the **spec-write hook**327 (full-interop mode only): when the written file path looks like a design/spec328 doc, reminder that the file is a draft view — the graph is the design record.329 Same envelope style, gated on `.tool_input.file_path` the way the push hook330 gates on the command text; exact JSON below.331- **`Stop`** → the **turn-without-a-change** guard. A turn that ends having332 announced what the agent is *about to* do — "I'll start with this one, if333 you don't mind" — ends the agent: no input is due, and it sits dead until334 someone pings it. The norm against this is written and gets violated335 anyway, which is the same shape as the memory rule: what a norm cannot336 catch, a hook fires at the exact moment the instinct does. So this one337 **blocks**, and the exemption is what makes it safe — a turn passes if it338 produced a change (an edit, a command, a node) **or** carries a question339 written where its addressee will find it. Announcing an intention is340 neither. Wire the announcement into the occupation line instead, which is341 where "what I am on" belongs.342343Each hook runs a shell `command` that echoes the hook envelope to stdout. The344nesting (`event → array → {"hooks":[{"type":"command","command":…}]}`) is the345easy part to get wrong:346```json347{ "hooks": { "SessionStart": [ { "hooks": [ { "type": "command",348 "command": "echo '{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"<orient reminder: realm + focus holon>\"}}'" } ] } ] } }349```350The `PostToolUse` entry adds `"matcher": "Bash"` and gates the echo on the351command: `jq -r '.tool_input.command // ""' | grep -q 'git push' && echo '<envelope>' || true`.352This matches the command *text*, so it will also fire on commands that merely353*mention* `git push` (an `echo`, a PR-body heredoc, this very hook's own354validation) — a known false-positive. Harmless for a non-blocking reminder, so355ship it as-is; just never promote this text-match to anything that gates work. To356cut the noise, also branch on `.tool_response` so the reminder fires only when357the push actually ran.358359The memory-guard hook — unlike the reminders it **blocks**: a `PreToolUse`360command that exits 2 stops the tool call and hands Claude the stderr message.361The path is unambiguous (`.claude/projects/<encoded>/memory/`), so false362positives are near zero. The message's last route follows the Step 1363cross-project-memory answer — under **no**, drop the personal-realm sentence:364```json365{ "matcher": "Write|Edit|MultiEdit", "hooks": [ { "type": "command",366 "command": "jq -r '.tool_input.file_path // \"\"' | grep -Eq '\\.claude/projects/.*/memory/' && { echo 'BLOCKED: local agent memory is forbidden entirely, not by category (AGENTS.md, Persistence rules). Route the fact: repo conventions / code facts → AGENTS.md; project state, this project's servers and dated duties → the project realm; a user-scoped fact no project owns → the personal realm @<handle>/mind (minding skill) — drop this route under cross-project-memory=no. This dir stays frozen at its prohibition stub.' >&2; exit 2; } || exit 0" } ] }367```368This entry goes under `"PreToolUse"` — its own event array, not the369`PostToolUse` one.370The spec-write hook (full-interop only), same gating style — a wide behavioral371glob; false positives are harmless for a non-blocking reminder, never promote372it to anything that gates work:373```json374{ "matcher": "Write|Edit", "hooks": [ { "type": "command",375 "command": "jq -r '.tool_input.file_path // \"\"' | grep -qE '(^|/)specs/[^/]+\\.md$|(^|/)docs/.*design[^/]*\\.md$' && echo '{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"A design draft was written; per AGENTS.md this file is a draft view — the graph is the design record. Intake it (intake skill, then design skill) in this session — do not defer to a push.\"}}' || true" } ] }376```377The spec-write entry merges into the same `PostToolUse` array as the git-push378hook — sibling objects, not replacements; the memory guard lives in its own379`PreToolUse` array.380381Self-check: all three base hooks present, and the spec-write hook present382**iff** the AGENTS.md interop stamp says `full` (absent stamp or `prose-only` →383it must NOT be wired — don't re-add it on refresh); `SessionStart` names the384real realm slug, focus holon and agent-karta seq, not placeholders; no385pre-existing hook entry from another suite was dropped by the merge.386387Heads-up: writing `.claude/settings.json` may be flagged by the harness as388self-modification and require explicit approval — surface the write for389confirmation rather than assuming it lands silently.390391### Step 5 — Repo hygiene392- Commit `.claude/settings.json`; ignore `.claude/settings.local.json` via393 `.gitignore`. If `.claude/` is broadly ignored, add an explicit un-ignore:394 `!.claude/settings.json`. Verify with `git check-ignore -v395 .claude/settings.json .claude/settings.local.json`.396- **Tracked secret/env files**: run `git ls-files '.env*' '*secret*' '*local*'`.397 If a real env/secret file is tracked (not just an `.example`), warn in *Code398 conventions*: never stage local edits — `git update-index --skip-worktree399 <file>`, never `git add -A` / `commit -a` (an agent editing a tracked env file400 otherwise leaks it into the PR).401- Local project-memory dir (`~/.claude/projects/<encoded-path>/memory/`):402 audit and **evacuate** it, then freeze it. Nothing keeps a place there —403 the prohibition is by dir, not by category. Project state (decisions,404 constraints, branch state, gotchas) → AGENTS.md / HANDOVER.md / NKS; this405 project's servers and dated duties → its realm; the user's own holdings406 (personal machines, expiries, people, cross-project findings) → the user's407 personal realm (**minding**) — but only under the Step 1 cross-project-memory408 answer **yes**; under **no** they stay in the repo's AGENTS.md if this repo409 must keep them, otherwise they are dropped with the user's knowledge.410 Working-style preferences are instructions, not facts: → the globally411 injected instruction file (minding §3 establishes it), never a node. Then412 freeze: `MEMORY.md` becomes a one-line413 prohibition stub («project state lives in the repo or the graph — see414 AGENTS.md, Persistence rules»), and the memory-guard hook (Step 4) blocks415 any further write at the moment the save-instinct fires. Evacuate before you416 freeze — a stub over unread content destroys what it was meant to relocate.417 Reason: reproducibility + multi-machine, multi-agent work — local memory is418 invisible to every other agent and machine.419- **The forge and its CLI — derive it, never assume GitHub.** Read `git remote420 -v`; the host decides the tool (`gh` GitHub, `fj` Forgejo/Codeberg, `glab`421 GitLab, `tea` Gitea). Check it is installed and authenticated, then name it in422 *Git workflow* together with its watch command. This is not cosmetic: opening423 the PR is the one hand-off step the agent owns outright, and an agent that424 can't name the tool turns it back into a question for the user. An425 unrecognized self-hosted host → ask which CLI they use; never guess `gh`426 because it is the one you know.427- *Stack*, *Commands*, *Project structure*, *Code conventions* hold real content428 proportional to maturity. Empty is fine day one; `TBD` is not.429- `HANDOVER.md` exists only if feature-branch work is in flight.430- `README.md` is short, human-facing, and doesn't duplicate AGENTS.md.431432### Step 6 — Subagent delegation roles433Project the delegation doctrine as **named role agents**, not as AGENTS.md434prose (orchestration mechanics stay out of AGENTS.md — the output contract435above). Doctrine + file templates: `references/delegation.md` (relative to436this skill).437- Always: `.claude/agents/reader.md` (cheap-tier recon),438 `.claude/agents/worker.md` (mid-tier brief execution), and439 `.claude/agents/verifier.md` (cold falsification-first acceptance audit).440 Use stable aliases for reader/worker (`haiku`/`sonnet`); resolve a supported441 top/session model for verifier rather than inheriting a cheap tier. The442 verifier is projected even where the repo has no runtime yet — it is what443 makes the *Reality* table actionable, and a repo that gains a carrier later444 should not need a re-run to gain its acceptor.445- When the repo shows OpenCode use (`opencode.json` / `.opencode/` present, or446 the user says so): `.opencode/agents/reader.md` + `worker.md` + `verifier.md`,447 `mode: subagent`, model **pinned** per file — an unpinned OpenCode subagent448 inherits the invoking primary's model, so the pin is the point, and on the449 verifier it decides whether acceptance is real. Resolve450 current `provider/model-id`s from the user's setup (ask, or read451 `opencode.json` / the global config); never hardcode from the reference.452- The `description` fields are the delivery channel — they sit in the453 agent/task tool list every session, so the routing trigger fires without any454 skill load. Keep them trigger-shaped: when to use, what comes back, what NOT455 to trust it with.456- Open-ended judgment (design, synthesis, exploratory review) gets no role457 file — it stays with the session model or a per-call top-tier override.458 `verifier` is the narrow exception: frozen claims and a falsification-first459 return contract make acceptance review delegable without delegating judgment460 about what the product should mean. It is also an expensive role: use it461 only for load-bearing claims where independent falsification can change462 acceptance.463- **Merge, never overwrite**: a same-named `reader` / `worker` / `verifier`464 agent file from another suite may already exist — fold your body/description465 in or rename yours (`verstak-reader`); the same rule the hooks merge follows.466- Self-check: role files parse (frontmatter); pinned models exist in the467 user's setup; AGENTS.md carries **no** inlined delegation doctrine (a468 pointer at most); no pre-existing agent file was overwritten.469470### Step 7 — Finalize471- Write the filled body to **`AGENTS.md`** — the vendor-neutral canonical name,472 which Codex and OpenCode read natively. **A pointer file is Claude Code's473 requirement alone** (it reads `CLAUDE.md`, not `AGENTS.md`); don't create one474 for a harness that doesn't need it. Two isomorphic forms, chosen by whether475 symlinks survive the checkout — decide by `git config core.symlinks` plus the476 platform, don't assume:477 - **Symlinks work (POSIX default):** `ln -s AGENTS.md CLAUDE.md`. One file,478 two names — nothing to keep in sync, and any tool reading `CLAUDE.md`479 literally gets the real content, not an import directive.480 - **Symlinks don't (Windows, `core.symlinks=false`):** copy `AGENTS.md` to481 `CLAUDE.md` byte-for-byte. A copy is a second source of truth, so it is482 regenerated on every verstakify run and listed in *What to update when*;483 edits go to `AGENTS.md` and never to the copy. A third form exists — a484 one-line `CLAUDE.md` containing `@AGENTS.md`, Claude Code's import (no485 backticks, a code span suppresses it) — use it where a copy would be worse486 than an import that only Claude Code understands.487 Don't churn a pointer that already works, whichever of the three it is.488 Per-harness specifics, including Codex's root→cwd merge and its489 `AGENTS.override.md` local override, are in `references/harness-surfaces.md`.490- **Legacy config already present** (the common case): use the skeleton as the491 frame and fold existing content in *by line kind* — re-project derived facts492 from their source (don't carry a stale version, command, or path forward just493 because it was written down) but preserve authored judgment (gotchas,494 why-clauses, nature) that has no checkable source, sanity-checking it against495 the code. Project-specific content with no slot moves to *Code conventions* or a496 new section. End with `AGENTS.md` as the one file + `CLAUDE.md` as the pointer497 (whichever of the three forms above the checkout supports) — if a *content-bearing*498 `CLAUDE.md` exists, fold its content into `AGENTS.md` and replace the file499 with the pointer. One source per concern — no duplicate sections.500- If Step 1 settled full interop or prose-only: render the501 `### Workflow-suite interop (superpowers)` subsection at the end of502 `## Session lifecycle`, taking the section text from this skill's503 `references/superpowers-interop.md` (deployable part only — the maintainers'504 re-verify checklist stays in the reference). Stamp it with the plain trailing505 line `*(interop: <full|prose-only> — verified against superpowers@<version> —506 re-check on suite upgrade)*` — the stamp records the settled mode; Step 4 and507 refresh runs read it. On refresh runs, audit the subsection like any other AGENTS.md508 concern: source of truth = the reference file + the installed suite version.509- **Verify pass (co-equal with the density pass):** re-check every *derived* line510 against its source from the map — **whole-artifact, not just the lines you511 touched.** The most dangerous errors sit in untouched, settled-looking lines512 that drift silently because nothing challenges them. A claim you can't tie to a513 source is either authored judgment (keep it, recognize it as such) or a guess514 (cut it).515- **Density pass:** for every body line ask "does this change what the agent516 does?" Cut narrative, motivation, design rationale (rationale → NKS).517- Drift between runs is guaranteed — the doc goes stale the moment code changes.518 verstakify re-verifies only when re-run; an automatic "claimed vs actual" check519 hook (e.g. doc versions vs `package.json`) is a **settled non-default** —520 generic prose-vs-source parsing is brittle, throws false positives, and the521 checker drifts alongside the doc it guards. Re-running verstakify is the522 discipline. A narrow per-repo checker on named lines is the only shape worth523 building; never a generic one.524- **Stamp the contract.** Trailing line of `AGENTS.md`: `*(verstakify: contract525 <the number from the top of this file> — re-run when the installed contract is526 higher, or when the sources this file derives from have moved since.)*` On a527 refresh, overwrite the old stamp; never leave two. A config carrying **no**528 stamp, or one carrying a **date** from the scheme this counter replaced,529 predates the contract — treat it as lower than any number and run the full arc.530- Confirm no `<…>` slot and no `<!-- … -->` note survived into `AGENTS.md`.531- **Every skill name written into `AGENTS.md` must resolve as written.** Check532 each against the live registry you can actually see, the same way tool names533 are checked — never from memory, and never in a form a previous generation534 used. Addressing depends on the install channel (a plugin namespaces its535 skills; a flat unpack leaves them bare), so write the form that resolves on536 the channel this repo declares. A name that cannot be invoked is a defect of537 the projection, not a typo: it raises no error, only a shrug, and the hook538 that pointed at a method keeps firing while the method never runs.539- On the bootstrap push, NKS reflects the change (vimarshas opened/closed,540 the bianhua map advanced).541- **Pass the baton — name the next step, never let the user guess it.** End by542 offering the first visible value: a quick roadmap teaser (`product-roadmap`543 skill, quick mode) over the freshly bootstrapped repo. Say its name, don't544 allude to it. After a quick-mode run the baton is two items in order: the545 teaser, then "say `verstakify` again for the gate, hooks and the interview".546 The chain from setup to first wow breaks wherever the user is expected to547 remember a word across a session restart.