# Verstakify

> 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.

- Skill: `verstak-ai/verstakify` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add verstak-ai/verstakify`
- Raw SKILL.md: https://api.skillmd.com/api/skills/verstak-ai/verstakify/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: verstak-ai (https://skillmd.com/u/verstak-ai)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/verstak-ai/verstakify

---


# 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:
1. **Imperative, addressed to the agent.** "Orient before coding," not "the
   agent should orient."
2. **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.
3. **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.
4. **Tables and bullets over paragraphs.** One directive per bullet.
5. **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:
1. **Full interop** (recommended) — AGENTS.md gets the interop subsection
   (from this skill's `references/superpowers-interop.md`) + the spec-write
   hook (Step 4);
2. **Prose-only** — the subsection, no spec-write hook;
3. **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:
```json
{ "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:
```json
{ "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:
```json
{ "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-id`s 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.

