gm-skill 0.1.2 → 2.0.1081

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.
Files changed (85) hide show
  1. package/AGENTS.md +1 -0
  2. package/LICENSE +21 -0
  3. package/README.md +20 -84
  4. package/agents/gm.md +22 -0
  5. package/agents/memorize.md +100 -0
  6. package/agents/research-worker.md +36 -0
  7. package/agents/textprocessing.md +47 -0
  8. package/bin/bootstrap.js +702 -0
  9. package/bin/plugkit.js +136 -0
  10. package/bin/plugkit.sha256 +7 -0
  11. package/bin/plugkit.version +1 -0
  12. package/bin/plugkit.wasm +0 -0
  13. package/bin/plugkit.wasm.sha256 +1 -0
  14. package/bin/rtk.sha256 +6 -0
  15. package/bin/rtk.version +1 -0
  16. package/gm-plugkit/bootstrap.js +694 -0
  17. package/gm-plugkit/cli.js +48 -0
  18. package/gm-plugkit/index.js +12 -0
  19. package/gm-plugkit/package.json +26 -0
  20. package/gm-plugkit/plugkit-wasm-wrapper.js +190 -0
  21. package/gm-plugkit/plugkit.sha256 +6 -0
  22. package/gm-plugkit/plugkit.version +1 -0
  23. package/gm.json +27 -0
  24. package/lang/browser.js +45 -0
  25. package/lang/ssh.js +166 -0
  26. package/lib/browser-spool-handler.js +130 -0
  27. package/lib/browser.js +131 -0
  28. package/lib/codeinsight.js +109 -0
  29. package/lib/daemon-bootstrap.js +253 -132
  30. package/lib/git.js +0 -1
  31. package/lib/learning.js +169 -0
  32. package/lib/skill-bootstrap.js +406 -0
  33. package/lib/spool-dispatch.js +100 -0
  34. package/lib/spool.js +87 -49
  35. package/lib/wasm-host.js +241 -0
  36. package/package.json +38 -20
  37. package/prompts/bash-deny.txt +22 -0
  38. package/prompts/pre-compact.txt +21 -0
  39. package/prompts/prompt-submit.txt +83 -0
  40. package/prompts/session-start.txt +15 -0
  41. package/scripts/run-hook.sh +7 -0
  42. package/scripts/watch-cascade.js +166 -0
  43. package/skills/browser/SKILL.md +80 -0
  44. package/skills/code-search/SKILL.md +48 -0
  45. package/skills/create-lang-plugin/SKILL.md +121 -0
  46. package/skills/gm/SKILL.md +10 -49
  47. package/skills/gm-complete/SKILL.md +16 -87
  48. package/skills/gm-emit/SKILL.md +17 -50
  49. package/skills/gm-execute/SKILL.md +18 -69
  50. package/skills/gm-skill/SKILL.md +43 -0
  51. package/skills/gm-skill/index.js +21 -0
  52. package/skills/governance/SKILL.md +97 -0
  53. package/skills/pages/SKILL.md +208 -0
  54. package/skills/planning/SKILL.md +21 -97
  55. package/skills/research/SKILL.md +43 -0
  56. package/skills/ssh/SKILL.md +71 -0
  57. package/skills/textprocessing/SKILL.md +40 -0
  58. package/skills/update-docs/SKILL.md +24 -43
  59. package/gm-complete.SKILL.md +0 -106
  60. package/gm-emit.SKILL.md +0 -70
  61. package/gm-execute.SKILL.md +0 -88
  62. package/gm.SKILL.md +0 -63
  63. package/index.js +0 -1
  64. package/lib/index.js +0 -37
  65. package/lib/loader.js +0 -66
  66. package/lib/manifest.js +0 -99
  67. package/lib/prepare.js +0 -14
  68. package/planning.SKILL.md +0 -118
  69. package/skills/gm/index.js +0 -113
  70. package/skills/gm-complete/index.js +0 -118
  71. package/skills/gm-complete.SKILL.md +0 -106
  72. package/skills/gm-emit/index.js +0 -90
  73. package/skills/gm-emit.SKILL.md +0 -70
  74. package/skills/gm-execute/index.js +0 -91
  75. package/skills/gm-execute.SKILL.md +0 -88
  76. package/skills/gm.SKILL.md +0 -63
  77. package/skills/planning/index.js +0 -107
  78. package/skills/planning.SKILL.md +0 -118
  79. package/skills/update-docs/index.js +0 -108
  80. package/skills/update-docs.SKILL.md +0 -66
  81. package/test-build.js +0 -29
  82. package/test-e2e.js +0 -117
  83. package/test-unified.js +0 -24
  84. package/test.js +0 -89
  85. package/update-docs.SKILL.md +0 -66
@@ -1,88 +0,0 @@
1
- ---
2
- name: gm-execute
3
- description: EXECUTE phase AND the foundational execution contract for every skill. Every exec:<lang> run, every witnessed check, every code search, in every phase, follows this skill's discipline. Resolve all mutables via witnessed execution. Any new unknown triggers immediate snake back to planning — restart chain from PLAN.
4
- ---
5
-
6
- # GM EXECUTE — Resolve every unknown by witness
7
-
8
- Entry: `.prd` with named unknowns. Exit: every mutable KNOWN → invoke `gm-emit`.
9
-
10
- A `@<discipline>` sigil propagates from PLAN through every recall, codesearch, and memorize call; reads without one fan across default plus enabled disciplines, writes without one go to default only.
11
-
12
- This skill is the execution contract for ALL phases — pre-emit witnesses, post-emit verifies, e2e checks all run on this discipline. Cross-cutting dispositions live in `gm` SKILL.md.
13
-
14
- ## Transitions
15
-
16
- - All mutables KNOWN → `gm-emit`
17
- - Still UNKNOWN → re-run from a different angle (max 2 passes)
18
- - New unknown OR unresolvable after 2 passes → `planning`
19
-
20
- ## Mutable discipline
21
-
22
- Each mutable carries: name, expected, current, resolution method.
23
-
24
- Resolves to KNOWN only when all four pass:
25
-
26
- - **ΔS = 0** — witnessed output equals expected
27
- - **λ ≥ 2** — two independent paths agree
28
- - **ε intact** — adjacent invariants hold
29
- - **Coverage ≥ 0.70** — enough corpus inspected to rule out contradiction
30
-
31
- Unresolved after 2 passes regresses to `planning`. Never narrate past an unresolved mutable.
32
-
33
- Every witness that resolves a mutable writes back to `.gm/mutables.yml` the same step: set `status: witnessed` and fill `witness_evidence` with concrete proof (file:line, codesearch hit, exec output snippet). No write-back = the mutable stays unknown and the EMIT-gate stays closed. The hook reads this file; the agent's memory of "I resolved it" does not unblock anything.
34
-
35
- Route candidates from PLAN are `weak_prior` only. Plausibility is the right to test, not the right to believe. A claim with no witness in the current session is a hypothesis — say so when stating it, and say what would settle it. The next reader (you, next turn) needs to know which lines were earned and which were carried forward.
36
-
37
- ## Verification budget
38
-
39
- Spend on `.prd` items in descending order of consequence-if-wrong × distance-from-witnessed. Items whose failure would collapse the headline finding must reach witnessed status before EMIT; sub-argument-level items need at minimum a stated fallback path.
40
-
41
- ## Code execution
42
-
43
- Code AND utility verbs both run through the file-spool. Write a file to `.gm/exec-spool/in/<lang-or-verb>/<N>.<ext>` — language stems (`in/nodejs/42.js`, `in/python/43.py`, `in/bash/44.sh`, plus typescript, go, rust, c, cpp, java, deno) or verb stems (`in/codesearch/45.txt`, `in/recall/46.txt`, `in/memorize/47.md`, plus wait, sleep, status, close, browser, runner, type, kill-port, forget, feedback, learn-status, learn-debug, learn-build, discipline, pause, health). The spool watcher executes and streams stdout to `out/<N>.out`, stderr to `out/<N>.err`, then writes `out/<N>.json` metadata sidecar at completion (taskId, lang, ok, exitCode, durationMs, timedOut, startedAt, endedAt). Both streams return as systemMessage with `--- stdout ---` / `--- stderr ---` separators. File I/O via a nodejs spool file + `require('fs')`. Only `git` and `gh` run directly in Bash. Never `Bash(node/npm/npx/bun)`, never `Bash(exec:<anything>)`.
44
-
45
- Pack runs: `Promise.allSettled`, each idea own try/catch, under 12s per call. Runner: write `in/runner/<N>.txt` with body `start` | `stop` | `status`.
46
-
47
- Every exec daemonizes. The hook tails the task logfile up to 30s wall-clock and returns whatever is there — short tasks complete inside the window and look synchronous; long tasks return a task_id with partial output. Continue with `exec:tail` (drain, bounded), `exec:watch` (resume blocking until match or timeout), or `exec:close` (terminate). Never re-spawn a long task to check on it — that orphans the first one. `exec:wait` is a pure timer; `exec:sleep` blocks on a specific task's output; `exec:watch` is the match-or-timeout primitive. Every execution-platform RPC returns the live list of running tasks for this session — close stragglers via `exec:close\n<id>` so the list stays scannable. Session-end (clear/logout/prompt_input_exit) kills the session's tasks; compaction/handoff preserves them.
48
-
49
- Every utility verb dispatches via `in/<verb>/<N>.txt`; the body of the file is the verb's argument. There is no inline form and no Bash-prefix form — both are denied by the hook.
50
-
51
- ## Codebase search
52
-
53
- `exec:codesearch` only. Grep, Glob, Find, Explore, raw grep/rg/find inside `exec:bash` are all hook-blocked.
54
-
55
- ```
56
- exec:codesearch
57
- <two-word query>
58
- ```
59
-
60
- Start two words, change/add one per pass, minimum four attempts before concluding absent. Known absolute path → `Read`. Known directory → `exec:nodejs` + `fs.readdirSync`.
61
-
62
- ## Utility verb failure handling
63
-
64
- **Utility verb failures must surface**: exec:memorize, exec:recall, exec:codesearch, and other utility verbs may fail (socket unavailable, timeout, network error). Failures do not block witness completion but must be reported to the user with error context. Fallback mechanisms (AGENTS.md for memorize) ensure memory preservation even when rs-learn is temporarily unavailable.
65
-
66
- ## Import-based execution
67
-
68
- Hypotheses become real by importing actual modules from disk. Reimplemented behavior is UNKNOWN. Write the import probe to the spool:
69
-
70
- ```
71
- # write .gm/exec-spool/in/nodejs/42.js
72
- const { fn } = await import('/abs/path/to/module.js');
73
- console.log(await fn(realInput));
74
- ```
75
-
76
- Differential diagnosis: smallest reproduction → compare actual vs expected → name the delta — that delta is the mutable.
77
-
78
- ## Edits depend on witnesses
79
-
80
- Hypothesis → run → witness → edit. An edit before a witness is a guess. Scan via `exec:codesearch` before creating or modifying — duplicate concern regresses to `planning`. Code-quality preference: native → library → structure → write.
81
-
82
- ## Parallel subagents
83
-
84
- Up to 3 `gm:gm` subagents for independent items in one message. Browser escalation: `exec:browser` → `browser` skill → screenshot only as last resort.
85
-
86
- ## CI is automated
87
-
88
- `git push` triggers the Stop hook to watch Actions for the pushed HEAD on the same repo (downstream cascades are not auto-watched). Green → Stop approves with summary; failure → run names + IDs surfaced, investigate via `gh run view <id> --log-failed`. Deadline 180s (override `GM_CI_WATCH_SECS`).
package/gm.SKILL.md DELETED
@@ -1,63 +0,0 @@
1
- ---
2
- name: gm
3
- description: Orchestrator dispatching PLAN→EXECUTE→EMIT→VERIFY→UPDATE-DOCS skill chain; spool-driven task execution with session isolation
4
- allowed-tools: Skill
5
- compatible-platforms:
6
- - gm-cc
7
- - gm-gc
8
- - gm-oc
9
- - gm-kilo
10
- - gm-codex
11
- - gm-copilot-cli
12
- - gm-vscode
13
- - gm-cursor
14
- - gm-zed
15
- - gm-jetbrains
16
- end-to-end: true
17
- ---
18
-
19
- # GM — Orchestrator
20
-
21
- Invoke `planning` immediately. Phases cascade: PLAN → EXECUTE → EMIT → VERIFY → UPDATE-DOCS.
22
-
23
- The user's request is authorization. When scope is unclear, pick the maximum reachable shape and declare it — the user can interrupt. Doubts resolve via witnessed probe or recall, never by asking back except for destructive-irreversible actions uncovered by the PRD.
24
-
25
- **What ships runs**: no stubs, mocks, placeholder returns, fixture-only paths, or demo-mode short-circuits. Real input through real code into real output. A shim is allowed only when delegating to real upstream behavior.
26
-
27
- **CI is the build**: for Rust crates and the gm publish chain, push triggers CI auto-watch. Green signals authority. Local cargo build is not a witness.
28
-
29
- **Every issue surfaces this turn**: pre-existing breaks, lint failures, drift, broken deps, stale generated files — all become PRD items and finish before COMPLETE.
30
-
31
- **LLM provider**: acptoapi (127.0.0.1:4800) is the preferred provider when available. rs-plugkit session_start spawns acptoapi daemon and auto-detects ACP agents (opencode, kilo-code, codex, gemini-cli, qwen-code). All downstream platforms (rs-learn, freddie, gm-skill daemon mode) read OPENAI_BASE_URL environment variable and default to 127.0.0.1:4800. Anthropic SDK is fallback only when acptoapi socket is unavailable (CI, headless mode).
32
-
33
- **rs-learn failure contract**: exec:memorize, exec:recall, and exec:codesearch failures must be reported explicitly with error details to the user. Fallback to AGENTS.md for memory preservation when socket/network unavailable. Never silently absorb errors because memory preservation requires explicit fallback. This rule applies across all phases (PLAN through UPDATE-DOCS).
34
-
35
- **Spool dispatch chain**: write to `.gm/exec-spool/in/<lang>/<N>.<ext>` or `in/<verb>/<N>.txt`. Watcher executes and streams `out/<N>.out` + `out/<N>.err` + `out/<N>.json` metadata. Languages: nodejs, python, bash, typescript, go, rust, c, cpp, java, deno. Verbs: codesearch, recall, memorize, wait, sleep, status, close, browser, runner, type, kill-port, forget, feedback, learn-status, learn-debug, learn-build, discipline, pause, health.
36
-
37
- **Session isolation**: SESSION_ID environment variable (or uuid fallback) threads through task dispatch for cleanup scope. rs-exec RPC handlers verify session_id match on all task-scoped operations.
38
-
39
- **Code does mechanics; meaning routes through textprocessing skill**: summarize, classify, extract intent, rewrite, translate, semantic dedup, rank, label — all via `Agent(subagent_type='gm:textprocessing', ...)`.
40
-
41
- **Recall before fresh execution**: before witnessing unknown via execution, recall first. Hits arrive as weak_prior; empty results confirm fresh unknown.
42
-
43
- **Memorize is the back-half of witness**: resolution incomplete until fact lives outside this context window. Fire `Agent(subagent_type='gm:memorize', model='haiku', run_in_background=true, prompt='## CONTEXT TO MEMORIZE\n<fact>')` alongside witness, in parallel, never blocking.
44
-
45
- **Parallel independent items**: up to 3 `gm:gm` subagents per message for independent PRD items. Serial for dependent items — no re-asking between them.
46
-
47
- **Terse response**: fragments OK. `[thing] [action] [reason]. [next step].` Code, commits, PRs use normal prose.
48
-
49
- ## End-to-End Phase Chaining (Skills-Based Platforms)
50
-
51
- When `end-to-end: true` is present in SKILL.md frontmatter, skill output includes structured JSON on stdout (final line):
52
-
53
- ```json
54
- {"nextSkill": "gm-execute" | "gm-emit" | "gm-complete" | "update-docs" | null, "context": {PRD and state dict}, "phase": "PLAN" | "EXECUTE" | "EMIT" | "COMPLETE"}
55
- ```
56
-
57
- Platform adapters (vscode, cursor, zed, jetbrains) that support `end-to-end: true` detection:
58
- 1. Invoke `Skill(skill="gm:gm")`
59
- 2. Parse stdout for trailing JSON blob
60
- 3. If `nextSkill` is non-null, invoke `Skill(skill="gm:<nextSkill>")` with context dict auto-passed
61
- 4. Repeat until `nextSkill` is null
62
-
63
- This collapses 5 manual skill invocations into 1 user invocation + 4 transparent auto-dispatches, achieving perceived single-flow parity with gm-cc's subagent orchestration.
package/index.js DELETED
@@ -1 +0,0 @@
1
- module.exports = require('./lib/index.js');
package/lib/index.js DELETED
@@ -1,37 +0,0 @@
1
- const daemon = require('./daemon-bootstrap.js');
2
- const manifest = require('./manifest.js');
3
- const loader = require('./loader.js');
4
- const prepareModule = require('./prepare.js');
5
-
6
- function getSkills() {
7
- return manifest.getAllSkills();
8
- }
9
-
10
- function getSkill(name) {
11
- return manifest.getSkill(name);
12
- }
13
-
14
- function loadSkill(skillName, baseDir) {
15
- return loader.dynamicLoadSkill(skillName, baseDir);
16
- }
17
-
18
- function bootstrapDaemon(daemonName, cmd) {
19
- return daemon.spawnDaemon(daemonName, cmd);
20
- }
21
-
22
- module.exports = {
23
- getSkills: getSkills,
24
- getSkill: getSkill,
25
- loadSkill: loadSkill,
26
- bootstrapDaemon: bootstrapDaemon,
27
- checkState: daemon.checkState,
28
- waitForReady: daemon.waitForReady,
29
- getSocket: daemon.getSocket,
30
- shutdown: daemon.shutdown,
31
- emitEvent: daemon.emitEvent,
32
- isDaemonRunning: daemon.isDaemonRunning,
33
- checkPortReachable: daemon.checkPortReachable,
34
- manifest: manifest,
35
- loader: loader,
36
- prepare: prepareModule.prepare
37
- };
package/lib/loader.js DELETED
@@ -1,66 +0,0 @@
1
- const path = require('path');
2
- const fs = require('fs');
3
-
4
- function loadSkill(skillName, skillPath) {
5
- if (!fs.existsSync(skillPath)) {
6
- throw new Error(`Skill path does not exist: ${skillPath}`);
7
- }
8
-
9
- const indexPath = path.join(skillPath, 'index.js');
10
- if (!fs.existsSync(indexPath)) {
11
- throw new Error(`Skill index.js not found at ${indexPath}`);
12
- }
13
-
14
- try {
15
- const skillModule = require(indexPath);
16
- return skillModule;
17
- } catch (e) {
18
- throw new Error(`Failed to load skill ${skillName} from ${indexPath}: ${e.message}`);
19
- }
20
- }
21
-
22
- function dynamicLoadSkill(skillName, baseDir) {
23
- const searchDirs = [];
24
-
25
- if (baseDir) {
26
- searchDirs.push(path.join(baseDir, 'skills', skillName));
27
- }
28
-
29
- searchDirs.push(path.join(__dirname, '..', 'skills', skillName));
30
- searchDirs.push(path.join(__dirname, '..', '..', 'gm-starter', 'skills', skillName));
31
- searchDirs.push(path.join(process.cwd(), 'skills', skillName));
32
-
33
- for (const searchDir of searchDirs) {
34
- if (fs.existsSync(searchDir)) {
35
- return loadSkill(skillName, searchDir);
36
- }
37
- }
38
-
39
- throw new Error(`Skill "${skillName}" not found in any search directory: ${searchDirs.join(', ')}`);
40
- }
41
-
42
- function getSkillPath(skillName, baseDir) {
43
- const searchDirs = [];
44
-
45
- if (baseDir) {
46
- searchDirs.push(path.join(baseDir, 'skills', skillName));
47
- }
48
-
49
- searchDirs.push(path.join(__dirname, '..', 'skills', skillName));
50
- searchDirs.push(path.join(__dirname, '..', '..', 'gm-starter', 'skills', skillName));
51
- searchDirs.push(path.join(process.cwd(), 'skills', skillName));
52
-
53
- for (const searchDir of searchDirs) {
54
- if (fs.existsSync(searchDir)) {
55
- return searchDir;
56
- }
57
- }
58
-
59
- return null;
60
- }
61
-
62
- module.exports = {
63
- loadSkill,
64
- dynamicLoadSkill,
65
- getSkillPath
66
- };
package/lib/manifest.js DELETED
@@ -1,99 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
-
4
- function parseSkillMarkdown(content) {
5
- const normalized = content.replace(/\r\n/g, '\n');
6
- const match = normalized.match(/^---\n([\s\S]*?)\n---/);
7
-
8
- if (!match) return {};
9
-
10
- const frontmatter = match[1];
11
- const metadata = {};
12
-
13
- frontmatter.split('\n').forEach(line => {
14
- const colonIdx = line.indexOf(':');
15
- if (colonIdx === -1) return;
16
-
17
- const key = line.substring(0, colonIdx).trim();
18
- const value = line.substring(colonIdx + 1).trim();
19
-
20
- if (key === 'allowed-tools') {
21
- metadata.allowedTools = value
22
- .split(',')
23
- .map(t => t.trim().replace(/^['\"]|['\"]$/g, ''));
24
- } else {
25
- metadata[key] = value;
26
- }
27
- });
28
-
29
- return metadata;
30
- }
31
-
32
- function readSkillManifest(skillName) {
33
- const searchPaths = [
34
- path.join(__dirname, '..', 'skills', skillName, 'SKILL.md'),
35
- path.join(__dirname, '..', '..', 'gm-starter', 'skills', skillName, 'SKILL.md')
36
- ];
37
-
38
- let skillMdPath = null;
39
- for (const p of searchPaths) {
40
- if (fs.existsSync(p)) {
41
- skillMdPath = p;
42
- break;
43
- }
44
- }
45
-
46
- if (!skillMdPath) {
47
- return {
48
- name: skillName,
49
- description: '',
50
- allowedTools: [],
51
- compatiblePlatforms: [],
52
- endToEnd: false,
53
- skillMdContent: ''
54
- };
55
- }
56
-
57
- const content = fs.readFileSync(skillMdPath, 'utf8');
58
- const metadata = parseSkillMarkdown(content);
59
-
60
- return {
61
- name: metadata.name || skillName,
62
- description: metadata.description || '',
63
- version: metadata.version || '1.0.0',
64
- category: metadata.category || 'skill',
65
- allowedTools: metadata.allowedTools || [],
66
- compatiblePlatforms: metadata['compatible-platforms']
67
- ? metadata['compatible-platforms'].split(',').map(p => p.trim())
68
- : [],
69
- endToEnd: metadata['end-to-end'] === 'true',
70
- skillMdContent: content
71
- };
72
- }
73
-
74
- function getManifest() {
75
- const skills = ['gm', 'planning', 'gm-execute', 'gm-emit', 'gm-complete', 'update-docs'];
76
- return {
77
- name: 'gm-skill',
78
- version: '1.0.0',
79
- description: 'gm skill manifest and daemon bootstrap integration',
80
- skills: skills.map(name => readSkillManifest(name))
81
- };
82
- }
83
-
84
- function getSkill(name) {
85
- return readSkillManifest(name);
86
- }
87
-
88
- function getAllSkills() {
89
- const skills = ['gm', 'planning', 'gm-execute', 'gm-emit', 'gm-complete', 'update-docs'];
90
- return skills.map(name => readSkillManifest(name));
91
- }
92
-
93
- module.exports = {
94
- getManifest,
95
- getSkill,
96
- getAllSkills,
97
- parseSkillMarkdown,
98
- readSkillManifest
99
- };
package/lib/prepare.js DELETED
@@ -1,14 +0,0 @@
1
- async function prepare(options = {}) {
2
- const sessionId = options.sessionId || process.env.CLAUDE_SESSION_ID || 'default';
3
- const cwd = options.cwd || process.cwd();
4
-
5
- return {
6
- sessionId,
7
- cwd,
8
- initialized: true
9
- };
10
- }
11
-
12
- module.exports = {
13
- prepare
14
- };
package/planning.SKILL.md DELETED
@@ -1,118 +0,0 @@
1
- ---
2
- name: planning
3
- description: State machine orchestrator. Mutable discovery, PRD construction, and full PLAN→EXECUTE→EMIT→VERIFY→COMPLETE lifecycle. Invoke at session start and on any new unknown.
4
- allowed-tools: Skill
5
- ---
6
-
7
- # Planning — PLAN phase
8
-
9
- Translate the request into `.gm/prd.yml` and hand to `gm-execute`. Re-enter on any new unknown in any phase.
10
-
11
- A `@<discipline>` sigil in the request scopes recall, codesearch, and memorize calls during PLAN to that discipline's store. Without one, retrievals fan across default plus enabled disciplines and writes land in default only.
12
-
13
- Cross-cutting dispositions (autonomy, fix-on-sight, nothing-fake, browser-witness, scope, recall, memorize) live in `gm` SKILL.md; this skill only carries what is unique to PLAN.
14
-
15
- ## Transitions
16
-
17
- - PLAN done → `gm-execute`
18
- - New unknown anywhere in chain → re-enter PLAN
19
- - EXECUTE unresolvable after 2 passes → PLAN
20
- - VERIFY: `.prd` empty + git clean + pushed → `update-docs`; else → `gm-execute`
21
-
22
- Cannot stop while `.gm/prd.yml` has items, git is dirty, or commits are unpushed.
23
-
24
- ## Orient
25
-
26
- Open every plan with one parallel pack of `exec:recall` + `exec:codesearch` against the request's nouns. Hits land as `weak_prior`; misses confirm the unknown is fresh. The pack runs in one message.
27
-
28
- **Auto-recall injection (skills-only platforms)**: derive a 2–6 word query from the request's nouns (subject, verb objects, key domain terms). Call `exec:recall <query>` at PLAN start before writing `.gm/prd.yml`, inline. This replaces the prompt-submit hook's auto-recall for platforms without hook infrastructure. Recall hits are injected as context into mutable discovery and PRD item acceptance criteria.
29
-
30
- ## Mutable discovery
31
-
32
- For each aspect of the work, ask: what do I not know, what could go wrong, what depends on what, what am I assuming. Unwitnessed assumptions are mutables.
33
-
34
- Fault surfaces to scan: file existence, API shape, data format, dep versions, runtime behavior, env differences, error conditions, concurrency, integration seams, backwards compat, rollback paths, CI correctness.
35
-
36
- Tag every item with a route family (grounding | reasoning | state | execution | observability | boundary | representation) and cross-reference the 16-failure taxonomy. `governance` skill holds the table.
37
-
38
- `existingImpl=UNKNOWN` is the default; resolve via `exec:codesearch` before adding the item. An existing concern routes to consolidation, not addition.
39
-
40
- Plan exits when zero new unknowns surfaced last pass AND every item has acceptance criteria AND deps are mapped.
41
-
42
- ## .gm/mutables.yml — co-equal with .gm/prd.yml
43
-
44
- Every unknown surfaced during PLAN lands as an entry in `.gm/mutables.yml` the same pass. Live during work, deleted when empty. Hook-gated: Write/Edit/NotebookEdit and `git commit`/`git push` are hard-blocked while any entry has `status: unknown`; turn-stop is hard-blocked the same way.
45
-
46
- ```yaml
47
- - id: kebab-id
48
- claim: One-line statement of what is assumed
49
- witness_method: exec:codesearch <query> | exec:nodejs import | exec:recall <query> | Read <path>
50
- witness_evidence: ""
51
- status: unknown
52
- ```
53
-
54
- `status: unknown` → `witnessed` only when `witness_evidence` is filled with concrete proof (file:line, codesearch hit, dispatched test output). Resolution lives in gm-execute. PRD items reference mutables via optional `mutables: [id1, id2]` field; an item is blocked while any referenced mutable is unresolved.
55
-
56
- ## .prd format
57
-
58
- Path: `./.gm/prd.yml`. Write via the Write tool or by emitting a nodejs spool file (`in/nodejs/<N>.js`) that calls `fs.writeFileSync`. Delete the file when empty.
59
-
60
- ```yaml
61
- - id: kebab-id
62
- subject: Imperative verb phrase
63
- status: pending
64
- description: Precise criterion
65
- effort: small|medium|large
66
- category: feature|bug|refactor|infra
67
- route_family: grounding|reasoning|state|execution|observability|boundary|representation
68
- load: 0.0-1.0
69
- failure_modes: []
70
- route_fit: unexamined|examined|dominant
71
- authorization: none|weak_prior|witnessed
72
- blocking: []
73
- blockedBy: []
74
- acceptance:
75
- - binary criterion
76
- edge_cases:
77
- - failure mode
78
- ```
79
-
80
- `load` is consequence-if-wrong: 0.9 = headline collapses, 0.7 = sub-argument rebuilt, 0.4 = local patch, 0.1 = nothing breaks. Verification budget = `load × (1 − tier_confidence)`. λ>0.75 must reach witnessed before EMIT.
81
-
82
- `status`: pending → in_progress → completed (then remove). `effort`: small <15min | medium <45min | large >1h.
83
-
84
- ## Parallel subagent launch
85
-
86
- After `.prd` is written, up to 3 parallel `gm:gm` subagents for independent items in one message. Browser tasks serialize.
87
-
88
- ```
89
- Agent(subagent_type="gm:gm", prompt="Work on .prd item: <id>. .prd path: <path>. Item: <full YAML>.")
90
- ```
91
-
92
- Items not parallelizable → invoke `gm-execute` directly.
93
-
94
- ## Observability gates in the plan
95
-
96
- Server: every subsystem exposes `/debug/<subsystem>`; structured logs `{subsystem, severity, ts}`. Client: `window.__debug` live registry; modules register on mount. `console.log` is not observability. Discovery of a gap during PLAN adds a `.prd` item the same pass — never deferred.
97
-
98
- `window.__debug` is THE in-page registry; `test.js` at project root is the sole out-of-page test asset. Any new file whose purpose is to exercise, smoke-test, demo, or sandbox in-page behavior outside that registry fights the discipline — extend the registry instead.
99
-
100
- ## Test discipline encoded in the plan
101
-
102
- One `test.js` at project root, 200-line hard cap, real data, real system. No fixtures, mocks, or scattered tests. A second test runner under any name in any directory is a smuggled parallel surface.
103
-
104
- The 200 lines are a *budget* for maximum surface coverage, not a target. Subsystems get one combined group each — names joined with `+` (`home+config+skin`, `mcp+swe+distributions+account+credpool`). When a new subsystem's failure mode overlaps an existing group's side-effects, fold the assertion in rather than creating a new group. When `wc -l test.js > 200`, the discipline is *merge groups + drop redundancy*, never split.
105
-
106
- ## Execution norms encoded in the plan
107
-
108
- Code execution AND utility verbs both write to `.gm/exec-spool/in/<lang-or-verb>/<N>.<ext>`. Languages live under `in/<lang>/` (nodejs, python, bash, typescript, go, rust, c, cpp, java, deno); verbs live under `in/<verb>/` (codesearch, recall, memorize, wait, sleep, status, close, browser, runner, type, kill-port, forget, feedback, learn-status, learn-debug, learn-build, discipline, pause, health). The spool watcher runs the file and streams to `out/<N>.out` (stdout) + `out/<N>.err` (stderr) line-by-line, then writes `out/<N>.json` metadata (exitCode, durationMs, timedOut, startedAt, endedAt) at completion. Both streams return as systemMessage with `--- stdout ---` / `--- stderr ---` separators. `in/` and `out/` are wiped at session start and at real-exit session end. Only `git` (and `gh`) run directly via Bash; never `Bash(node/npm/npx/bun)`, never `Bash(exec:<anything>)`. Spool paths in nodejs files are platform-literal — use `os.tmpdir()` and `path.join`. The spool enforces per-task timeouts; on timeout, partial output is preserved and the watcher emits `[exec timed out after Nms; partial output above]`.
109
-
110
- `exec:codesearch` only — Grep/Glob/Find/Explore are hook-blocked. Start two words, change/add one per pass, minimum four attempts before concluding absent.
111
-
112
- Pack runs use `Promise.allSettled`, each idea its own try/catch, under 12s per call.
113
-
114
- ## Dev workflow encoded in the plan
115
-
116
- No comments. 200-line per-file cap. Fail loud. No duplication. Scan before edit. AGENTS.md edits route through the memorize sub-agent only. CHANGELOG.md gets one entry per commit.
117
-
118
- Minimal-code process, stop at the first that resolves: native → library → structure (map / pipeline) → write.
@@ -1,113 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
-
4
- async function gmSkill(input) {
5
- const context = {
6
- request: input.request || '',
7
- taskId: input.taskId || require('crypto').randomUUID(),
8
- sessionId: process.env.SESSION_ID || require('crypto').randomUUID(),
9
- timestamp: new Date().toISOString(),
10
- phases: [],
11
- prd: [],
12
- mutables: {},
13
- };
14
-
15
- const skillsDir = path.join(__dirname);
16
- const gmDir = path.dirname(path.dirname(skillsDir));
17
-
18
- let currentSkill = 'planning';
19
- let chainDepth = 0;
20
- const maxDepth = 6;
21
-
22
- console.log(`[gm] orchestrator starting; request="${context.request}"; task=${context.taskId}`);
23
-
24
- while (currentSkill && chainDepth < maxDepth) {
25
- chainDepth++;
26
- console.error(`[gm] depth=${chainDepth}; invoking ${currentSkill}`);
27
-
28
- const skillPath = path.join(skillsDir, currentSkill, 'index.js');
29
- if (!fs.existsSync(skillPath)) {
30
- console.error(`[gm] ERROR: skill not found: ${skillPath}`);
31
- return {
32
- nextSkill: null,
33
- context,
34
- phase: 'ERROR',
35
- error: `Skill ${currentSkill} not found`,
36
- };
37
- }
38
-
39
- try {
40
- const skillModule = require(skillPath);
41
- const result = await skillModule(input, context);
42
-
43
- if (!result || typeof result !== 'object') {
44
- console.error(`[gm] ERROR: skill returned invalid result`);
45
- return {
46
- nextSkill: null,
47
- context,
48
- phase: 'ERROR',
49
- error: `Skill ${currentSkill} returned invalid result`,
50
- };
51
- }
52
-
53
- context.phases.push({
54
- skill: currentSkill,
55
- phase: result.phase,
56
- timestamp: new Date().toISOString(),
57
- });
58
-
59
- currentSkill = result.nextSkill || null;
60
-
61
- if (!currentSkill) {
62
- console.error(`[gm] chain complete`);
63
- return {
64
- nextSkill: null,
65
- context,
66
- phase: 'COMPLETE',
67
- };
68
- }
69
-
70
- input = { ...input, context };
71
- } catch (error) {
72
- console.error(`[gm] ERROR in ${currentSkill}:`, error.message);
73
- return {
74
- nextSkill: null,
75
- context,
76
- phase: 'ERROR',
77
- error: `${currentSkill} failed: ${error.message}`,
78
- };
79
- }
80
- }
81
-
82
- if (chainDepth >= maxDepth) {
83
- console.error(`[gm] ERROR: max chain depth exceeded`);
84
- return {
85
- nextSkill: null,
86
- context,
87
- phase: 'ERROR',
88
- error: 'Skill chain exceeded maximum depth',
89
- };
90
- }
91
-
92
- return {
93
- nextSkill: null,
94
- context,
95
- phase: 'COMPLETE',
96
- };
97
- }
98
-
99
- if (require.main === module) {
100
- const input = {
101
- request: process.argv[2] || 'test task',
102
- context: null,
103
- };
104
-
105
- gmSkill(input).then(result => {
106
- console.log(JSON.stringify(result, null, 2));
107
- }).catch(err => {
108
- console.error('Fatal error:', err);
109
- process.exit(1);
110
- });
111
- }
112
-
113
- module.exports = gmSkill;