gm-plugkit 2.0.2481 → 2.0.2482
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/SKILL.md +9 -113
- package/package.json +1 -1
package/SKILL.md
CHANGED
|
@@ -6,124 +6,20 @@ allowed-tools: Skill, Read, Write, AskUserQuestion, Bash(bun *), Bash(npx *), Ba
|
|
|
6
6
|
|
|
7
7
|
# gm
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Every response must contain a tool call, or the conversation ends there permanently -- no next turn resumes it. Never end with a closing/summary sentence or a permission question; dispatch the next verb instead, or `Skill(skill="gm-continue")` at genuine `phase=COMPLETE AND prd_pending_count=0`. There is no other exit. `instruction` dispatch returns the live phase-prose and next-step guidance; dispatch it whenever uncertain, never invent the next step from memory.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Verbs write to `.gm/exec-spool/in/<verb>/<N>.txt` as JSON; read the paired `.gm/exec-spool/out/<verb>-<N>.json` in the SAME tool-call block, never narrate before reading it. Phase/PRD/mutables state lives on disk (`.gm/exec-spool/.turn-summary.json`, `.gm/prd.yml`, `.gm/mutables.yml`) and in every response body -- never assumed from context. A `phase` mismatch between `.turn-summary.json` and a fresh `instruction` response always resolves to the fresh response.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Boot probe, one call: `cat .gm/exec-spool/.status.json 2>/dev/null; echo ---; cat .gm/exec-spool/.turn-summary.json 2>/dev/null; echo ---; date +%s%3N`. Boot/reboot: `bun x gm-plugkit@latest spool` (`npx -y gm-plugkit@latest spool` if no bun) -- fire-and-forget, does not wait for serving; write your first verb right after. Dead watcher = `.status.json` `ts` stale >5min AND no future `busy_until`: boot fresh, re-dispatch. A `busy_until` in the future licenses a bounded wait (condition-poll the out/ file, never a blind sleep); it does not license declaring the watcher dead. `dispatch_orphaned` = expected mid self-update handoff, bare re-dispatch once `ts` is fresh again.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Spool verbs: `codesearch`, `recall`, `fetch`, `exec_js`, `browser`, `memorize-fire`, `prd-add`/`prd-resolve`/`mutable-add`/`mutable-resolve`, `transition`, `phase-status`, the git verb family (`git_status`, `git_finalize`, `git_push`, ...). Every capability routes through its verb -- codesearch (never Grep/Glob for discovery), browser (never raw Chrome/playwright), git verbs (never raw `git` via Bash, gated `deviation.bash-git-bypass`). `git_finalize {message}` bundles add->commit->porcelain-gate->push->CI-watch in one dispatch.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
`browser` body is plain-text prefixed, never CLI-flag syntax: `session new`, `session list`, `session close <id>` / `session reset <id>`, `timeout=<ms>\n<expr>`, `url=<target>\n<expr>`, `screenshot[=name]\n<expr>`, `dom=<selector>\n<expr>`, or a bare JS body. Prefixes stack top-to-bottom. Sessions persist a live Chrome process across dispatches until closed/idle-reaped. Every response includes `result.debug: {console, pageErrors, network, performance, gl}` unconditionally.
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Client-side edits (`.html .js .jsx .ts .tsx .vue .svelte .mjs .css`) require a `browser` witness before `transition to=COMPLETE`; a project with `.gm/browser-config.json` requires one every turn regardless of edit count.
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Phase graph (default; a project's `.gm/instructions/fsm/graph.json` can define another): SPECIFY -> PROVE -> EMIT -> STATE -> CONC -> SEC -> RES -> DECIDE -> COMPLETE, with feedback edges from every later stage back to an earlier one. Each transition is an explicit `transition {to:"PHASE"}` dispatch. COMPLETE gate: worktree clean, remote pushed, PRD empty, mutables resolved, residual-scan fired, CI green (`.ci-validated`'s `head_sha` matches current HEAD), browser-witness coverage, submodules clean, no hedge language. Mark it via `fs_write {path:".gm/exec-spool/.ci-validated", content:"{\"head_sha\":\"<sha>\"}"}` after a green CI watch.
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Spool input from PowerShell must be UTF-8 no-BOM. First-turn body is `{"prompt":"<user request>"}`; later dispatches may use `{}`. Batch independent dispatches in one message; never edit the same file twice in one block.
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
Check `.gm/exec-spool/.turn-summary.json` at turn start. If `update_available` is set, dispatch `bun x gm-plugkit@latest spool` first. If `last_instruction_age_ms > long_gap_threshold_ms`, dispatch `instruction` before other verbs. Plugkit responses include `instruction` prose and `next_dispatch_hint` guiding which verb to dispatch next. `next_dispatch_hint: null` is not an error -- it means the served phase-prose itself (or `next_phase_hint`) is the guide for this dispatch; read the prose, act on it, never treat a null hint as a stall.
|
|
28
|
-
|
|
29
|
-
A `phase` reading that disagrees between `.turn-summary.json` and the immediately-following `instruction` response is not a bug to chase -- the wasm state is the single source of truth and `.turn-summary.json` is a point-in-time snapshot that can lag a fresh dispatch (another concurrent writer, or the state simply advanced between the two reads). The `instruction` response's own `phase` field always wins; re-dispatch `instruction` once more if still uncertain, never reason from the stale snapshot.
|
|
30
|
-
|
|
31
|
-
When `phase=COMPLETE` and `prd_pending_count=0`, work is terminal. New prompts are processed as new sessions. Dispatching another `instruction` after terminal state records as `deviation.complete-chain-poll`.
|
|
32
|
-
|
|
33
|
-
Client file edits (`.html .js .jsx .ts .tsx .vue .svelte .mjs .css` or HTML-loaded) are tracked in `.turn-browser-edits.json`. `browser` dispatch witnesses them via `page.evaluate`. `transition to=COMPLETE` gate checks `.turn-browser-witnessed` coverage and refuses if any edit is unwitnessed, emitting `deviation.client-edit-no-witness`.
|
|
34
|
-
|
|
35
|
-
`browser` dispatch can expose state as `window.*` and read it via `page.evaluate`. This surface can both diagnose problems and witness correctness in the same dispatch.
|
|
36
|
-
|
|
37
|
-
Code/file/symbol lookup uses `codesearch` (`{"query":"..."}`) or `recall` (prior knowledge from memory). `codesearch` indexes the current working directory only. Sibling repos or known paths use `Read` or `exec_js` directly. Cross-repo queries return nothing by design.
|
|
38
|
-
|
|
39
|
-
Spool verbs are the primary interface: `codesearch`, `recall`, `fetch`, `exec_js`, `browser`, `memorize-fire`, git verbs (`git_status`, `git_log`, `git_diff`, `git_show`, `git_branch`, `git_add`, `git_commit`, `git_finalize`, `git_push`, `git_checkout`, `git_fetch`, `git_rm`, `git_revert`, `git_reset`). Git operations via Bash/PowerShell are recorded as `deviation.bash-git-bypass`. `git_finalize {message}` bundles add->commit->porcelain-gate->push in one dispatch.
|
|
40
|
-
|
|
41
|
-
`background-convert` (`{"verb": "...", "task": "..."}`) lets an agent detach an already-dispatched slow verb (e.g. `exec_js`, `browser`) mid-flight so it keeps running independently instead of holding up the daemon worker -- agent-initiated only, never a timer/auto-threshold. Responds `{"ok":true,"converted":true}` or `{"ok":false,"error":"already_completed"}`; the original dispatch still writes its real result to the same `out/<verb>-<task>.json` path whenever it finishes. Detail: `.gm/daemon-config-reference.md`.
|
|
42
|
-
|
|
43
|
-
`prd-resolve` accepts an optional `commit_comment` (a one-line resolution note) alongside `id`/`witness_evidence`. When present, the row's note rides until the repo's next `git_commit`/`git_finalize`, which bundles every pending note for that repo into the commit message under a "Resolved PRD rows" section and clears those rows from `.gm/prd.yml`. Unrelated issues discovered mid-task are `prd-add`, never a same-turn detour and never dropped -- a later cover picks them up deliberately.
|
|
44
|
-
|
|
45
|
-
**Single-writer discipline: `.gm/prd.yml` and `.gm/mutables.yml` are shared state, not exclusively yours.** A `prd_pending_count` that jumped since your last read, or a fresh `.gm/exec-spool/` file mtime you didn't write, means a second session is driving the same repo concurrently -- not a bug to chase. Detect it: unexplained pending-count growth between two close-together reads, or a repo's `git status --porcelain` showing edits mid-flight in files you have not touched this turn. On detection: name the actively-changing surface in a `prd-add`/`mutable-add` row (what's changing, why you are deferring), back off committing into that specific tree until it goes quiet (`git status --porcelain` empty, no fresh mtimes), and resume once it settles -- never race a commit against a concurrent writer's in-progress edit. This applies per-repo, not per-session: a multi-repo walk can safely keep working other repos while one is actively contended.
|
|
46
|
-
|
|
47
|
-
Missing `.gm/exec-spool` on first use is normal. Boot the watcher before dispatching work.
|
|
48
|
-
|
|
49
|
-
Boot probe at session start, one Bash call:
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
cat .gm/exec-spool/.status.json 2>/dev/null; echo ---; cat .gm/exec-spool/.turn-summary.json 2>/dev/null; echo ---; date +%s%3N
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
`.turn-summary.json` fields: `phase`, `prd_pending`, `last_instruction_age_ms`, `long_gap_threshold_ms`, `update_available`, `deviations_30m`. (The pending-row count is `prd_pending` on `.turn-summary.json`; the same count arrives as `prd_pending_count` on the `instruction`/`transition` RESPONSE body -- the terminal condition elsewhere in this doc names the response field, so grep `.turn-summary.json` for `prd_pending`, not `prd_pending_count`.) If `update_available` is set, dispatch `bun x gm-plugkit@latest spool`. If `last_instruction_age_ms` exceeds `long_gap_threshold_ms`, dispatch `instruction` before other verbs. `.status.json` `ts` within 5min = watcher alive; gap > 5min = dead. Exception: if `busy_until` is in the future, watcher is handling a long verb (browser, chromium spawn). The supervisor itself kills a watcher whose heartbeat is stale >30s with no future `busy_until` (its own `STATUS_STALE_MS`); this 5-minute rule is the deliberately-looser operator-side dead-detection threshold, so a long verb isn't false-flagged as dead. A watcher that keeps reappearing under a NEW pid every ~30-90s is being supervisor-killed on the 30s limit, not merely idle -- see Reboot-loop escape below rather than re-booting into the same loop.
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
bun x gm-plugkit@latest spool
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
(`npx -y gm-plugkit@latest spool` if no `bun`.) Fire-and-forget: spawns the detached daemon and returns immediately (already-alive watcher also returns at once, unchanged) -- it does NOT wait for the watcher to check serving. No `&`, no `sleep`, no re-`cat`; write your first verb to `in/` right after it returns. A first-read "file does not exist" on that verb is normal (the just-spawned watcher hasn't noticed the file yet) -- re-Read next message, same as any dead-watcher-adjacent recheck. If you need to actively check serving before dispatching (rare), read `.gm/exec-spool/.status.json` yourself and check `ts` freshness.
|
|
62
|
-
|
|
63
|
-
**The boot line resolves to agentplug-runner, the sole spool loader; `bun x gm-plugkit@latest spool` is the thin launcher that re-execs into it.** `gm-plugkit/cli.js::tryDelegateToRunner` execs `~/.gm-tools/agentplug-runner` -- a native wasmtime binary that loads gm.wasm alongside shared `bert`/`libsql`/`treesitter` plugins (so gm runs `plugkit-slim.wasm`, browser via direct CDP, task via a native registry); `.status.json` `runtime` reads `agentplug` when it serves. A missing runner binary is downloaded and sha256-verified automatically on the next boot attempt -- no separate install step. agentplug-runner auto-updates both its served `plugkit.wasm` and its own executable fully autonomously (600s poll each): a newer runner build is staged to `.new` in the background, then swapped in via a self-triggered `takeover` handoff on the next idle tick -- no agent action, no restart ever required.
|
|
64
|
-
|
|
65
|
-
The `Resolving dependencies` / `Saved lockfile` chatter before the JSON payload is `bunx` re-resolving the `@latest` tag against the registry, not gm-plugkit hanging -- the daemon already spawns detached+unref'd and the CLI itself exits the instant that happens; the visible delay is entirely bunx's own network round-trip, unavoidable on `@latest` (a pinned exact version, once bunx-cached, skips it). `GM_PLUGKIT_SKIP_SELF_STALE_CHECK=1` skips the CLI's own redundant npm-registry version probe (already covered by `@latest`'s resolution) for a faster boot on repeat same-session invocations. In PowerShell 5.1, never `2>&1`-redirect this command into another cmdlet (e.g. `| Select-Object`) -- PowerShell wraps every stderr line from a native exe in a `NativeCommandError` record and reports failure even on exit 0, turning bun's routine stderr progress output into a misleading red error block; run it bare or capture stdout only.
|
|
66
|
-
|
|
67
|
-
Two more real, code-checked env toggles beyond `GM_PLUGKIT_SKIP_SELF_STALE_CHECK`: `AGENTPLUG_NO_DAEMON` (set on the agentplug-runner process to force the non-daemon single-shot code path instead of registering with the shared machine-wide daemon) and `CLAUDE_PROJECT_DIR` (read by `gm-plugkit/bootstrap.js`/`cli.js`, `agentplug-runner`'s `main.rs`, and allowlisted through rs-plugkit's `env_get` verb -- the explicit project-root override used when the working directory isn't the project root, e.g. under a Workflow's worktree isolation).
|
|
68
|
-
|
|
69
|
-
**Dispatch shape: Write request + Read response, SAME tool-call block.** Never proceed/narrate/begin work before reading the response and following its `instruction` field. First-read "file does not exist" mid-verb = normal, re-Read next message. Never poll with `sleep && ls` -- plugkit is synchronous; missing response = dead watcher (recheck `ts`) or slow verb, never "still processing."
|
|
70
|
-
|
|
71
|
-
**Dead-watcher recovery is mandatory, not optional.** Two consecutive missing re-Reads AND stale `ts` (>5min) AND no future `busy_until` = dead: `bun x gm-plugkit@latest spool` boots fresh, re-dispatch the original verb. If `busy_until` is set, the watcher is processing a long verb; wait instead of rebooting. Recovery = notice-dead -> boot -> re-dispatch, always -- never substitute a raw tool for the dead verb.
|
|
72
|
-
|
|
73
|
-
**Waiting out a real `busy_until` window (a long `browser`/`exec_js` dispatch genuinely still running) is not the same thing as the banned bare-`sleep`-then-`ls` poll above -- the ban is on blind, unconditional sleeping when nothing indicates work is actually in flight; a live `busy_until` in the future is exactly the condition that licenses a bounded wait for it.** On a host with a background-monitor primitive (a tool that runs a shell condition and notifies on completion rather than blocking the turn), the correct shape is a condition loop over the OUT file's existence, not a fixed-duration sleep: `until [ -f .gm/exec-spool/out/<verb>-<N>.json ]; do sleep 2; done` handed to that primitive, so the wait happens off-turn and a completion notification (not a guessed delay) resumes work. On a host with no such primitive, a single bounded `sleep` no longer than the dispatch's own declared `busy_until` remaining-window (never an arbitrary guess, never chained/repeated past that one wait) is the fallback -- re-check `.status.json`'s `ts`/`busy_until` once after it elapses, do not loop blind sleeps. Either way: never poll faster than realistic verb latency (sub-second loops are themselves a form of the banned pattern), and never fall back to declaring the watcher dead just because a wait felt long -- dead is defined structurally (stale `ts` AND no future `busy_until`), not by elapsed wall-clock alone.
|
|
74
|
-
|
|
75
|
-
**Reboot-loop escape (watcher dies ~30-90s after every boot).** If a fresh `bun x gm-plugkit@latest spool` boots but the watcher dies again shortly after (heartbeat `ts` goes stale >30s with no future `busy_until`, then a new pid appears, repeatedly), the on-disk index has not finished embedding and each boot re-triggers the same synchronous code-index embed that can block the heartbeat past the supervisor's 30s stale limit (`STATUS_STALE_MS`). Confirm by reading `.gm/exec-spool/.watcher.log` for repeated `codeinsight_rebuild` + `partial pass (wall budget) ... deferred_files=N` lines whose `deferred_files` never reaches 0. The embed is genuinely converging in that case: do NOT immediately re-boot on the first stale reading -- read `.watcher.log`, and as long as `deferred_files` is strictly decreasing across `codeinsight_index_partial` events the index is converging (each accepted verb advances it one wall-budget); give it repeated single verbs until a `code_index: done` / `deferred_files=0` line appears, then normal dispatch resumes. Rebooting mid-convergence resets this progress -- the loop is the reboot, not the embed.
|
|
76
|
-
|
|
77
|
-
A `dispatch_orphaned` response ("claimed by a daemon that died before answering... a self-update handoff") is expected during a runner takeover, never a real failure -- bare re-dispatch the exact same verb once `.status.json`'s `ts` is fresh again. `.status.json`'s `last_completed_runner_swap`/`loaded_plugin_versions` are diagnostic-only, worth diffing against a prior read to notice served behavior changed mid-session; neither changes what to dispatch next.
|
|
78
|
-
|
|
79
|
-
**Apparent tooling failure is never grounds to ask the user, never a blind restart.** "Spooler not working" / missing response / stale watcher / `gm_plugkit_stale` flagged in a response = your own mechanical self-recovery: honor a future `busy_until` (wait), else boot + re-dispatch. You have boot authority; asking the user to do what a verb can do is a deviation. Staleness of any kind (stale watcher version, stale served prose vs published source) is itself a deviation to resolve immediately, the same turn it's noticed -- `bun x gm-plugkit@latest spool` first, before any other work.
|
|
80
|
-
|
|
81
|
-
`browser` dispatch can surface state as `window.*` and read it via `page.evaluate`. `exec_js` responses include `duration_ms`.
|
|
82
|
-
|
|
83
|
-
**Correct `browser` verb body shape (real spec, not CLI-flag syntax): plain-text prefixed bodies only.** The body is NEVER `-s <id> -e "<script>"` or any other CLI-flag-style string -- that is raw playwriter CLI syntax and does not apply here; the native agentplug-host `browser` handler parses the body itself using these prefixes: `session new` (bare, no script), `session list` (bare, no script), `session close <id>` / `session reset <id>` (id required, own line, no script -- `reset` is the idempotent form, no error if the id wasn't live), `timeout=<ms>\n<expr>`, `url=<target>\n<expr>` (or a bare `https://...` URL alone), `screenshot[=name]\n<expr>`, `dom=<selector>\n<expr>`, or a bare JS expression/statement body with no prefix. Prefixes stack top-to-bottom, e.g. `timeout=90000\nurl=http://host/path?a=1&b=2\nawait page.waitForTimeout(5000);\nreturn {ok:true};`. A `?`-query-string `&` in a URL is safe to include directly (fixed, see below) -- do not URL-encode it defensively. A normal eval dispatch (no `session *` prefix) always targets the dispatch's own sessionId automatically; only `session close <id>`/`session reset <id>` take an explicit id argument, which lets one dispatch close a DIFFERENT session than the one it's nominally running under.
|
|
84
|
-
|
|
85
|
-
Sessions persist a real live Chrome process (reused directly until `session close`/`session reset`, idle-reaped via `.gm/browser-config.json`'s `session_idle_timeout_ms`, or daemon exit). Reconnection targets the exact same CDP page (a persisted `target_id`, not "whichever page target CDP's `/json/list` happens to return first") -- so a session stays on the correct tab even when Chrome has more than one open. `session list` reports every live session as `{session_id, port, alive, idle_ms}`. Rationale: the recall store (`recall: gm SKILL.md browser session persistence rationale`).
|
|
86
|
-
|
|
87
|
-
**`.gm/browser-config.json` is optional and per-project** -- `BrowserConfig::load` re-reads it every dispatch, and any missing file or field falls back to its default, so an unconfigured project behaves identically. Six tunable fields with their defaults: the recall store (`recall: browser-config.json field reference`).
|
|
88
|
-
|
|
89
|
-
Debug capture, GL error tracking, and profiling are always on (no `capture`/`profile`/`trace` prefix needed for basic visibility): every `browser` response includes `result.debug: {console, pageErrors, network, performance, gl: {errors, drawCalls, errorTotalCount}}` regardless of body shape. `window.__gmGlErrors`/`__gmGlDrawCalls`/`__gmGlErrorTotalCount`/`__gmGlLastDrainedError` are live-readable via `page.evaluate` for GPU rendering-bug root-causing. `capture\n<expr>` / `profile interval=<us> topN=<n>\n<expr>` / `trace\n<expr>` prefixes remain for CPU sampling / CDP GPU-compositor tracing specifically. Mechanism detail: the recall store (`recall: gm SKILL.md browser verb GL-capture mechanism detail`).
|
|
90
|
-
|
|
91
|
-
Prior playwriter-wrapper bug sweep (Windows shell-truncation, bun argv panic, stdout-truncation, wrong Puppeteer method name) and the GL-error dedup fix: both resolved and detailed in the recall store (`recall: gm SKILL.md historical playwriter-wrapper-bugs sweep`, `recall: gm SKILL.md GL-error dedup history`).
|
|
92
|
-
|
|
93
|
-
If similar symptoms recur (stub-like responses, silent truncation, debug fields always empty), do NOT re-add a stale-bug workaround section here -- instead root-cause in the real browser-host source, which is now native in agentplug (clone `AnEntrypoint/agentplug`, edit `crates/agentplug-host/src/browser.rs` and its embedded `cdp_eval.js`, rebuild agentplug-runner, check live against the locally-built `~/.gm-tools/agentplug-runner`, then commit+push to `AnEntrypoint/agentplug` main so the fix ships through the agentplug-bin release path) and update this section with the real fix, the same discipline used for the bugs above.
|
|
94
|
-
|
|
95
|
-
**Windows-specific transient flakiness that is NOT a plugkit/wrapper bug, just retry it:** `bun x <pkg>@<version>` (any package, e.g. the gm-plugkit boot line itself) occasionally hangs indefinitely at "Resolving dependencies" with zero further output even with a pinned exact cached version -- a known intermittent Bun/Windows dependency-resolution stall, unrelated to browser automation. A bare re-dispatch of the exact same command has resolved it every time observed. Do not chase this as a code bug -- 2-3 retries is the correct response.
|
|
96
|
-
|
|
97
|
-
**Never drive Chrome/browser automation directly (no raw headless Chrome launch, no playwright/playwriter CLI) -- the `browser` verb is the only sanctioned interface, for debugging or any other purpose.** This binds the calling agent, not just the browser-host implementation: reaching for `puppeteer`/`playwright`/a raw `chrome.exe --headless` invocation via `exec_js`/Bash instead of dispatching the `browser` verb is the same class of deviation as bypassing `codesearch` with raw `Grep`, or bypassing git verbs with raw `git` via Bash. The verb's own native implementation (`crates/agentplug-host/src/browser.rs`, see below) already drives Chrome directly over CDP with no playwriter dependency -- that is an implementation detail of the sanctioned path, not license to reach around it and drive Chrome/playwright by hand.
|
|
98
|
-
|
|
99
|
-
**The browser verb drives Chrome directly over CDP, native in agentplug-host -- the playwriter relay is not on the eval path.** agentplug-runner launches Chrome with `--remote-debugging-port`, obtains a live DevTools `webSocketDebuggerUrl`, and runs the script in-page via `Runtime.evaluate` over that websocket directly (`crates/agentplug-host/src/browser.rs` + its embedded `cdp_eval.js`), so no relay attach+eval is ever spawned. This is the standing browser eval path. A flaky browser witness is therefore a real bug to root-cause in the CDP path or the Chrome launch, never a `blockedBy: external` tooling gap -- everything is fixable: if a browser dispatch fails, read the CDP endpoint (`http://127.0.0.1:<port>/json/version`), check the Chrome launch args, and fix the actual failure rather than parking it. There is no accepted "external tooling gap" resolution for the browser verb.
|
|
100
|
-
|
|
101
|
-
Spool input from PowerShell must be UTF-8 no-BOM (`-Encoding utf8` or `[System.IO.File]::WriteAllText`); UTF-16+BOM causes `spool.body-encoding-recoded`. First-turn body is `{"prompt":"<user request>"}` (derives orient_nouns + recall_hits); later turns may use `{}`. Batch independent dispatches: multiple `prd-add`, `prd-resolve`, `mutable-add`, `recall`+`codesearch`, or inspection `Read` calls in a single tool block. Avoid editing the same file twice in one block; collapse changes into a single Edit.
|
|
102
|
-
|
|
103
|
-
**Apply "every possible" to every noun, at SPECIFY and every re-entry to it.** SPECIFY is exhaustive, not minimal: every noun the request touches gets every possible task/validation/mutable/corner-case/caveat/failure-mode/empty-overflow-reentry-degenerate state as its own PRD row. A single-digit PRD count on a non-trivial or long-horizon request means it stopped early -- re-orient, re-enumerate, push more rows. Long-horizon prompts routinely produce high-tens-to-hundreds of rows; density at SPECIFY is the only protection against silently stopping with work undone. Everything is fixable: a row that looks unreachable is a row to build a way into (drive the crashing tool directly, spawn your own instance, open the cross-repo change), never a `blockedBy: external` resting state and never a way to shrink the row count for tedious/large/multi-step work.
|
|
104
|
-
|
|
105
|
-
**Every SPECIFY pass also asks: what architectural change makes this practical and low-maintenance going forward, not just correct right now?** For each row, before accepting the literal ask as the whole scope: is there a structural change (removing an obsolete mechanism, consolidating duplicated logic, replacing a bespoke reimplementation with a maintained one, fixing a wrong abstraction at its root instead of patching around it) that would make this and future similar work cheaper, not just this one instance? If yes, that becomes its own PRD row alongside the literal ask -- never silently skipped as "out of scope" or "nice to have." A plan that only satisfies the literal request while leaving an obvious maintenance burden in place under-covers by the same standard as a plan that misses a corner case.
|
|
106
|
-
|
|
107
|
-
**PROVE resolves all mutables before EMIT, discovers more, resolves those too, rearchitects immediately on in-spirit discovery.** Any architectural improvement discovered mid-PROVE or mid-EMIT is an immediate `transition to=SPECIFY`, re-`prd-add` the affected row with its existing id (re-scope, never remove-and-re-add) -- maximal-effort correctness over preservation-for-its-own-sake, no deferral, no "note for later."
|
|
108
|
-
|
|
109
|
-
**`prd-resolve` is bound by the false-completion rule in every phase, SPECIFY included -- not only at DECIDE.** A row resolved on a hedge ("deferred", "pending next session", "awaits recovery") is undone work labeled done -- forbidden, the same class as a mock standing in for real code. The served SPECIFY/DECIDE `instruction` prose carries the full hedge taxonomy, the `blockedBy: [external, ...]` handling for genuine outside-session blockers, and the recurring-blocker-becomes-its-own-row rule; dispatch `instruction` for it rather than re-deriving it here.
|
|
110
|
-
|
|
111
|
-
DECIDE is adversarial, never confirmatory: run the real code path and read its actual output via `exec_js` or `browser` -- a finding is only real once witnessed by execution this turn. Never assert a crash, pass, or defect from memory, prior session state, or written prose alone. A gate denial (e.g. `residual.skipped` on dirty worktree) is resolved immediately by the named recovery action (commit or revert the listed files, then re-dispatch the same verb) in the same turn -- it is never grounds to re-enter SPECIFY, add unrelated PRD rows, or narrate the blocker instead of clearing it.
|
|
112
|
-
|
|
113
|
-
**Every residual is triaged this turn; "pre-existing" is not a stop excuse.** Non-empty `git status --porcelain`: every entry is yours now -- commit (real work), add to managed gitignore (transient runtime files), or revert (stale junk). PRD entries live in `.gm/prd.yml`. `.gm/disciplines/` and new memorize-fire JSON are tracked. `.gm/witness/` and staleness markers go in managed gitignore.
|
|
114
|
-
|
|
115
|
-
**Noticing is a planning event, every phase, not just SPECIFY.** Anything observed mid-walk -- outstanding work, an unfinished surface, an improvable shape, drift from these rules -- is `prd-add` this turn; response-body-only observations evaporate at turn end. Density grows along the whole walk, not just at SPECIFY; exiting DECIDE with the same row-count SPECIFY started with is lost discoveries, not a clean run.
|
|
116
|
-
|
|
117
|
-
`git push` only when `git status --porcelain` is empty. Dirty tree blocks the DECIDE -> COMPLETE gate. Prefer `git_push` verb over Bash git commands; git via Bash records as `deviation.bash-git-bypass`.
|
|
118
|
-
|
|
119
|
-
Phase transitions (the built-in default graph, not an exhaustive list of legal phase names): SPECIFY -> PROVE -> EMIT -> STATE -> CONC -> SEC -> RES -> DECIDE -> COMPLETE, with feedback edges from every later stage back to SPECIFY (reshaping), EMIT (repair), STATE (boundary enforcement), and PROVE (empirical fitness). Each requires `transition {to:"PHASE"}` dispatch. SPECIFY writes the PRD. PROVE drains `.gm/mutables.yml` (gated). EMIT writes file changes (gated on source hygiene). STATE/CONC/SEC/RES audit the diff per stage (functional core, concurrency, security, resilience; each boundary gated on its mechanically-checkable subset). DECIDE validates adversarially via `exec_js`/`browser`, pushes via `git_finalize` or `git_push`, then witnesses CI/CD pipeline green. COMPLETE gate requires: worktree clean, remote pushed, PRD empty, mutables resolved, residual-scan fired, CI green (`.ci-validated` marker matching current HEAD), browser-witness coverage, submodules clean, claim-audit clean, no hedge language. A project's `.gm/instructions/fsm/graph.json` (written by the `fsm-vendor` verb) can define a different phase set, additional states, or a different edge/gate shape entirely. Never assume this exact chain; dispatch `instruction` and read its `phase`/`next_phase_hint` fields to discover the live graph's actual state, whatever a specific project's graph happens to define.
|
|
120
|
-
|
|
121
|
-
CI/CD validation in DECIDE phase: After push succeeds, watch the triggered workflow. When pipeline goes green, dispatch `fs_write {path:".gm/exec-spool/.ci-validated", content:"{\"head_sha\":\"<current commit SHA>\"}"}` to mark validation complete -- the marker's file CONTENT is the JSON string `{"head_sha":"<SHA>"}`, passed under the `content` field the fs_write handler reads (not a `body`/`head_sha` object, which the handler ignores). `.ci-validated`'s head_sha must match current HEAD; COMPLETE gate refuses if stale or missing. Red runs require fix + re-push + re-watch; no skip for "it looked safe."
|
|
122
|
-
|
|
123
|
-
Memory via `memorize-fire` dispatch writes both `.gm/memories/<key>.md` (tracked, durable) and a vector row in `.gm/gm.db` (untracked, derived, rebuilt on first touch if missing), retrieved via `recall` and `auto_recall`. `discipline-note {discipline, text}` writes `.gm/disciplines/<name>/policy.md`; `instruction` auto-surfaces policies from disciplines listed in `.gm/disciplines/enabled.txt`.
|
|
124
|
-
|
|
125
|
-
`auto_recall` attaches to `instruction` responses on turn entry. `memorize-prune {key}` or `memorize-prune {query}` deletes or reviews memory entries.
|
|
126
|
-
|
|
127
|
-
Subagent prompts should reference the gm skill and task specifics only, without restating verb names, spool paths, or protocol mechanics already supplied by invocation.
|
|
128
|
-
|
|
129
|
-
**This file is not gm's whole procedure.** The phase-specific behavioral prose lives elsewhere: SPECIFY/PROVE/EMIT/STATE/CONC/SEC/RES/DECIDE, gate reasons, and deviation text. rs-plugkit's `instruction` verb serves it live from `AnEntrypoint/gm-config`, not from this file. Resolution is three-tier, per key, each tier overriding the one before. Tier one: `.gm/instructions/<key>.md`, a local vendored override, always wins. Tier two: `gm-config`'s cached checkout, consulted with zero configuration by default. Point `.gm/config.source.json` at a fork or a private repo to use a different one. Tier three: a compiled-in Rust default. It serves only as an emergency fallback when `gm-config` is genuinely unreachable. A skill-improvement pass (for example workflow-forge) that edits only this file's numbered steps misses that entire layer. The actual served prose lives in `gm-config`'s `prose/*.md`. Edit it and push it directly to `gm-config` main -- no rs-plugkit rebuild, no cascade, no release. Editing `rs-plugkit/crates/plugkit-core/src/orchestrator/instructions/prose/*.md` changes only the emergency fallback text. It never changes what a healthy project resolves. This file holds only invocation syntax, transition markers, gate-condition summaries, spool-dispatch mechanics, and constraints. It is the boot-edge ABI a skill-runner uses before the served prose takes over.
|
|
25
|
+
**This file is boot-edge ABI only.** Phase-specific behavior (SPECIFY/PROVE/EMIT/STATE/CONC/SEC/RES/DECIDE prose, gate reasons, deviation text, install/bootstrap/observability detail, memory discipline) is served live by the `instruction` verb from `AnEntrypoint/gm-config`, three-tier resolved (`.gm/instructions/<key>.md` project override -> gm-config checkout -> compiled Rust default as emergency fallback only). Editing this file's prose never changes served behavior; edit `gm-config`'s `prose/*.md` and push directly, no rebuild needed. Subagent prompts dispatching gm-driven work say only "use the gm skill for this" plus task specifics -- never restate verb names, spool paths, or phase mechanics already supplied by `Skill(skill="gm")` itself.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gm-plugkit",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2482",
|
|
4
4
|
"description": "Bootstrap and daemon-spawn tool for gm plugkit binary. Downloads the correct platform wasm, verifies SHA256, and launches agentplug-runner (the native wasm host) as the spool watcher daemon.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|