gm-skill 2.0.1493 → 2.0.1494

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
@@ -40,7 +40,7 @@ Agents dispatch verbs by writing to `.gm/exec-spool/in/<verb>/<N>.txt` (request
40
40
 
41
41
  **git verbs**: git is a first-class spool surface, never a shell command; `git_finalize {message}` is the bundled COMPLETE-phase push surface and `git_push` is the only admissible raw push (porcelain-gated, rebase-retry). A git-dominant `bash`/`powershell` body is gated (`deviation.bash-git-bypass`). Full per-verb shapes, host_git `.exe` resolution, and the gate detail live in rs-learn (`recall: git verbs rs-plugkit spool surface`).
42
42
 
43
- **filter verb**: pure stdout compact-stdout transformation, in-wasm, no subprocess; pipe raw command output through it before it enters context. Full per-kind spec in rs-learn (`recall: filter verb rs-plugkit spool spec`).
43
+ **filter verb**: pure stdout -> compact-stdout transformation, in-wasm, no subprocess; pipe raw command output through it before it enters context. Full per-kind spec in rs-learn (`recall: filter verb rs-plugkit spool spec`).
44
44
 
45
45
  ## Documentation Policy
46
46
 
@@ -56,7 +56,9 @@ Only record non-obvious technical caveats that cost multiple runs to discover. R
56
56
 
57
57
  **No comments in code.** No inline, block, or JSDoc comments in every possible location, source, generated output, hooks, scripts.
58
58
 
59
- **Skill SKILL.md files:** Strip explanatory prose. Keep ONLY invocation syntax, transition arrows, gate conditions, constraint lists, and code examples showing exact usage.
59
+ **No graphical symbols; convert to industry-standard text on sight.** Decorative glyphs are forbidden in all output and source: arrow glyphs, box and geometric glyphs, stars, filled or hollow dots and bullets, checkmarks and crosses, emojis, and any non-ASCII decorative symbol. The instant one is found anywhere, convert it to its ASCII equivalent in the same turn (arrow glyph to `->`, bullet glyph to `-` or `*`, check/cross to `[x]`/`[ ]` or the words done/todo/pass/fail, status dot to the word it means). This is the tell-tale-AI class: one sighting spawns the full-codebase sweep, never a one-off local edit. Exempt and narrow: functional code operators (`=>`, `??`, `?.`, comparison/math), frozen historical changelog and git-log entries, binary stores, and intentional icon-font or CSS-content product glyphs.
60
+
61
+ **Skill SKILL.md files:** Strip explanatory prose. Keep ONLY invocation syntax, transition markers (`->`), gate conditions, constraint lists, and code examples showing exact usage.
60
62
 
61
63
  **Implicit, not explicit, in skill prose.** Skill files (and prompt-submit.txt) elicit behavior, they do not describe it. Write terse imperative principles whose phrasing triggers the model's already-learned dispositions, not numbered procedures that spell out what to do. Forbidden: "1. agent runs N parallel calls 2. then writes 3. then…", "see paper IV §2.3", "as documented in docs/skills.html", citations to the site or papers, multi-step recipes. The skill is a prompt, not a manual; if it reads like a manual the behavior gets imitated as a script and breaks at the first edge case. The papers and site are *outputs* of the discipline, not *inputs* to it; never link from a skill into the docs. Cross-cutting rules that need a citation belong in this file (AGENTS.md), not in skills.
62
64
 
@@ -68,9 +70,9 @@ There is no build step. The repo root is the published artifact. `npm publish` f
68
70
 
69
71
  ## the agent is the orchestrator; plugkit is the brain it drives
70
72
 
71
- **The agent orchestrates.** Plugkit is the stateful library the agent drives by dispatching verbs. Plugkit does not act autonomously, does not advance phases in the background, does not validate transitions while the agent waits. Every possible state change is a verb the agent writes into `.gm/exec-spool/in/<verb>/<N>.txt`. If a session shows zero dispatches but the agent narrated a full PLANCOMPLETE walk, the agent fabricated the walk, plugkit's dispatch ledger is ground truth.
73
+ **The agent orchestrates.** Plugkit is the stateful library the agent drives by dispatching verbs. Plugkit does not act autonomously, does not advance phases in the background, does not validate transitions while the agent waits. Every possible state change is a verb the agent writes into `.gm/exec-spool/in/<verb>/<N>.txt`. If a session shows zero dispatches but the agent narrated a full PLAN->COMPLETE walk, the agent fabricated the walk, plugkit's dispatch ledger is ground truth.
72
74
 
73
- The PLAN EXECUTE EMIT VERIFY COMPLETE state machine lives natively in rs-plugkit; plugkit owns phase/mutables/memorize/transition-legality *as data + gate checks*, but the agent triggers every operation by dispatching an orchestrator verb — the harness never reimplements the state machine and never expects plugkit to act without a verb. Plugkit is synchronous from the agent's view; 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`).
75
+ The PLAN -> EXECUTE -> EMIT -> VERIFY -> COMPLETE state machine lives natively in rs-plugkit; plugkit owns phase/mutables/memorize/transition-legality *as data + gate checks*, but the agent triggers every operation by dispatching an orchestrator verb — the harness never reimplements the state machine and never expects plugkit to act without a verb. Plugkit is synchronous from the agent's view; 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`).
74
76
 
75
77
  ## gm-skill is the canonical universal harness
76
78
 
@@ -102,7 +104,7 @@ Every possible skill's `allowed-tools:` frontmatter is reduced to `Skill, Read,
102
104
 
103
105
  **Mundane user-facing output is suppressed or stripped to the bone**: every possible mundane line of user-facing text is suppressed or cut to the bone — drop articles, drop preamble, drop the play-by-play; boot-probe narration, dispatch echoes, restating prose just read, status recaps do not ship. What survives is substantive: a real finding, a decision and its one-line reason, a blocker, the single-line PRD-read declaration. Terse means fewer/shorter words, NEVER zero tool calls and NEVER silent work — the turn still ends in the chain-advancing tool call and the agent still states in one terse clause what it is about to do. Cut the mundane, never the chain.
104
106
 
105
- **Noticing is a planning event, at every phase, in every dispatch window**: any observation the agent makes during the chain, anything that should be done, anything outstanding, anything unfinished, anything improvable, anything misaligned with user preferences, anything the work itself surfaces about what *else* the work touches, is a `prd-add` the agent dispatches this turn. Observations carried in the response body without conversion to a PRD row evaporate when the turn ends; only the PRD store survives. The default response to noticing is to convert. The discovery surface keeps producing new in-scope items as the chain walks PLANEXECUTEEMITVERIFY, every phase has its own noticing-to-PRD pressure. Skipping the conversion ("I'll mention it in the summary" / "future work" / "note for later") is the canonical drift mechanism: the observation does not persist, the future turn does not arrive, the residual goes silent. Density grows along the walk, not just at PLAN-time; a chain that exits PLAN with N rows and reaches COMPLETE with N rows has either had no real discoveries (unlikely on a non-trivial task) or has lost them. When the discovery is structural rather than concrete, "the project would benefit from X", "this surface has no test coverage", "the docs do not mention Y", "the agent's preference for Z is being violated here", it is still a PRD row, written with the witness that motivated it. Preference-aware noticing applies the same conversion: when the agent observes that current state diverges from user-stated preferences (dense PRDs, residual-triage, no name-and-defer, every-possible expansion, browser-witness coverage, push-on-clean), each divergence is a `prd-add` describing what the aligned state looks like.
107
+ **Noticing is a planning event, at every phase, in every dispatch window**: any observation the agent makes during the chain, anything that should be done, anything outstanding, anything unfinished, anything improvable, anything misaligned with user preferences, anything the work itself surfaces about what *else* the work touches, is a `prd-add` the agent dispatches this turn. Observations carried in the response body without conversion to a PRD row evaporate when the turn ends; only the PRD store survives. The default response to noticing is to convert. The discovery surface keeps producing new in-scope items as the chain walks PLAN->EXECUTE->EMIT->VERIFY, every phase has its own noticing-to-PRD pressure. Skipping the conversion ("I'll mention it in the summary" / "future work" / "note for later") is the canonical drift mechanism: the observation does not persist, the future turn does not arrive, the residual goes silent. Density grows along the walk, not just at PLAN-time; a chain that exits PLAN with N rows and reaches COMPLETE with N rows has either had no real discoveries (unlikely on a non-trivial task) or has lost them. When the discovery is structural rather than concrete, "the project would benefit from X", "this surface has no test coverage", "the docs do not mention Y", "the agent's preference for Z is being violated here", it is still a PRD row, written with the witness that motivated it. Preference-aware noticing applies the same conversion: when the agent observes that current state diverges from user-stated preferences (dense PRDs, residual-triage, no name-and-defer, every-possible expansion, browser-witness coverage, push-on-clean), each divergence is a `prd-add` describing what the aligned state looks like.
106
108
 
107
109
  **A turn without a tool call is a stop; summary is a stop; both are forbidden until plugkit pronounces COMPLETE**: every programming agent, regardless of vendor, reads only tool calls and their outputs, so an assistant message that ends in prose with no tool call IS the turn ending and the session halts there. This is the mechanical root of the "agent did one small piece and stopped" failure: the model wrote a wrap-up paragraph, emitted no tool call, and the harness read that as done. The rule is therefore absolute and tool-agnostic: while the chain is in-flight (phase ≠ COMPLETE OR prd_pending_count > 0) the agent NEVER ends a turn in prose and NEVER writes a summary/recap/"what I did" closure, every turn terminates in a tool call that advances the chain (`instruction`, the next named verb, `transition`, `phase-status`). The only event that authorizes a prose-only turn is plugkit returning `phase=COMPLETE` AND `prd_pending_count=0`; the agent's own sense that "the work feels done" authorizes nothing. Before any apparent stop or any summary, the agent dispatches `phase-status` and rechecks, a non-terminal phase means the urge to stop was drift, and the recovery is to dispatch `instruction` and continue. This depends on nothing but the verb spool, so it holds on every agent with no hook and no tool-specific feature; any continuation mechanism that relies on a hook or a single tool's behavior is non-portable and must be replaced by this spool-only discipline.
108
110
 
@@ -136,7 +138,7 @@ Every possible skill's `allowed-tools:` frontmatter is reduced to `Skill, Read,
136
138
 
137
139
  ## Cascade pipeline
138
140
 
139
- Push to any rs-* sibling triggers `cascade.yml` rs-plugkit `release.yml` single `plugkit.wasm` (npm `plugkit-wasm` + `plugkit-bin` Releases) auto-bump `gm.json::plugkitVersion` `publish.yml` ships gm-skill + gm-plugkit + the SKILL.md mirror. Full step sequence + PUBLISHER_TOKEN setup in rs-learn (`recall: cascade pipeline`).
141
+ Push to any rs-* sibling triggers `cascade.yml` -> rs-plugkit `release.yml` -> single `plugkit.wasm` (npm `plugkit-wasm` + `plugkit-bin` Releases) -> auto-bump `gm.json::plugkitVersion` -> `publish.yml` ships gm-skill + gm-plugkit + the SKILL.md mirror. Full step sequence + PUBLISHER_TOKEN setup in rs-learn (`recall: cascade pipeline`).
140
142
 
141
143
  Three npm packages publish from this repo: `gm-skill` (the skill harness), `gm-plugkit` (bootstrap + watcher), `plugkit-wasm` (wasm binary). publish.yml + the rs-plugkit cascade ships all three on every version-bump commit. The legacy 15 downstream repos (gm-cc, gm-gc, gm-oc, gm-kilo, gm-codex, gm-qwen, gm-copilot-cli, gm-hermes, gm-thebird, gm-vscode, gm-cursor, gm-zed, gm-jetbrains, gm-antigravity, gm-windsurf) are archived on GitHub, no further releases, no orphan-commit publish step.
142
144
 
@@ -186,7 +188,7 @@ Three persistent diagnostic files at `.gm/exec-spool/` root are updated by the r
186
188
 
187
189
  **Landing page renderer**: the deployed `/` route on https://anentrypoint.github.io/gm/ is rendered by `site/theme.mjs` from `site/content/pages/home.yaml` via flatspace. `site/index.html` + `site/main.js` build `docs/bundle.js` for non-flatspace standalone preview only. Landing edits go through `site/theme.mjs` (Hero) and `site/content/pages/home.yaml` (content), never `site/index.html`.
188
190
 
189
- **docs/styles.css is generated**: regenerated from `site/input.css` by `site/package.json` build script (copies input.css docs/styles.css after esbuild). Direct edits to docs/styles.css are wiped on next build, append to site/input.css instead.
191
+ **docs/styles.css is generated**: regenerated from `site/input.css` by `site/package.json` build script (copies input.css -> docs/styles.css after esbuild). Direct edits to docs/styles.css are wiped on next build, append to site/input.css instead.
190
192
 
191
193
  ## Made with gm Page
192
194
 
package/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  > **more coushin' for the puhin'**
4
4
 
5
- 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."
5
+ 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."
6
6
 
7
- 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.
7
+ 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.
8
8
 
9
9
  built over ~200 commits of daily use. free, open source, maintained by one person.
10
10
 
@@ -32,18 +32,18 @@ This repo IS the published `gm-skill` npm package. No build step, no factory. Th
32
32
 
33
33
  ```
34
34
  gm/
35
- ├── skills/gm-skill/ the skill (SKILL.md + index.js, ~12 lines of prose)
36
- ├── bin/ bootstrap + plugkit launcher (gmsniff / ccsniff are separate npm packages, `bun x gmsniff`, `bun x ccsniff`)
37
- ├── lib/ runtime: spool dispatch, skill bootstrap, daemon mgmt
38
- ├── agents/ subagent prompts (gm, memorize, research-worker, textprocessing)
39
- ├── prompts/ bash-deny, session-start, prompt-submit, pre-compact
40
- ├── lang/ language packs (browser, ssh)
41
- ├── gm-plugkit/ separate npm package that ships the wasm-wrapper
42
- ├── gm.json version + plugkit pin
43
- ├── package.json npm publish manifest
44
- ├── AGENTS.md architectural rules (present-tense, no history)
45
- ├── CHANGELOG.md release history
46
- └── site/ flatspace site source (built to dist/ by CI)
35
+ ├── skills/gm-skill/ <- the skill (SKILL.md + index.js, ~12 lines of prose)
36
+ ├── bin/ <- bootstrap + plugkit launcher (gmsniff / ccsniff are separate npm packages, `bun x gmsniff`, `bun x ccsniff`)
37
+ ├── lib/ <- runtime: spool dispatch, skill bootstrap, daemon mgmt
38
+ ├── agents/ <- subagent prompts (gm, memorize, research-worker, textprocessing)
39
+ ├── prompts/ <- bash-deny, session-start, prompt-submit, pre-compact
40
+ ├── lang/ <- language packs (browser, ssh)
41
+ ├── gm-plugkit/ <- separate npm package that ships the wasm-wrapper
42
+ ├── gm.json <- version + plugkit pin
43
+ ├── package.json <- npm publish manifest
44
+ ├── AGENTS.md <- architectural rules (present-tense, no history)
45
+ ├── CHANGELOG.md <- release history
46
+ └── site/ <- flatspace site source (built to dist/ by CI)
47
47
  ```
48
48
 
49
49
  The two npm packages this repo publishes:
@@ -55,7 +55,7 @@ The two npm packages this repo publishes:
55
55
 
56
56
  ### the state machine
57
57
 
58
- 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.
58
+ 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.
59
59
 
60
60
  ### tools
61
61
 
package/agents/gm.md CHANGED
@@ -10,7 +10,7 @@ mode: primary
10
10
  **CRITICAL: Skills are invoked via the Skill tool ONLY. Do NOT use the Agent tool to load skills. Skills are not agents. Use: `Skill tool` with `skill: "gm"` (or `"planning"`, `"gm-execute"`, `"gm-emit"`, `"gm-complete"`, `"update-docs"`). Using the Agent tool for skills is a violation.**
11
11
 
12
12
  All work coordination, planning, execution, and verification happens through the skill tree:
13
- - `planning` skill `gm-execute` skill `gm-emit` skill `gm-complete` skill `update-docs` skill
13
+ - `planning` skill -> `gm-execute` skill -> `gm-emit` skill -> `gm-complete` skill -> `update-docs` skill
14
14
  - `memorize` sub-agent — background only, non-sequential. Invocation: `Agent(subagent_type='memorize', model='haiku', run_in_background=true, prompt='## CONTEXT TO MEMORIZE\n<what was learned>')`
15
15
 
16
16
  All code execution uses `exec:<lang>` via the Bash tool — never direct `Bash(node ...)` or `Bash(npm ...)`.
@@ -18,7 +18,7 @@ If the reach check returns out-of-reach:
18
18
 
19
19
  - **Do** ingest classified facts into rs-learn (Step 2) — rs-learn is per-user, not per-project, so private notes about a project the user is reading-but-not-owning are safe there.
20
20
  - **Do not** read or edit `<project root>/AGENTS.md` (Step 3). Skip the file entirely.
21
- - **Do not** run the AGENTS.md rs-learn migration audit (Step 4). The audit edits AGENTS.md.
21
+ - **Do not** run the AGENTS.md <-> rs-learn migration audit (Step 4). The audit edits AGENTS.md.
22
22
 
23
23
  Reason: agents running in a cwd that points at a third-party repo (e.g. running Claude inside a checkout of `nousresearch/hermes-agent` while building a downstream port) must not write project-specific notes into the upstream project's AGENTS.md. That AGENTS.md belongs to the upstream maintainers. Personal porting notes belong in the user's downstream repo's AGENTS.md, or — when the work spans multiple repos and there's no clean home — in rs-learn only.
24
24
 
@@ -78,12 +78,12 @@ A non-obvious technical caveat qualifies if it required multiple failed runs to
78
78
 
79
79
  For each qualifying fact from context:
80
80
  - Read AGENTS.md first if not already read this run
81
- - If AGENTS.md already covers it skip
82
- - If genuinely non-obvious append to the appropriate section
81
+ - If AGENTS.md already covers it -> skip
82
+ - If genuinely non-obvious -> append to the appropriate section
83
83
 
84
84
  Never add: obvious patterns, active task progress, redundant restatements.
85
85
 
86
- ## STEP 4: AGENTS.md RS-LEARN MIGRATION (BENCHMARK + DRAIN)
86
+ ## STEP 4: AGENTS.md -> RS-LEARN MIGRATION (BENCHMARK + DRAIN)
87
87
 
88
88
  AGENTS.md is the **always-on context buffer** — every prompt sees it. rs-learn is the **conditional retrieval store** — only relevant facts surface. The migration loop turns AGENTS.md into a benchmark for rs-learn's recall quality:
89
89
 
@@ -91,8 +91,8 @@ AGENTS.md is the **always-on context buffer** — every prompt sees it. rs-learn
91
91
  2. For each item, derive a 2-6 word query that a future agent would naturally use to find this fact.
92
92
  3. Run `exec:recall` with that query.
93
93
  4. Decide:
94
- - **Recall accurate AND complete** the rs-learn store has internalized this fact; **remove it from AGENTS.md**. Frees buffer space and confirms learning.
95
- - **Recall partial / outdated / missing** keep the AGENTS.md item AND ingest a refined version of the fact via `exec:memorize` so next round it can pass. Note the outcome in your run log.
94
+ - **Recall accurate AND complete** -> the rs-learn store has internalized this fact; **remove it from AGENTS.md**. Frees buffer space and confirms learning.
95
+ - **Recall partial / outdated / missing** -> keep the AGENTS.md item AND ingest a refined version of the fact via `exec:memorize` so next round it can pass. Note the outcome in your run log.
96
96
  5. Report the audit cycle in the run output (items checked, removed, refined). Do not write the audit result to AGENTS.md — it is changelog-shaped and AGENTS.md forbids dated audit sections.
97
97
 
98
98
  Why: AGENTS.md grows monotonically without this loop. rs-learn already filters by relevance per-prompt, so duplicating stable facts in AGENTS.md just inflates the always-on context. The migration drains AGENTS.md into the retrieval store as the store proves it can recall. Failed migrations leave the fact in AGENTS.md (safe default) and improve the store. Success rate over time = a metric for how well gm is learning this project.
@@ -18,15 +18,15 @@ Agent(subagent_type='gm:textprocessing', model='haiku', prompt='## INPUT\n<body>
18
18
 
19
19
  ## OUTPUT CONTRACT
20
20
 
21
- - Plain-text instruction plain-text output, no fences, no labels.
22
- - JSON instruction (e.g. "return as a JSON array of {id, label}") exactly that JSON, parseable by `JSON.parse`, no fences, no surrounding prose.
23
- - Multi-document input requested as a list one entry per input doc in the same order, no skips.
21
+ - Plain-text instruction -> plain-text output, no fences, no labels.
22
+ - JSON instruction (e.g. "return as a JSON array of {id, label}") -> exactly that JSON, parseable by `JSON.parse`, no fences, no surrounding prose.
23
+ - Multi-document input requested as a list -> one entry per input doc in the same order, no skips.
24
24
 
25
25
  If the instruction is ambiguous about the output shape, default to plain text. If the input is empty, return empty output (empty string or `[]` for JSON).
26
26
 
27
27
  ## BATCH PATTERN
28
28
 
29
- N independent items N parallel `Agent(textprocessing)` calls in ONE message, each with its own item under `## INPUT`. Never serialize independent items. The runner collects results and assembles the batch.
29
+ N independent items -> N parallel `Agent(textprocessing)` calls in ONE message, each with its own item under `## INPUT`. Never serialize independent items. The runner collects results and assembles the batch.
30
30
 
31
31
  For one large body that exceeds a single-prompt budget: the *caller* chunks the body deterministically (paragraph, section, fixed-token) and fans out one Agent call per chunk in parallel, then merges. The agent itself does not chunk; it processes whatever it receives in one shot.
32
32
 
@@ -35,7 +35,7 @@ For one large body that exceeds a single-prompt budget: the *caller* chunks the
35
35
  Code for mechanics, agent for meaning.
36
36
 
37
37
  - Mechanics (use code): char/word/token count, byte length, split on delimiter, exact-string find/replace, regex match/extract, sort, group-by-key, dedup-by-equality, lowercase/uppercase, JSON parse/stringify, base64, URL encode.
38
- - Meaning (use this agent): summarize, classify, extract entities/intents, rewrite for tone/audience, translate, semantic dedup (same meaning, different words), rank/score by quality, label by topic, decide if two texts are "about the same thing", paraphrase, simplify, expand outline prose.
38
+ - Meaning (use this agent): summarize, classify, extract entities/intents, rewrite for tone/audience, translate, semantic dedup (same meaning, different words), rank/score by quality, label by topic, decide if two texts are "about the same thing", paraphrase, simplify, expand outline -> prose.
39
39
 
40
40
  A loop in code that "checks if this string contains certain meaning" via keyword lists is a stub of this agent. Replace it with one Agent call (or N parallel ones) per item.
41
41
 
@@ -44,4 +44,4 @@ A loop in code that "checks if this string contains certain meaning" via keyword
44
44
  - Model is fixed at `haiku` — fast, cheap, sufficient for transform tasks. Escalate to opus only when the agent's haiku output fails an acceptance check, never preemptively.
45
45
  - No tools beyond Read/Write — the agent processes text it receives, optionally reads/writes chunks for multi-pass jobs. Never spawns subagents.
46
46
  - Background-spawnable: `run_in_background=true` for fire-and-forget batch processing where the caller polls results later.
47
- - Idempotent: same input + same instruction same output (modulo haiku sampling noise). Callers needing deterministic output specify `temperature=0` in the prompt.
47
+ - Idempotent: same input + same instruction -> same output (modulo haiku sampling noise). Callers needing deterministic output specify `temperature=0` in the prompt.
package/bin/bootstrap.js CHANGED
@@ -375,7 +375,7 @@ async function extractNpmPackageWasm(destPath, version) {
375
375
  }
376
376
 
377
377
  fs.copyFileSync(nodeModulesPath, destPath);
378
- log(`extracted ${nodeModulesPath} ${destPath}`);
378
+ log(`extracted ${nodeModulesPath} -> ${destPath}`);
379
379
  obsEvent('bootstrap', 'npm.extract.end', { dur_ms: Date.now() - startMs, ok: true });
380
380
  } finally {
381
381
  try { fs.rmSync(tempDir, { recursive: true, force: true, maxRetries: 1, retryDelay: 50 }); } catch (_) {}
@@ -237,7 +237,7 @@ async function extractNpmPackageWasm(destPath, version) {
237
237
  }
238
238
 
239
239
  fs.copyFileSync(nodeModulesPath, destPath);
240
- log(`extracted ${nodeModulesPath} ${destPath}`);
240
+ log(`extracted ${nodeModulesPath} -> ${destPath}`);
241
241
  obsEvent('bootstrap', 'npm.extract.end', { dur_ms: Date.now() - startMs, ok: true });
242
242
  } finally {
243
243
  try { fs.rmSync(tempDir, { recursive: true, force: true, maxRetries: 1, retryDelay: 50 }); } catch (_) {}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-plugkit",
3
- "version": "2.0.1493",
3
+ "version": "2.0.1494",
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": {
@@ -2279,7 +2279,7 @@ async function runSpoolWatcher(instance, spoolDir) {
2279
2279
  if (!_selfStaleLoggedOnce) {
2280
2280
  _selfStaleLoggedOnce = true;
2281
2281
  try { logEvent('plugkit', 'gm-plugkit.self-stale', { running_version: own, latest_version: latest, detected_by: 'watcher-periodic-probe' }); } catch (_) {}
2282
- console.error(`[plugkit-wasm] gm-plugkit self-stale: running ${own}, latest npm ${latest} spawning replacement via bun x gm-plugkit@latest spool and exiting`);
2282
+ console.error(`[plugkit-wasm] gm-plugkit self-stale: running ${own}, latest npm ${latest} -> spawning replacement via bun x gm-plugkit@latest spool and exiting`);
2283
2283
  try {
2284
2284
  const cp = require('child_process');
2285
2285
  const bunPath = process.env.GM_BUN_PATH || 'bun';
@@ -2402,7 +2402,7 @@ async function runSpoolWatcher(instance, spoolDir) {
2402
2402
  file_version: fileV,
2403
2403
  action: 'exit-for-respawn',
2404
2404
  });
2405
- console.error(`[plugkit-wasm] version drift detected: instance=${instV} file=${fileV} exiting so supervisor reloads fresh wasm`);
2405
+ console.error(`[plugkit-wasm] version drift detected: instance=${instV} file=${fileV} -> exiting so supervisor reloads fresh wasm`);
2406
2406
  try {
2407
2407
  fs.writeFileSync(path.join(spoolDir, '.shutdown-reason.json'), JSON.stringify({
2408
2408
  reason: 'version-change',
@@ -2485,7 +2485,7 @@ async function runSpoolWatcher(instance, spoolDir) {
2485
2485
  file_sha: cur.slice(0, 12),
2486
2486
  action: 'exit-for-respawn',
2487
2487
  });
2488
- console.error(`[plugkit-wasm] wrapper.js drift detected exiting so supervisor reloads fresh wrapper`);
2488
+ console.error(`[plugkit-wasm] wrapper.js drift detected -> exiting so supervisor reloads fresh wrapper`);
2489
2489
  try {
2490
2490
  fs.writeFileSync(path.join(spoolDir, '.shutdown-reason.json'), JSON.stringify({
2491
2491
  reason: 'wrapper-change',
@@ -2793,7 +2793,7 @@ async function runSpoolWatcher(instance, spoolDir) {
2793
2793
  const bodyBytes = new TextEncoder().encode(body);
2794
2794
 
2795
2795
  const t0 = Date.now();
2796
- console.log(`[dispatch] verb=${verb} task=${taskBase} body=${bodyBytes.length}b`);
2796
+ console.log(`[dispatch] -> verb=${verb} task=${taskBase} body=${bodyBytes.length}b`);
2797
2797
  logEvent('plugkit', 'dispatch.start', { verb, task: taskBase, body_bytes: bodyBytes.length, cwd: process.cwd() });
2798
2798
 
2799
2799
  // Network-bound git verbs block the event loop for the duration of a push/fetch (~30s),
@@ -2852,7 +2852,7 @@ async function runSpoolWatcher(instance, spoolDir) {
2852
2852
  const outName = dir === '.' ? `${taskBase}.json` : `${verb}-${taskBase}.json`;
2853
2853
  fs.writeFileSync(path.join(outDir, outName), resultStr);
2854
2854
  const dur_ms = Date.now() - t0;
2855
- console.log(`[dispatch] verb=${verb} task=${taskBase} ms=${dur_ms} out=${resultStr.length}b`);
2855
+ console.log(`[dispatch] <- verb=${verb} task=${taskBase} ms=${dur_ms} out=${resultStr.length}b`);
2856
2856
  logEvent('plugkit', 'dispatch.end', { verb, task: taskBase, dur_ms, out_bytes: resultStr.length });
2857
2857
  emitOrchestratorEvents(verb, taskBase, resultStr);
2858
2858
 
@@ -3225,7 +3225,7 @@ async function runSpoolWatcher(instance, spoolDir) {
3225
3225
  instruction: 'plugkit is out of date. Update with: bun x gm-plugkit@latest --kill-stale-watchers; bun x gm-plugkit@latest spool. A fresh boot downloads the new wasm and respawns; an in-place running watcher does not self-download.',
3226
3226
  update_url,
3227
3227
  }, null, 2));
3228
- console.log(`[update] available: installed=${installed} latest=${latest} wrote ${UPDATE_AVAILABLE_PATH}`);
3228
+ console.log(`[update] available: installed=${installed} latest=${latest} -> wrote ${UPDATE_AVAILABLE_PATH}`);
3229
3229
  if (_lastKnownDrift !== latest) {
3230
3230
  logEvent('plugkit', 'update.available', { installed, latest, update_url });
3231
3231
  _lastKnownDrift = latest;
package/gm.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.1493",
3
+ "version": "2.0.1494",
4
4
  "description": "Spool-dispatch orchestration engine with unified state machine, skills, and automated git enforcement",
5
5
  "author": "AnEntrypoint",
6
6
  "license": "MIT",
@@ -209,7 +209,7 @@ const SPOOL_POLL_PATTERNS = [
209
209
  /\b(?:xargs|parallel|fzf)\b[^|]*\.gm[\\/](?:exec-spool|spool)/i,
210
210
  ];
211
211
 
212
- const SPOOL_POLL_REASON = 'spool POLLING (sleep+cat, while !test, ls/find on the spool dirs) is forbidden — plugkit is synchronous from your view, so the response file is there the moment the watcher finishes the verb. Specific replacements:\n\n- Instead of `ls .gm/exec-spool/out/` check the specific response file you wrote, e.g. `Read .gm/exec-spool/out/<verb>-<N>.json`\n- Instead of `sleep N; cat .gm/exec-spool/<...>` just Read the response file directly; if it doesn\'t exist yet, the watcher is dead (the SKILL.md boot probe `cat .gm/exec-spool/.status.json; date +%s%3N` is the way to check liveness) or the verb is slow (Read .gm/exec-spool/.watcher.log for the dispatch trace)\n- Instead of `while [ ! -f ... ]; do sleep ...; done` write the request, Read the response in the same message, accept the file-not-found and re-Read in the next message\n\nThe SKILL.md-prescribed boot probe (`cat .gm/exec-spool/.status.json; date +%s%3N`) is NOT a violation — it is the canonical liveness check because it pipes with `date` for ts comparison. The Read tool can\'t do that in one call. What this gate denies is the *polling* pattern around the spool dirs, not the boot-probe cat. You are the state machine. Plugkit serves the response the moment you write the request file.';
212
+ const SPOOL_POLL_REASON = 'spool POLLING (sleep+cat, while !test, ls/find on the spool dirs) is forbidden — plugkit is synchronous from your view, so the response file is there the moment the watcher finishes the verb. Specific replacements:\n\n- Instead of `ls .gm/exec-spool/out/` -> check the specific response file you wrote, e.g. `Read .gm/exec-spool/out/<verb>-<N>.json`\n- Instead of `sleep N; cat .gm/exec-spool/<...>` -> just Read the response file directly; if it doesn\'t exist yet, the watcher is dead (the SKILL.md boot probe `cat .gm/exec-spool/.status.json; date +%s%3N` is the way to check liveness) or the verb is slow (Read .gm/exec-spool/.watcher.log for the dispatch trace)\n- Instead of `while [ ! -f ... ]; do sleep ...; done` -> write the request, Read the response in the same message, accept the file-not-found and re-Read in the next message\n\nThe SKILL.md-prescribed boot probe (`cat .gm/exec-spool/.status.json; date +%s%3N`) is NOT a violation — it is the canonical liveness check because it pipes with `date` for ts comparison. The Read tool can\'t do that in one call. What this gate denies is the *polling* pattern around the spool dirs, not the boot-probe cat. You are the state machine. Plugkit serves the response the moment you write the request file.';
213
213
 
214
214
  function stripHeredocsAndStringLiterals(command) {
215
215
  let s = String(command);
@@ -291,7 +291,7 @@ function checkDispatchGates(sessionId, operation, extra) {
291
291
  logDeviation('deviation.bash-git-bypass', { verb: extra.verb, cmd: cmd.slice(0, 80) });
292
292
  return {
293
293
  allowed: false,
294
- reason: `bash-git-bypass: a \`${extra.verb}\` verb invoking \`git\` is denied — git is a first-class spool surface, not a shell command. Use the git verb: 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 addcommitporcelain-gatepush in ONE dispatch.`,
294
+ reason: `bash-git-bypass: a \`${extra.verb}\` verb invoking \`git\` is denied — git is a first-class spool surface, not a shell command. Use the git verb: 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.`,
295
295
  };
296
296
  }
297
297
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-skill",
3
- "version": "2.0.1493",
3
+ "version": "2.0.1494",
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",
@@ -17,10 +17,10 @@ State machine transitions — each line is a verb YOU dispatch when the exit con
17
17
  VERIFY with PRD items remaining: YOU dispatch `transition` with body "EXECUTE"
18
18
 
19
19
  State regressions — also YOUR dispatches, not plugkit's:
20
- Any new unknown YOU dispatch `transition` body "PLAN"
21
- EMIT logic wrong YOU dispatch `transition` body "EXECUTE"
22
- VERIFY file broken YOU dispatch `transition` body "EMIT"
23
- VERIFY logic wrong YOU dispatch `transition` body "EXECUTE"
20
+ Any new unknown -> YOU dispatch `transition` body "PLAN"
21
+ EMIT logic wrong -> YOU dispatch `transition` body "EXECUTE"
22
+ VERIFY file broken -> YOU dispatch `transition` body "EMIT"
23
+ VERIFY logic wrong -> YOU dispatch `transition` body "EXECUTE"
24
24
 
25
25
  A phase claim in text without the corresponding `transition` dispatch is fabrication. Plugkit's record of phase walk is ground truth; your narration is not. If gmsniff shows zero dispatches for a session in which you claimed COMPLETE, you lied to yourself.
26
26
 
@@ -30,7 +30,7 @@ After PLAN completes: dispatch independent .prd items in parallel — batch the
30
30
 
31
31
  === MEMORIZE ON RESOLUTION — HARD RULE ===
32
32
 
33
- Every unknownknown transition MUST be memorized THE SAME TURN it resolves — not at phase end, not in a batch. This is the most violated rule. Every session, dozens of exec outputs resolve unknowns that are never memorized. Those facts die on compaction.
33
+ Every unknown->known transition MUST be memorized THE SAME TURN it resolves — not at phase end, not in a batch. This is the most violated rule. Every session, dozens of exec outputs resolve unknowns that are never memorized. Those facts die on compaction.
34
34
 
35
35
  The ONLY acceptable memorize form is the spool dispatch:
36
36
 
@@ -44,7 +44,7 @@ Trigger (any = fire NOW, same turn, before next tool):
44
44
  - Fix works for non-obvious reason
45
45
  - Tool / env quirk observed (blocked commands, path oddities, platform differences)
46
46
 
47
- Parallel dispatch: N facts in one turn N memorize-fire spool writes in ONE message, parallel tool blocks. NEVER serialize.
47
+ Parallel dispatch: N facts in one turn -> N memorize-fire spool writes in ONE message, parallel tool blocks. NEVER serialize.
48
48
 
49
49
  End-of-turn self-check (mandatory, no exceptions): before closing ANY response, scan the entire turn for exec outputs and code reads that resolved an unknown but were NOT memorized. Dispatch ALL missed ones now. "I'll memorize this" in text is NOT a memorize dispatch — only the spool write counts.
50
50
 
@@ -52,7 +52,7 @@ Skipping memorize = memory leak = critical bug. Saying you will memorize ≠ mem
52
52
 
53
53
  === NO NARRATION BEFORE EXECUTION ===
54
54
 
55
- Do NOT output text describing what you are about to do before doing it. Run the tool first. State findings AFTER. Pattern: tool call tool result brief text summary of what was found. NOT: text describing upcoming tool tool call.
55
+ Do NOT output text describing what you are about to do before doing it. Run the tool first. State findings AFTER. Pattern: tool call -> tool result -> brief text summary of what was found. NOT: text describing upcoming tool -> tool call.
56
56
 
57
57
  "I'll check the file:" followed by Read = violation.
58
58
  "Let me search for X" followed by a codesearch dispatch = violation.
@@ -64,7 +64,7 @@ Every sentence of text output must be AFTER at least one tool result that justif
64
64
 
65
65
  A written PRD is the user's authorization. EXECUTE owns the work to COMPLETE. Resolve every doubt that arises during execution by witnessed probe, by recall, or by re-reading the PRD — never by routing the doubt back to the user. Any question whose answer the agent could obtain itself belongs to the agent, not the user.
66
66
 
67
- Asking is permitted only as last resort — destructive-irreversible action with no PRD coverage, OR user intent genuinely irrecoverable from PRD/memory/code. Channel: `exec:pause` (renames .gm/prd.yml .gm/prd.paused.yml; question in header). In-conversation asking is last-resort beneath last-resort.
67
+ Asking is permitted only as last resort — destructive-irreversible action with no PRD coverage, OR user intent genuinely irrecoverable from PRD/memory/code. Channel: `exec:pause` (renames .gm/prd.yml -> .gm/prd.paused.yml; question in header). In-conversation asking is last-resort beneath last-resort.
68
68
 
69
69
  The size of the task, the cost of context, the duration of CI, and the number of repos involved are never grounds to ask. Neither is "this change touches files the user reads" — your job is to land the change correctly, not to defer to a review you imagine the user wants. Audit findings, prose rewrites, configuration edits, and refactors all ship inside the same turn as the analysis that produced them. Stopping mid-loop to ask "should I apply these?" is itself the deviation pattern: it routes the doubt back to the user instead of executing.
70
70
 
@@ -5,12 +5,12 @@ BLOCKING REQUIREMENT — READ THIS FIRST: Your VERY FIRST action on EVERY user m
5
5
  Skill tool: invoke the gm-skill by name. Never use the Agent tool to load skills.
6
6
 
7
7
  Every capability with a plugkit verb routes through the spool, never a platform-native tool:
8
- code/file/symbol search codesearch verb (.gm/exec-spool/in/codesearch/<N>.txt)
9
- prior knowledge recall verb
10
- running code exec_js verb / the exec spool
11
- a real browser browser verb
12
- fetching a URL / web search fetch verb
13
- persisting memory memorize-fire verb
14
- git status / branch / push git_status / branch_status / git_push verbs
8
+ code/file/symbol search -> codesearch verb (.gm/exec-spool/in/codesearch/<N>.txt)
9
+ prior knowledge -> recall verb
10
+ running code -> exec_js verb / the exec spool
11
+ a real browser -> browser verb
12
+ fetching a URL / web search -> fetch verb
13
+ persisting memory -> memorize-fire verb
14
+ git status / branch / push -> git_status / branch_status / git_push verbs
15
15
 
16
16
  Glob/Grep/Find/Explore and host-native search are blocked — use the codesearch verb instead. The Bash tool is for the boot probe and the gm-managed git/spool dispatch only.
@@ -14,7 +14,7 @@ allowed-tools: Skill, Read, Write, Bash(bun *), Bash(npx *)
14
14
 
15
15
  **Every possible action begins and ends with `instruction`.** When in doubt, dispatch instruction. When denied, dispatch instruction. When the next move is unclear, dispatch instruction. There is no other recovery primitive and there is no situation in which improvising beats re-reading the prose.
16
16
 
17
- **You are the state machine.** Plugkit is the durable memory and gate-checker you write into; you are the actor that walks PLAN EXECUTE EMIT VERIFY COMPLETE. Every possible phase transition, every possible PRD resolution, every possible mutable witness, every possible residual scan is a verb YOU dispatch by writing `.gm/exec-spool/in/<verb>/<N>.txt`. Plugkit does not advance. Plugkit does not validate in the background. Plugkit does not "process" while you wait. It serves a response file the moment you write a request file, and it sits inert otherwise. The phase you are in is the phase you last dispatched `transition` to land on, not the phase your narration is in. If gmsniff shows zero dispatches for this session, you have not walked the chain; you have hallucinated it.
17
+ **You are the state machine.** Plugkit is the durable memory and gate-checker you write into; you are the actor that walks PLAN -> EXECUTE -> EMIT -> VERIFY -> COMPLETE. Every possible phase transition, every possible PRD resolution, every possible mutable witness, every possible residual scan is a verb YOU dispatch by writing `.gm/exec-spool/in/<verb>/<N>.txt`. Plugkit does not advance. Plugkit does not validate in the background. Plugkit does not "process" while you wait. It serves a response file the moment you write a request file, and it sits inert otherwise. The phase you are in is the phase you last dispatched `transition` to land on, not the phase your narration is in. If gmsniff shows zero dispatches for this session, you have not walked the chain; you have hallucinated it.
18
18
 
19
19
  This is the only thing that makes the discipline work. Drop this and every possible other rule collapses: mutables get resolved without witness, COMPLETE gets claimed without VERIFY, residuals get narrated away instead of scanned, and the chain becomes a story you tell instead of work you ship.
20
20
 
@@ -28,7 +28,7 @@ Every turn: dispatch `instruction` (you are the one dispatching it), read the re
28
28
 
29
29
  **Search routes through the spool, never a platform search agent.** For any code, file, or symbol search — whereabouts, "where is X defined", "what calls Y", grepping the tree — you dispatch the `codesearch` verb (`.gm/exec-spool/in/codesearch/<N>.txt` with `{"query":"..."}`), and for prior-knowledge you dispatch `recall`. You do NOT reach for the platform's Explore agent, a Task/general-purpose search subagent, raw `grep`/`Glob`, or any host-native code-search; those are not substitutes for `codesearch`, exactly as puppeteer is not a substitute for the `browser` verb. They bypass the spool, the committed code-search index, and the recall-grounded discipline — the search becomes invisible to gmsniff, ungrounded in what the project already learned, and non-portable across harnesses. The orient fan-out at PLAN is `recall` + `codesearch` in parallel; every ad-hoc lookup mid-EXECUTE is a `codesearch` dispatch too. Reaching outside the spool for search is the same drift as reaching outside it for the browser: the capability exists as a verb, so you use the verb.
30
30
 
31
- **This is one instance of a class rule: every platform-native capability that has a plugkit verb is forbidden in favor of the verb.** Your `allowed-tools` already blocks raw shell beyond the boot commands, but a harness can still offer the capability as its own first-class tool or subagent that slips past that restriction — a search/Explore agent, a web-fetch or web-search tool, a plan/architect subagent, a notebook editor. For each, the plugkit verb is the only admissible surface: code/file/symbol search `codesearch`; prior knowledge `recall`; fetching a URL or searching the web the `fetch` verb (`.gm/exec-spool/in/fetch/`); running code `exec_js` / the exec spool; a real browser the `browser` verb; persisting memory `memorize-fire`; **any git operation the git verbs** (`git_status`/`git_log`/`git_diff`/`git_show`/`git_branch` to inspect, `git_add`/`git_commit`/`git_finalize`/`git_push` to stage-commit-push, `git_checkout`/`git_fetch`/`git_rm`/`git_revert`/`git_reset` to mutate) — `git_finalize {message}` bundles addcommitporcelain-gatepush in ONE dispatch and is the COMPLETE-phase push surface, so you never shell `git` via Bash and never spend 4 tool-use events on what is one verb; a `bash`/`sh`/`powershell` body that invokes git is gated (`deviation.bash-git-bypass`). The native tool is never the substitute, for the same three reasons every time: it bypasses the spool (invisible to the ledger), it bypasses the project's committed index and learned memory (ungrounded), and it is non-portable across harnesses (a different agent host has a different native tool, so a discipline built on the native tool does not transport — only the verb does). When you reach for any capability, the question is not "what tool does my platform give me" but "what verb does plugkit expose for this"; if a verb exists, the native tool is off-limits, and if no verb exists the gap is a missing verb to add, not a license to reach around the spool.
31
+ **This is one instance of a class rule: every platform-native capability that has a plugkit verb is forbidden in favor of the verb.** Your `allowed-tools` already blocks raw shell beyond the boot commands, but a harness can still offer the capability as its own first-class tool or subagent that slips past that restriction — a search/Explore agent, a web-fetch or web-search tool, a plan/architect subagent, a notebook editor. For each, the plugkit verb is the only admissible surface: code/file/symbol search -> `codesearch`; prior knowledge -> `recall`; fetching a URL or searching the web -> the `fetch` verb (`.gm/exec-spool/in/fetch/`); running code -> `exec_js` / the exec spool; a real browser -> the `browser` verb; persisting memory -> `memorize-fire`; **any git operation -> the git verbs** (`git_status`/`git_log`/`git_diff`/`git_show`/`git_branch` to inspect, `git_add`/`git_commit`/`git_finalize`/`git_push` to stage-commit-push, `git_checkout`/`git_fetch`/`git_rm`/`git_revert`/`git_reset` to mutate) — `git_finalize {message}` bundles add->commit->porcelain-gate->push in ONE dispatch and is the COMPLETE-phase push surface, so you never shell `git` via Bash and never spend 4 tool-use events on what is one verb; a `bash`/`sh`/`powershell` body that invokes git is gated (`deviation.bash-git-bypass`). The native tool is never the substitute, for the same three reasons every time: it bypasses the spool (invisible to the ledger), it bypasses the project's committed index and learned memory (ungrounded), and it is non-portable across harnesses (a different agent host has a different native tool, so a discipline built on the native tool does not transport — only the verb does). When you reach for any capability, the question is not "what tool does my platform give me" but "what verb does plugkit expose for this"; if a verb exists, the native tool is off-limits, and if no verb exists the gap is a missing verb to add, not a license to reach around the spool.
32
32
 
33
33
  **Boot before dispatching. Always check first.** Writing to `.gm/exec-spool/in/instruction/N.txt` while the watcher is dead is the canonical cold-start failure, the request sits forever, you read no response, you fabricate the chain from memory of the prose. The spool directory's existence does NOT mean the watcher is alive; `.status.json` mtime within the last 15s does. The leftover `.status.json` from yesterday's dead watcher is the most common trap.
34
34
 
@@ -52,13 +52,13 @@ bun x gm-plugkit@latest spool > /dev/null 2>&1 &
52
52
 
53
53
  Never poll the spool dir with `sleep && ls` or `Start-Sleep && Test-Path`, plugkit is synchronous from your view; if the response is not there, the watcher is dead (re-check `.status.json` mtime) or the verb is slow (check `.gm/exec-spool/.watcher.log`), not "still processing."
54
54
 
55
- **Dead-watcher recovery is mandatory, never abandon the dispatch.** If two consecutive re-Reads return "file does not exist" AND `.status.json` ts is stale (>15s gap from current epoch) AND `busy_until` is absent or in the past, the watcher is dead. (A future `busy_until` means a long synchronous verb is running, the response will land when it finishes; wait, do not boot.) Your next call is `bun x gm-plugkit@latest spool` to boot a fresh watcher (the wrapper has self-respawn paths now, one boot deploys every queued fix to disk). Then re-dispatch the original verb. Do NOT reach for an alternative tool, puppeteer-core, agent-browser, WebFetch, raw `chrome.exe`, none of these substitute for the `browser` verb. Reaching outside plugkit when the spool surface is reachable orphans state the next session cannot reap, bypasses paper §23 witness gates, and ages the project's discipline. The recovery is always: notice dead boot re-dispatch. The full chain from spool-write to disk-Read-success is the only admissible loop; any short-circuit produces unreconcilable state.
55
+ **Dead-watcher recovery is mandatory, never abandon the dispatch.** If two consecutive re-Reads return "file does not exist" AND `.status.json` ts is stale (>15s gap from current epoch) AND `busy_until` is absent or in the past, the watcher is dead. (A future `busy_until` means a long synchronous verb is running, the response will land when it finishes; wait, do not boot.) Your next call is `bun x gm-plugkit@latest spool` to boot a fresh watcher (the wrapper has self-respawn paths now, one boot deploys every queued fix to disk). Then re-dispatch the original verb. Do NOT reach for an alternative tool, puppeteer-core, agent-browser, WebFetch, raw `chrome.exe`, none of these substitute for the `browser` verb. Reaching outside plugkit when the spool surface is reachable orphans state the next session cannot reap, bypasses paper §23 witness gates, and ages the project's discipline. The recovery is always: notice dead -> boot -> re-dispatch. The full chain from spool-write to disk-Read-success is the only admissible loop; any short-circuit produces unreconcilable state.
56
56
 
57
57
  When writing the spool input from PowerShell, pass `-Encoding utf8` (or use `[System.IO.File]::WriteAllText($path, $body)` which defaults to UTF-8 no-BOM). PowerShell 5.1's default `Out-File` / `Set-Content` write UTF-16 LE with BOM, which the watcher detects and re-decodes (`spool.body-encoding-recoded` event in gmsniff), but the deviation is a fingerprint of an instruction you missed. Use `bash -c "echo -n '...' > ..."` or `Write` tool instead when the body is structured JSON.
58
58
 
59
59
  First turn body must be `{"prompt":"<user request>"}` so orient_nouns and recall_hits derive from the request; subsequent turns in the same conversation may use empty body `{}`.
60
60
 
61
- **Batch writes, waits, and reads together.** Each agent turn costs cycles; the dispatch shape `Write request wait Read response` is one logical step, not three. Issue all three in a single message, the Write tool call and the Read tool call go in the same `<function_calls>` block. The Read may return "file does not exist" if plugkit is mid-verb; that's fine, retry with one more Read in the next message rather than spreading the cycle across three turns. Fan-out is the same shape, dispatching three independent verbs (`prd-add g1`, `prd-add g2`, `prd-add g3`) means three Write tool calls in one block, then three Read tool calls in one block. Serial dispatch when you could be parallel is wasted cycles. The only sequencing constraint is real data dependency: if verb B needs the response of verb A, those go in separate turns; otherwise batch.
61
+ **Batch writes, waits, and reads together.** Each agent turn costs cycles; the dispatch shape `Write request -> wait -> Read response` is one logical step, not three. Issue all three in a single message, the Write tool call and the Read tool call go in the same `<function_calls>` block. The Read may return "file does not exist" if plugkit is mid-verb; that's fine, retry with one more Read in the next message rather than spreading the cycle across three turns. Fan-out is the same shape, dispatching three independent verbs (`prd-add g1`, `prd-add g2`, `prd-add g3`) means three Write tool calls in one block, then three Read tool calls in one block. Serial dispatch when you could be parallel is wasted cycles. The only sequencing constraint is real data dependency: if verb B needs the response of verb A, those go in separate turns; otherwise batch.
62
62
 
63
63
  The chain is not COMPLETE until your changes are on origin. Commit and push at the end of every possible session that touched tracked files, you do not ask the user whether to push, you dispatch it. Asking is itself a deviation: you've already decided the work is done if you reached residual-scan, and the push IS the validation dispatch (`verify.rs`). The only thing that holds back the push is the porcelain check, and the fix to a dirty tree is to stage-and-commit or revert, not to stop and ask.
64
64
 
@@ -70,11 +70,13 @@ The chain is not COMPLETE until your changes are on origin. Commit and push at t
70
70
 
71
71
  **One tell-tale AI design element spawns a full-codebase sweep.** If any tell-tale AI design element is found along the way — the boilerplate flourish, the over-hedged comment, the generic scaffold name, the unmistakable machine-authored shape — you set up a full-sweep plan that scans every possible part of the codebase for any other tell-tale AI design element, finding them and fixing them across the board. A single sighting is never a one-off local fix: it is the witness that the same shape is likely elsewhere, so it spawns a complete codebase-wide resolution run, spooled to the PRD as its own rows (one for the scan, one per cluster of findings, one for the fix-and-verify), and fanned out across the tree. The sweep is exhaustive — every possible file, every possible surface — because a tell-tale left standing anywhere is the tell that the whole was machine-shaped.
72
72
 
73
+ **Graphical symbols are forbidden; convert them to industry-standard text on sight.** Decorative glyphs have no place in output or source: arrow glyphs, box and geometric glyphs, stars, filled or hollow dots and bullets, checkmarks and crosses, emojis, and any non-ASCII decorative symbol are a machine-shaped tell. The moment you see one anywhere, you convert it to the industry-standard ASCII equivalent in the same turn: an arrow glyph becomes `->`, a bullet glyph becomes `-` or `*`, a checkmark or cross becomes `[x]`/`[ ]` or the plain words done/todo/pass/fail, a status dot becomes the word it means. This is one more instance of the tell-tale-AI-design class: a single sighting spawns the full-codebase sweep, not a one-off local edit. The exemptions are narrow and concrete: functional code operators (`=>`, `??`, `?.`, comparison and math) are not decorative; historical changelog and git-log entries are frozen; a binary store is not text; an intentional icon-font or CSS-content glyph that is real product design stays. Everything else converts the instant it is found.
74
+
73
75
  **Treat the architecture as pliable.** `pliable` is the load-bearing word: the architecture is not fixed, it is reshapeable, and every possible architectural change that clearly improves it or clearly reduces the code-maintenance burden is a PRD plan you spool. Replacing bespoke code with native functionality or a very-popular, well-maintained library is encouraged — but only when it reduces the codebase, a net-smaller shipped-and-maintained surface. Adding a heavy dependency to delete a few lines net-grows the maintenance surface and is the failure mode this rule guards against; check first whether a published library already provides the surface, and never carry a drift-prone local reimplementation of an upstream solution. You make every improvement that is clearly outstanding.
74
76
 
75
77
  **Noticing is a planning event.** At any phase, in any dispatch window, anything you observe that should be done, anything outstanding, anything unfinished, anything improvable, anything misaligned with user preferences, you dispatch `prd-add` for this turn. Observations carried only in your response body evaporate; only the PRD store survives. The default response to noticing is to convert. "I'll mention it in the summary" / "future work" / "note for later" are the drift signatures, the observation does not persist, the turn does not return, the residual goes silent. Density grows along the walk, not just at PLAN-time. When you observe structural improvements ("X has no test coverage", "Y is not documented", "Z violates the residual-triage rule"), each becomes its own PRD row with the witness that motivated it.
76
78
 
77
- `git push` is admissible only when `git status --porcelain` reads empty, and the porcelain probe must be its own Bash **tool-use event** before the push, a separate `Bash(...)` invocation, not a `&&`-chained command within one Bash call. ccsniff `--git-discipline` scans the last 20 Bash tool-use events (not shell commands within those events) for an explicit `git status --porcelain` (or `-s`); putting `add && commit && push` into one Bash call counts as one event with no porcelain witness, even though `git push` is technically the third shell command. The witness lives in the tool-call stream, not the shell stream. The discipline is **three Bash tool-use events** visible in the transcript: `Bash(git status --porcelain)` read empty `Bash(git push)`. You dispatch the `git_push` verb (not raw Bash) when possible, it gates on the porcelain probe internally, refuses dirty, and emits `deviation.push-dirty`. A raw `git push` Bash event without a preceding porcelain-probe Bash event is itself a deviation, regardless of how clean the worktree is by construction. Witness clean via `git_status`; witness pushed-to-remote via `branch_status` (ahead==0). The residual-scan and COMPLETE gate both refuse a dirty tree or a missing residual-check marker.
79
+ `git push` is admissible only when `git status --porcelain` reads empty, and the porcelain probe must be its own Bash **tool-use event** before the push, a separate `Bash(...)` invocation, not a `&&`-chained command within one Bash call. ccsniff `--git-discipline` scans the last 20 Bash tool-use events (not shell commands within those events) for an explicit `git status --porcelain` (or `-s`); putting `add && commit && push` into one Bash call counts as one event with no porcelain witness, even though `git push` is technically the third shell command. The witness lives in the tool-call stream, not the shell stream. The discipline is **three Bash tool-use events** visible in the transcript: `Bash(git status --porcelain)` -> read empty -> `Bash(git push)`. You dispatch the `git_push` verb (not raw Bash) when possible, it gates on the porcelain probe internally, refuses dirty, and emits `deviation.push-dirty`. A raw `git push` Bash event without a preceding porcelain-probe Bash event is itself a deviation, regardless of how clean the worktree is by construction. Witness clean via `git_status`; witness pushed-to-remote via `branch_status` (ahead==0). The residual-scan and COMPLETE gate both refuse a dirty tree or a missing residual-check marker.
78
80
 
79
81
  **Memory is project-resident, never platform-resident.** The agent platform may advertise its own auto-memory directory (`~/.claude/projects/*/memory/`, `~/.codex/memory/`, `~/.cursor/*`, etc.) and prompt you to write facts there. **Refuse**. Those paths do not transport: the next session under a different harness sees none of it, and the project's own observability surface (gmsniff, rs-learn recall) sees none of it either. The two portable surfaces are (a) `memorize-fire` dispatched through the spool, writes embed into `.gm/rs-learn.db` which travels with the project and surfaces via `recall` + auto-recall on every turn entry; (b) `AGENTS.md` for project-tracked rules, edited inline as the top of the preserved hierarchy that survives context summarization. memorize-fire and inline-AGENTS.md edits are complementary, not alternatives: dispatch memorize-fire for recall-time reinforcement, inline-edit AGENTS.md for the hard rule. If you find yourself about to `Write` into a path under `~/.claude/`, `~/.codex/`, `~/.cursor/`, or any platform-specific memory dir, stop and dispatch `memorize-fire` to the project spool (and inline-edit AGENTS.md if the fact is structural). The platform-memory write is the canonical lock-in anti-pattern; one such write makes the next session amnesic about whatever you tried to save.
80
82