gm-skill 2.0.1549 → 2.0.1551
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 +62 -70
- package/gm-plugkit/instructions/browser.md +14 -21
- package/gm-plugkit/instructions/emit.md +8 -12
- package/gm-plugkit/instructions/entry.md +37 -41
- package/gm-plugkit/instructions/execute.md +20 -34
- package/gm-plugkit/instructions/plan.md +11 -19
- package/gm-plugkit/instructions/update_docs.md +11 -17
- package/gm-plugkit/instructions/verify.md +21 -31
- package/gm-plugkit/package.json +1 -1
- package/gm-plugkit/scripts/sync-instruction-consts.mjs +36 -0
- package/gm.json +1 -1
- package/package.json +1 -1
- package/prompts/bash-deny.txt +2 -2
- package/prompts/pre-compact.txt +1 -1
- package/prompts/prompt-submit.txt +24 -64
- package/scripts/check-prose-bundle.mjs +28 -0
- package/skills/gm-skill/SKILL.md +32 -42
package/AGENTS.md
CHANGED
|
@@ -22,161 +22,153 @@ Skills encode environment-specific constraints that override general knowledge.
|
|
|
22
22
|
|
|
23
23
|
# Architecture & Philosophy
|
|
24
24
|
|
|
25
|
-
This repo IS the published `gm-skill` npm package
|
|
25
|
+
This repo IS the published `gm-skill` npm package: repo root = package root, no factory, no build step generating a separate output dir. `skills/gm-skill/SKILL.md` is the entry point; orchestration logic lives in rs-plugkit, served on demand via the `instruction` verb. Agent-facing prose (phase instruction text + gate/residual messages) is externalized to an editable bundle in `gm-plugkit/instructions/`, shipped by gm-plugkit and provisioned into `.gm/instructions/<key>.md`; `rs-plugkit/src/prose.rs` serves the bundle entry per key and falls back to the compiled `const` when absent -- so editing prose is a gm-plugkit republish with no Rust rebuild. The bundle .md and the rs-plugkit `src/orchestrator/instructions/<key>.rs` consts are kept byte-aligned by `gm-plugkit/scripts/sync-instruction-consts.mjs` (regenerates each `<key>.rs` as `pub const TEXT` from the .md). Detail in rs-learn (`recall: string-externalization project`).
|
|
26
26
|
|
|
27
27
|
## WASM-only
|
|
28
28
|
|
|
29
|
-
The plugkit stack runs as a wasm cdylib loaded by `plugkit-wasm-wrapper.js` under Node/bun
|
|
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` (~149MB, embeds bge-small-en-v1.5 for offline in-wasm embeddings) is fetched at bootstrap from `plugkit-wasm` npm / `plugkit-bin` gh-releases, sha256-pinned. Size/embedding 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")]
|
|
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`).
|
|
32
32
|
|
|
33
|
-
**`plugkit-wasm-wrapper.js` is ESM; import node builtins at module scope, never inline `require()
|
|
33
|
+
**`plugkit-wasm-wrapper.js` is ESM; import node builtins at module scope, never inline `require()`** (throws silently under bun's ESM inside `catch(_){}`). Incident in rs-learn (`recall: wrapper require not defined under bun`).
|
|
34
34
|
|
|
35
|
-
**Every single-instance
|
|
35
|
+
**Every single-instance/lock guard is atomic** (`fs.openSync(path,'wx')` O_EXCL or atomic-rename), never check-then-act; count plugkit processes by executable Name, not command-line substring. Incident in rs-learn (`recall: supervisor churn TOCTOU atomic guard`).
|
|
36
36
|
|
|
37
37
|
## Spool dispatch ABI
|
|
38
38
|
|
|
39
|
-
Agents dispatch verbs by writing
|
|
39
|
+
Agents dispatch verbs by writing `.gm/exec-spool/in/<verb>/<N>.txt` and reading `.gm/exec-spool/out/<verb>-<N>.json` (nested) or `out/<N>.json` (root). The wasm orchestrator services every verb; the harness never executes side effects directly.
|
|
40
40
|
|
|
41
|
-
**Orchestrator verbs**: `instruction`, `transition`, `phase-status`, `mutable-resolve`, `memorize-fire`, `residual-scan`, `auto-recall`.
|
|
42
|
-
|
|
43
|
-
**
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
**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`).
|
|
48
|
-
|
|
49
|
-
**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`).
|
|
41
|
+
- **Orchestrator verbs**: `instruction`, `transition`, `phase-status`, `mutable-resolve`, `memorize-fire`, `residual-scan`, `auto-recall`.
|
|
42
|
+
- **Wasm-direct verbs**: fs/kv/exec/fetch/env, recall, codesearch, memorize(+prune), health, filter, full git verb family. Enumeration in rs-learn (`recall: wasm-direct plugkit verbs full list`).
|
|
43
|
+
- **memorize-prune**: deletes bad/superseded memories (a wrong recall hit is worse than a miss). `{key}`/`{keys:[...]}` deletes; `{query}` returns review-only candidates to judge before re-dispatching stale keys -- never a blind similarity-delete. Spec in rs-learn (`recall: memorize-prune verb two-mode spec`).
|
|
44
|
+
- **git verbs**: git is a first-class spool surface, never a shell command; `git_finalize {message}` is the bundled COMPLETE-phase push surface, `git_push` the only admissible raw push (porcelain-gated, rebase-retry). A git-dominant `bash`/`powershell` body is gated (`deviation.bash-git-bypass`). Per-verb shapes + host_git `.exe` resolution in rs-learn (`recall: git verbs rs-plugkit spool surface`).
|
|
45
|
+
- **filter**: pure stdout -> compact-stdout transform, in-wasm, no subprocess; pipe raw command output through it before it enters context. Spec in rs-learn (`recall: filter verb rs-plugkit spool spec`).
|
|
50
46
|
|
|
51
47
|
## Documentation Policy
|
|
52
48
|
|
|
53
|
-
|
|
49
|
+
Record only non-obvious technical caveats that cost multiple runs to discover; remove what no longer applies; never document what is obvious from the code.
|
|
54
50
|
|
|
55
|
-
**No changelog history in AGENTS.md.** Every
|
|
51
|
+
**No changelog history in AGENTS.md.** Every entry is a present-tense rule about what must/must-not be the case in code now. Forbidden: `(FIXED)` markers, commit hashes, dated audit entries, `## Learning audit` sections, "(added 2026-...)" annotations, "we used to X, now Y". History belongs in `git log` and `CHANGELOG.md`.
|
|
56
52
|
|
|
57
|
-
**Detail-heavy caveats live in rs-learn (`.gm/rs-learn.db`), not here.** Per-crate runtime quirks, Windows process-spawn mechanics, hook
|
|
53
|
+
**Detail-heavy caveats live in rs-learn (`.gm/rs-learn.db`), not here.** Per-crate runtime quirks, Windows process-spawn mechanics, hook details, ocw/site/workflow specifics, and similar fact-base material are exfiltrated to rs-learn (`exec:recall`); AGENTS.md keeps only top-level rules governing gm-the-repo. In doubt: cross-cutting policy stays here, single-crate/single-platform mechanism goes to rs-learn.
|
|
58
54
|
|
|
59
|
-
**Every memorize run also drains AGENTS.md -- migration is bidirectional, deflation is the back-pressure.** AGENTS.md
|
|
55
|
+
**Every memorize run also drains AGENTS.md -- migration is bidirectional, deflation is the back-pressure.** AGENTS.md bloats past the budget it protects if flow is only inward, so every session firing `memorize-fire` for new facts ALSO exfiltrates a few existing detail-heavy/single-crate/single-platform entries: fire the substance to the default namespace, then delete or compress the paragraph to a one-line pointer in the same commit. Witnessed by the store gaining the fact AND the byte-count dropping. A few entries per run, never a wholesale rewrite; top-level rules stay, everything recall-reachable drains.
|
|
60
56
|
|
|
61
57
|
## Coding Style
|
|
62
58
|
|
|
63
|
-
**No comments in code
|
|
59
|
+
**No comments in code** -- no inline, block, or JSDoc comments anywhere (source, generated output, hooks, scripts).
|
|
64
60
|
|
|
65
|
-
**No graphical symbols; convert to industry-standard text on sight.** Decorative glyphs are forbidden in all output and source:
|
|
61
|
+
**No graphical symbols; convert to industry-standard text on sight.** Decorative glyphs are forbidden in all output and source: arrows, box/geometric glyphs, stars, filled/hollow dots and bullets, checks/crosses, emojis, any non-ASCII decorative symbol. Convert on sight in the same turn (arrow -> `->`, bullet -> `-`/`*`, check/cross -> `[x]`/`[ ]` or done/todo/pass/fail, status dot -> the word). 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`).
|
|
66
62
|
|
|
67
|
-
**Skill SKILL.md files:**
|
|
63
|
+
**Skill SKILL.md files:** strip explanatory prose; keep ONLY invocation syntax, transition markers (`->`), gate conditions, constraint lists, exact-usage code examples.
|
|
68
64
|
|
|
69
|
-
**Implicit, not explicit, in skill prose.** Skill files (and prompt-submit.txt) elicit behavior, they do not describe it
|
|
65
|
+
**Implicit, not explicit, in skill prose.** Skill files (and prompt-submit.txt) elicit behavior, they do not describe it: terse imperative principles that trigger already-learned dispositions, not numbered procedures. Forbidden: step-by-step recipes, "see paper section X", citations to the site/papers, multi-step manuals. A skill that reads like a manual gets imitated as a script and breaks at the first edge case. The papers and site are outputs of the discipline, not inputs; never link from a skill into the docs. Cross-cutting rules needing a citation belong here, not in skills.
|
|
70
66
|
|
|
71
67
|
## Build
|
|
72
68
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
`AnEntrypoint/gm-skill` is a back-compat repo mirror that receives only `skills/gm-skill/SKILL.md` per release. The canonical install is `bun x skills add AnEntrypoint/gm`.
|
|
76
|
-
|
|
77
|
-
## the agent is the orchestrator; plugkit is the brain it drives
|
|
69
|
+
No build step; the repo root is the published artifact. `npm publish` from root publishes `gm-skill`; `package.json` `files:` pins the shipped paths. `AnEntrypoint/gm-skill` is a back-compat mirror receiving only `skills/gm-skill/SKILL.md` per release. Canonical install: `bun x skills add AnEntrypoint/gm`.
|
|
78
70
|
|
|
79
|
-
|
|
71
|
+
## The agent is the orchestrator; plugkit is the brain it drives
|
|
80
72
|
|
|
81
|
-
The PLAN -> EXECUTE -> EMIT -> VERIFY -> COMPLETE state machine lives natively in rs-plugkit
|
|
73
|
+
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`).
|
|
82
74
|
|
|
83
75
|
## gm-skill is the canonical universal harness
|
|
84
76
|
|
|
85
|
-
`skills/gm-skill/SKILL.md` is the single source of truth for harness behavior
|
|
77
|
+
`skills/gm-skill/SKILL.md` is the single source of truth for harness behavior and the only skill shipped; the legacy 15-platform fanout (gm-cc/gm-gc/gm-oc/gm-codex/gm-kilo/gm-qwen/gm-hermes/gm-thebird/gm-vscode/gm-cursor/gm-zed/gm-jetbrains/gm-copilot-cli/gm-antigravity/gm-windsurf) is retired and those repos archived. Users install gm-skill directly into whatever harness they use.
|
|
86
78
|
|
|
87
79
|
## Tool surface is plugkit-only
|
|
88
80
|
|
|
89
|
-
Every
|
|
81
|
+
Every skill's `allowed-tools:` is reduced to `Skill, Read, Write` (plus the SKILL.md boot commands `Bash(bun *)`/`Bash(npx *)`); `Write` is permitted exclusively for spool dispatch. Every other side effect -- code execution, git, browser, recall, memorize, codesearch -- routes through the spool and is serviced by plugkit. The harness never reaches around plugkit; a missing capability is a new plugkit verb, not a skill-side tool.
|
|
90
82
|
|
|
91
83
|
## Core Rules
|
|
92
84
|
|
|
93
|
-
**Shared memory & search index are tracked, never ignored**: `.gm/rs-learn.db` and `.gm/code-search/` are committed so
|
|
85
|
+
**Shared memory & search index are tracked, never ignored**: `.gm/rs-learn.db` and `.gm/code-search/` are committed so state shares across machines, sessions, CI runs. Never add `.gm/`, `.gm/rs-learn.db`, `.gm/code-search/`, or legacy `.code-search/` to ignore rules; transient `.gm/*` entries are listed one-by-one between the managed markers (parent-re-include caveat). Entry list + `ensureGitignored` mechanics in rs-learn (`recall: gm managed-gitignore mechanics`). Project-local persistent state writes under `.gm/<name>/`, never a top-level dotfile/dotdir.
|
|
94
86
|
|
|
95
|
-
**Disciplines are isolated knowledge stores**: per-project
|
|
87
|
+
**Disciplines are isolated knowledge stores**: per-project at `<project>/.gm/disciplines/<name>/{rs-learn.db, code-search/}`, each owning its own DB + index. A `@<name>` sigil makes isolation strict (cross-discipline reads forbidden). Without a sigil, reads (recall/codesearch) fan across `default` plus every enabled discipline (one per line in `enabled.txt`), merge-ranked with `[discipline:<name>]` prefixes; writes without a sigil go to `default` only. Disciplines are tracked, never ignored (`ensureGitignored` must not list `.gm/disciplines` or any subpath). The harness and every spool verb propagate the `@<name>` sigil verbatim.
|
|
96
88
|
|
|
97
|
-
**Nothing fake in source the user runs**: every
|
|
89
|
+
**Nothing fake in source the user runs**: every stub, mock, placeholder return, fixture-only path, demo-mode short-circuit, and "TODO: implement" body is forbidden in shipped code. Scaffolds/shims are permitted only when they delegate to real behavior (real upstream API, subprocess, disk); before adding a shim, check whether a published library already provides the surface. Detection is behavioral: code that always succeeds, returns the same value regardless of input, or short-circuits a real call to satisfy a type signature is a stub. Acceptance is real input through real code into real output, witnessed.
|
|
98
90
|
|
|
99
|
-
**Spool dispatch gates**: `lib/spool-dispatch.js::checkDispatchGates(sessionId, operation)` reads `.gm/` marker files and returns `{allowed, reason}`; denials surface the reason
|
|
91
|
+
**Spool dispatch gates**: `lib/spool-dispatch.js::checkDispatchGates(sessionId, operation)` reads `.gm/` marker files and returns `{allowed, reason}`; denials surface the reason as imperative instruction, never mutate args. Marker semantics in rs-learn (`recall: spool dispatch gates marker files`).
|
|
100
92
|
|
|
101
|
-
**Done is plugkit's pronouncement, never the agent's claim**: the chain is COMPLETE only when `transition to=COMPLETE` returns COMPLETE phase and
|
|
93
|
+
**Done is plugkit's pronouncement, never the agent's claim**: the chain is COMPLETE only when `transition to=COMPLETE` returns COMPLETE phase and the on-disk state file reflects it. The COMPLETE gate (gates.rs) is the single arbiter -- it refuses on PRD-open, mutables-unresolved, dirty worktree, or missing residual-scan marker. The agent drives the chain into a gate-allowing state, dispatches the verb, reads the response; every alternative is narration.
|
|
102
94
|
|
|
103
|
-
**Every residual is triaged this turn, never named-and-deferred**: every
|
|
95
|
+
**Every residual is triaged this turn, never named-and-deferred**: every `git status --porcelain` entry at residual-scan or COMPLETE-attempt is triaged now -- (a) commit (real session/upstream work), (b) add to the managed gitignore block (transient runtime emission like `.gm/witness/`, `.gm/exec-spool/.*-stale.json`), or (c) revert (junk). "Pre-existing residual" is the outcome of triage (a)/(c), never a stop excuse. `blockedBy: external` is admissible only when triage needs authority this session cannot reach; for local-tree files the agent always has authority. Disciplines are tracked; new memorize-fire `mem-*.json` are committed. The managed block (between `# >>> plugkit managed` markers) carries only runtime artifacts with no future read value.
|
|
104
96
|
|
|
105
|
-
**"Every possible" is the load-bearing test, applied to every noun the request names**: PLAN-phase PRD construction is exhaustive, not minimal
|
|
97
|
+
**"Every possible" is the load-bearing test, applied to every noun the request names**: PLAN-phase PRD construction is exhaustive, not minimal -- "every possible" task/validation/mutable/corner-case/caveat/failure-mode/interaction/empty-overflow-reentry/degenerate-input produces rows. A non-trivial request yielding a single-digit PRD has not finished enumerating. After the first pass, the list feeds a second transform: for each row, what every possible corner case looks like becomes more rows; closed when applying "every possible" yields nothing new, not when the agent feels done. Validations, edge cases, anticipated mutables are first-class rows. Long-horizon requests routinely produce high-tens-to-hundreds; the row count is the resolution of the cover, which is what the user asked for. Sparse PRDs orphan the work; dense PRDs make completion observable.
|
|
106
98
|
|
|
107
|
-
**Every possible aspect that can be checked for jank is a PRD row; the architecture is pliable**: at PLAN, for every surface the
|
|
99
|
+
**Every possible aspect that can be checked for jank is a PRD row; the architecture is pliable**: at PLAN, for every surface the prompt concerns, enumerate every aspect checkable for `jank` -- every immaturity, unfinished edge, half-wired path -- across gui/ux/ui/client-state/server-state/the boundary and any surface reached, each its own row including a profiling row and a security row per surface. `jank` is load-bearing: hunt the rough/unpolished/almost-done, not only outright bugs. Scoped to the prompt's concern + its reachable closure, exhaustive within it. Every issue found opens its own debug-and-repair plan spooled the same turn; every quick improvement is spooled too. `pliable`: every architectural change that clearly improves or reduces maintenance burden is a spooled plan -- replacing bespoke code with native functionality or a popular well-maintained library is encouraged ONLY when it nets a smaller maintained surface (a heavy dep for a few lines is the guarded failure mode). Fan-out is the spool-native shape (parallel `prd-add`/`codesearch`/`exec_js`, plugkit task-spawn), never the platform's Task/Explore subagent. One tell-tale AI design element (boilerplate flourish, over-hedged comment, generic scaffold name, machine-authored shape) spawns a full-codebase sweep plan -- scan/per-cluster/fix-and-verify rows, exhaustive over every file, never a one-off fix.
|
|
108
100
|
|
|
109
|
-
**Client-side debugging exposes globals and evaluates in-browser, never blind-restarts**:
|
|
101
|
+
**Client-side debugging exposes globals and evaluates in-browser, never blind-restarts**: surface the relevant state as a `window.*` global and read it live via the `browser` verb's `page.evaluate`, running experiments in the browser, rather than blind experimentation + server restarts. The live page is the debugger; the same `browser` surface that witnesses an edit also diagnoses it.
|
|
110
102
|
|
|
111
|
-
**Mundane user-facing output is suppressed or stripped to the bone**:
|
|
103
|
+
**Mundane user-facing output is suppressed or stripped to the bone**: drop articles, preamble, 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 + one-line reason, a blocker, the single-line PRD-read declaration. Terse = fewer/shorter words, NEVER zero tool calls and NEVER silent work -- the turn still ends in the chain-advancing tool call.
|
|
112
104
|
|
|
113
|
-
**Noticing is a planning event, at every phase, in every dispatch window**: any observation
|
|
105
|
+
**Noticing is a planning event, at every phase, in every dispatch window**: any observation -- anything outstanding, unfinished, improvable, misaligned with user preferences, or that the work surfaces about what else it touches -- is a `prd-add` this turn. Observations carried in the response body without conversion evaporate when the turn ends; only the PRD store survives. Density grows along the walk, not just at PLAN-time; a chain exiting PLAN with N rows and reaching COMPLETE with N rows has lost its discoveries. Structural noticing ("no test coverage on X", "docs miss Y", "commit Z violates a rule") and preference-aware noticing (state diverging from dense-PRDs/residual-triage/no-name-and-defer/every-possible-expansion/browser-witness/push-on-clean) each become a row with the witness that motivated it.
|
|
114
106
|
|
|
115
|
-
**A turn without a tool call is a stop; summary is a stop; both are forbidden until plugkit pronounces COMPLETE**: every programming agent
|
|
107
|
+
**A turn without a tool call is a stop; summary is a stop; both are forbidden until plugkit pronounces COMPLETE**: every programming agent reads only tool calls and their outputs, so a prose-only message ends the turn and halts the session -- the mechanical root of "agent did one piece and stopped". Deferred intent is the same stop facing forward (a turn-final sentence naming the next move instead of making it strands the chain where the prose pointed). Absolute and tool-agnostic: while in-flight (phase != COMPLETE OR prd_pending_count > 0) the agent NEVER ends a turn in prose -- every turn ends in a chain-advancing tool call (`instruction`, the next named verb, `transition`, `phase-status`). Surface a decision through `AskUserQuestion` or `prd-add`, never a prose-only "confirming direction." Only `phase=COMPLETE` AND `prd_pending_count=0` authorizes a prose-only turn; the agent's sense that "the work feels done" authorizes nothing. Before any apparent stop, dispatch `phase-status` and recheck. Depends only on the verb spool, so it holds on every agent with no hook.
|
|
116
108
|
|
|
117
|
-
**Always seek the next state transition**:
|
|
109
|
+
**Always seek the next state transition**: not-COMPLETE means a next move exists; idle mid-chain is a deviation. `phase-status` tells you where you are, `instruction` what's next. No "I'll wait for the user" mid-chain -- the user authorized closure at request time, not phase-by-phase.
|
|
118
110
|
|
|
119
|
-
**Return to plugkit on every possible drift**: `instruction` is the recovery primitive
|
|
111
|
+
**Return to plugkit on every possible drift**: `instruction` is the recovery primitive -- against every stall, gate-denial, error, or uncertainty, dispatch `instruction` and read the prose, never improvise. Synchronous, cheap, idempotent; over-dispatching has no cost, under-dispatching is the canonical drift mechanism. Every gate denial names the next verb in its `reason` field; read it and dispatch that verb, never argue around the denial.
|
|
120
112
|
|
|
121
|
-
**Push is part of COMPLETE, never optional, never asked**: every
|
|
113
|
+
**Push is part of COMPLETE, never optional, never asked**: every session that mutates tracked files ends with commit + push to origin. Asking "do you want me to push?" is a deviation -- the push IS the validation dispatch (`verify.rs`). The chain is not COMPLETE until the remote reflects HEAD. ccsniff `--git-discipline` and `deviation.complete-without-push` flag sessions closing without pushing.
|
|
122
114
|
|
|
123
|
-
**Direct-push to main, never a branch, never a PR**: every
|
|
115
|
+
**Direct-push to main, never a branch, never a PR**: every gm/rs-* change commits straight to `main` and pushes; the git verbs (`git_finalize`/`git_push`) already target `main`, and the cascade ships from `main`. A feature branch, PR, or fork is a deviation -- the workflow has no review-gate, the push IS the validation dispatch. For a sibling repo with an open PR, merge to `main`, push, delete the branch. The only admissible remote refs are `main` and `gh-pages`; holds for siblings via `git_push {repo, branch:"main"}` as for gm.
|
|
124
116
|
|
|
125
|
-
**Push requires clean worktree witnessed in its own tool-use event**: `git push` is admissible only when `git status --porcelain`
|
|
117
|
+
**Push requires clean worktree witnessed in its own tool-use event**: `git push` is admissible only when `git status --porcelain` is empty, and the porcelain probe is its own Bash tool-use event before the push, never `&&`-chained (`add && commit && push` in one call = one event with no witness). A dirty-tree push orphans the unstaged delta. The `git_push`/`git_finalize` verbs gate this internally and are preferred. Enforcement-location enumeration in rs-learn (`recall: push clean worktree enforcement locations`).
|
|
126
118
|
|
|
127
|
-
**
|
|
119
|
+
**AGENTS.md / CLAUDE.md are inline-edited AND dual-written to the store**: edit AGENTS.md/CLAUDE.md inline for structural rules (the top of the preserved hierarchy, the only doc surviving context summarization), AND in the same session dispatch `memorize-fire` (`.gm/exec-spool/in/memorize-fire/<N>.txt`, raw text or `{text, namespace?}`) for the same rule so `recall`/`auto_recall` surface it on future turns. The two are complementary, not alternatives. Never pass `namespace:"AGENTS.md"`; load-bearing rules go to the default namespace. The classifier rejects changelog-shaped facts from AGENTS.md ingestion (the rs-learn store still accepts them).
|
|
128
120
|
|
|
129
|
-
**Behavioral discipline lives in plugkit's `instruction` verb**: dispatch `instruction` for the live phase-specific prose (Three-Layer Admission Filter, maturity-first emit, closure anti-shapes, code invariants); do not duplicate it here.
|
|
121
|
+
**Behavioral discipline lives in plugkit's `instruction` verb**: dispatch `instruction` for the live phase-specific prose (Three-Layer Admission Filter, maturity-first emit, closure anti-shapes, code invariants); do not duplicate it here. Enumeration in rs-learn (`recall: instruction-verb behavioral discipline invariants`).
|
|
130
122
|
|
|
131
|
-
**The agent IS the LLM rs-learn calls
|
|
123
|
+
**The agent IS the LLM rs-learn calls**: rs-learn never reaches a separate judge model for a quality score, relevance call, prune decision, route outcome, or loss signal -- plugkit IS the harness and the agent IS the model, so each is an inline decision reported through the spool. Heavy `recall`+`learn` grounds the judgments. Per-core internals (MicroLoRA self-report logit, FastGRNN router, deep-core record_loss, attention nudge_relation, memorize-prune) in rs-learn (`recall: rs-learn self-report core internals`).
|
|
132
124
|
|
|
133
|
-
**host_exec_js is synchronous**: pass a real per-call `timeoutMs` (zero/missing is a hard error); long subprocesses block the watcher; no async/background exec under wasm.
|
|
125
|
+
**host_exec_js is synchronous**: pass a real per-call `timeoutMs` (zero/missing is a hard error); long subprocesses block the watcher; no async/background exec under wasm. Detail in rs-learn (`recall: host_exec_js synchronous`).
|
|
134
126
|
|
|
135
|
-
**Sync-before-emit (codeinsight + search)**: codeinsight/search output must come from a freshly-synced index this invocation (cache serves only on digest match); unverified-index emit = stale ground truth.
|
|
127
|
+
**Sync-before-emit (codeinsight + search)**: codeinsight/search output must come from a freshly-synced index this invocation (cache serves only on digest match); unverified-index emit = stale ground truth. Mechanics in rs-learn (`recall: sync-before-emit codeinsight search`).
|
|
136
128
|
|
|
137
|
-
**Auto-recall on turn entry**: the `instruction` verb attaches an `auto_recall` pack
|
|
129
|
+
**Auto-recall on turn entry**: the `instruction` verb attaches an `auto_recall` pack on the first dispatch after a >30s idle gap or session-start; orientation comes through that pack, not legacy hooks. Detail in rs-learn (`recall: auto-recall on turn entry`).
|
|
138
130
|
|
|
139
131
|
**Skill SKILL.md frontmatter `allowed-tools:` is harness-enforced**: a skill must list `Skill` (and `Read`/`Write`, Write only for spool dispatch) or it loses downstream-skill invocation that turn. Detail in rs-learn (`recall: SKILL.md frontmatter allowed-tools`).
|
|
140
132
|
|
|
141
|
-
**rs-learn observability**: every learning-pipeline state change emits a structured `evt:{event,sess,ts,...}` line into `.gm/exec-spool/.watcher.log` + gm-log; recall replies carry `mode`/`namespace`/`derived_query`/per-hit `score`; gmsniff/ccsniff expose the taxonomy.
|
|
133
|
+
**rs-learn observability**: every learning-pipeline state change emits a structured `evt:{event,sess,ts,...}` line into `.gm/exec-spool/.watcher.log` + gm-log; recall replies carry `mode`/`namespace`/`derived_query`/per-hit `score`; gmsniff/ccsniff expose the taxonomy. Taxonomy + flag list in rs-learn (`recall: rs-learn observability taxonomy`).
|
|
142
134
|
|
|
143
|
-
**Bootstrap contract (skill-init + SKILL.md auto-refresh + project wiring)**: `bootstrapPlugkit`/`ensureReady` initialize wasm hook-free (failures non-fatal), sha256-rewrite stale installed SKILL.md, and seed per-project `CLAUDE.md` (`@AGENTS.md`) + `.gm/next-step.md
|
|
135
|
+
**Bootstrap contract (skill-init + SKILL.md auto-refresh + project wiring)**: `bootstrapPlugkit`/`ensureReady` initialize wasm hook-free (failures non-fatal), sha256-rewrite stale installed SKILL.md, and seed per-project `CLAUDE.md` (`@AGENTS.md`) + `.gm/next-step.md`; the wiring lives in `gm-plugkit/bootstrap.js::ensureReady` (the consumer-project watcher boot path), not only repo-root `bin`/`lib`. Detail in rs-learn (`recall: skill-initiated bootstrap contract`, `recall: SKILL.md auto-refresh`).
|
|
144
136
|
|
|
145
137
|
## Cascade pipeline
|
|
146
138
|
|
|
147
|
-
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.
|
|
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. Step sequence + PUBLISHER_TOKEN setup in rs-learn (`recall: cascade pipeline`).
|
|
148
140
|
|
|
149
|
-
Three npm packages publish from this repo: `gm-skill` (
|
|
141
|
+
Three npm packages publish from this repo: `gm-skill` (harness), `gm-plugkit` (bootstrap + watcher), `plugkit-wasm` (wasm binary) -- all shipped on every version-bump commit. The legacy 15 downstream repos are archived (no further releases).
|
|
150
142
|
|
|
151
|
-
**Repos involved (push to any triggers cascade):** `AnEntrypoint/{rs-exec, rs-codeinsight, rs-search, rs-plugkit, rs-learn, gm}`
|
|
143
|
+
**Repos involved (push to any triggers cascade):** `AnEntrypoint/{rs-exec, rs-codeinsight, rs-search, rs-plugkit, rs-learn, gm}` -- rs-plugkit Cargo.toml is the version source-of-truth, gm.json holds plugkitVersion. Per-repo roles in rs-learn (`recall: cascade repos involved roles`).
|
|
152
144
|
|
|
153
|
-
**To update every possible thing**: push to the relevant repo. No manual version bumps, no local cargo builds
|
|
145
|
+
**To update every possible thing**: push to the relevant repo. No manual version bumps, no local cargo builds -- never run `cargo update`/`cargo build` locally, push and let CI build.
|
|
154
146
|
|
|
155
|
-
**Timeout enforcement**: every
|
|
147
|
+
**Timeout enforcement**: every `exec_js` dispatch carries a positive `timeoutMs`; the host treats missing or zero as a hard error.
|
|
156
148
|
|
|
157
149
|
## Spool-dispatch architecture replaces hooks
|
|
158
150
|
|
|
159
|
-
Orchestration state is tracked via `.gm/` marker files, not hook events; the CLI layer calls `checkDispatchGates()` before tool execution to gate Write/Edit/git. Marker set (`prd.yml, mutables.yml, needs-gm, gm-fired-<sessionId>, residual-check-fired`)
|
|
151
|
+
Orchestration state is tracked via `.gm/` marker files, not hook events; the CLI layer calls `checkDispatchGates()` before tool execution to gate Write/Edit/git. Marker set (`prd.yml, mutables.yml, needs-gm, gm-fired-<sessionId>, residual-check-fired`) + SpoolDispatcher mechanism in rs-learn (`recall: gate enforcement layer`, `recall: spool dispatch gates marker files`).
|
|
160
152
|
|
|
161
|
-
**gm-skill tool-use sequencing**:
|
|
153
|
+
**gm-skill tool-use sequencing**: `Skill(skill="gm-skill")` writes `.gm/gm-fired-<sessionId>` to clear the needs-gm gate (cleared at turn start to reset it). One shipped skill, no subagent variant.
|
|
162
154
|
|
|
163
|
-
**The skill is the driver, not a post-hoc witness**: when a request carries the standing instruction to use gm-skill (every `/loop` fire, any prompt naming `/gm-skill`), the FIRST working action
|
|
155
|
+
**The skill is the driver, not a post-hoc witness**: when a request carries the standing instruction to use gm-skill (every `/loop` fire, any prompt naming `/gm-skill`), the FIRST working action is `Skill(skill="gm-skill")`, and the skill prose drives the chain PLAN->COMPLETE. Dispatching spool verbs directly without first entering the skill executes the work outside the skill the user asked to drive it; entering only at the end to confirm terminal state does NOT satisfy the instruction. The boot probe (`cat .gm/exec-spool/.status.json` ...) is prescribed by the skill and may precede invocation; everything that mutates state happens inside the skill-driven session.
|
|
164
156
|
|
|
165
|
-
**Dead-watcher recovery uses `bun x gm-plugkit@latest spool`, never direct-node boot** (mechanism
|
|
157
|
+
**Dead-watcher recovery uses `bun x gm-plugkit@latest spool`, never direct-node boot** (mechanism in rs-learn: `recall: dead-watcher recovery bun x not direct-node`).
|
|
166
158
|
|
|
167
|
-
**The first verb after a genuine multi-minute IDLE is `instruction`, to reset the long-gap clock
|
|
159
|
+
**The first verb after a genuine multi-minute IDLE is `instruction`, to reset the long-gap clock**: the gate fires on genuine idle only (>300s since the last instruction AND >300s since any verb), so active back-to-back work verbs keep the chain alive without an interleaved `instruction` -- do not inject defensive instruction dispatches between active work. A true wait (version download, overnight, long external CI watch) trips it, and the first verb back is `instruction`. When the wait is self-inflicted and predictable (a blocking `TaskOutput`/`gh run watch`), dispatch `instruction` immediately BEFORE entering the wait, not only after. Mechanism in rs-learn (`recall: first verb after multi-minute wait instruction long-gap`).
|
|
168
160
|
|
|
169
|
-
**A stop-hook firing on a terminal chain does not authorize re-polling**: when a stop-hook
|
|
161
|
+
**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.
|
|
170
162
|
|
|
171
163
|
**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`).
|
|
172
164
|
|
|
173
165
|
## Spool observability surface
|
|
174
166
|
|
|
175
|
-
One-shot system-state probe: dispatch `plugkit health` via the file-spool before assuming any component is broken. Three runtime diagnostic files at `.gm/exec-spool/` root (`.status.json`, `.last-session-start.json`, `.bootstrap-error.json`) are readable directly via Read (runtime-data exception).
|
|
167
|
+
One-shot system-state probe: dispatch `plugkit health` via the file-spool before assuming any component is broken. Three runtime diagnostic files at `.gm/exec-spool/` root (`.status.json`, `.last-session-start.json`, `.bootstrap-error.json`) are readable directly via Read (runtime-data exception). Field enumeration in rs-learn (`recall: plugkit health verb fields`).
|
|
176
168
|
|
|
177
169
|
## Site Build & Documentation
|
|
178
170
|
|
|
179
|
-
|
|
171
|
+
Site build is single-surface detail in rs-learn (`recall: gm site build details`): navigation.yaml grouped-entry format + flatspace `C.Topbar` dropdowns, the `site/theme.mjs`+`home.yaml` landing renderer (never `site/index.html`), in-page topbar sync, Mermaid render, generated `docs/styles.css`, and the `docs/made-with.html` showcase.
|
|
180
172
|
|
|
181
173
|
|
|
182
174
|
@.gm/next-step.md
|
|
@@ -1,50 +1,43 @@
|
|
|
1
1
|
# BROWSER
|
|
2
2
|
|
|
3
|
-
## Hard Rule: Browser Witness Mandate (paper
|
|
3
|
+
## Hard Rule: Browser Witness Mandate (paper section 23)
|
|
4
4
|
|
|
5
|
-
**Every
|
|
5
|
+
**Every edit to code that runs in a browser requires a live `browser` dispatch in the same turn as the edit.** Client-side surfaces -- `.html`, `.js`, `.jsx`, `.ts`, `.tsx`, `.vue`, `.svelte`, `.mjs`, `.css`, web components, service workers, every asset loaded by `<script>`, every path reached by `import` from a browser-side entry -- must be witnessed by a live `page.evaluate` of the specific invariant the edit establishes. A passing node test, build, `curl` of the HTML, or static-analysis pass witnesses server delivery, not browser behavior, and is non-substitutive. The witness IS the proof; prose is not.
|
|
6
6
|
|
|
7
|
-
Protocol
|
|
7
|
+
Protocol: (1) boot the real surface -- server up, page reachable, HTTP 200 witnessed; (2) `browser` dispatch -> navigate -> poll for the global the change affects; (3) `page.evaluate` asserting the invariant, capturing witnessed values into `stdout`; (4) variance -> fix at root cause, re-witness. Never advance on unwitnessed client behavior, never queue validation for "later" -- the same turn that edits a client-side file dispatches the browser verb validating it.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- **EXECUTE**: edit a client-side file → dispatch `browser` in the same turn against the live page asserting the invariant the edit establishes
|
|
11
|
-
- **EMIT**: post-emit re-witness — the page still passes the invariant after the full diff lands
|
|
12
|
-
- **VERIFY**: final gate — `browser-witness-hash-mismatch` deviation fires if any file you witnessed earlier has changed without re-witnessing
|
|
9
|
+
Fires across phases: **EXECUTE** edit -> same-turn browser dispatch asserting the invariant; **EMIT** post-emit re-witness (page still passes after the full diff); **VERIFY** final gate -- `deviation.browser-witness-hash-mismatch` fires if a witnessed file changed without re-witnessing. Pure-prose static-document edits (no JS, no CSS-driven behavior, no DOM mutation) are the ONLY exempt category, and the exemption must be named explicitly in the response so the skip is auditable. Silent skip on actual behavior change is forced closure.
|
|
13
10
|
|
|
14
|
-
|
|
11
|
+
YOU drive the browser through the spool: plugkit holds the Chromium handle, per-project profile, and session table; you advance by writing `.gm/exec-spool/in/browser/<N>.txt` and reading `out/<N>.json`. There is no library import, no puppeteer/playwright/CDP handle that shortcuts this. The verb is the surface; every other reach is fabrication.
|
|
15
12
|
|
|
16
|
-
|
|
13
|
+
## Body shapes
|
|
17
14
|
|
|
18
|
-
The body is a string
|
|
15
|
+
The body is a string, five shapes only:
|
|
19
16
|
|
|
20
17
|
```
|
|
21
18
|
session new
|
|
22
19
|
session list
|
|
23
|
-
session
|
|
20
|
+
session close <id>
|
|
24
21
|
<arbitrary JS expression evaluated in page context>
|
|
25
22
|
timeout=<ms>\n<expression>
|
|
26
23
|
```
|
|
27
24
|
|
|
28
|
-
A bare expression with no live session opens one
|
|
29
|
-
|
|
30
|
-
Default per-evaluation timeout is 14000ms. Operations that legitimately exceed this (long page loads, multi-step navigation, slow remote APIs) prefix `timeout=<ms>\n` with the desired millisecond cap; the wrapper clamps to 50000ms maximum. The response includes `timeout_ms_used` so you witness which budget actually applied. `browser.runner-timeout` event fires when the runner hits the cap — read your `stderr`, narrow the operation, or raise timeout; do not retry blind at the same budget.
|
|
25
|
+
A bare expression with no live session opens one against `about:blank`; with a live session it reuses it. `session new` returns the id you carry; with more than one open, target it via `session=<id>\n<expr>`. (`session close` and `session kill` are aliases.) Default per-eval timeout 14000ms; operations that legitimately exceed it prefix `timeout=<ms>\n` (wrapper clamps to 50000ms). The response carries `timeout_ms_used`; `browser.runner-timeout` fires at the cap -- read `stderr`, narrow or raise, never retry blind at the same budget.
|
|
31
26
|
|
|
32
27
|
## Envelope
|
|
33
28
|
|
|
34
|
-
|
|
29
|
+
`{ok, stdout, stderr, exit_code, session_id?}`. `stdout` = stringified eval result; `stderr` = page errors + launch diagnostics; `exit_code` non-zero = the dispatch did not land -- read `stderr` and re-dispatch, never blind.
|
|
35
30
|
|
|
36
31
|
## Headed by default
|
|
37
32
|
|
|
38
|
-
The window opens on the user's screen
|
|
33
|
+
The window opens on the user's screen -- that IS the witness. `GM_BROWSER_HEADLESS=1` opts into headless; absent it, a session with no visible window is a launch you did not make. Do not assume or request headless to "be quiet"; the flash is the proof.
|
|
39
34
|
|
|
40
35
|
## Profile
|
|
41
36
|
|
|
42
|
-
`session new` (or a bare expression with no live session) spawns a locally-profiled Chromium at `<cwd>/.gm/browser-profile
|
|
37
|
+
`session new` (or a bare expression with no live session) spawns a locally-profiled Chromium at `<cwd>/.gm/browser-profile/`; the runner attaches via `--direct <wsEndpoint>`. Cookies/storage/extensions persist across sessions, turns, and runs. A second concurrent launch contends the SingletonLock; the watcher reuses the live CDP rather than re-launching. The runner's extension-attach mode ("Waiting for extension to connect") is never the default or what you want -- seeing it in `stderr` means the host failed to spawn local Chromium; dispatch `instruction` for recovery, not a blind retry.
|
|
43
38
|
|
|
44
39
|
## Discipline
|
|
45
40
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
A dispatch that returns `ok:false` with a launch error is plugkit telling you the environment refused; you read the `stderr`, you dispatch `instruction`, you do not loop the same body waiting for a different answer.
|
|
41
|
+
Never spawn Chromium yourself, `npm i puppeteer`, or shell `chrome.exe`; the verb owns the handle, and bypassing it orphans state plugkit cannot reap and breaks the next session's first read. Navigate by evaluating `location.href = '...'` through the spool; screenshot by dispatching the verb that returns one. A dispatch returning `ok:false` with a launch error is plugkit reporting the environment refused -- read `stderr`, dispatch `instruction`, do not loop the same body.
|
|
49
42
|
|
|
50
|
-
**Dead-watcher recovery, never substitute.** If
|
|
43
|
+
**Dead-watcher recovery, never substitute.** If a Write to `.gm/exec-spool/in/browser/<N>.txt` produces no response after two re-Reads AND `.status.json` ts is stale (>15s from current epoch), the watcher is dead: boot `bun x gm-plugkit@latest spool`, then re-dispatch the browser body. Do NOT reach for puppeteer-core, puppeteer, playwright, agent-browser, `chrome.exe`, `npx browserless`, WebFetch, or curl-then-parse -- the browser verb is the only admissible browser surface; substitutes spawn orphan Chromium plugkit cannot reap, bypass section 23 witness-marked events, and produce evidence the gate cannot read. The recovery loop is always: empty response -> check `.status.json` -> if stale, boot -> re-dispatch.
|
|
@@ -1,31 +1,27 @@
|
|
|
1
1
|
# EMIT
|
|
2
2
|
|
|
3
|
-
YOU are the state machine. Plugkit is the synchronous library serving this prose; advancing the chain is your dispatch
|
|
3
|
+
YOU are the state machine. Plugkit is the synchronous library serving this prose; advancing the chain is your dispatch. Every write lands only through the verb you dispatch to land it.
|
|
4
4
|
|
|
5
|
-
L3 audit on disk.
|
|
5
|
+
L3 audit on disk. Land every node of the covering family; your first emit = closure.
|
|
6
6
|
|
|
7
7
|
## Read-before-write
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
The target file's on-disk content is the goal-relative reference; diffing an unread file diffs an imagined baseline, leaving your candidate unmeasured. On observed disk divergence, `transition` back to PLAN.
|
|
10
10
|
|
|
11
11
|
## Fresh index
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Feed search outputs into EMIT only when the digest matches the live filesystem; a stale-index result is an L1 bluff.
|
|
14
14
|
|
|
15
15
|
## Write-then-verify
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
One write per artifact, then a disk Read against every touched path to assert the change -- verified disk state IS the witness, not the tool-call return. On discrepancy, regress to root cause, do not retry.
|
|
18
18
|
|
|
19
|
-
**Client-side artifacts: write-then-browser-witness,
|
|
19
|
+
**Client-side artifacts: write-then-browser-witness, same turn.** If the artifact is `.html .js .jsx .ts .tsx .vue .svelte .mjs .css` or any browser-loaded path, the disk Read is necessary but not sufficient -- also dispatch a `browser` verb that `page.evaluate`s the invariant the artifact establishes (the page-side assertion is the real witness; the disk Read only witnesses serialization). Skipping it ships a green-checked stub. The COMPLETE gate refuses without the paired browser-witness for every client-side file edited this session (`deviation.client-edit-no-witness`, gates.rs), and you regress to dispatch the missing witness.
|
|
20
20
|
|
|
21
21
|
## Artifact scope
|
|
22
22
|
|
|
23
|
-
PRD names the artifacts you may write
|
|
24
|
-
|
|
25
|
-
If during write-then-verify you notice an adjacent artifact the user clearly meant included, or an improvement the act of writing exposes (a generated file the build needs, a doc that names the new artifact, a witness script the artifact deserves) — you dispatch `prd-add` for it this turn, not as a follow-on. The same noticing-to-PRD discipline applies in EMIT: an observation that does not land as a PRD row evaporates with the turn.
|
|
26
|
-
|
|
27
|
-
Between artifacts, between disk-Read checks, between a write you're uncertain about and the next — you re-dispatch `instruction`. Closure is the EMIT discipline; re-reading the prose between artifacts is how you avoid partial emits.
|
|
23
|
+
PRD names the artifacts you may write; direct closure narrative to the commit message + `memorize-fire`. A file PRD does not name is your response body displacing the dispatch surface. If write-then-verify exposes an adjacent artifact the user meant included or an improvement the act of writing reveals (a generated file the build needs, a doc naming the new artifact, a witness script), `prd-add` it this turn -- an observation that does not land as a row evaporates with the turn. Between artifacts and uncertain writes, re-dispatch `instruction`.
|
|
28
24
|
|
|
29
25
|
## Dispatch
|
|
30
26
|
|
|
31
|
-
|
|
27
|
+
`transition` when every planned artifact is written and disk-verified. On a new unknown, `transition` back to PLAN.
|