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
@@ -0,0 +1,7 @@
1
+ #!/bin/sh
2
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT}}"
3
+ [ -z "$PLUGIN_ROOT" ] && exit 0
4
+ PLUGKIT="$PLUGIN_ROOT/bin/plugkit"
5
+ [ -f "$PLUGIN_ROOT/bin/plugkit.exe" ] && PLUGKIT="$PLUGIN_ROOT/bin/plugkit.exe"
6
+ [ ! -f "$PLUGKIT" ] && exit 0
7
+ "$PLUGKIT" hook "$1"
@@ -0,0 +1,166 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { execSync, spawnSync } = require('child_process');
5
+
6
+ const REPOS = {
7
+ 'rs-exec': 'AnEntrypoint/rs-exec',
8
+ 'rs-codeinsight':'AnEntrypoint/rs-codeinsight',
9
+ 'rs-search': 'AnEntrypoint/rs-search',
10
+ 'rs-plugkit': 'AnEntrypoint/rs-plugkit',
11
+ 'gm': 'AnEntrypoint/gm',
12
+ 'gm-cc': 'AnEntrypoint/gm-cc',
13
+ };
14
+
15
+ const POLL_MS = 20000;
16
+ const TIMEOUT_MS = 30 * 60 * 1000;
17
+
18
+ function gh(args) {
19
+ const r = spawnSync('gh', args, { encoding: 'utf8' });
20
+ if (r.status !== 0) throw new Error(r.stderr.trim() || `gh ${args.join(' ')} failed`);
21
+ return r.stdout.trim();
22
+ }
23
+
24
+ function latestRun(repo) {
25
+ const out = gh(['run', 'list', '--repo', repo, '--limit', '1', '--json', 'databaseId,status,conclusion,name,headBranch,createdAt']);
26
+ const rows = JSON.parse(out);
27
+ return rows[0] || null;
28
+ }
29
+
30
+ function getGmCcSha() {
31
+ return gh(['api', 'repos/AnEntrypoint/gm-cc/git/refs/heads/main', '--jq', '.object.sha']);
32
+ }
33
+
34
+ function getInstalledSha() {
35
+ const os = require('os');
36
+ const path = require('path');
37
+ const fs = require('fs');
38
+ const base = path.join(os.homedir(), '.claude/plugins/cache/gm-cc/gm');
39
+ if (!fs.existsSync(base)) return null;
40
+ const dirs = fs.readdirSync(base).filter(d => /^[0-9a-f]{12,}$/.test(d));
41
+ dirs.sort((a, b) => {
42
+ try {
43
+ const av = JSON.parse(fs.readFileSync(path.join(base, a, 'gm.json'), 'utf8')).version || '0';
44
+ const bv = JSON.parse(fs.readFileSync(path.join(base, b, 'gm.json'), 'utf8')).version || '0';
45
+ return bv.localeCompare(av, undefined, { numeric: true });
46
+ } catch { return 0; }
47
+ });
48
+ if (!dirs[0]) return null;
49
+ const gm = JSON.parse(fs.readFileSync(path.join(base, dirs[0], 'gm.json'), 'utf8'));
50
+ return { hash: dirs[0], version: gm.version, plugkitVersion: gm.plugkitVersion };
51
+ }
52
+
53
+ function getPlugkitVersion() {
54
+ const fs = require('fs');
55
+ const cargo = 'C:/dev/rs-plugkit/Cargo.toml';
56
+ if (!fs.existsSync(cargo)) return null;
57
+ const m = fs.readFileSync(cargo, 'utf8').match(/^version\s*=\s*"([^"]+)"/m);
58
+ return m ? m[1] : null;
59
+ }
60
+
61
+ function validate(label, fn) {
62
+ try {
63
+ const result = fn();
64
+ console.log(` ✓ ${label}: ${result}`);
65
+ return true;
66
+ } catch (e) {
67
+ console.log(` ✗ ${label}: ${e.message}`);
68
+ return false;
69
+ }
70
+ }
71
+
72
+ async function watchRun(repo, runId, label) {
73
+ const start = Date.now();
74
+ while (Date.now() - start < TIMEOUT_MS) {
75
+ const out = gh(['run', 'view', String(runId), '--repo', repo, '--json', 'status,conclusion']);
76
+ const { status, conclusion } = JSON.parse(out);
77
+ process.stdout.write(`\r ${label}: ${status} ${conclusion || ''} `);
78
+ if (status === 'completed') {
79
+ process.stdout.write('\n');
80
+ if (conclusion !== 'success') throw new Error(`${label} concluded: ${conclusion}`);
81
+ return;
82
+ }
83
+ await sleep(POLL_MS);
84
+ }
85
+ throw new Error(`${label} timed out after ${TIMEOUT_MS / 60000}min`);
86
+ }
87
+
88
+ function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
89
+
90
+ async function waitForNewRun(repo, label, afterTime, maxWaitMs = 5 * 60 * 1000) {
91
+ const start = Date.now();
92
+ while (Date.now() - start < maxWaitMs) {
93
+ const run = latestRun(repo);
94
+ if (run && new Date(run.createdAt).getTime() > afterTime) return run;
95
+ process.stdout.write(`\r Waiting for ${label} run to appear... `);
96
+ await sleep(POLL_MS);
97
+ }
98
+ process.stdout.write('\n');
99
+ throw new Error(`No new run appeared in ${repo} within ${maxWaitMs / 60000}min`);
100
+ }
101
+
102
+ async function main() {
103
+ const triggerTime = Date.now();
104
+
105
+ console.log('\n=== Cascade Watcher ===');
106
+ console.log('Monitoring full pipeline: rs-{exec,codeinsight,search} → rs-plugkit → gm → gm-cc\n');
107
+
108
+ console.log('[1] Baseline');
109
+ const baseGmCcSha = getGmCcSha();
110
+ const baseInstalled = getInstalledSha();
111
+ const basePlugkitVersion = getPlugkitVersion();
112
+ console.log(` gm-cc HEAD: ${baseGmCcSha}`);
113
+ console.log(` installed hash: ${baseInstalled ? baseInstalled.hash : 'unknown'} (gm v${baseInstalled?.version}, plugkit v${baseInstalled?.plugkitVersion})`);
114
+ console.log(` local plugkit: v${basePlugkitVersion}`);
115
+
116
+ console.log('\n[2] rs-plugkit Release run');
117
+ const plugkitRun = await waitForNewRun('AnEntrypoint/rs-plugkit', 'rs-plugkit Release', triggerTime - 10 * 60 * 1000);
118
+ console.log(` Run #${plugkitRun.databaseId} "${plugkitRun.name}" on ${plugkitRun.headBranch}`);
119
+ await watchRun('AnEntrypoint/rs-plugkit', plugkitRun.databaseId, 'rs-plugkit Release');
120
+
121
+ console.log('\n[3] Validate rs-plugkit version bumped');
122
+ validate('rs-plugkit Cargo.toml version', () => {
123
+ const v = getPlugkitVersion();
124
+ if (!v) throw new Error('Could not read');
125
+ return `v${v}`;
126
+ });
127
+
128
+ validate('gm-starter/gm.json plugkitVersion', () => {
129
+ const fs = require('fs');
130
+ const p = 'C:/dev/plugforge/gm-starter/gm.json';
131
+ if (!fs.existsSync(p)) throw new Error('file not found');
132
+ const j = JSON.parse(fs.readFileSync(p, 'utf8'));
133
+ return `v${j.plugkitVersion}`;
134
+ });
135
+
136
+ console.log('\n[4] gm Build & Publish run');
137
+ const afterPlugkit = Date.now();
138
+ const pfRun = await waitForNewRun('AnEntrypoint/gm', 'Build & Publish Plugins', afterPlugkit - 3 * 60 * 1000);
139
+ console.log(` Run #${pfRun.databaseId} "${pfRun.name}" on ${pfRun.headBranch}`);
140
+ await watchRun('AnEntrypoint/gm', pfRun.databaseId, 'Build & Publish Plugins');
141
+
142
+ console.log('\n[5] Validate gm-cc updated');
143
+ const newGmCcSha = getGmCcSha();
144
+ validate('gm-cc HEAD changed', () => {
145
+ if (newGmCcSha === baseGmCcSha) throw new Error(`still ${baseGmCcSha}`);
146
+ return newGmCcSha;
147
+ });
148
+
149
+ console.log('\n[6] Validate local installed plugin (requires /plugin + /reload-plugins)');
150
+ const installed = getInstalledSha();
151
+ validate('installed hash matches gm-cc HEAD prefix', () => {
152
+ if (!installed) throw new Error('no installed plugin found');
153
+ if (!newGmCcSha.startsWith(installed.hash)) throw new Error(`installed ${installed.hash} != gm-cc ${newGmCcSha.slice(0, 12)}`);
154
+ return `${installed.hash} (gm v${installed.version}, plugkit v${installed.plugkitVersion})`;
155
+ });
156
+
157
+ console.log('\n=== Cascade complete ===');
158
+ console.log(` gm-cc: ${baseGmCcSha.slice(0, 12)} → ${newGmCcSha.slice(0, 12)}`);
159
+ if (installed && newGmCcSha.startsWith(installed.hash)) {
160
+ console.log(' Local plugin is up to date.');
161
+ } else {
162
+ console.log(' ⚠ Run /plugin then /reload-plugins to update local cache.');
163
+ }
164
+ }
165
+
166
+ main().catch(e => { console.error('\nFATAL:', e.message); process.exit(1); });
@@ -0,0 +1,80 @@
1
+ ---
2
+ name: browser
3
+ description: Browser automation via playwriter. Use when user needs to interact with websites, navigate pages, fill forms, click buttons, take screenshots, extract data, test web apps, or automate any browser task.
4
+ allowed-tools: Skill
5
+ ---
6
+
7
+ # Browser automation
8
+
9
+ Two pathways — never mix in the same spool dispatch.
10
+
11
+ `exec:browser` runs JS against `page`. Globals available: `page`, `snapshot`, `screenshotWithAccessibilityLabels`, `state`. 15s live window, then backgrounds; output drains automatically on every subsequent plugkit call.
12
+
13
+ `browser:` prefix is playwriter session management. One command per block.
14
+
15
+ ## Core
16
+
17
+ Write to `.gm/exec-spool/in/browser/<N>.txt`:
18
+
19
+ ```
20
+ await page.goto('https://example.com')
21
+ await snapshot({ page })
22
+ ```
23
+
24
+ ```
25
+ browser:
26
+ playwriter session new --direct
27
+ ```
28
+
29
+ ```
30
+ browser:
31
+ playwriter -s 1 -e 'await page.goto("http://example.com")'
32
+ ```
33
+
34
+ Session state persists across `browser:` calls. `-e` arg uses single quotes outside, double inside JS strings.
35
+
36
+ ## Timing
37
+
38
+ Never `await setTimeout(N)` with N > 10000. Poll instead.
39
+
40
+ Write to `.gm/exec-spool/in/browser/<N>.txt`:
41
+
42
+ ```
43
+ const start = Date.now()
44
+ while (!state.done && Date.now() - start < 12000) {
45
+ await new Promise(r => setTimeout(r, 500))
46
+ }
47
+ console.log(state.result)
48
+ ```
49
+
50
+ `Assertion failed: UV_HANDLE_CLOSING` is normal background-on-exit noise; ignore it.
51
+
52
+ ## Patterns
53
+
54
+ Data extraction — write to `.gm/exec-spool/in/browser/<N>.txt`:
55
+
56
+ ```
57
+ const items = await page.$$eval('.title', els => els.map(e => e.textContent))
58
+ console.log(JSON.stringify(items))
59
+ ```
60
+
61
+ Console monitoring — set listeners first, then poll. Write to `.gm/exec-spool/in/browser/<N>.txt`:
62
+
63
+ ```
64
+ state.logs = []
65
+ page.on('console', msg => state.logs.push({ type: msg.type(), text: msg.text() }))
66
+ ```
67
+
68
+ Then write to `.gm/exec-spool/in/browser/<N+1>.txt`:
69
+
70
+ ```
71
+ console.log(JSON.stringify(state.logs.slice(-20)))
72
+ ```
73
+
74
+ ## Constraints
75
+
76
+ - One playwriter command per `browser:` block
77
+ - `exec:browser` body is plain JS, no shell quoting
78
+ - Browser tasks drain automatically on every plugkit interaction
79
+ - Sessions reap after 5–15 min idle; cleaned up on session end
80
+ - Never write standalone `.mjs`/`.js` Playwright scripts as a fallback — `exec:browser` errors must be debugged through `exec:browser` retries, not by creating test files on disk
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: code-search
3
+ description: Mandatory codebase search workflow. Use whenever you need to find anything in the codebase. Start with two words, iterate by changing or adding words until found.
4
+ ---
5
+
6
+ # Codebase search
7
+
8
+ `exec:codesearch` is the only codebase search tool. Never use Grep, Glob, Find, Explore, raw `grep`/`rg`/`find` inside `exec:bash`. No fallback.
9
+
10
+ A `@<discipline>` first-token after the verb scopes the search to that discipline's index; absent the sigil, results fan across default plus enabled disciplines, prefixed by source.
11
+
12
+ Handles exact symbols, exact strings, file-name fragments, regex-ish patterns, natural-language queries, and PDF pages (cite `path/doc.pdf:<page>`).
13
+
14
+ Direct-read exceptions: known absolute path → `Read`. Known directory listing → `exec:nodejs` + `fs.readdirSync`.
15
+
16
+ ## Syntax
17
+
18
+ ```
19
+ exec:codesearch
20
+ <two-word query>
21
+ ```
22
+
23
+ ## Iteration
24
+
25
+ Start at exactly two words. No results → change one word. Still none → add a third. Still none → swap the changed word again. Minimum four attempts before concluding absent. Never one word, never a full sentence, never switch tools.
26
+
27
+ ## Examples
28
+
29
+ ```
30
+ exec:codesearch
31
+ session cleanup idle
32
+ ```
33
+
34
+ No results, then:
35
+
36
+ ```
37
+ exec:codesearch
38
+ cleanup sessions timeout
39
+ ```
40
+
41
+ PDF:
42
+
43
+ ```
44
+ exec:codesearch
45
+ usb descriptor endpoint
46
+ ```
47
+
48
+ Returns `docs/usb-spec.pdf:42` — cite the page; `Read` if surrounding text is needed.
@@ -0,0 +1,121 @@
1
+ ---
2
+ name: create-lang-plugin
3
+ description: Create a lang/ plugin that wires any CLI tool or language runtime into gm-cc — adds exec:<id> dispatch, optional LSP diagnostics, and optional prompt context injection. Zero hook configuration required.
4
+ ---
5
+
6
+ # Create lang plugin
7
+
8
+ Single CommonJS file at `<projectDir>/lang/<id>.js`. Auto-discovered — no hook editing.
9
+
10
+ ## Plugin shape
11
+
12
+ ```js
13
+ 'use strict';
14
+ module.exports = {
15
+ id: 'mytool',
16
+ exec: {
17
+ match: /^exec:mytool/,
18
+ run(code, cwd) { /* returns string or Promise<string> */ }
19
+ },
20
+ lsp: {
21
+ check(fileContent, cwd) { /* returns Diagnostic[] */ }
22
+ },
23
+ extensions: ['.ext'],
24
+ context: `=== mytool ===\n...`
25
+ };
26
+ ```
27
+
28
+ `type Diagnostic = { line: number; col: number; severity: 'error'|'warning'; message: string }`
29
+
30
+ `exec.run` runs in a child process, 30s timeout, async OK. Called when Claude writes `exec:mytool\n<code>`. `lsp.check` is synchronous-only, called per prompt-submit. `context` is injected into every prompt, truncated to 2000 chars.
31
+
32
+ ## Identify the tool
33
+
34
+ What is the CLI name or npm package? Does it run a single expression (`tool eval`, `tool -e`, HTTP POST) or a file (`tool run <file>`)? What is its lint/check mode and output format? File extensions? Does it require a running server, or does it run headless?
35
+
36
+ ## exec.run patterns
37
+
38
+ HTTP eval against a running server:
39
+
40
+ ```js
41
+ function httpPost(port, urlPath, body) {
42
+ return new Promise((resolve, reject) => {
43
+ const data = JSON.stringify(body);
44
+ const req = http.request(
45
+ { hostname: '127.0.0.1', port, path: urlPath, method: 'POST',
46
+ headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) } },
47
+ res => { let raw = ''; res.on('data', c => raw += c); res.on('end', () => resolve(JSON.parse(raw))); }
48
+ );
49
+ req.setTimeout(8000, () => { req.destroy(); reject(new Error('timeout')); });
50
+ req.on('error', reject);
51
+ req.write(data); req.end();
52
+ });
53
+ }
54
+ ```
55
+
56
+ File-based, headless:
57
+
58
+ ```js
59
+ function runFile(code, cwd) {
60
+ const tmp = path.join(os.tmpdir(), `plugin_${Date.now()}.ext`);
61
+ fs.writeFileSync(tmp, code);
62
+ try { return execFileSync('mytool', ['run', tmp], { cwd, encoding: 'utf8', timeout: 10000 }); }
63
+ finally { try { fs.unlinkSync(tmp); } catch (_) {} }
64
+ }
65
+ ```
66
+
67
+ Single-expression detection:
68
+
69
+ ```js
70
+ const isSingleExpr = code => !code.trim().includes('\n') && !/\b(func|def|fn |class|import)\b/.test(code);
71
+ ```
72
+
73
+ ## lsp.check
74
+
75
+ ```js
76
+ function check(fileContent, cwd) {
77
+ const tmp = path.join(os.tmpdir(), `lsp_${Math.random().toString(36).slice(2)}.ext`);
78
+ try {
79
+ fs.writeFileSync(tmp, fileContent);
80
+ const r = spawnSync('mytool', ['check', tmp], { encoding: 'utf8', cwd });
81
+ return (r.stdout + r.stderr).split('\n').reduce((acc, line) => {
82
+ const m = line.match(/^.+:(\d+):(\d+):\s+(error|warning):\s+(.+)$/);
83
+ if (m) acc.push({ line: +m[1], col: +m[2], severity: m[3], message: m[4].trim() });
84
+ return acc;
85
+ }, []);
86
+ } catch (_) { return []; }
87
+ finally { try { fs.unlinkSync(tmp); } catch (_) {} }
88
+ }
89
+ ```
90
+
91
+ ## context
92
+
93
+ Under 300 chars:
94
+
95
+ ```js
96
+ context: `=== mytool ===\nexec:mytool\n<expression>\n\nRuns via <how>. Use for <when>.`
97
+ ```
98
+
99
+ ## Verify
100
+
101
+ Write to `.gm/exec-spool/in/nodejs/<N>.js`:
102
+
103
+ ```js
104
+ const p = require('/abs/path/lang/mytool.js');
105
+ console.log(p.id, typeof p.exec.run, p.exec.match.toString());
106
+ ```
107
+
108
+ Then test dispatch by writing to `.gm/exec-spool/in/mytool/<N>.txt`:
109
+
110
+ ```
111
+ <simple test expression>
112
+ ```
113
+
114
+ ## Constraints
115
+
116
+ - `exec.run` async OK, 30s timeout
117
+ - `lsp.check` synchronous only — no Promises
118
+ - CommonJS only — no ES module syntax
119
+ - No persistent processes
120
+ - `id` must match filename exactly
121
+ - First match wins — keep `match` specific
@@ -1,63 +1,24 @@
1
1
  ---
2
2
  name: gm
3
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
4
+ allowed-tools: Skill, Read, Write
16
5
  end-to-end: true
17
6
  ---
18
7
 
19
- # GMOrchestrator
8
+ # gmORCHESTRATOR
20
9
 
21
- Invoke `planning` immediately. Phases cascade: PLAN EXECUTE EMIT VERIFY UPDATE-DOCS.
10
+ The user's request is the authorization. The PRD is the receipt. Once the user has spoken, the chain runs to COMPLETE without re-asking, without permission gates between phases, without narrating each step as if it were a deliverable. Re-asking "want me to do X?" after the user said "do X" is forced closure dressed as deference.
22
11
 
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.
12
+ When scope exceeds reach, the response is a maximal cover, not a single slice with the rest deferred. Distributed refusal is the same failure dressed as triage. Pick the wider read, declare the read in one line so the user can interrupt mid-chain, execute.
24
13
 
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.
14
+ The skill chain is one continuous motion: PLAN EXECUTE EMIT → VERIFY → UPDATE-DOCS. No stop between phases. No approval gates. No summarizing-as-completion. The next skill fires the moment the current skill's transition is named. A skill that ends without invoking its successor has stalled the chain.
26
15
 
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.
16
+ ## Dispatch
28
17
 
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.
18
+ Every operation routes through the spool. Write `.gm/exec-spool/in/<verb>/<N>.txt` with the body. Read `.gm/exec-spool/out/<N>.json`. The orchestrator owns FSM state; the skill reads `nextSkill` and dispatches.
30
19
 
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).
20
+ Verbs available here: `phase-status`, `transition`, `mutable-resolve` (auto-fires memorize), `memorize-fire`, plus `recall`, `codesearch`, `memorize`, `health`, all language stems.
32
21
 
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).
22
+ ## Transition
34
23
 
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.
24
+ Read `out/<N>.json::nextSkill`. Invoke `Skill(skill="gm:<nextSkill>")` immediately. End of skill body no trailing narration, no "I will now". The invocation IS the transition.
@@ -1,106 +1,35 @@
1
1
  ---
2
2
  name: gm-complete
3
3
  description: VERIFY and COMPLETE phase. End-to-end system verification and git enforcement. Any new unknown triggers immediate snake back to planning — restart chain.
4
+ allowed-tools: Skill, Read, Write
4
5
  ---
5
6
 
6
- # GM COMPLETE Verify, then close
7
+ # gm-completeVERIFY
7
8
 
8
- Entry: EMIT gates clear, from `gm-emit`. Exit: `.prd` deleted + test.js green + pushed + CI green `update-docs`.
9
+ COMPLETE is earned, not declared. Three preconditions: git clean, pushed to remote, CI green. Any one missing means the phase has not concluded.
9
10
 
10
- Cross-cutting dispositions live in `gm` SKILL.md.
11
+ ## CI Is The Build
11
12
 
12
- ## Transitions
13
+ For Rust crates (rs-exec, rs-codeinsight, rs-search, rs-learn, rs-plugkit) and the gm publish chain, `git push` triggers the build matrix across six target platforms. `cargo build` and `cargo test` are not run locally — a local build covers exactly one platform and proves nothing about the other five. Push, watch CI, fix on red. Toolchain mismatches and rustc skew never block a push.
13
14
 
14
- - `.prd` items remain → `gm-execute`
15
- - `.prd` empty AND test.js green AND pushed AND CI green → `update-docs`
16
- - Broken file output → `gm-emit`
17
- - Wrong logic → `gm-execute`
18
- - New unknown or wrong requirements → `planning`
15
+ Watch protocol: after push, poll `gh run list --branch <branch> --limit 3 --json status,conclusion,name` until the run completes, up to `GM_CI_WATCH_SECS` (default 180). On red, triage the failure shape (import error check manifests; type error → snake to PLAN; test failure → root cause; lint → fix in-band; build timeout → re-trigger once, else PRD `blockedBy: external`). Fix at root, push, re-watch. Green CI is the precondition for VERIFY → UPDATE-DOCS.
19
16
 
20
- Failure triage: broken output to EMIT, wrong logic to EXECUTE, new unknown to PLAN. Never patch around surprises.
17
+ ## Single Integration Test
21
18
 
22
- ## Mutables that must resolve before COMPLETE
19
+ One `test.js` at project root. 200-line hard cap. No fixtures, no mocks, no scattered test files. `gm-complete` runs it. Failure = regression to EXECUTE. Prefer compaction over expansion when editing: merge groups, drop redundancy.
23
20
 
24
- - `witnessed_e2e` — real end-to-end run with witnessed output
25
- - `browser_validated` — for any change touching client / UI / browser-facing code, see gate below. test.js + node-side imports DO NOT satisfy this gate.
26
- - `git_clean` — `git status --porcelain` returns empty
27
- - `git_pushed` — `git log origin/main..HEAD --oneline` returns empty
28
- - `ci_passed` — every GitHub Actions run reaches `conclusion: success`
29
- - `mutables_resolved` — `.gm/mutables.yml` deleted OR every entry `status: witnessed`. Stop hook hard-blocks turn-stop while any entry is `status: unknown`.
30
- - `prd_empty` — `.gm/prd.yml` deleted AFTER residual scan: enumerate every in-spirit reachable residual surfaced this session; any hit re-enters `planning`, appends PRD items, executes. Empty PRD is necessary, not sufficient — done = empty PRD AND zero reachable in-spirit residuals. Out-of-spirit-or-unreachable residuals are named in the response and skipped; everything else is this turn's work.
31
- - `stress_suite_clear` — change walked through M1–D1 (governance), none flunked
32
- - `hidden_decision_posture` — open → down_weighted → closed only when CI is green AND stress suite is clear
21
+ ## Residual-Scan Gate
33
22
 
34
- ## End-to-end verification
23
+ Before allowing transition to update-docs, fire the `residual-scan` verb. Empty PRD is necessary but not sufficient — the gate asks what the agent should have decided to do but did not. Either re-enter planning with appended items and execute, or explicitly state "residual scan: none reachable in-spirit." The `.gm/residual-check-fired` marker makes this one-shot per stopping window. Common residuals: pre-existing build break surfaced this turn, neighboring lint failure, obvious refactor win, observability gap, doc drift, follow-on work the user clearly implied.
35
24
 
36
- Real system, real data, witness actual output. Doc updates, "saying done", and screenshots alone are not verification. Write the e2e probe to the spool (`.gm/exec-spool/in/nodejs/<N>.js`):
25
+ ## Git Gate
37
26
 
38
- ```
39
- const { fn } = await import('/abs/path/to/module.js');
40
- console.log(await fn(realInput));
41
- ```
27
+ `git status` clean. `git log` shows the commit pushed. `gh run list` shows the most recent run for the branch concluded green. All three witnessed before transition.
42
28
 
43
- After every success, enumerate what remains — never stop at first green.
29
+ ## Dispatch
44
30
 
45
- ## Browser validation gate
31
+ `phase-status`, `transition`, `residual-scan`. Spool the CI watch through `in/bash/` so timeouts respect the spool budget.
46
32
 
47
- Required when this session changed any code that runs in a browser: anything under `client/`, UI components, shaders, page-loaded JS, served HTML, gh-pages assets, dev-server endpoints, or any module imported into the page bundle.
33
+ ## Transition
48
34
 
49
- Trigger detection (any one): `git diff --name-only origin/main..HEAD` includes paths under `client/`, `apps/*/index.js` with client export, `docs/`, `*.html`, shader files, or any file imported by a browser entry; new/changed export consumed by `window.*` or rendered in DOM/canvas/WebGL; visual, layout, animation, input, network-on-page, or shader behavior altered.
50
-
51
- Protocol: boot the real server (or open the static page) on a known URL — witness HTTP 200. `exec:browser` → `page.goto(url)` → wait for app init by polling for the global the change affects (`window.__app.<system>`). Probe via `page.evaluate(() => …)` asserting the specific invariant the change was supposed to establish — instance counts, scene meshes, DOM nodes, render stats, network frames. Capture witnessed numbers in the response — "looks fine" is not a witness. Failures route to `gm-execute` (logic) or `gm-emit` (output) — never paper over.
52
-
53
- Long-running probes split into navigate-call → `exec:wait N` → probe-call to stay under the per-call budget. Do not stack multi-second `setTimeout` inside one `exec:browser` invocation.
54
-
55
- Exempt only when: change is server-only with zero browser-facing surface, OR the repository has no browser surface at all (pure CLI / library). Exemption requires explicit tag in the response: `BROWSER EXEMPT: <reason — must reference diff paths showing zero browser-facing surface>`. Default posture is NOT exempt — burden is on the agent to prove exemption with diff evidence.
56
-
57
- Pre-flight: run `git diff --name-only origin/main..HEAD` directly via Bash, then dispatch a nodejs spool file that reads the diff list and filters lines matching `client/|docs/|\.html$|\.glsl$|\.frag$|\.vert$`. Any hit AND no `exec:browser` block in this session → mandatory regression to `gm-execute`.
58
-
59
- ## Integration test gate
60
-
61
- Write to `.gm/exec-spool/in/nodejs/<N>.js`:
62
-
63
- ```
64
- const { execSync } = require('child_process');
65
- try { execSync('node test.js', { stdio: 'inherit', timeout: 30000 }); console.log('PASS'); }
66
- catch (e) { console.error('FAIL'); process.exit(1); }
67
- ```
68
-
69
- Failure → `gm-execute`. No test.js in a repo with testable surface → `gm-execute` to create it.
70
-
71
- ## Git enforcement
72
-
73
- Run directly via Bash:
74
-
75
- ```
76
- git status --porcelain
77
- git log origin/main..HEAD --oneline
78
- ```
79
-
80
- Both must return empty. Local commit without push is not complete.
81
-
82
- ## CI is automated
83
-
84
- The Stop hook watches Actions for the pushed HEAD. Do not call `gh run list` manually. All-green → Stop approves with CI summary in next-turn context. Failure → Stop blocks with run names + IDs; investigate via `gh run view <id> --log-failed`, fix, push, hook re-watches. Deadline 180s (override `GM_CI_WATCH_SECS`); slow jobs get a "still in progress" approve.
85
-
86
- ## Hygiene sweep
87
-
88
- 1. Files >200 lines → split
89
- 2. Comments in code → remove
90
- 3. Scattered test files (`.test.js`, `.spec.js`, `__tests__/`, `fixtures/`, `mocks/`) → delete, consolidate into root `test.js`
91
- 4. Mock / stub / simulation files → delete
92
- 5. Unnecessary doc files (not CHANGELOG, CLAUDE, README, TODO.md) → delete
93
- 6. Duplicate concern → regress to `planning` with restructuring instructions
94
- 7. Hardcoded values → derive from ground truth
95
- 8. Fallback / demo modes → remove, fail loud
96
- 9. TODO.md → empty or deleted
97
- 10. CHANGELOG.md → entries for this session
98
- 11. Observability gaps → server subsystems expose `/debug/<subsystem>`; client modules register in `window.__debug`
99
- 12. Memorize → every fact from verification handed off via background `Agent(memorize)` at moment of resolution
100
- 13. Deploy / publish → if deployable, deploy; if npm package, publish
101
- 14. GitHub Pages → check `.github/workflows/pages.yml` + `docs/index.html` exist; invoke `pages` skill if absent
102
- 15. Governance stress-suite → walk change through M1, F1, C1, H1, S1, B1, A1, D1; any flunk regresses to the owning phase
103
-
104
- ## Completion
105
-
106
- All true at once: witnessed e2e | browser_validated when client work touched | failure paths exercised | test.js passes | `.prd` deleted | git clean and pushed | CI green | hygiene sweep clean | TODO.md gone | CHANGELOG.md updated.
35
+ Residual-scan clear AND git clean AND CI green `Skill(skill="gm:update-docs")`. Anything else `Skill(skill="gm:planning")` or `Skill(skill="gm:gm-execute")` per the gap.