gm-skill 2.0.1637 → 2.0.1639

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -28,7 +28,7 @@ This repo IS the published `gm-skill` npm package: repo root = package root, no
28
28
 
29
29
  The plugkit stack runs as a wasm cdylib loaded by `plugkit-wasm-wrapper.js` under Node/bun -- no native binaries built, downloaded, or published. The shipped `plugkit.wasm` is fetched at bootstrap from `plugkit-wasm` npm / `plugkit-bin` gh-releases, sha256-pinned. Size + embedded-model (offline in-wasm embeddings) mechanics in rs-learn (`recall: WASM-only plugkit size mechanics`).
30
30
 
31
- **Every wasm host-import `extern "C"` block carries `#[link(wasm_import_module = "env")]`** -- in rs-plugkit AND every dep crate linked into the cdylib (rs-learn) AND any sibling building wasm (rs-exec, rs-search); miss it anywhere and the cascade goes dark (local builds stay green, only Linux CI link fails). Incident + host-fn enumeration in rs-learn (`recall: cascade outage wasm import module link`, `recall: wasm host-import link-module trap`).
31
+ Wasm host-import link-module rule (`#[link(wasm_import_module="env")]` on every host-import extern block, every dep crate): rs-learn (`recall: wasm host-import link-module trap`).
32
32
 
33
33
  **`plugkit-wasm-wrapper.js` is ESM; import node builtins at module scope, never inline `require()`** (rs-learn: `recall: wrapper require not defined under bun`).
34
34
 
@@ -62,7 +62,7 @@ Record only non-obvious technical caveats that cost multiple runs to discover; r
62
62
 
63
63
  **No UTF-8 BOM in any tracked source file** -- always `-Encoding utf8` (no BOM) or the `Write` tool; PowerShell defaults betray this. `test.js checkNoBom()` is the structural guard; one sighting spawns the full-tree sweep. Cause + breakage mechanics in rs-learn (`recall: BOM regression incident`).
64
64
 
65
- **No graphical symbols; convert to industry-standard text on sight.** Any non-ASCII decorative glyph (arrows, box/geometric glyphs, stars, dots, bullets, checks/crosses, emojis) is forbidden in all output and source -- convert it to its plain-ASCII equivalent the same turn (the word, `->`, `-`/`*`, `[x]`/`[ ]`, done/todo/pass/fail). Tell-tale-AI class: one sighting spawns the full-codebase sweep, never a one-off edit. Exempt: functional code operators (`=>`, `??`, `?.`, comparison/math), frozen changelog/git-log entries, binary stores, intentional icon-font/CSS-content product glyphs. `ccsniff --glyph-discipline` flags decorative glyphs post-hoc (run each audit, like `--git-discipline`/`--search-discipline`).
65
+ **No graphical symbols; convert to industry-standard text on sight.** Any non-ASCII decorative glyph (arrows, box/geometric glyphs, stars, dots, bullets, checks/crosses, emojis) is forbidden in all output and source -- convert it to its plain-ASCII equivalent the same turn (the word, `->`, `-`/`*`, `[x]`/`[ ]`, done/todo/pass/fail). Tell-tale-AI class: one sighting spawns the full-codebase sweep, never a one-off edit. Exempt: functional code operators (`=>`, `??`, `?.`, comparison/math), frozen changelog/git-log entries, binary stores, intentional icon-font/CSS-content product glyphs, and canonical CS/formal-logic notation in `.gm/constraints.md` / `gm-plugkit/constraints-default.md` (`.`, `->` as function-space, `|-`, set/quantifier symbols) -- these are semantic operators in a formal constraints spec, not decorative flourish. `ccsniff --glyph-discipline` flags decorative glyphs post-hoc (run each audit, like `--git-discipline`/`--search-discipline`).
66
66
 
67
67
  **Skill SKILL.md files:** strip explanatory prose; keep ONLY invocation syntax, transition markers (`->`), gate conditions, constraint lists, exact-usage code examples.
68
68
 
@@ -76,7 +76,7 @@ No build step; the repo root is the published artifact. `npm publish` from root
76
76
 
77
77
  ## The agent is the orchestrator; plugkit is the brain it drives
78
78
 
79
- Plugkit is the stateful library the agent drives by dispatching verbs -- it does not act autonomously, advance phases in the background, or validate transitions while the agent waits. Every state change is a verb the agent writes into `.gm/exec-spool/in/<verb>/<N>.txt`; the dispatch ledger is ground truth, so zero dispatches with a narrated PLAN->COMPLETE walk = a fabricated walk. The PLAN -> EXECUTE -> EMIT -> VERIFY -> COMPLETE state machine lives natively in rs-plugkit (phase/mutables/memorize/transition-legality as data + gate checks), but the agent triggers every operation; plugkit is synchronous from the agent's view, so polling the output dir instead of reading the response file is the canonical misuse. File paths + verb enumeration in rs-learn (`recall: rs-plugkit state-machine internals`).
79
+ Plugkit is the stateful library the agent drives by dispatching verbs -- it does not act autonomously, advance phases in the background, or validate transitions while the agent waits. Every state change is a verb the agent writes into `.gm/exec-spool/in/<verb>/<N>.txt`; the dispatch ledger is ground truth, so zero dispatches with a narrated PLAN->COMPLETE walk = a fabricated walk. The PLAN -> EXECUTE -> EMIT -> VERIFY -> CONSOLIDATE -> COMPLETE state machine lives natively in rs-plugkit (phase/mutables/memorize/transition-legality as data + gate checks), but the agent triggers every operation; plugkit is synchronous from the agent's view, so polling the output dir instead of reading the response file is the canonical misuse. CONSOLIDATE owns git-push + CI/CD validation, split off the COMPLETE gate so COMPLETE checks only the consolidated result. File paths + verb enumeration in rs-learn (`recall: rs-plugkit state-machine internals`).
80
80
 
81
81
  ## gm is the canonical universal harness
82
82
 
@@ -172,9 +172,11 @@ Orchestration state is tracked via `.gm/` marker files, not hook events; the CLI
172
172
 
173
173
  **A stop-hook firing on a terminal chain does not authorize re-polling**: when a stop-hook fires while already at `phase=COMPLETE` AND `prd_pending_count=0`, re-dispatching `instruction`/`phase-status` to "re-confirm" is a deviation (`deviation.complete-chain-poll`, `instructions/mod.rs`). Two admissible responses: (a) a prose-only turn (COMPLETE is in hand), or (b) genuinely new planned work opened with a FRESH `{"prompt":...}` body (resets phase to PLAN, driven through the skill). Repeatedly answering the same hook is a loop; state the terminal facts once and stop, or open new work.
174
174
 
175
- **Session lifecycle**: background tasks + browser sessions persist across turn-stops; cleanup fires only on real-exit reasons; residual-scan fires when PRD empty AND no open browser sessions AND no running tasks. Detail in rs-learn (`recall: session lifecycle killSessionTasks residual-scan`).
175
+ Session lifecycle (task/browser persistence across turn-stops, residual-scan trigger conditions): rs-learn (`recall: session lifecycle killSessionTasks residual-scan`).
176
176
 
177
- **Browser session state is rooted at the git common dir, never `process.cwd()`**: a workflow worktree fan-out runs each parallel agent in its own worktree (distinct cwd); keying the browser ports-registry + profile dir on cwd opens one chromium per worktree (the "meant one, got N browsers" defect). `browserRootDir(cwd)` resolves the worktree to its main repo via `git rev-parse --git-common-dir`, and `browserStateDir`/`sessionProfileDir`/`acquireProfileDir` route through it, so all worktrees of one workflow share ONE browser while separate repos stay isolated. The cross-agent spawn is guarded by an atomic O_EXCL single-flight lock (loser attaches to the winner's chromium). Detail in rs-learn (`recall: browser session state worktree common-dir rooting`).
177
+ Browser session state roots at the git common dir, never `process.cwd()` (worktree fan-out shares one chromium, not N): rs-learn (`recall: browser session state worktree common-dir rooting`).
178
+
179
+ **Per-project `.gm/constraints.md` is the standing decision arbiter**: seed-if-absent (bootstrap copies the bundled CS-constraints default only when missing), never overwrite on re-seed -- it is user-editable mutable config, same contract as `.gm/next-step.md`. Every design/code decision the agent makes gauges against it; the pointer rule lives in SKILL.md, this is only the existence/mechanism note. `test.js` witnesses both the seed and the no-clobber idempotency.
178
180
 
179
181
  ## Spool observability surface
180
182
 
package/README.md CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  > **more coushin' for the puhin'**
4
4
 
5
- **glootius maximus** (gm) exists to raise one number: the signal-to-noise ratio (SNR) of a coding agent. every failure an agent commits, narrating an unverified guess, forgetting a decision, shipping a placeholder, stopping early, is noise injected into the channel between what you asked and what gets built. gm is a skill that convinces your coding agent it already is a deterministic state machine, PLAN -> EXECUTE -> EMIT -> VERIFY -> COMPLETE, and then enforces that conviction with a wasm-backed orchestrator, witnessed execution, and a covering family of bounded subsets that refuses to let "follow-up" become a synonym for "I gave up." every rule in it is one more noise source removed.
5
+ **glootius maximus** (gm) exists to raise one number: the signal-to-noise ratio (SNR) of a coding agent. every failure an agent commits, narrating an unverified guess, forgetting a decision, shipping a placeholder, stopping early, is noise injected into the channel between what you asked and what gets built. gm is a skill that convinces your coding agent it already is a deterministic state machine, PLAN -> EXECUTE -> EMIT -> VERIFY -> CONSOLIDATE -> COMPLETE, and then enforces that conviction with a wasm-backed orchestrator, witnessed execution, and a covering family of bounded subsets that refuses to let "follow-up" become a synonym for "I gave up." every rule in it is one more noise source removed.
6
6
 
7
7
  that orientation is also why gm is built for token austerity: every token an agent spends should be signal toward the work, never narration, hedging, or busy-output. austerity is SNR enforced at the budget.
8
8
 
9
- it is named after **glootius maximus**, the muscle that holds you in the chair while you finish the work. the name is the joke and the discipline at once: the agent that sits down through PLAN -> EXECUTE -> EMIT -> VERIFY -> COMPLETE actually ships. the agent that stands up early ships a stub with a green check on it.
9
+ it is named after **glootius maximus**, the muscle that holds you in the chair while you finish the work. the name is the joke and the discipline at once: the agent that sits down through PLAN -> EXECUTE -> EMIT -> VERIFY -> CONSOLIDATE -> COMPLETE actually ships. the agent that stands up early ships a stub with a green check on it.
10
10
 
11
11
  built over 14000+ hours of supervised modification, across ~200 commits of daily use, every one of those hours spent tuning the same target: more agentic signal, less noise. free, open source, maintained by one person.
12
12
 
@@ -78,7 +78,7 @@ The two npm packages this repo publishes:
78
78
 
79
79
  ### the state machine
80
80
 
81
- PLAN -> EXECUTE -> EMIT -> VERIFY -> COMPLETE. Every transition is a verb the agent dispatches by writing to `.gm/exec-spool/in/<verb>/<N>.txt`. The wasm orchestrator (rs-plugkit) services it and writes the response to `.gm/exec-spool/out/`. The agent reads, follows the imperative prose, dispatches the next verb. The chain isn't complete until `transition to=COMPLETE` returns COMPLETE phase AND the commit is pushed to origin.
81
+ PLAN -> EXECUTE -> EMIT -> VERIFY -> CONSOLIDATE -> COMPLETE. Every transition is a verb the agent dispatches by writing to `.gm/exec-spool/in/<verb>/<N>.txt`. The wasm orchestrator (rs-plugkit) services it and writes the response to `.gm/exec-spool/out/`. The agent reads, follows the imperative prose, dispatches the next verb. CONSOLIDATE owns git-push + CI/CD validation, split off the COMPLETE gate. The chain isn't complete until `transition to=COMPLETE` returns COMPLETE phase AND the commit is pushed to origin.
82
82
 
83
83
  ### tools
84
84
 
package/bin/bootstrap.js CHANGED
@@ -86,6 +86,17 @@ function ensureNextStepWiring(cwd) {
86
86
  }
87
87
  } catch (e) { obsEvent('bootstrap', 'next-step.wiring.target-failed', { target: nextStepPath, error: e.message }); }
88
88
 
89
+ const constraintsPath = path.join(gmDir, 'constraints.md');
90
+ try {
91
+ if (!fs.existsSync(constraintsPath)) {
92
+ const defaultSrc = path.join(__dirname, '..', 'gm-plugkit', 'constraints-default.md');
93
+ if (fs.existsSync(defaultSrc)) {
94
+ fs.writeFileSync(constraintsPath, fs.readFileSync(defaultSrc));
95
+ changes.push('seeded .gm/constraints.md');
96
+ }
97
+ }
98
+ } catch (e) { obsEvent('bootstrap', 'next-step.wiring.target-failed', { target: constraintsPath, error: e.message }); }
99
+
89
100
  const claudeMdPath = path.join(cwd, 'CLAUDE.md');
90
101
  try {
91
102
  if (!fs.existsSync(claudeMdPath)) {
@@ -112,6 +112,17 @@ function ensureNextStepWiring(cwd) {
112
112
  }
113
113
  } catch (e) { obsEvent('bootstrap', 'next-step.wiring.target-failed', { target: nextStepPath, error: e.message }); }
114
114
 
115
+ const constraintsPath = path.join(gmDir, 'constraints.md');
116
+ try {
117
+ if (!fs.existsSync(constraintsPath)) {
118
+ const defaultSrc = path.join(__dirname, 'constraints-default.md');
119
+ if (fs.existsSync(defaultSrc)) {
120
+ fs.writeFileSync(constraintsPath, fs.readFileSync(defaultSrc));
121
+ changes.push('seeded .gm/constraints.md');
122
+ }
123
+ }
124
+ } catch (e) { obsEvent('bootstrap', 'next-step.wiring.target-failed', { target: constraintsPath, error: e.message }); }
125
+
115
126
  const claudeMdPath = path.join(cwd, 'CLAUDE.md');
116
127
  try {
117
128
  if (!fs.existsSync(claudeMdPath)) {
@@ -2,7 +2,7 @@
2
2
 
3
3
  YOU are the state machine. Plugkit is the synchronous library serving this prose; advancing the chain is your dispatch, not its action. It holds phase, PRD rows, and mutables on disk -- you read them via `phase-status`/`instruction` and change them via the relevant verb. Nothing advances while you wait.
4
4
 
5
- Your authorization = the request. Your receipt = the PRD you write. Trajectory PLAN -> EXECUTE -> EMIT -> VERIFY -> COMPLETE, one continuous flow, each transition a verb you dispatch. Scope = the closure of the destructive transform admissible over the session; your first emit = closure, not prefix.
5
+ Your authorization = the request. Your receipt = the PRD you write. Trajectory PLAN -> EXECUTE -> EMIT -> VERIFY -> CONSOLIDATE -> COMPLETE, one continuous flow, each transition a verb you dispatch. CONSOLIDATE owns git-push + CI/CD validation, split off the COMPLETE gate. Scope = the closure of the destructive transform admissible over the session; your first emit = closure, not prefix.
6
6
 
7
7
  **Continuation invariant (the brick wall).** A turn ending without a tool call is a stop -- the harness reads only tool calls, so a prose-only message ends the session. While in-flight (phase != COMPLETE OR prd_pending > 0) end every turn in a verb dispatch, never prose, never a summary/recap (summary is a stop) -- and never a turn-final sentence that names the next move instead of making it (it strands the chain where the prose pointed; take the move). Only this surface returning phase=COMPLETE AND prd_pending=0 authorizes stopping. Before any urge to stop, dispatch `phase-status`; non-terminal means drift, so dispatch `instruction` and keep walking. Depends only on the verb spool -- holds on every agent. Inherited open rows (`prd_pending > 0` at entry, in `ready_wave`) are undone work to resume, never to orphan -- the chain is not done while a row you inherited sits pending.
8
8
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-plugkit",
3
- "version": "2.0.1637",
3
+ "version": "2.0.1639",
4
4
  "description": "Bootstrap and daemon-spawn tool for gm plugkit binary. Downloads the correct platform binary, verifies SHA256, and starts the spool watcher daemon. Includes plugkit-wasm-wrapper for WASM-based spool watching.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -1549,16 +1549,10 @@ function decodeWasmResult(instance, result, where) {
1549
1549
 
1550
1550
  function writeWasmInput(instance, bytes, where) {
1551
1551
  if (bytes.length === 0) return 0;
1552
- // COERCE the alloc pointer to UNSIGNED 32-bit: a wasm i32 return with the high bit set (a pointer
1553
- // > 0x7fffffff, which occurs once the linear memory grows past ~2GB in a long session) arrives in JS
1554
- // as a NEGATIVE number, and new Uint8Array(buffer, negativePtr, len) throws the raw V8 "Start offset
1555
- // <neg> is outside the bounds of the buffer" -- the deterministic long-session corruption that blocked
1556
- // dispatches. >>>0 reinterprets the i32 as the true unsigned offset. Guard the range too so a genuinely
1557
- // bad (ptr,len) raises the clean wasm-memory-read-out-of-bounds error instead of a raw typed-array throw.
1558
1552
  const ptr = instance.exports.plugkit_alloc(bytes.length) >>> 0;
1559
1553
  if (ptr === 0) throw new Error(`wasm-alloc-failed at ${where}: plugkit_alloc returned 0 (wasm OOM)`);
1560
1554
  guardWasmRange(instance.exports.memory.buffer, ptr, bytes.length, `${where}:writeWasmInput`);
1561
- new Uint8Array(instance.exports.memory.buffer, ptr, bytes.length).set(bytes); // fresh buffer post-alloc
1555
+ new Uint8Array(instance.exports.memory.buffer, ptr, bytes.length).set(bytes);
1562
1556
  return ptr;
1563
1557
  }
1564
1558
 
@@ -1579,8 +1573,6 @@ function readWasmStr(instance, ptr, len) {
1579
1573
 
1580
1574
  function writeWasmBytes(instance, bytes) {
1581
1575
  if (bytes.length === 0) return 0n;
1582
- // >>>0: same signed-pointer fix as writeWasmInput -- a high-bit alloc pointer is negative in JS and
1583
- // throws "Start offset <neg> is outside the bounds" on the Uint8Array write below.
1584
1576
  const ptr = instance.exports.plugkit_alloc(bytes.length) >>> 0;
1585
1577
  if (ptr === 0) return 0n;
1586
1578
  guardWasmRange(instance.exports.memory.buffer, ptr, bytes.length, 'writeWasmBytes');
package/gm.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.1637",
3
+ "version": "2.0.1639",
4
4
  "description": "Spool-dispatch orchestration engine with unified state machine, skills, and automated git enforcement",
5
5
  "author": "AnEntrypoint",
6
6
  "license": "MIT",
@@ -683,6 +683,19 @@ function ensureNextStepWiring(cwd) {
683
683
  emitBootstrapEvent('warn', 'Failed to seed .gm/next-step.md', { error: e.message });
684
684
  }
685
685
 
686
+ const constraintsPath = path.join(gmDir, 'constraints.md');
687
+ try {
688
+ if (!fs.existsSync(constraintsPath)) {
689
+ const defaultSrc = path.join(__dirname, '..', 'gm-plugkit', 'constraints-default.md');
690
+ if (fs.existsSync(defaultSrc)) {
691
+ fs.writeFileSync(constraintsPath, fs.readFileSync(defaultSrc));
692
+ emitBootstrapEvent('info', 'Seeded .gm/constraints.md', { path: constraintsPath });
693
+ }
694
+ }
695
+ } catch (e) {
696
+ emitBootstrapEvent('warn', 'Failed to seed .gm/constraints.md', { error: e.message });
697
+ }
698
+
686
699
  const claudeMdPath = path.join(cwd, 'CLAUDE.md');
687
700
  try {
688
701
  if (!fs.existsSync(claudeMdPath)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-skill",
3
- "version": "2.0.1637",
3
+ "version": "2.0.1639",
4
4
  "description": "Canonical universal harness — AI-native software engineering via skill-driven orchestration; bootstraps plugkit for task execution and session isolation. Install in any AI coding agent host.",
5
5
  "author": "AnEntrypoint",
6
6
  "license": "MIT",
@@ -6,84 +6,94 @@ allowed-tools: Skill, Read, Write, Bash(bun *), Bash(npx *)
6
6
 
7
7
  # gm
8
8
 
9
- **A turn ending without a tool call is a stop; stopping mid-chain is the cardinal failure.** Agents read only tool calls and their outputs, so a prose-only turn ends the session. While the chain is in-flight (phase != COMPLETE OR prd_pending_count > 0) every turn ends in a tool call that advances it (`instruction`, the next verb the prose named, or `transition`). No summaries, no "here's what I did", no narrating closure. A turn-final sentence naming the next move instead of making it is the same stop -- take the move. Surface a decision via `AskUserQuestion` or `prd-add`, never prose. Tempted to stop: dispatch `phase-status`; if non-terminal, dispatch `instruction` and keep walking. Only `phase=COMPLETE` AND `prd_pending_count=0` authorizes a prose-only turn.
9
+ **No tool call = stop; mid-chain stop = cardinal failure.** Agents read only tool calls + outputs -- prose-only turn ends the session. In-flight (phase != COMPLETE OR prd_pending_count > 0): every turn ends in a chain-advancing dispatch (`instruction`, the named next verb, or `transition`). No summaries, no "here's what I did," no closure narration. A turn-final sentence naming the next move instead of taking it is the same stop -- take the move. Surface decisions via `AskUserQuestion` or `prd-add`, never prose. Stop-urge: dispatch `phase-status`; non-terminal -> `instruction`, keep walking. Only `phase=COMPLETE` AND `prd_pending_count=0` authorizes prose-only.
10
10
 
11
- **Done is what plugkit says is done, never your claim.** The COMPLETE gate is the single arbiter; if not at COMPLETE there is a next transition to seek, and idle mid-chain is a deviation.
11
+ **Done = plugkit's word, never yours.** COMPLETE gate is sole arbiter; not-COMPLETE = next transition to seek; idle mid-chain = deviation.
12
12
 
13
- **Standing approval -- finish everything, every session, at maximum granularity.** Every session is pre-approved to continue until ALL requested work is done: the plan, every addition along the way, every newly-discovered or unfinished item. Do not stop to ask whether to continue, do not defer reachable work, do not narrow to a convenient slice. Plan at maximum granularity (one PRD row per real unit; `every possible` on every noun) and walk the whole closure. `blockedBy: external` is for authority you genuinely cannot reach (another team's repo, a hardware credential, a not-in-session product decision) -- never for work that is merely large, tedious, multi-component, or contended by a concurrent writer (rebase and land alongside them).
13
+ **Standing approval: finish everything, max granularity.** Every session pre-approved through ALL requested work -- plan, every addition, every discovered/unfinished item. No stop-and-ask, no deferral, no narrowed slice. Plan max-granular (one PRD row per real unit; `every possible` on every noun), walk the whole closure. `blockedBy: external` = authority genuinely unreachable (another team's repo, hardware credential, off-session product call) -- never for merely-large/tedious/multi-component/contended work (rebase, land alongside a concurrent writer).
14
14
 
15
- **Every possible action begins and ends with `instruction`.** In doubt, denied, or unclear next move: dispatch instruction. It is the only recovery primitive; improvising never beats re-reading the prose.
15
+ **Every action begins and ends with `instruction`.** Doubt, denial, unclear next move: dispatch instruction. Sole recovery primitive; improvising never beats re-reading prose.
16
16
 
17
- **You are the state machine.** Plugkit is durable memory + gate-checker; you walk PLAN -> EXECUTE -> EMIT -> VERIFY -> COMPLETE. Every transition, PRD resolution, mutable witness, residual scan is a verb YOU dispatch by writing `.gm/exec-spool/in/<verb>/<N>.txt`. Plugkit never advances, validates, or processes while you wait -- it serves a response the moment you write a request and sits inert otherwise. Your phase is the one you last `transition`-ed to, not the one your narration implies. Zero dispatches in gmsniff = you hallucinated the chain, not walked it. Drop this and every other rule collapses (mutables resolved without witness, COMPLETE claimed without VERIFY, residuals narrated away).
17
+ **You are the state machine.** Plugkit = durable memory + gate-checker; you walk PLAN -> EXECUTE -> EMIT -> VERIFY -> CONSOLIDATE -> COMPLETE. Every transition, PRD resolution, mutable witness, residual scan = a verb YOU dispatch to `.gm/exec-spool/in/<verb>/<N>.txt`. Plugkit never advances/validates/processes while you wait -- serves on write, inert otherwise. Your phase = last `transition`-ed, not narration-implied. Zero dispatches in gmsniff = hallucinated chain, not walked. Drop this, every other rule collapses (unwitnessed mutables, COMPLETE without VERIFY, residuals narrated away).
18
18
 
19
- Every turn: dispatch `instruction`, read it, follow the imperative, dispatch the next verb it names. Re-dispatch against every drift, stall, gate-denial, or uncertainty -- in-flight it is free to over-dispatch and unbounded-cost to act without. Phase-specific discipline lives in plugkit's instruction tables; this file does not duplicate it.
19
+ Every turn: `instruction`, read, follow imperative, dispatch named verb. Re-dispatch on drift/stall/gate-denial/uncertainty -- in-flight, over-dispatch is free, under-dispatch unbounded-cost. Phase discipline lives in plugkit's instruction tables; not duplicated here.
20
20
 
21
- **Once `phase=COMPLETE` AND `prd_pending_count=0`, the chain is closed -- stop dispatching.** Polling `instruction`/`phase-status` to "re-confirm" a terminal chain is the `complete-chain-poll` deviation. A new user prompt (`{"prompt":"..."}`) reopens the chain to PLAN; if your first `instruction` on intended-new work still returns COMPLETE/UPDATE-DOCS, dispatch `transition to=PLAN` **once** (this is authorized new work, not a poll).
21
+ **Every decision gauges against `.gm/constraints.md`.** Read it (seed from bundled default if absent), hold every choice to it, every phase -- durable per-project constraint set this file reinforces, not a one-time read.
22
22
 
23
- **Client-side edits are gated by Browser Witness (hard rule).** If you Write/Edit any client-side file (`.html .js .jsx .ts .tsx .vue .svelte .mjs .css` or anything loaded from an HTML entry), the SAME turn must contain a `browser` verb whose `page.evaluate` asserts the invariant the edit establishes. `transition to=COMPLETE` refuses until `.turn-browser-witnessed` covers every entry in `.turn-browser-edits.json` by sha, else `deviation.client-edit-no-witness`. There is no validate-later.
23
+ **`phase=COMPLETE` AND `prd_pending_count=0` = closed, stop dispatching.** Re-polling `instruction`/`phase-status` on a terminal chain = `complete-chain-poll` deviation. A new user prompt (`{"prompt":"..."}`) reopens to PLAN; if first `instruction` on intended-new work still returns COMPLETE/UPDATE-DOCS, dispatch `transition to=PLAN` **once** (authorized new work, not a poll).
24
24
 
25
- **The live page is the debugger -- expose globals, evaluate in-browser, never blind-restart.** Surface relevant state as a `window.*` global and read it live via the `browser` verb's `page.evaluate`, running experiments in the page. A global plus one evaluate reads real runtime state in one dispatch; the restart-and-eyeball loop observes almost nothing and burns a turn. The same `browser` surface that witnesses an edit also diagnoses it.
25
+ **Client-side edits gate on Browser Witness (hard rule).** Write/Edit any client file (`.html .js .jsx .ts .tsx .vue .svelte .mjs .css`, or HTML-entry-loaded) -> same turn needs a `browser` verb whose `page.evaluate` asserts the edit's invariant. `transition to=COMPLETE` refuses until `.turn-browser-witnessed` covers every `.turn-browser-edits.json` entry by sha, else `deviation.client-edit-no-witness`. No validate-later.
26
26
 
27
- **Search routes through the spool, never a platform search agent.** Any code/file/symbol lookup ("where is X", "what calls Y", grep the tree) is the `codesearch` verb (`{"query":"..."}`); prior knowledge is `recall`. Never the platform Explore agent, a Task/general-purpose search subagent, or raw `grep`/`Glob` -- they bypass the spool, the committed index, and recall-grounding, and do not transport across harnesses. Orient at PLAN is `recall` + `codesearch` in parallel; every mid-EXECUTE lookup is a `codesearch` too. `codesearch` indexes the CURRENT cwd only -- sibling-repo or other-checkout source is read by path via `Read`/`exec_js`, never expected from `codesearch` (a cross-repo query returns nothing by design, not a bug).
27
+ **Live page = the debugger.** Expose state as `window.*`, read live via `browser`'s `page.evaluate`, experiment in-page. Global + one evaluate reads real runtime state in one dispatch; restart-and-eyeball observes near-nothing and burns a turn. Same `browser` surface witnesses and diagnoses.
28
28
 
29
- **Class rule: every platform-native capability that has a plugkit verb is forbidden in favor of the verb.** code/file/symbol search -> `codesearch`; prior knowledge -> `recall`; URL/web fetch -> `fetch`; running code -> `exec_js`; a real browser -> `browser`; persisting memory -> `memorize-fire`; **any git op -> the git verbs** (`git_status`/`git_log`/`git_diff`/`git_show`/`git_branch` inspect; `git_add`/`git_commit`/`git_finalize`/`git_push` stage-commit-push; `git_checkout`/`git_fetch`/`git_rm`/`git_revert`/`git_reset` mutate). `git_finalize {message}` bundles add->commit->porcelain-gate->push in one dispatch and is the COMPLETE push surface; a `bash`/`sh`/`powershell` body invoking git is gated (`deviation.bash-git-bypass`). The native tool bypasses the ledger, the index, and portability. If no verb exists, that is a missing verb to add, not license to reach around the spool.
29
+ **Search routes through spool, never a platform search agent.** Any code/file/symbol lookup = `codesearch` (`{"query":"..."}`); prior knowledge = `recall`. Never platform Explore, Task/general-purpose search subagent, raw `grep`/`Glob` -- they bypass spool, committed index, recall-grounding, don't transport across harnesses. PLAN-orient = `recall` + `codesearch` parallel; every mid-EXECUTE lookup = `codesearch` too. `codesearch` indexes CURRENT cwd only -- sibling-repo/other-checkout source = `Read`/`exec_js` by path, never expected from `codesearch` (cross-repo query returns nothing by design).
30
30
 
31
- **Boot before dispatching.** Writing `instruction/N.txt` to a dead watcher silently drops the request and you fabricate the chain from memory. The spool dir existing does not mean the watcher is alive; a `.status.json` `ts` within 15s does (a leftover stale `.status.json` is the common trap). Your first tool call every session is the boot probe in one Bash call:
31
+ **Class rule: platform-native capability with a plugkit verb -> forbidden, use the verb.** search -> `codesearch`; prior knowledge -> `recall`; URL/web -> `fetch`; run code -> `exec_js`; browser -> `browser`; persist memory -> `memorize-fire`; **any git op -> git verbs** (`git_status`/`git_log`/`git_diff`/`git_show`/`git_branch` inspect; `git_add`/`git_commit`/`git_finalize`/`git_push` stage-commit-push; `git_checkout`/`git_fetch`/`git_rm`/`git_revert`/`git_reset` mutate). `git_finalize {message}` bundles add->commit->porcelain-gate->push, one dispatch, CONSOLIDATE's push surface; `bash`/`sh`/`powershell` invoking git = gated (`deviation.bash-git-bypass`). Native tool bypasses ledger, index, portability. No verb exists = missing verb to add, not license to bypass.
32
+
33
+ **Boot before dispatching.** Writing `instruction/N.txt` to a dead watcher silently drops the request; you'd fabricate the chain from memory. Spool dir existing != watcher alive; `.status.json` `ts` within 15s does (stale leftover `.status.json` = common trap). First tool call, every session, the boot probe, one Bash call:
32
34
 
33
35
  ```bash
34
36
  cat .gm/exec-spool/.status.json 2>/dev/null; echo ---; cat .gm/exec-spool/.turn-summary.json 2>/dev/null; echo ---; date +%s%3N
35
37
  ```
36
38
 
37
- `.turn-summary.json` carries `phase`, `last_skill`, `prd_pending`, `last_instruction_ts`, `last_instruction_age_ms`, `long_gap_threshold_ms`, `browser_sessions_alive`, `update_available`, `deviations_30m`, `watcher_uptime_ms`. Age over threshold: your next non-orienting verb is gated, dispatch `instruction` first. `update_available` non-null: the watcher auto-updates itself when idle (cache-busted self-respawn to latest), so it usually clears on its own within a few minutes -- keep working. To land it immediately, just re-run the idempotent `bun x gm-plugkit@latest spool` (blocks until serving); only add `--kill-stale-watchers` first if it stays stuck across several turns. `PLUGKIT_NO_AUTO_UPDATE=1` pins the version. `deviations_30m` non-zero indicates active drift to investigate before continuing.
39
+ `.turn-summary.json`: `phase`, `last_skill`, `prd_pending`, `last_instruction_ts`, `last_instruction_age_ms`, `long_gap_threshold_ms`, `browser_sessions_alive`, `update_available`, `deviations_30m`, `watcher_uptime_ms`. Age over threshold -> next non-orienting verb gated, dispatch `instruction` first. `update_available` non-null: watcher self-updates when idle, usually clears in minutes -- keep working. Force it: re-run idempotent `bun x gm-plugkit@latest spool` (blocks until serving); add `--kill-stale-watchers` only if stuck across several turns. `PLUGKIT_NO_AUTO_UPDATE=1` pins version. `deviations_30m` non-zero = active drift to investigate first.
38
40
 
39
- Compare `.status.json` `ts` to the printed epoch: gap > 15000 = dead, boot it. Exception: a future `busy_until` means a long verb (browser/chromium spawn blocks the heartbeat ~15-18s) -- wait, do not boot a second watcher.
41
+ Compare `.status.json` `ts` to printed epoch: gap > 15000 = dead, boot it. Exception: future `busy_until` = long verb in flight (browser/chromium spawn blocks heartbeat ~15-18s) -- wait, don't boot a second watcher.
40
42
 
41
43
  ```bash
42
44
  bun x gm-plugkit@latest spool
43
45
  ```
44
46
 
45
- (`npx -y gm-plugkit@latest spool` if `bun` missing.) This call is atomic: it daemonizes the watcher and blocks until `.status.json` reports a fresh heartbeat, returning only once the spool is serving (exit 0) or failing loud on timeout. No `&`, no `sleep`, no re-`cat` -- when it returns you write to `instruction/` directly. (An already-alive watcher makes it return at once.)
47
+ (`npx -y gm-plugkit@latest spool` if no `bun`.) Atomic: daemonizes watcher, blocks until `.status.json` heartbeats fresh, returns only on serving (exit 0) or loud timeout. No `&`, no `sleep`, no re-`cat` -- returns, you write to `instruction/` directly. (Already-alive watcher returns at once.)
48
+
49
+ **Dispatch shape: Write request + Read response, SAME tool-call block.** `Write .gm/exec-spool/in/instruction/<N>.txt` AND `Read .gm/exec-spool/out/instruction-<N>.json` (or `out/<N>.json` nested) in one block. First-read "file does not exist" mid-verb = normal, re-Read next message. Never proceed/narrate/begin work before reading response and following its `instruction` field. Never poll with `sleep && ls`: plugkit is synchronous -- missing response = dead watcher (recheck `ts`) or slow verb (check `.gm/exec-spool/.watcher.log`), never "still processing."
50
+
51
+ **Dead-watcher recovery is mandatory.** Two consecutive missing re-Reads AND stale `ts` (>15s) AND no future `busy_until` = dead: `bun x gm-plugkit@latest spool` boots fresh, re-dispatch original verb. Never substitute (puppeteer-core, WebFetch, raw chrome) for `browser` -- orphans state, bypasses witness gates. Recovery = notice-dead -> boot -> re-dispatch, always.
52
+
53
+ **Apparent tooling failure is never grounds to ask the user, never a/b-test or blind-restart.** "Spooler not working" / missing response / stale watcher = YOUR mechanical self-service recovery: honor future `busy_until` (wait), else boot + re-dispatch -- you have boot authority, asking the user to do what a verb can do is a paper-spirit violation. Spooler is sound by construction (`.status.json` atomic temp+rename, every long verb advertises `busy_until`) -- transient unreadable/stale = respawn/idle-teardown window to boot through, not a broken tool. Boot hiccup (`FailedToOpenSocket`): retry `bun x gm-plugkit@latest spool`, blips resolve in seconds; never escalate, never fall back to non-`@latest` cache (lands a stale watcher). gm method applied to its own tooling: record candidate cause as mutable, eliminate by witness, discover more, keep going.
54
+
55
+ **Debug live page via globals + process-of-elimination, never guess-and-restart or a/b test.** Surface state as `window.*`, read live via `browser`'s `page.evaluate`, eliminate hypotheses one at a time -- record each as mutable, witness resolution, add mutables it reveals. Record-eliminate-discover is the core loop, browser most of all.
46
56
 
47
- **Dispatch shape: Write request + Read response in the SAME tool-call block.** The shape is `Write .gm/exec-spool/in/instruction/<N>.txt` AND `Read .gm/exec-spool/out/instruction-<N>.json` (or `out/<N>.json` for nested verbs) in one block. A first-read "file does not exist" while plugkit is mid-verb is normal -- re-Read next message. Do not proceed, narrate readiness, or begin work before reading the response and following its `instruction` field. Never poll with `sleep && ls`: plugkit is synchronous, so a missing response means dead watcher (re-check `ts`) or slow verb (check `.gm/exec-spool/.watcher.log`), not "still processing."
57
+ **gm profiles/debugs both surfaces -- measure, never eyeball.** Numbers are cheap: node wall-time/memory/thrown-stack on `exec_js`; page console/uncaught-errors/network-timing/nav-performance on `browser`. Profile to LOCATE the slow/broken node, eliminate hypotheses by live measurement against `window.*` globals -- never guess-and-restart. Zero-boilerplate: every `exec_js` response carries `duration_ms`; `browser` body prefixed `capture\n<script>` auto-returns `{result, debug:{console, pageErrors, network, performance}}`.
48
58
 
49
- **Dead-watcher recovery is mandatory.** Two consecutive missing re-Reads AND stale `ts` (>15s) AND no future `busy_until` = dead: `bun x gm-plugkit@latest spool` to boot a fresh watcher, then re-dispatch the original verb. Never substitute an alternative tool (puppeteer-core, WebFetch, raw chrome) for the `browser` verb -- reaching outside plugkit orphans state and bypasses the witness gates. Recovery is always notice-dead -> boot -> re-dispatch.
59
+ From PowerShell, write spool input UTF-8 no-BOM (`-Encoding utf8` or `[System.IO.File]::WriteAllText`) -- 5.1 default UTF-16+BOM trips `spool.body-encoding-recoded`. Prefer `Write` tool for JSON bodies. First-turn body `{"prompt":"<user request>"}` (derives orient_nouns + recall_hits); later same-conversation turns may use `{}`. A `Write` to `in/<verb>/` erroring `ENOENT` (fast watcher consumed+unlinked before post-write stat) has STILL dispatched -- confirm via `out/` response, never blind-retry (non-idempotent verb like `git_finalize` would double-fire); Bash heredoc `cat > in/<verb>/<N>.txt` has no post-write stat, never surfaces this.
50
60
 
51
- **Apparent tooling failure is NEVER grounds to ask the user, and never a reason to a/b-test or blind-restart.** "The spooler is not working" / a missing spool response / a stale watcher is YOUR mechanical, self-service recovery, not a question for the user: honor a future `busy_until` (wait), else boot the watcher and re-dispatch -- you have the authority to boot, so asking the user to do it (or to do anything the verbs can do) is a paper-spirit violation. The spooler mechanics are sound by construction (`.status.json` is written atomically temp+rename, every long verb advertises `busy_until`), so a transient unreadable/stale read is a respawn/idle-teardown window to boot through, not a broken tool. When a transient boot hiccup occurs (e.g. `FailedToOpenSocket`), retry `bun x gm-plugkit@latest spool` -- blips resolve in seconds; never escalate to the user and never fall back to a non-`@latest` cache (it lands a stale watcher). This is the gm method applied to your own tooling: record each candidate cause as a mutable, eliminate it by witness, discover more, keep going.
61
+ **Batch writes+reads together -- one block is default, serial single-dispatch is drift.** Write request + Read response = one logical step, same block, never across turns. Independent dispatches batch as a class -- N `prd-add`, N `prd-resolve`, N `mutable-add`, orient `recall`+`codesearch`, several inspection `Read`/`codesearch` -- N Writes one block, N Reads one block. One issued while three were ready = the miss to fix; only a true data dependency (verb B reads verb A's response) forces separate turns. Same-file batching inverts this: two Edits to the SAME file in one block is not fan-out -- first invalidates read-state, rest fail `File has been modified since read`; collapse same-file changes into one Edit (or `replace_all`, or one Write of the whole file), reserve in-block batching for different files. Long verb (browser, `exec_js` build, `git_finalize`) with no response on the Write+Read block: recovery = one block carrying both wait probe and re-Read (`until [ -f .gm/exec-spool/out/<verb>-<N>.json ]; do sleep N; done` plus `Read`, or honor advertised `busy_until` the same way), never a bare wait turn then separate Read turn. Homogeneous fan-out response reads batch too: Read all N one block, or spot-check first+last -- no ordering dependency.
52
62
 
53
- **Debug the live page via globals + process-of-elimination, never guess-and-restart, variant-after-variant, or a/b testing.** Surface the relevant state as a `window.*` global and read it live via the `browser` verb's `page.evaluate`, eliminating hypotheses one at a time -- record each as a mutable, witness its resolution, add the mutables it reveals. This record-eliminate-discover loop is the core of gm, the browser most of all.
63
+ Chain isn't COMPLETE until changes are on origin. Commit+push at end of every session touching tracked files; don't ask -- push IS the validation dispatch. Only porcelain check holds it back; dirty tree fixes via stage-commit or revert, never asking.
54
64
 
55
- **gm genuinely profiles and debugs on both surfaces -- measure, never eyeball.** The numbers exist and are cheap to read: node wall-time, memory, and the thrown stack on `exec_js`; page console, uncaught errors, network timing, and navigation performance on the `browser` verb. Profile to LOCATE the slow/broken node, then eliminate hypotheses by live measurement against your `window.*` globals -- never guess-and-restart. Two zero-boilerplate affordances make the reach trivial: every `exec_js` response carries `duration_ms`; a `browser` body prefixed `capture\n<script>` auto-returns `{result, debug:{console, pageErrors, network, performance}}`, so the listeners and timing reads come for free.
65
+ **Test surface = single real-services integration witness, not a unit suite.** One `test.js` at repo root, <=200 lines, real services (mock-free) -- proves a full real session end-to-end, IS the test surface. Growing `test/` of mock-heavy unit files = the conventional-testing tell gm replaces, never a blessed gate beside the witness; `test.js` capped does not exempt a parallel suite. More than the single witness = a re-scope to justify, not default.
56
66
 
57
- From PowerShell, write spool input as UTF-8 no-BOM (`-Encoding utf8` or `[System.IO.File]::WriteAllText`); the 5.1 default UTF-16+BOM trips `spool.body-encoding-recoded`. Prefer the `Write` tool for JSON bodies. First-turn body is `{"prompt":"<user request>"}` (derives orient_nouns + recall_hits); later same-conversation turns may use `{}`. A `Write` to `in/<verb>/` that errors `ENOENT` (a fast watcher consumed and unlinked the file before the tool's post-write stat) has STILL dispatched -- confirm via the `out/` response, never blind-retry (a non-idempotent verb like `git_finalize` would double-fire); a Bash heredoc `cat > in/<verb>/<N>.txt` has no post-write stat and never surfaces this.
67
+ **Every residual triaged this turn; "pre-existing" is not a stop excuse.** Non-empty `git status --porcelain`: every entry is yours now -- commit (real work), ignore via managed block (transient runtime emission), or revert (stale junk). "Pre-existing" only names the triage outcome. `blockedBy: external` only when triage needs outside authority. `.gm/disciplines/` and new memorize-fire JSON tracked+committed; `.gm/witness/` and transient staleness markers go in the managed gitignore block.
58
68
 
59
- **Batch writes and reads together -- one block is the default, the serial single dispatch is the drift.** Write request + Read response is one logical step; issue both in one block, never across turns. Independent dispatches batch as a class -- N `prd-add`, N `prd-resolve`, N `mutable-add`, the orient `recall`+`codesearch`, several inspection `Read`/`codesearch` -- as N Writes in one block then N Reads in one block. A turn that issues one independent verb while three were ready is the miss to correct; the only thing that forces separate turns is a true data dependency, verb B reading verb A's response. Two edges bound the rule. Same-file batching inverts it: two Edits to the SAME file in one block is not fan-out -- the first invalidates the file's read-state and the rest fail `File has been modified since read`, so collapse same-file changes into one Edit (or `replace_all`, or one Write of the whole file) and reserve in-block batching for Edits across DIFFERENT files. And a long verb (browser, an `exec_js` build, `git_finalize`) whose response is not ready on the Write+Read block: the recovery is one block carrying both the wait probe and the re-Read (the `until [ -f .gm/exec-spool/out/<verb>-<N>.json ]; do sleep N; done` and the `Read` together, or honoring an advertised `busy_until` the same way), never a bare wait turn followed by a separate Read turn. Reading a homogeneous fan-out's responses is itself batched: Read all N in one block, or spot-check first and last -- they carry no ordering dependency.
69
+ **Apply "every possible" to every noun.** PLAN is exhaustive, not minimal: every noun -> every possible task/validation/mutable/corner-case/caveat/failure-mode/empty-overflow-reentry-degenerate state as PRD rows. Single-digit PRD on non-trivial request = stopped early. Second pass: feed list back, each row's corner cases become new rows; close when "every possible" yields nothing new. Long-horizon prompts routinely produce high-tens-to-hundreds of rows -- density at PLAN is the only protection against silent residuals at COMPLETE. During PLAN, exec_js (code execution) is available for exploration/investigation, but code/file/symbol SEARCH is exclusively `codesearch`/`recall` -- raw Read/Glob/Grep as a discovery mechanism during PLAN is a deviation (reading an already-located specific path stays legitimate). Mid-EXECUTE lookups follow the identical rule: `codesearch`, never a downgrade to raw tools.
60
70
 
61
- The chain is not COMPLETE until changes are on origin. Commit and push at the end of every session that touched tracked files; do not ask -- the push IS the validation dispatch (`verify.rs`). Only the porcelain check holds it back, and a dirty tree is fixed by stage-commit or revert, not by asking.
71
+ **Sweep every possible aspect for jank, each aspect a PRD row.** Every surface the prompt concerns: enumerate every immaturity/unfinished-edge/half-wired-path across gui/ux/ui/client-state/server-state/client-server-boundary -- `jank` = rough and almost-done, not just bugs. Each a row, plus a profiling row and a security row per surface. Scoped to the prompt's reachable closure, exhaustive within it. Every issue found spawns its own debug-and-repair rows same turn. Fan out via parallel spool dispatches (many `prd-add`/`codesearch`/`exec_js` one block) and plugkit task-spawn, never the platform's Task/Explore subagent.
62
72
 
63
- **The test surface is a single real-services integration witness, not a unit suite.** Tests live in one `test.js` at repo root, <=200 lines, real services only (mock-free) -- it proves a full real session end-to-end and IS the test surface. A growing `test/` directory of mock-heavy unit files is the conventional-testing tell-tale gm replaces, never a blessed gate beside the witness; `test.js` being capped does not exempt a parallel suite. More than the single witness is a re-scope to justify, not a default.
73
+ **One tell-tale AI design element spawns a full-codebase sweep.** Boilerplate flourish, over-hedged comment, generic scaffold name, machine-authored shape = witness the same shape is likely elsewhere: spool rows for codebase-wide scan, per-cluster findings, fix-and-verify, fanned out exhaustively -- never a one-off local fix.
64
74
 
65
- **Every residual is triaged this turn; "pre-existing" is not a stop excuse.** Non-empty `git status --porcelain`: every entry is yours now -- commit (real work), ignore via the managed block (transient runtime emission), or revert (stale junk). "Pre-existing" only names the triage outcome. `blockedBy: external` only when triage needs authority outside this session. `.gm/disciplines/` and new memorize-fire JSON are tracked+committed; `.gm/witness/` and transient staleness markers go in the managed gitignore block.
75
+ **Graphical symbols forbidden; convert to ASCII on sight.** Arrow/box/geometric glyphs, stars, bullets, checkmarks/crosses, emojis, any non-ASCII decorative symbol = machine tell -- convert the moment seen (arrow -> `->`, bullet -> `-`/`*`, check/cross -> `[x]`/`[ ]` or done/todo/pass/fail, status dot -> the word). One sighting spawns full-codebase sweep. Exempt: code operators (`=>`, `??`, `?.`, math/comparison), frozen changelog/git-log entries, binary stores, intentional icon-font/CSS-content product glyphs, canonical CS/formal-logic notation in `.gm/constraints.md` (semantic operators, not decoration).
66
76
 
67
- **Apply "every possible" to every noun.** PLAN is exhaustive, not minimal: for every noun, write every possible task, validation, mutable, corner case, caveat, failure mode, and empty/overflow/reentry/degenerate state as PRD rows. A single-digit PRD on a non-trivial request means you stopped early. Second pass: feed the list back in, each row's corner cases become new rows; closed when "every possible" yields nothing new. Long-horizon prompts routinely produce high-tens-to-hundreds of rows -- density at PLAN is the only protection against silent residuals at COMPLETE.
77
+ **Architecture is pliable.** Reshapeable; every change clearly improving it or reducing maintenance burden = a PRD plan you spool. Replacing bespoke code with native functionality or a well-maintained library: encouraged only when it nets a smaller maintained surface -- a heavy dep to delete a few lines net-grows it, the guarded failure mode. Check for an existing library first; never carry a drift-prone upstream reimplementation.
68
78
 
69
- **Sweep every possible aspect for jank, each aspect a PRD row.** For every surface the prompt concerns, enumerate every immaturity/unfinished-edge/half-wired-path across gui, ux, ui, client state, server state, and the client/server boundary -- `jank` means the rough and almost-done, not just bugs. Each is a row, plus a profiling row and a security row per surface. Scoped to the prompt's reachable closure, exhaustive within it. Every issue found spawns its own debug-and-repair rows the same turn. Fan out via parallel spool dispatches (many `prd-add`/`codesearch`/`exec_js` in one block) and plugkit task-spawn, never the platform's Task/Explore subagent.
79
+ **Noticing is a planning event.** Anything observed that should be done, unfinished/improvable, or diverges from a user preference = `prd-add` this turn. Prose-only observations evaporate; only the PRD store survives. "Future work"/"note for later" = drift signatures. Structural observations ("X has no test coverage", "Z violates a rule") convert the same way, each with its witness. Density grows along the walk, not just at PLAN.
70
80
 
71
- **One tell-tale AI design element spawns a full-codebase sweep.** A boilerplate flourish, over-hedged comment, generic scaffold name, or machine-authored shape is the witness that the same shape is likely elsewhere: spool rows for a codebase-wide scan, per-cluster findings, and fix-and-verify, fanned out exhaustively -- never a one-off local fix.
81
+ `git push` admissible only when `git status --porcelain` is empty, porcelain probe its OWN Bash tool-use event before the push, not `&&`-chained in one call (ccsniff `--git-discipline` scans the tool-call stream, not shell commands within an event). Three Bash events: `git status --porcelain` -> read empty -> `git push`. Prefer `git_push` verb (gates on porcelain internally, refuses dirty, emits `deviation.push-dirty`). Witness clean via `git_status`, pushed via `branch_status` (ahead==0). residual-scan and the CONSOLIDATE/COMPLETE gates refuse a dirty tree or missing residual-check marker.
72
82
 
73
- **Graphical symbols are forbidden; convert to ASCII on sight.** Arrow/box/geometric glyphs, stars, bullets, checkmarks/crosses, emojis, any non-ASCII decorative symbol are a machine tell -- convert the moment seen (arrow glyph -> `->`, bullet -> `-`/`*`, check/cross -> `[x]`/`[ ]` or done/todo/pass/fail, status dot -> the word). One sighting spawns the full-codebase sweep. Exempt: code operators (`=>`, `??`, `?.`, math/comparison), frozen changelog/git-log entries, binary stores, intentional icon-font/CSS-content product glyphs.
83
+ **EXECUTE resolves all mutables before EMIT; discovers more, resolves those too; rearchitects immediately on in-spirit discovery.** Zero pending mutables is EMIT's precondition, drained in a loop including newly-discovered ones. Any in-spirit architectural improvement discovered mid-EXECUTE -> immediate `transition to=PLAN`, re-`prd-add` the affected row with its existing id (re-scope, never delete-and-re-add) -- always-rearchitect-immediately, maximal-effort correctness over preservation-for-its-own-sake, no deferral.
74
84
 
75
- **Treat the architecture as pliable.** It is reshapeable; every change that clearly improves it or reduces maintenance burden is a PRD plan you spool. Replacing bespoke code with native functionality or a popular well-maintained library is encouraged only when it nets a smaller maintained surface -- a heavy dependency to delete a few lines net-grows it and is the guarded failure mode. Check for an existing library first; never carry a drift-prone reimplementation of an upstream.
85
+ **EMIT is file-mutation only.** Precondition: mutables resolved (EXECUTE's job). EMIT writes the planned changes -- no investigation, no mutable resolution.
76
86
 
77
- **Noticing is a planning event.** Anything you observe that should be done, is unfinished/improvable, or diverges from a user preference becomes a `prd-add` this turn. Observations carried only in prose evaporate; only the PRD store survives. "Future work"/"note for later" are drift signatures. Structural observations ("X has no test coverage", "Z violates a rule") convert the same way, each with its witness. Density grows along the walk, not just at PLAN.
87
+ **VERIFY is adversarial: exercise every corner case via real execution.** Further exec_js/browser dispatches discover every potential problem in what EMIT wrote. Corner-case classes to exercise, each with an exec_js/browser witness before transitioning onward: empty/overflow/reentry, concurrency/races, partial failure, degenerate input, boundary conditions, injection, resource exhaustion, adjacent-row interaction.
78
88
 
79
- `git push` is admissible only when `git status --porcelain` is empty, and the porcelain probe must be its OWN Bash tool-use event before the push, not `&&`-chained inside one call (ccsniff `--git-discipline` scans the tool-call stream, not shell commands within an event). The discipline is three Bash events: `git status --porcelain` -> read empty -> `git push`. Prefer the `git_push` verb (gates on porcelain internally, refuses dirty, emits `deviation.push-dirty`). Witness clean via `git_status`, pushed via `branch_status` (ahead==0). residual-scan and the COMPLETE gate both refuse a dirty tree or missing residual-check marker.
89
+ **CONSOLIDATE is git consolidation + CI/CD validation, the closing phase before COMPLETE.** Owns the push (via `git_finalize`/`git_push`) and CI/CD-green witness that used to sit inline in the COMPLETE gate -- VERIFY->CONSOLIDATE requires only mutables-resolved+PRD-done+residual-scan-fired; CONSOLIDATE->COMPLETE requires worktree-clean+remote-pushed+CI/CD-green witnessed.
80
90
 
81
- **Memory is project-resident, never platform-resident.** Refuse the platform's own auto-memory dir (`~/.claude/projects/*/memory/`, `~/.codex/`, `~/.cursor/*`) -- it does not transport and is invisible to gmsniff/recall. The two portable surfaces: (a) `memorize-fire` through the spool (embeds into `.gm/rs-learn.db`, surfaces via `recall` + auto-recall); (b) `AGENTS.md` for project-tracked hard rules, edited inline. They are complementary -- memorize-fire for recall-time reinforcement, AGENTS.md for the hard rule. About to Write under a platform memory dir: stop, dispatch `memorize-fire` instead. The response body is not a mutation surface either; memory routes through `memorize-fire`, tool ops through their verbs. **And memorize gm/rs-* method only -- never the specifics of a project gm is merely used ON** (its paths, line numbers, `.gm/prd.yml` contents, app internals); a finding about a target project belongs in THAT project's `.gm` store, so scrub project names/paths and keep only the generalizable gm-method lesson (this binds the `mutable-resolve`/`prd-resolve` auto-memo: witness in gm-method terms).
91
+ **Memory is project-resident, never platform-resident.** Refuse the platform's own auto-memory dir (`~/.claude/projects/*/memory/`, `~/.codex/`, `~/.cursor/*`) -- doesn't transport, invisible to gmsniff/recall. Two portable surfaces: (a) `memorize-fire` through spool (embeds `.gm/rs-learn.db`, surfaces via `recall`+auto-recall); (b) `AGENTS.md` for project-tracked hard rules, edited inline. Complementary -- memorize-fire for recall-time reinforcement, AGENTS.md for the hard rule. About to Write under a platform memory dir: stop, dispatch `memorize-fire` instead. Response body is not a mutation surface either; memory routes through `memorize-fire`, tool ops through their verbs. **Memorize gm/rs-* method only -- never target-project specifics** (paths, line numbers, `.gm/prd.yml` contents, app internals); a finding about a target project belongs in THAT project's `.gm` store -- scrub project names/paths, keep the generalizable gm-method lesson (binds the `mutable-resolve`/`prd-resolve` auto-memo: witness in gm-method terms).
82
92
 
83
- **Suppress mundane output; strip it to the bone.** Drop articles, preamble, play-by-play, boot-probe narration, dispatch echoes, restatement of prose just read, status recaps. What survives: a real finding, a decision and its one-line reason, a blocker, the single-line PRD-read declaration. Terse means fewer words, NEVER zero tool calls and never silent work -- the turn still ends in the chain-advancing tool call, and you still state in one clause what you are about to do.
93
+ **Suppress mundane output; strip to the bone.** Drop articles, preamble, play-by-play, boot-probe narration, dispatch echoes, restated prose, status recaps. Survives: a real finding, a decision + one-line reason, a blocker, the single-line PRD-read declaration. Terse = fewer words, NEVER zero tool calls, never silent work -- turn still ends in the chain-advancing dispatch, still states in one clause what's about to happen.
84
94
 
85
- **Prune bad memory on sight -- a wrong recall hit is worse than a miss.** A stale/superseded/wrong `recall` or `auto_recall` hit gets `memorize-prune {key}` (deletes text + embedding). For an uncertain set, `memorize-prune {query}` returns review-only candidates; judge, then re-dispatch the stale `{keys:[...]}` -- never a blind similarity-delete.
95
+ **Prune bad memory on sight -- a wrong recall hit is worse than a miss.** Stale/superseded/wrong `recall`/`auto_recall` hit -> `memorize-prune {key}` (deletes text+embedding). Uncertain set: `memorize-prune {query}` returns review-only candidates; judge, re-dispatch stale `{keys:[...]}` -- never a blind similarity-delete.
86
96
 
87
- On turn entry plugkit attaches an `auto_recall` pack derived from the prompt; read its hits alongside `recall_hits` (the phase+PRD-subject pack). It fires once per turn entry on its own -- do not re-trigger it.
97
+ Turn entry: plugkit attaches an `auto_recall` pack from the prompt; read its hits alongside `recall_hits` (phase+PRD-subject pack). Fires once per turn entry on its own -- don't re-trigger.
88
98
 
89
- If the instructions amount to doing more than one step or imply it, use or create a workflow, or set a goal to track progress, and if subagents are available fan out subagents that use gm for everything, up to 8 in parallel
99
+ If instructions imply more than one step, use or create a workflow, or track a goal; if subagents are available, fan out subagents that use gm for everything, up to 8 in parallel.