@lovrozagar/grunt 0.5.2 → 0.6.1

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 (157) hide show
  1. package/.agents/agents/grunt.md +2 -24
  2. package/.agents/agents/orchestrator.md +5 -50
  3. package/.agents/skills/ask/SKILL.md +5 -12
  4. package/.agents/skills/auto/SKILL.md +7 -12
  5. package/.agents/skills/browser/SKILL.md +4 -8
  6. package/.agents/skills/clasp/SKILL.md +11 -0
  7. package/.agents/skills/commit/SKILL.md +3 -1
  8. package/.agents/skills/commit-push/SKILL.md +2 -0
  9. package/.agents/skills/commit-push-deploy/SKILL.md +2 -0
  10. package/.agents/skills/commit-push-release/SKILL.md +2 -0
  11. package/.agents/skills/explain/SKILL.md +7 -13
  12. package/.agents/skills/google-workspace/SKILL.md +13 -0
  13. package/.agents/skills/handoff/SKILL.md +7 -11
  14. package/.agents/skills/implement-plan/SKILL.md +5 -109
  15. package/.agents/skills/listen/SKILL.md +15 -0
  16. package/.agents/skills/pickup/SKILL.md +6 -12
  17. package/.agents/skills/speak/SKILL.md +13 -0
  18. package/.agents/skills/tmp/SKILL.md +6 -10
  19. package/.agents/skills/write-plan/SKILL.md +5 -77
  20. package/.claude/agents/grunt.md +2 -26
  21. package/.claude/agents/orchestrator.md +12 -50
  22. package/.claude/skills/ask/SKILL.md +5 -12
  23. package/.claude/skills/auto/SKILL.md +7 -12
  24. package/.claude/skills/browser/SKILL.md +4 -8
  25. package/.claude/skills/clasp/SKILL.md +11 -0
  26. package/.claude/skills/commit/SKILL.md +3 -1
  27. package/.claude/skills/commit-push/SKILL.md +2 -0
  28. package/.claude/skills/commit-push-deploy/SKILL.md +2 -0
  29. package/.claude/skills/commit-push-release/SKILL.md +2 -0
  30. package/.claude/skills/explain/SKILL.md +7 -13
  31. package/.claude/skills/google-workspace/SKILL.md +13 -0
  32. package/.claude/skills/handoff/SKILL.md +7 -11
  33. package/.claude/skills/implement-plan/SKILL.md +5 -109
  34. package/.claude/skills/listen/SKILL.md +15 -0
  35. package/.claude/skills/pickup/SKILL.md +6 -12
  36. package/.claude/skills/speak/SKILL.md +13 -0
  37. package/.claude/skills/tmp/SKILL.md +6 -10
  38. package/.claude/skills/write-plan/SKILL.md +5 -77
  39. package/.codex/agents/grunt.toml +2 -26
  40. package/.codex/agents/orchestrator.toml +4 -50
  41. package/.grok/agents/grunt.md +2 -24
  42. package/.grok/agents/orchestrator.md +4 -48
  43. package/.grok/global-settings.toml +1 -3
  44. package/.grok/hooks/orchestrate-parent.js +190 -358
  45. package/.grok/skills/ask/SKILL.md +5 -12
  46. package/.grok/skills/auto/SKILL.md +7 -12
  47. package/.grok/skills/browser/SKILL.md +4 -8
  48. package/.grok/skills/clasp/SKILL.md +11 -0
  49. package/.grok/skills/commit/SKILL.md +3 -1
  50. package/.grok/skills/commit-push/SKILL.md +2 -0
  51. package/.grok/skills/commit-push-deploy/SKILL.md +2 -0
  52. package/.grok/skills/commit-push-release/SKILL.md +2 -0
  53. package/.grok/skills/explain/SKILL.md +7 -13
  54. package/.grok/skills/google-workspace/SKILL.md +13 -0
  55. package/.grok/skills/handoff/SKILL.md +7 -11
  56. package/.grok/skills/implement-plan/SKILL.md +5 -109
  57. package/.grok/skills/listen/SKILL.md +15 -0
  58. package/.grok/skills/pickup/SKILL.md +6 -12
  59. package/.grok/skills/speak/SKILL.md +13 -0
  60. package/.grok/skills/tmp/SKILL.md +6 -10
  61. package/.grok/skills/write-plan/SKILL.md +5 -77
  62. package/.rulesync/hooks.jsonc +1 -1
  63. package/.rulesync/mcp-policy.jsonc +0 -2
  64. package/.rulesync/reference/INDEX.md +30 -20
  65. package/.rulesync/reference/browser.md +13 -6
  66. package/.rulesync/reference/cascade.md +6 -86
  67. package/.rulesync/reference/clasp.md +21 -0
  68. package/.rulesync/reference/google-workspace.md +79 -0
  69. package/.rulesync/reference/hooks.md +7 -11
  70. package/.rulesync/reference/implementation-format.md +113 -0
  71. package/.rulesync/reference/law.md +5 -3
  72. package/.rulesync/reference/listen.md +80 -0
  73. package/.rulesync/reference/map.md +40 -36
  74. package/.rulesync/reference/output.md +3 -51
  75. package/.rulesync/reference/plan-format.md +4 -2
  76. package/.rulesync/reference/refs-map.md +12 -5
  77. package/.rulesync/reference/rtk.md +3 -2
  78. package/.rulesync/reference/scope.md +37 -0
  79. package/.rulesync/reference/setup.md +27 -0
  80. package/.rulesync/reference/skills-map.md +13 -12
  81. package/.rulesync/reference/speak.md +59 -0
  82. package/.rulesync/rules/CLAUDE.md +3 -49
  83. package/.rulesync/rules/overview.md +9 -47
  84. package/.rulesync/skills/ask/SKILL.md +5 -12
  85. package/.rulesync/skills/auto/SKILL.md +5 -12
  86. package/.rulesync/skills/browser/SKILL.md +4 -8
  87. package/.rulesync/skills/clasp/SKILL.md +9 -0
  88. package/.rulesync/skills/commit/SKILL.md +3 -1
  89. package/.rulesync/skills/commit-push/SKILL.md +2 -0
  90. package/.rulesync/skills/commit-push-deploy/SKILL.md +2 -0
  91. package/.rulesync/skills/commit-push-release/SKILL.md +2 -0
  92. package/.rulesync/skills/explain/SKILL.md +7 -14
  93. package/.rulesync/skills/google-workspace/SKILL.md +11 -0
  94. package/.rulesync/skills/handoff/SKILL.md +7 -11
  95. package/.rulesync/skills/implement-plan/SKILL.md +5 -119
  96. package/.rulesync/skills/listen/SKILL.md +13 -0
  97. package/.rulesync/skills/pickup/SKILL.md +6 -12
  98. package/.rulesync/skills/speak/SKILL.md +13 -0
  99. package/.rulesync/skills/tmp/SKILL.md +6 -10
  100. package/.rulesync/skills/write-plan/SKILL.md +5 -84
  101. package/.rulesync/subagents/grunt.md +2 -24
  102. package/.rulesync/subagents/orchestrator.md +14 -59
  103. package/AGENTS.md +9 -47
  104. package/CHANGELOG.md +67 -0
  105. package/CLAUDE.md +1 -49
  106. package/README.md +89 -80
  107. package/cli/grunt.mjs +21 -3
  108. package/cli/grunt.test.ts +47 -3
  109. package/cli/init.mjs +134 -234
  110. package/cli/init.test.ts +241 -58
  111. package/cli/prompt.mjs +9 -36
  112. package/cli/prompt.test.ts +14 -0
  113. package/package.json +10 -2
  114. package/scripts/browser.mjs +128 -7
  115. package/scripts/doctor.mjs +104 -10
  116. package/scripts/emit-gemini.mjs +2 -2
  117. package/scripts/emit-mcp-policy.mjs +1 -1
  118. package/scripts/gate-fat-tools.mjs +223 -173
  119. package/scripts/google-workspace.mjs +713 -0
  120. package/scripts/grunt-job.mjs +453 -69
  121. package/scripts/guarded-md.mjs +230 -0
  122. package/scripts/guarded-roots.mjs +1 -1
  123. package/scripts/interactive.mjs +15 -0
  124. package/scripts/listen.mjs +829 -0
  125. package/scripts/parse-need.mjs +21 -2
  126. package/scripts/persist-implementation.mjs +278 -0
  127. package/scripts/prompt.mjs +32 -0
  128. package/scripts/scrub-spawn-prompt.mjs +3 -50
  129. package/scripts/setup.mjs +746 -0
  130. package/scripts/speak.mjs +291 -0
  131. package/.agents/agents/implementer.md +0 -32
  132. package/.agents/agents/thinker.md +0 -29
  133. package/.agents/skills/cascade/SKILL.md +0 -28
  134. package/.agents/skills/parent/SKILL.md +0 -6
  135. package/.agents/skills/solo/SKILL.md +0 -25
  136. package/.claude/agents/implementer.md +0 -37
  137. package/.claude/agents/thinker.md +0 -36
  138. package/.claude/skills/cascade/SKILL.md +0 -28
  139. package/.claude/skills/parent/SKILL.md +0 -6
  140. package/.claude/skills/solo/SKILL.md +0 -25
  141. package/.codex/agents/implementer.toml +0 -26
  142. package/.codex/agents/thinker.toml +0 -26
  143. package/.grok/agents/implementer.md +0 -27
  144. package/.grok/agents/thinker.md +0 -27
  145. package/.grok/parent.md +0 -1
  146. package/.grok/roles/implementer.toml +0 -5
  147. package/.grok/roles/thinker.toml +0 -5
  148. package/.grok/skills/cascade/SKILL.md +0 -28
  149. package/.grok/skills/parent/SKILL.md +0 -6
  150. package/.grok/skills/solo/SKILL.md +0 -25
  151. package/.rulesync/grunt.config.jsonc +0 -7
  152. package/.rulesync/skills/cascade/SKILL.md +0 -28
  153. package/.rulesync/skills/parent/SKILL.md +0 -6
  154. package/.rulesync/skills/solo/SKILL.md +0 -25
  155. package/.rulesync/subagents/implementer.md +0 -49
  156. package/.rulesync/subagents/thinker.md +0 -49
  157. package/scripts/grunt-config.mjs +0 -50
@@ -2,45 +2,55 @@
2
2
 
3
3
  # Law
4
4
 
5
- Protocol stays cascade/overview; domain fills this.
5
+ Protocol stays overview; domain fills this.
6
6
 
7
7
  ## Skills naming
8
8
 
9
- Reserved (do not reuse in consumer custom skills): `ask` `auto` `browser` `cascade` `commit` `commit-and-push` `commit-push` `commit-push-deploy` `commit-push-release` `explain` `handoff` `implement-plan` `parent` `pickup` `solo` `tmp` `write-plan`.
9
+ Reserved (do not reuse in consumer custom skills): `ask` `auto` `browser` `clasp` `commit` `commit-and-push` `commit-push` `commit-push-deploy` `commit-push-release` `explain` `google-workspace` `handoff` `implement-plan` `listen` `pickup` `speak` `tmp` `write-plan`.
10
10
 
11
- Override: same name → one SSOT path (`.rulesync/skills/<name>/`). Re-init force-refresh overwrites grunt-owned names; consumer extras kept. Maps `origin` badge ≠ content picker.
11
+ Override: same name → one SSOT path (`.rulesync/skills/<name>/`). Re-init / `grunt upgrade` force-refresh overwrites grunt-owned names; consumer extras kept. Maps `origin` badge ≠ content picker.
12
+
13
+ Upgrade copies the current package trees and product scripts, then deletes cumulative retired grunt-owned names (skills `parent` `solo` `cascade`; agents `implementer` `thinker`; scripts `telemetry.mjs` `grunt-config.mjs`; paths `.grok/parent.md` `.grok/skills/shared` `.rulesync/grunt.config.jsonc` `.rulesync/grunt.config.local.jsonc` `.rulesync/grunt.config.local.jsonc.example`) and any reserved skill dir this package no longer ships. `fs.cpSync` does not remove dest extras; prune is what drops them. Consumer skills/refs/scripts not on those lists stay.
12
14
 
13
15
  # Skills
14
16
 
15
17
  | name | origin | description | task | commandPath | refs |
16
18
  | --- | --- | --- | --- | --- | --- |
17
- | ask | local | Session leftover-gate. /ask sets leftover-gate ask for this session — leftover triple wait on advise-class recaps. Not… | | | |
18
- | auto | local | Session leftover-gate. /auto sets leftover-gate auto for this session — Implement-typed pick2 chains write-plan persist… | | | |
19
- | browser | local | Live URL/interact → this; not websearch. /browser or browse a URL. Call node scripts/browser.mjs nav\|snap\|click\|fill\|sh… | | | |
20
- | cascade | local | Session mode. /cascade exits solo and restores the grunt cascade for this session — spawn, orchestrator, recap, need\|ve… | | | |
19
+ | ask | local | Session flag. Finish one step, recap, then ask before the next. | | | |
20
+ | auto | local | Session flag. Default. Work the task through. Ask on blockers instead of monkey-patching. | | | |
21
+ | browser | local | Browse via node scripts/browser.mjs (Lightpanda). App e2e uses Playwright. | | | |
22
+ | clasp | local | Low-level Apps Script CLI. Prefer /google-workspace for sheet, doc, meeting, mail. | | | |
21
23
  | commit | local | Inspect the diff and commit with a Conventional Commits subject line. Use for /commit, "commit this", "commit these cha… | | | |
22
24
  | commit-and-push | local | Alias of commit-push (1-release stub). Use for /commit-and-push, "commit and push", "commit this and push". Must push.… | | | |
23
25
  | commit-push | local | Commit with a Conventional Commits subject, then push. Use for /commit-push, "commit and push", "commit this and push".… | | | |
24
26
  | commit-push-deploy | local | Commit, push, then deploy only if allowlisted infra already exists. Use for /commit-push-deploy, "commit push deploy",… | | | |
25
27
  | commit-push-release | local | Commit, push, bump package.json, tag vX.Y.Z, push the tag. CI publishes. Use for /commit-push-release, "commit push rel… | | | |
26
- | explain | local | One-off human recap. /explain. First action = spawn grunt\|implementer\|thinker if facts/work; else recap already-visible… | | | |
27
- | handoff | local | Parent writes a session handoff under .tmp/grunt/handoffs/ and tells the user to continue in a fresh session. Use for /… | | | |
28
- | implement-plan | local | Implementer executes a local .tmp/grunt/plans checklist: continue, resume, or pick among plans. Empty /implement-plan r… | | | |
29
- | parent | local | One-turn parent-orchestrator escape. Use for /parent. Not a session mode. | | | |
30
- | pickup | local | Pick up/continue a session handoff under .tmp/grunt/handoffs/. Use for /pickup, pick up, continue handoff, serial, drag… | | | |
31
- | solo | local | Session mode. /solo disables the grunt cascade for this session — one normal agent, no spawn, no orchestrator. /cascade… | | | |
32
- | tmp | local | One-off convo artifact dump under .tmp/grunt/. Use for /tmp, dump a draft, save a note/email/script from this session.… | | | |
33
- | write-plan | local | Thinker drafts a local implementer-ready checklist plan; parent Write persists .tmp/grunt/plans/{serial}-{slug}-{YYYYMM… | | | |
28
+ | explain | local | Longer human recap this reply only. | | | |
29
+ | google-workspace | local | Google Sheets, Docs, Slides, Calendar, Gmail via node scripts/google-workspace.mjs. | | | |
30
+ | handoff | local | Write a session handoff under .tmp/grunt/handoffs/. Continue with /pickup. | | | |
31
+ | implement-plan | local | Execute remaining leaves in a .tmp/grunt/plans checklist. Skip [x]. | | | |
32
+ | listen | local | Speech-to-text via node scripts/listen.mjs (ffmpeg mic + local whisper.cpp, OpenAI fallback). Input only. | | | |
33
+ | pickup | local | Continue a handoff under .tmp/grunt/handoffs/. | | | |
34
+ | speak | local | Text-to-speech via node scripts/speak.mjs (ElevenLabs or OpenAI). Output only. | | | |
35
+ | tmp | local | Dump a one-off convo artifact under .tmp/grunt/. | | | |
36
+ | write-plan | local | Write a local checklist under .tmp/grunt/plans/. Then /implement-plan {n}. | | | |
34
37
 
35
38
  # Refs
36
39
 
37
40
  | path | title | tags | summary |
38
41
  | --- | --- | --- | --- |
39
- | .rulesync/reference/browser.md | Browser | browser | Zero-config in-tree session rail. Not MCP. Not env. Not raw Playwright. |
40
- | .rulesync/reference/cascade.md | Cascade | cascade | Shipped protocol: **parent-only spawn**. Only the parent **orchestrator** session calls `spawn_subagent`. Implementer a… |
42
+ | .rulesync/reference/browser.md | Browser | browser | Zero-config in-tree session rail. Not MCP. Not env. Not raw Playwright. Lightpanda first; swap to Chromium when blocked. |
43
+ | .rulesync/reference/cascade.md | Protocol | cascade | The session agent has tools. Fat Read/Grep/Bash dumps are rewritten to `scripts/grunt-job.mjs` (squeez + stash). Isolat… |
44
+ | .rulesync/reference/clasp.md | Clasp | clasp | Low-level Apps Script CLI. Optional. Doctor reports it. |
45
+ | .rulesync/reference/google-workspace.md | google-workspace | google-workspace | Create and edit Google Sheets, Docs, Slides, Calendar events, and Gmail from the session. |
41
46
  | .rulesync/reference/hooks.md | Hooks | hooks | SessionStart: keep empty (token baseline). Do not inject context. Do not register a SessionStart hook on `../../.grok/h… |
42
- | .rulesync/reference/law.md | Law | | Protocol stays cascade/overview; domain fills this. |
47
+ | .rulesync/reference/implementation-format.md | Implementation format (SSOT) | | Local session journal for `/implement-plan`. Not a plan, handoff, or git commit. |
48
+ | .rulesync/reference/law.md | Law | | Protocol stays overview; domain fills this. |
49
+ | .rulesync/reference/listen.md | Listen | listen | Speech-to-text from the session. Input only. Not TTS. Not a live voice agent. Not MCP. |
43
50
  | .rulesync/reference/map.md | Map | map | Cheap outline. Not a file dump. |
44
- | .rulesync/reference/output.md | Output | output | en-US unless asked. every output maximal superterse. Fragments OK. Sacrifice grammar; keep meaning. Parent and child. E… |
45
- | .rulesync/reference/plan-format.md | Plan format (SSOT) | | Local implementer checklist. Not a design doc, PR stack, or DAG. |
51
+ | .rulesync/reference/output.md | Output | output | en-US unless asked. Concise complete sentences with natural grammar. Skip filler and fluff. |
52
+ | .rulesync/reference/plan-format.md | Plan format (SSOT) | | Local session checklist. Not a design doc, PR stack, or DAG. |
46
53
  | .rulesync/reference/rtk.md | RTK | rtk | Shell stdout compression. PreToolUse: Bash → `rtk <cmd>`. Not Read/Grep/Glob/prompts/images. |
54
+ | .rulesync/reference/scope.md | Scope | scope | Default: do the work. Escalate only when it is not a straight shot. This file is the size-gate SSOT. |
55
+ | .rulesync/reference/setup.md | Setup | setup | Handheld machine setup for optional integrations. Any OS. Secrets stay in `~/.grunt/` (Windows `%USERPROFILE%\.grunt`).… |
56
+ | .rulesync/reference/speak.md | Speak | speak | Text-to-speech from the session. Output only. Not STT. Not a mic. Not MCP. Speech-to-text is `/listen`: `.rulesync/refe… |
@@ -4,13 +4,13 @@ tags: [browser]
4
4
 
5
5
  # Browser
6
6
 
7
- Zero-config in-tree session rail. Not MCP. Not env. Not raw Playwright.
7
+ Zero-config in-tree session rail. Not MCP. Not env. Not raw Playwright. Lightpanda first; swap to Chromium when blocked.
8
8
 
9
9
  ```
10
- node scripts/browser.mjs nav|snap|click|fill|shot|pdf|stop|doctor|ensure
10
+ node scripts/browser.mjs nav|snap|click|fill|scroll|wait|hover|select|shot|pdf|stop|doctor|ensure
11
11
  ```
12
12
 
13
- Default engine: **Lightpanda** (`lightpanda` on PATH). Chromium only when a rule below requires it.
13
+ Default engine: **Lightpanda** (`lightpanda` on PATH). Chromium when a rule below requires it. Never report "can't browse" while Chromium is available.
14
14
 
15
15
  ## Verbs
16
16
 
@@ -20,6 +20,10 @@ Default engine: **Lightpanda** (`lightpanda` on PATH). Chromium only when a rule
20
20
  | `snap` | markdown + numbered AX refs (default read) |
21
21
  | `click <ref>` | click a ref from last `snap` |
22
22
  | `fill <ref> <text>` | fill a ref from last `snap` |
23
+ | `scroll [ref|down|up|N]` | scroll a snap ref into view, or the window |
24
+ | `wait [ms]` | pause (default 1000, cap 15000) |
25
+ | `hover <ref>` | hover a snap ref |
26
+ | `select <ref> <value>` | set a select/option value |
23
27
  | `shot` | screenshot (Chromium paint) |
24
28
  | `pdf` | PDF (Chromium paint) |
25
29
  | `stop` | reap engine pid; clear session; idempotent |
@@ -30,7 +34,7 @@ Session + profile + artifacts: `.tmp/grunt/browser/` only.
30
34
 
31
35
  ## Install
32
36
 
33
- Run `grunt doctor` / `node scripts/doctor.mjs`. See README Prerequisites.
37
+ Run `grunt doctor` / `node scripts/doctor.mjs`. Handheld engine hints (no keys): `node scripts/setup.mjs browser`. Doctor/setup is enough. Do not read a README unless those are missing; then https://github.com/lovrozagar/grunt#prerequisites (not the consumer README).
34
38
 
35
39
  ## Engine
36
40
 
@@ -40,9 +44,12 @@ Chromium immediately when any of:
40
44
 
41
45
  - verb is `shot` | `pdf` | `trace`
42
46
  - `process.platform === "win32"`
43
- - paint-host URL (tiny set): figma, Google docs / sheets / slides, mail.google, earth
47
+ - Chromium-first host: figma, Google docs / sheets / slides, mail.google, earth, amazon
44
48
  - `lightpanda` missing from PATH and a Chromium binary is present
45
49
  - Lightpanda probe fails **once** → one Chromium replay of last URL; no loop
50
+ - `snap` on Lightpanda is empty, a bot/JS wall, or client-rendered junk → one Chromium replay, then snap again
51
+
52
+ The session agent does not invent a "can't" for Amazon or other client-rendered sites. The rail swaps. One swap cap. App e2e stays Playwright (`playwright test`), not this CLI.
46
53
 
47
54
  No user env. Never `GRUNT_BROWSER*`. Never `LIGHTPANDA_CDP_URL`.
48
55
 
@@ -50,7 +57,7 @@ No user env. Never `GRUNT_BROWSER*`. Never `LIGHTPANDA_CDP_URL`.
50
57
 
51
58
  - MCP browser servers
52
59
  - user env knobs
53
- - raw Playwright as the agent tool
60
+ - raw Playwright as the browse tool (Playwright is the app e2e runner)
54
61
  - grunt `job:browse`
55
62
  - teaching thinker / orchestrator to browse
56
63
 
@@ -2,94 +2,14 @@
2
2
  tags: [cascade]
3
3
  ---
4
4
 
5
- # Cascade
5
+ # Protocol
6
6
 
7
- Shipped protocol: **parent-only spawn**. Only the parent **orchestrator** session calls `spawn_subagent`. Implementer and thinker never spawn. Isolation is a **grunt sibling**. See [map](map.md).
7
+ The session agent has tools. Fat Read/Grep/Bash dumps are rewritten to `scripts/grunt-job.mjs` (squeez + stash). Isolation facts stay ≤8 lines.
8
8
 
9
- ## Parent orchestrator
9
+ Run `node scripts/grunt-job.mjs --job search|exec|slice|fetch|test` first. Spawn a grunt model only when the dump needs judgment (browse snap, messy test log). Isolation work may run as grunt.
10
10
 
11
- Always-do lives in orchestrator/overview (do not open this file first). Peek/kill/`need:` stay here as reference.
12
- ⚠ / validate / sim → spawn implementer; not stop.
13
- Child prompt first sentence only: `You are {agent} subagent.` Then task + abs paths + verdicts only. Browse tags match → prompt must include abs `.rulesync/skills/browser/SKILL.md` and `.rulesync/reference/browser.md`.
11
+ `need:` JSON (search|exec|slice|fetch) may be intercepted in-hook (cap 4). Peek/kill if a child is running: Grok `get_command_or_subagent_output` `timeout_ms=60000`. Other hosts: block on spawn return.
14
12
 
15
- Always spawn + prompt. First token = spawn. Parent Read/Bash deny expected if forgotten. Only `/solo` (effective spawnMode solo) escapes spawn workflow. `/parent` is last-ditch hook stamp not skill-instructed Read/Bash. No try-then-spawn. No parent probe. No tiny-read/grep/list_dir/bash/grunt-job for the user. No skip-spawn.
16
- Create/change product files → grunt facts first; then thinker advise/plan/stop unless small/simple or prompt-is-spec → implementer. Default without detailed spec = grunt check → thinker advise/plan → stop. Advise-first stop wins until unlock. Unlock implementer only on: Implement-typed numbered/label pick1 or pick2 or `/implement-plan {n}` or explicit implement (=pick1 iff Implement-typed). Write-typed leftover never spawns implementer. `ok`/`yes`/`y`/`continue` ≠ either pick (`continue` = write-plan file gate only). Thinker recap alone ≠ spec-ready; do not auto-implement. Conversational advise recap = stop.
17
- Advise leftover: numbered pick each on own line after tagged recap (not same-line); one empty blank line immediately before leftover 1. (leftover last; not adjacent to recap/body). Always-print typed leftover triple (advise-class final recap only) unless effective leftover-gate=auto and Implement-typed (pick2 chains write-plan persist → implement-plan `{n}`; skip leftover wait). Write-typed under auto still leftover wait; never spawn implementer. One verb per recap; never jammed Implement/write. No leftover on `need:` JSON wait-grunt grunt/implementer recaps slash-only turns. Effective leftover-gate: stamp `auto-ask-{sid}` > `.rulesync/grunt.config.jsonc` `leftoverGate` > `ask`. Effective spawn: stamp `spawn-mode-{sid}` body `solo`|`cascade` > one-release `grunt-off` presence as solo > `.rulesync/grunt.config.jsonc` `spawnMode` > `cascade`. Fail-closed cascade. `/auto` `/ask` session leftover-gate, not spawn-escape.
18
- 1. {Implement|Write} with verbal plan
19
- 2. {same verb} with file plan
20
- 3. Tweak
21
- Type Implement = in-repo product writes. Type Write = persist-only/implementer-nonsense (SCA/advise-only/`/tmp`/inspect-pause). Recap remainder still names the human gate; leftover is not `4. Contact bank`. `/handoff` stays slash not Write pick1. No omit 1/2. No frozen 4. Do not relabel 3. Parent echoes printed leftover. Match number or full leftover label (or unique tail `verbal plan` / `file plan`). Always-do leftover match printed lines; not Skill-name (`2` ≠ write-plan). Implement pick1 = spawn implementer; paste last [thinker] recap as spec (how+why; implementer must not paste why into code comments); no `.tmp/grunt/plans`; no write-plan; no implement-plan. Implement pick2 = persist `.tmp/grunt/plans/{n}` then spawn implementer `plan=/abs/...` one-shot skip pause. Write pick1 = `/tmp` persist recap/body under `.tmp/grunt/`; no implementer. Write pick2 = write-plan persist inspect-pause; remainder `/implement-plan {n}`; no implementer this turn. Parent still no Write — existing write-plan/`/tmp` path/skill sequencing. 3 / Tweak → stay advise; extra text → thinker; bare 3/Tweak = stop wait notes. Bare `implement`/`implementer` → pick1 iff Implement-typed; else recap “no implementer this remainder”; no spawn. Bare `write` → pick1 iff Write-typed; else not a match. Type-mismatch → that recap no spawn. Alias `Implementer with …` → pick1/pick2 iff Implement-typed. `/write-plan` persist-only inspect-pause; remainder ask `/implement-plan {n}`. Not leftover pick 2. `/implement-plan {n}` stays disk/file run; ≠ conversational verbal pick. Disk leftover may invoke without user slash; verbal ≠ implement-plan.
22
- Owned-defect after grunt: check/see-if = grunt first. Verdict names defect in path we control (in-tree or package we publish) → writes remain → spawn thinker; not fact-stop; not implementer yet unless user already said fix / prompt-is-spec / small. Not ours → fact-stop/workaround OK; no Implement pick1. Unsure ownership → thinker. Control ≠ cwd; human-owned package still Fix {path} from consumer session; can't write → remainder `fix in {checkout path}` + ask switch. Recap `{decided}=Fix {path+bug}`; leftover always-print typed triple (Implement when in-repo writes; 3=tweak); do not relabel 3. Workaround = why rejected-alt never remainder. Grunt no leftover.
23
- Never parent Write/Edit/Bash/Skill-that-writes. Child returned is not terminal if writes remain after that gate or spawn count is 0 on a pick1/pick2/`/implement-plan {n}`/spec/small file-change turn. plan/spec ready + writes remain → spawn implementer only on Implement-typed pick1/pick2 or `/implement-plan {n}`/spec/small; else recap-stop. plan-only `/write-plan` → recap + remainder `/implement-plan` (ask).
13
+ Session flags: `/auto` (default) keeps going and asks on blockers instead of monkey-patching. `/ask` finishes one step, recaps, then asks. Slash `/ask` stamps `.tmp/grunt/orchestrator-logs/session-gate-{sid}`; `/auto` unlinks.
24
14
 
25
- Precedence: slash → obvious fact/false+/reuse → advise-class row → prompt-is-spec → write.
26
- 1. Tools (facts / search / exec / git / web / test / low-reason mechanical write) → grunt. Facts/search → grunt, never thinker.
27
- 2. Write defined solution (prompt-is-spec or small/simple) → implementer. **Blocked if advise-class stems present** unless prompt-is-spec / obvious comment-spec false+. Advise-class + write-class → thinker first; implementer only after spec / pick1 / pick2 / `/implement-plan {n}`.
28
- 3. Think / plan / advise / recommend / how / why / explain (ask-us; not slash `/explain`; not one-cmd/last-log/source-token) → thinker. Facts=grunt/`need:`. **No implementer this turn**. Unsure → thinker. Cheap false+: I think / terraform plan / `/implement-plan` / `/solo` / source tokens / one-cmd / how- last-log / why. Why = judgment not patch not dump; parent cannot invent why; **parent cannot drop why**. Thinker recap without why = incomplete (leftover 3 / re-spawn; not silent; not invent). One re-spawn max then recap-as-is + flag.
29
- Reuse iff ALL: (1) same parent transcript already has finished `[thinker]:` (or the fact recap they’re poking); (2) user turn is advise-class again with no new path/error/snippet/name/“what about/also/now/but/instead”; (3) no implementer or grunt after that answer; no unresolved `need:`; (4) not “more/deeper/details/walk through/wrong”. Any tick fail / new session / `/pickup` / `/handoff` / compaction ate the body → spawn. Echo last `[thinker]:` recap one-line (don’t paraphrase; no-strip why; no compress-to-verdict). Reuse echo: reprint last thinker’s leftover triple. Type-mismatch / bare implement on Write-typed → recap “no implementer this remainder”; ≠ spawn. Prose → `/explain` on visible child. Always-why recap ≠ `/explain`. Not grunt for parrot. Tag `[orchestrator]:` on no-spawn — don’t fake `[thinker]:`. Pitfalls: deeper→thinker; code moved invalidates; `need:` open; compaction.
30
- 4. Snippet / cite / "what is X" / world fact → grunt `job: web`. URL-in-a-cite ≠ browse. URL / browse / click / fill / snap / live DOM → grunt; child prompt must include abs `.rulesync/skills/browser/SKILL.md` and `.rulesync/reference/browser.md`; Read then `node scripts/browser.mjs`; Lightpanda default; never websearch that page. Never answer from memory. No `job:browse`.
31
-
32
- Spawn only `grunt` | `implementer` | `thinker`. Omit `model`. Isolation `none` unless asked.
33
-
34
- Implementer may tiny-Read/Grep/list_dir. Thinker named-file Read of prompt SSOT only; investigate/search/trees → `need:` grunt. Fat dumps via `need:` JSON.
35
-
36
- Long parent sessions rely on two-pass compaction; prefer a new parent session per task rather than unbounded resume chains. `[features] two_pass_compaction = true` must live in `~/.grok/config.toml` (from `.grok/global-settings.toml` via `npm run sync:globals` dry-run / `npm run sync:globals:apply`). Project `.grok/config.toml` cannot set `[features]`. Do not add a SessionStart hook.
37
-
38
- ## Wait / peek
39
-
40
- Parent-only. Non-blocking spawn so each child has a host id immediately. Per-child, not one global timer.
41
- Every 60s peek is real host status (no `sleep` then guess). `timeout_ms=60000` every peek.
42
- Quote host fields only (`status`, elapsed since spawn, last activity/output snippet) or quote the error. Never invent.
43
- Classify `done` | `alive` | `stuck` vs prior peek: **done** (completed/failed), **alive** (running + fields/output changed), **stuck** (running + unchanged). Unchanged snippet = stuck, not “still working”.
44
- Loop until done. No auto-kill. Kill only if the user asks and the host has a kill tool.
45
- Final recap uses [output.md](output.md) natural buckets (completed / in-flight / remainder / blocker; omit empty). Do not redo the child's work. Exceptions: in-flight wait = `[orchestrator]: wait grunt` only; `need:` stop = JSON only; max 3 `resume_from` → blocker recap + gathered verdicts (ask).
46
-
47
- Parent Stop (`MAX_STOP=3`): do not waive fenced/impl finals for `tools-used` stamp. Parent `end_turn` is tagged recap (advise leftover numbered pick on own lines after one empty blank line) or `[orchestrator]: wait grunt`. First non-empty line must match legal `[orchestrator|grunt|implementer|thinker|handoff|tmp]:`. Advise leftover numbered pick may follow the tagged recap after one empty blank line (echo printed leftover; format only; hook does not map leftover numbers → skills; no leftover-label parser). Siblings still run → role tag + one-line echo. In-flight wait recap is `[orchestrator]: wait grunt` only. Mid-turn stays exactly `[orchestrator]: wait grunt`. Or consume `parent-escape-{sid}` once. Else block. No `isCheap` / trivia / long definitions.
48
- `/handoff` is the other in-parent turn: context large + work unfinished → parent writes one `.tmp/grunt/handoffs/` file from its own transcript (no child sees the session), recaps `[handoff]: serial=… path=…`, tells the user to continue in a new session. No spawn, one write, not a mode.
49
- `/tmp` is in-parent dump: parent writes one `.tmp/grunt/` root artifact from this session, recaps `[tmp]: serial=… path=…`. No spawn, one write, not a handoff, not a plan, no pickup.
50
- `/pickup` is spawn-first pickup, not in-parent write; parent never Read. Inverse of `/handoff`.
51
- `/solo` `/cascade` are session mode (not one-turn): `beforeSubmitPrompt` write-or-unlink `.tmp/grunt/orchestrator-logs/spawn-mode-{sid}` vs config (`solo`|`cascade`); slash==config unlinks; slash≠config writes body token; **always** unlink `grunt-off` (new+legacy). Effective stamp>one-release `grunt-off`>config>`cascade`. Fail-closed cascade. Unreadable/bad stamp body ignored. Every gate short-circuits while effective solo. Antigravity: skill-only, no stamp create (see hooks.md). `/auto` `/ask` session leftover-gate (not spawn-escape): stamp `.tmp/grunt/orchestrator-logs/auto-ask-{sid}` body `auto`|`ask` when slash ≠ config; slash==config unlinks. Effective stamp>config>ask. auto+Implement-typed pick2 chain skip leftover wait; Write-typed leftover wait. `/parent` is last-ditch hook stamp (not a mode, not skill-instructed Read/Bash): UserPromptSubmit writes `.tmp/grunt/orchestrator-logs/parent-escape-{sid}`; Stop consumes+unlinks once. Next Stop resumes spawn/recap rules. `/explain` is human recap after children; never parent Read; not a mode; not spawn-escape. Skills point here; do not paste this file. Never parent-Read protocol files.
52
-
53
- Host mapping (in-tree only; do not invent peek/kill APIs). GAP rows: no fake peeks, no auto-kill.
54
-
55
- | Host | Spawn | Peek | Kill |
56
- | --- | --- | --- | --- |
57
- | Grok | `spawn_subagent` `background:true` → `task_id` | `get_command_or_subagent_output` + `timeout_ms=60000` | `kill_command_or_subagent` (user-ask only) |
58
- | Claude Code | `Agent` if the parent session exposes it | GAP unless an in-tree schema names a status/output tool on that id (do not invent `TaskOutput`); else block on Agent return and classify `done`. Agent launch ≠ child done; in-flight host Stop → only `[orchestrator]: wait grunt`; no SendMessage | GAP unless in-tree; no auto-kill |
59
- | Codex | host agent/call | GAP; block on host agent/call return; classify `done` | GAP; no auto-kill |
60
- | Antigravity | main-session parent | GAP peek/kill; main-session parent | GAP; no auto-kill |
61
- | Gemini | not emitted; tracked gap | GAP; no fake peeks | GAP; no auto-kill |
62
-
63
- ## Late dump (`need:` + `resume_from`)
64
-
65
- If implementer/thinker still needs a fat dump: it **stops**. The stop message for dumps is this JSON line only (no prose):
66
-
67
- ```
68
- need: [{"job":"search","query":"..."}]
69
- ```
70
-
71
- `job` ∈ search|exec|web|test. 1–N jobs. Cap one batch at 4 jobs; overflow stays for the next loop. Do not emit N sequential single-job stops for known-parallel dumps.
72
-
73
- If a child still emits `need:` and every job is `search|exec`, SubagentStop (and child `Stop` with `subagentType`) runs grunt-job in-hook and continues the child with concatenated `verdict:` blobs (`decision: "block"` + `additionalContext`). Mixed / web / test batches are not intercepted: parent `scripts/parse-need.mjs` + LLM grunt. Thinker has no bash; intercept still applies.
74
-
75
- Parent: parse with `scripts/parse-need.mjs` (same grammar). If parse succeeds, fan out those jobs as parallel grunt spawns; do not interpret surrounding prose. Wait; one `resume_from: <child id>` with **new** `verdict:` blobs only. Do not fresh-spawn. Max 3 `resume_from` for one child id; then parent blocker recap + the verdicts already gathered (ask).
76
-
77
- Resume prompt = `You are {agent} subagent.` plus the new verdicts. Do not re-send the original task, cascade, or prior verdicts (`resume_from` already has the transcript).
78
-
79
- Voice: [output](output.md). Does not change need:/verdict:/plan grammar.
80
-
81
- ## Isolation grunt `verdict:`
82
-
83
- ```
84
- verdict: ok|fail|empty
85
- n: <count>
86
- - path:line — fact
87
- ```
88
-
89
- Fail: first 3 error lines. ≤8 lines. No dumps, recap, HTML, JSON, full logs.
90
-
91
- Implementer/thinker: fat dumps via `need:` JSON. Implementer shell via rtk; cat/rg/curl/tests without rtk → fat `need:`.
92
-
93
- Child prompt first sentence only: `You are {agent} subagent.` Then task + abs paths + verdicts only. Browse tags match → prompt must include abs `.rulesync/skills/browser/SKILL.md` and `.rulesync/reference/browser.md`.
94
-
95
- Grok PostToolUse is observe-only. SessionStart stays empty (token baseline). See [hooks](hooks.md).
15
+ Scratch: `.tmp/grunt/`. Stash: `.tmp/grunt/stash/`. Sessions: `.tmp/grunt/sessions/{sid}/`. Browser: `.tmp/grunt/browser/`.
@@ -0,0 +1,21 @@
1
+ ---
2
+ tags: [clasp]
3
+ ---
4
+
5
+ # Clasp
6
+
7
+ Low-level Apps Script CLI. Optional. Doctor reports it.
8
+
9
+ For create/edit sheet, doc, slide, meeting, or mail, use **google-workspace**: `.rulesync/reference/google-workspace.md` and `node scripts/google-workspace.mjs`. Do not start from clasp.
10
+
11
+ ```
12
+ npm i -g @google/clasp
13
+ clasp login
14
+ clasp create --type standalone --title <name>
15
+ clasp pull
16
+ clasp push
17
+ clasp run <function>
18
+ clasp status
19
+ ```
20
+
21
+ Script files live next to `appsscript.json`. Git tracks them. `clasp run` needs the Apps Script API and an API-executable deployment. That path is for custom `.gs`, not day-to-day Workspace.
@@ -0,0 +1,79 @@
1
+ ---
2
+ tags: [google-workspace]
3
+ ---
4
+
5
+ # google-workspace
6
+
7
+ Create and edit Google Sheets, Docs, Slides, Calendar events, and Gmail from the session.
8
+
9
+ ```
10
+ node scripts/google-workspace.mjs whoami
11
+ node scripts/google-workspace.mjs scopes
12
+ node scripts/google-workspace.mjs login
13
+ node scripts/google-workspace.mjs sheet create --title "Q3" --csv "item,qty\nA,2"
14
+ node scripts/google-workspace.mjs sheet set --id ID --cell A1 --value x
15
+ node scripts/google-workspace.mjs sheet get --id ID --range A1:B10
16
+ node scripts/google-workspace.mjs sheet append --id ID --csv "c,3"
17
+ node scripts/google-workspace.mjs sheet clear --id ID --range A1:Z
18
+ node scripts/google-workspace.mjs doc create --title "Notes" --body "hello"
19
+ node scripts/google-workspace.mjs doc append --id ID --body "more"
20
+ node scripts/google-workspace.mjs drive list --query "mimeType='application/vnd.google-apps.spreadsheet'"
21
+ node scripts/google-workspace.mjs slide create --title "Deck"
22
+ node scripts/google-workspace.mjs meeting create --title "Standup" --start 2026-09-15T09:00:00Z --end 2026-09-15T09:15:00Z --attendees a@x.com,b@y.com
23
+ node scripts/google-workspace.mjs mail send --to you@example.com --subject hi --body hello
24
+ node scripts/google-workspace.mjs mail list
25
+ ```
26
+
27
+ Each person has their own Google Cloud app. Creds stay in `~/.grunt/` on that machine. Do not share OAuth JSON or tokens. Do not commit them. Inviting others to a meeting is attendee emails, not shared creds.
28
+
29
+ Handheld (any OS): `node scripts/setup.mjs google-workspace` or `npm exec grunt setup` → google-workspace. Opens each Cloud Console page, waits, copies the Desktop JSON into `~/.grunt/google-oauth.json`, then browser Allow. Non-TTY: `--creds PATH` to a Desktop download. `--account NAME` for a second Google user.
30
+
31
+ Doctor reports google-workspace as optional: `ok` when Desktop OAuth JSON, tokens, gcloud ADC, or `~/.clasprc.json` exists, else `missing (optional)`. It prints source names (`oauth` `tokens` `adc` `clasprc`), not secrets. `clasprc` is Drive-only.
32
+
33
+ Two Google accounts on one machine: `--account NAME` (or `WORKSPACE_ACCOUNT`). Default is `default` (legacy files `~/.grunt/google-oauth.json` + `workspace-tokens.json` still work). Other accounts use `~/.grunt/workspace/NAME/`.
34
+
35
+ ```
36
+ node scripts/google-workspace.mjs --account work login
37
+ node scripts/google-workspace.mjs --account work whoami
38
+ node scripts/google-workspace.mjs accounts
39
+ ```
40
+
41
+ Each account needs its own Desktop JSON in that folder (`google-oauth.json`) and its own `login`.
42
+
43
+ Clasp’s public OAuth client is Drive-only. Calendar and Gmail are restricted; Google blocks extra scopes on that app. Use **your** Desktop OAuth client.
44
+
45
+ ## Agent: setup e2e
46
+
47
+ If `whoami` works but `meeting` / `mail` / `sheet set` fail with missing scope or “app is blocked”, run **this user** through `node scripts/setup.mjs google-workspace` (TTY). Do not reuse another person’s JSON. Do not invent a client JSON.
48
+
49
+ Local dir is created by setup (`~/.grunt/`, mode 700 on Unix). Manual equivalent: `mkdir -p "$HOME/.grunt" && chmod 700 "$HOME/.grunt"` then:
50
+
51
+ 1. Open `https://console.cloud.google.com/projectcreate` — **Create**. Org can be their Workspace org. Note **Project ID** from the dashboard URL (`?project=`).
52
+ 2. Open `https://console.cloud.google.com/auth/overview/create?project=PROJECT_ID` (or **Google Auth Platform → Branding**).
53
+ - App name: anything (`autorun` is fine). That string is only the Allow screen.
54
+ - User support email: their address.
55
+ - Audience: **Internal** if the Google account is a paid Workspace org (e.g. `@rearm.co`). **Testing** + add their own address as a test user if it is a personal `@gmail.com` (Internal is not offered). APIs work on both; only this consent type changes.
56
+ - Next / Create through the wizard.
57
+ 3. Open `https://console.cloud.google.com/flows/enableapi?apiid=calendar-json.googleapis.com,gmail.googleapis.com,sheets.googleapis.com,docs.googleapis.com,drive.googleapis.com&project=PROJECT_ID` — **Enable**.
58
+ 4. Open `https://console.cloud.google.com/auth/clients/create?project=PROJECT_ID`.
59
+ - Application type: **Desktop app**.
60
+ - Create → **Download JSON**.
61
+ 5. Copy the download to `$HOME/.grunt/google-oauth.json` (Windows: `%USERPROFILE%\.grunt\google-oauth.json`). chmod 600 on Unix. Confirm it has `"installed"` and `client_id`. For `--account NAME`, use `$HOME/.grunt/workspace/NAME/google-oauth.json`.
62
+ 6. From the repo: `node scripts/google-workspace.mjs login` (or `--account NAME`) — browser Allow. Tokens write beside the JSON (`workspace-tokens.json` or `workspace/NAME/tokens.json`).
63
+ 7. Smoke:
64
+
65
+ ```
66
+ node scripts/google-workspace.mjs whoami
67
+ node scripts/google-workspace.mjs scopes
68
+ node scripts/google-workspace.mjs sheet create --title smoke-sheet --csv "k,v\nok,1"
69
+ node scripts/google-workspace.mjs doc create --title smoke-doc --body ok
70
+ node scripts/google-workspace.mjs slide create --title smoke-slide
71
+ node scripts/google-workspace.mjs meeting create --title smoke-meeting --start 2026-09-16T09:00:00Z --end 2026-09-16T09:15:00Z
72
+ node scripts/google-workspace.mjs mail send --to THEIR_EMAIL --subject smoke --body ok
73
+ ```
74
+
75
+ `scopes` must include `calendar`, `gmail.modify` or `gmail.send`, `spreadsheets`, `documents`, `drive`. If login times out, they did not finish Allow; re-run `login`.
76
+
77
+ If `google-oauth.json` is missing, `login` prints `setup: node scripts/setup.mjs google-workspace`. Prefer the handheld setup (it opens the Project ID URLs). Manual steps above still work.
78
+
79
+ `gcloud` on PATH is an alternate login (`gcloud auth application-default login` with the extra scopes). Still per person, still local.
@@ -6,22 +6,18 @@ tags: [hooks]
6
6
 
7
7
  SessionStart: keep empty (token baseline). Do not inject context. Do not register a SessionStart hook on `../../.grok/hooks/orchestrate-parent.json`.
8
8
 
9
- Grok PostToolUse / UserPromptSubmit / SessionStart are observe-only — do not attempt output scrub; compress via RTK / spawn / isolation verdict only. Do not add PostToolUse scrub hooks.
9
+ Grok PostToolUse / SessionStart are observe-only — do not attempt output scrub; compress via RTK / spawn / isolation facts only. Do not add PostToolUse scrub hooks. Grok UserPromptSubmit may emit a one-line `sessionGate=auto|ask` plus session receipt (`hookSpecificOutput.additionalContext`). Skip host Stop banners. `/ask` exact-match slash stamps `session-gate-{sid}` to `ask`. `/auto` unlinks. Sid-less: no stamp. Default: `auto`.
10
10
 
11
- Claude / Codex / Antigravity PreToolUse still run `../../scripts/scrub-spawn-prompt.mjs` and `../../scripts/gate-fat-tools.mjs`. Grok does not — spawn/fat rewrite is `../../.grok/hooks/orchestrate-parent.js` only. RTK stays `../../.grok/hooks/rtk.json`.
11
+ In `sessionGate=ask`, parent Stop on `end_turn` blocks unless the recap asks (`?`) or is exactly `[orchestrator]: wait grunt`. Reason: `ask after this step`. Cap 3. `sessionGate=auto` does not Stop-block.
12
12
 
13
- Parent Read|Write|Edit|Bash|Skill deny unless `/solo` (session) or `/parent` last-ditch stamp. Grok PreToolUse has no matcher (Read included). Skills spawn-first; do not instruct parent Read/Bash. `.tmp/grunt/plans/`, `.tmp/grunt/handoffs/`, and `.tmp/grunt/` root-file Write still persist. Parent Bash still allowed for workspace `../../scripts/grunt-job.mjs` `--job search|exec`. Children with a type skip parent-deny (fat-only). Skill allowlist without escape: `parent|explain|solo|cascade|auto|ask|handoff|tmp|pickup|write-plan|implement-plan`. Deny reason: `First action=spawn implementer|grunt|thinker. Deny expected. Only /solo this session escapes.`. Parent `end_turn` is tagged recap (advise leftover numbered pick on own lines after) or `[orchestrator]: wait grunt`. Mid-turn stays exactly `[orchestrator]: wait grunt`. Leftover-required under ask waived iff effective leftover-gate=auto.
13
+ Claude / Codex / Antigravity PreToolUse still run `../../scripts/scrub-spawn-prompt.mjs` and `../../scripts/gate-fat-tools.mjs`. Grok spawn/fat rewrite is `../../.grok/hooks/orchestrate-parent.js`. RTK stays `../../.grok/hooks/rtk.json`.
14
14
 
15
- Parent `run_terminal_command` is deny-by-default except `node` (optional leading `rtk`) invoking `{workspace}/scripts/grunt-job.mjs` with `--job search|exec` and `--query`. Optional `--path` `--glob` (repeatable) `--cwd`. Not `web|test`, not other scripts. META strips `--query` value first so `|` inside query is allowed; pipes/`&&` outside query still deny. Never `cd &&`. Exec shell-meta in query is grunt-job FALLBACK (exit 2), not a parent-bash allow. Unknown flags → FALLBACK.
15
+ Session agent tools are on. Fat Read/Grep/Glob/Bash still gate. Writes under `.tmp/grunt/plans/`, `.tmp/grunt/handoffs/`, `.tmp/grunt/implementations/`, and `.tmp/grunt/` root files persist via `../../scripts/persist-plan.mjs` / `persist-handoff.mjs` / `persist-implementation.mjs` / `persist-tmp.mjs`. Invalid body denies.
16
16
 
17
- SubagentStop (and child Stop with `subagentType`) intercepts a parseable `need:` whose jobs are all `search|exec` (cap 4): runs grunt-job in-hook and continues the child with concatenated `verdict:` blobs. Mixed/web/test, parse fail, FALLBACK, `stopHookActive`, or more than 3 intercepts per child session → empty stdout (allow stop; parent LLM path). Parent `write` is deny-by-default except `.tmp/grunt/plans/` (`../../scripts/persist-plan.mjs`), `.tmp/grunt/handoffs/` (`../../scripts/persist-handoff.mjs`), and `.tmp/grunt/` root files (`../../scripts/persist-tmp.mjs`); all validate + rewrite path/content, invalid body denies. Parent Stop (`MAX_STOP=3`): do not waive impl finals for `tools-used`. Parent `end_turn` is tagged recap (advise leftover numbered pick on own lines after) or `[orchestrator]: wait grunt`. Mid-turn stays exactly `[orchestrator]: wait grunt`. First non-empty line must match legal `[orchestrator|grunt|implementer|thinker|handoff|tmp]:`. Ask leftover-required: `[orchestrator]:` needs leftover triple (not exact wait-grunt); `[thinker]:` with >1 nonempty line needs it; `[grunt]|[implementer]|[handoff]|[tmp]:` do not. Missing triple → existing `STOP_REASONS` block. Waived iff effective leftover-gate=auto. Claude Agent launch ≠ done; in-flight host Stop → wait recap `[orchestrator]: wait grunt` only; no SendMessage. Or consume `parent-escape-{sid}` once (`/parent` last-ditch, not “use parent tools”). No `isCheap` / trivia. Stamps: `tools-used` / `stop-block` / `need-intercept` / `parent-escape` / `auto-ask` / `spawn-mode`. Skills point to cascade; do not paste protocol here.
17
+ SubagentStop (and child Stop with `subagentType`) intercepts a parseable `need:` whose jobs are all `search|exec|slice|fetch` (cap 4): runs grunt-job in-hook and continues the child with concatenated facts. Mixed/web/test, parse fail, FALLBACK, `stopHookActive`, or more than 3 intercepts per child session → empty stdout (allow stop).
18
18
 
19
- `/solo` `/cascade` write-or-unlink `spawn-mode-{sid}` vs config (`beforeSubmitPrompt`, exact-match only). Slash==config unlinks; slash≠config writes body `solo`|`cascade`. **Always** unlink `grunt-off` (new+legacy). Sid-less: no stamp. Effective: valid stamp body `solo`|`cascade` > one-release `grunt-off` presence as solo > config `spawnMode` > `cascade`. Fail-closed cascade. Unreadable/bad stamp body ignored (dual-read `grunt-off` else config). While effective solo: PreToolUse allows parent tools (fat gate still runs) and skips the `defaultGrunt` spawn rewrite; Stop returns 0 **before** the `parent-escape` consume, so solo never burns the one-turn stamp. Session-scoped. Antigravity: skill-only, no stamp create.
19
+ Stop and SubagentStop timeout is 30s (grunt-job cap is 20s). PreToolUse / UserPromptSubmit stay at 5s.
20
20
 
21
- `/auto` `/ask` write `auto-ask-{sid}` body `auto`|`ask` when slash ≠ config leftoverGate; slash==config unlinks (`beforeSubmitPrompt`, exact-match only). Sid-less: no stamp. Effective: stamp > config > ask. Leftover-required waived iff effective=auto. Not spawn-escape. Antigravity: skill-only, no stamp create (same solo degrade).
22
-
23
- rulesync canonical event is `beforeSubmitPrompt` (→ Claude/Codex `UserPromptSubmit`), not `userPromptSubmit` — an unknown key makes Zod reject the whole `.rulesync/hooks.jsonc`, emitting nothing while `--check` still reports up to date. Antigravity supports neither `beforeSubmitPrompt` nor `subagentStop`; `/solo` `/auto` `/ask` degrade there to the skill body alone.
24
-
25
- Stop and SubagentStop timeout is 30s (grunt-job cap is 20s). PreToolUse / PostToolUse / UserPromptSubmit stay at 5s. If the intercept times out, the hook fail-opens and the child stops without verdicts.
21
+ rulesync canonical event is `beforeSubmitPrompt` (→ Claude/Codex `UserPromptSubmit`), not `userPromptSubmit`.
26
22
 
27
23
  `[features] two_pass_compaction` must live in `~/.grok/config.toml` (from `.grok/global-settings.toml` via `npm run sync:globals` / `npm run sync:globals:apply`). Project `.grok/config.toml` cannot set `[features]`.
@@ -0,0 +1,113 @@
1
+ # Implementation format (SSOT)
2
+
3
+ Local session journal for `/implement-plan`. Not a plan, handoff, or git commit.
4
+
5
+ Created when `/implement-plan` starts. Straight shots skip this file. Do not merge into the plan (plan = flip the box only).
6
+
7
+ ## Path
8
+
9
+ `.tmp/grunt/implementations/{serial}-{slug}-{YYYYMMDDTHHMMSSZ}.md`
10
+
11
+ - **serial:** own counter (not plan serials). Unpadded decimal int ≥ 1. Never `0001`.
12
+ - **filename:** unpadded serial, slug, UTC datetime stamp. Same regex as new plans: `^[0-9]+-[a-z0-9]+(-[a-z0-9]+)*-\d{8}T\d{6}Z\.md$`
13
+ - **lookup:** integer equality on leading digits.
14
+ - Frontmatter `serial:` line must match `^serial: [1-9][0-9]*$`.
15
+ - New writes always stamped. Collision: increment serial, same stamp.
16
+
17
+ ## Link
18
+
19
+ Frontmatter `plan:` is the plan serial (`6`) or `none`. Own serial stays independent.
20
+
21
+ ## Slugify / allocate
22
+
23
+ Same as plans (`slugify`, `nextSerial` on this dir). Body line 1: `IMPL_NAME: <3-6 word name>`. Optional `IMPL_PLAN: <n|none>` (default `none`).
24
+
25
+ ## Frontmatter (required)
26
+
27
+ ```yaml
28
+ ---
29
+ serial: 1
30
+ plan: 6 # unpadded int or none
31
+ name: add-auth
32
+ status: in-progress # in-progress | done | blocked
33
+ created: 2026-08-26T14:30:00Z
34
+ source: "<≤120 chars of user task>"
35
+ ---
36
+ ```
37
+
38
+ ### Status machine
39
+
40
+ `in-progress` → `done` | `blocked`
41
+
42
+ - Fresh write: `in-progress`
43
+ - Plan Verify done and journal caught up: `done`
44
+ - Cannot finish: `blocked` (`## Blockers` must not be `(none)`)
45
+
46
+ ## Body headings (this order only)
47
+
48
+ `# {slug}`, `## Done`, `## Issue`, `## Files`, `## Log`, `## Blockers`, `## Notes`
49
+
50
+ No other `##` headings.
51
+
52
+ | Section | Amount |
53
+ |---|---|
54
+ | Done | bullets. What landed and why. Past tense. Fresh: `(none)` |
55
+ | Issue | bug root cause bullets, or `(none)` |
56
+ | Files | repo-relative product paths as `- path` bullets. Default `/commit` stage set. No abs paths. No `.tmp/`. Fresh: `(none)` |
57
+ | Log | append-only. Fresh: `(none)`. After each plan leaf: `N.M [x] one line` (notes, fail, skip). `[x]` allowed |
58
+ | Blockers | open problems. `(none)` unless `status: blocked` |
59
+ | Notes | short leftovers, or `(none)` |
60
+
61
+ ## Write
62
+
63
+ Write under `.tmp/grunt/implementations/` (any filename in that dir). Grok `orchestrate-parent.js` runs `scripts/persist-implementation.mjs` on create (`IMPL_NAME:`): serial/slug from the name, injects frontmatter, rewrites path + content. Updates to an existing file keep the path; full-body writes are validated in place. Invalid create/update denies — fix the body, do not retry elsewhere.
64
+
65
+ Host without that hook: name the file per **Path**, or pipe the body to `node scripts/persist-implementation.mjs --workspace {repo}` and use its `path`.
66
+
67
+ Never allocate a new serial to log a leaf. Append Log, update Files/Done, flip the plan box.
68
+
69
+ ## Validation checklist
70
+
71
+ - filename stamped unpadded; serial int equals leading digits; `name` equals slug
72
+ - frontmatter keys: `serial`, `plan`, `name`, `status`, `created`, `source`
73
+ - `plan` is `none` or unpadded int ≥ 1; `status` ∈ `in-progress` | `done` | `blocked`
74
+ - headings in order only; no extra `##`
75
+ - Done / Issue / Files / Log / Blockers / Notes: bullets and/or `(none)`; none of those sections empty
76
+ - Files: repo-relative; reject abs and `.tmp/`
77
+ - `status: blocked` ⇒ Blockers is not only `(none)`
78
+
79
+ ## Worked example
80
+
81
+ File: `.tmp/grunt/implementations/1-add-tmp-ignore-20260826T143000Z.md`
82
+
83
+ ```markdown
84
+ ---
85
+ serial: 1
86
+ plan: 6
87
+ name: add-tmp-ignore
88
+ status: in-progress
89
+ created: 2026-08-26T14:30:00Z
90
+ source: "gitignore .tmp so local plans stay untracked"
91
+ ---
92
+
93
+ # add-tmp-ignore
94
+
95
+ ## Done
96
+ - Repo `.gitignore` ignores `.tmp/` so plans stay untracked
97
+
98
+ ## Issue
99
+ (none)
100
+
101
+ ## Files
102
+ - .gitignore
103
+
104
+ ## Log
105
+ 1.1 [x] read existing gitignore
106
+ 1.2 [x] appended .tmp/
107
+
108
+ ## Blockers
109
+ (none)
110
+
111
+ ## Notes
112
+ (none)
113
+ ```
@@ -1,9 +1,11 @@
1
1
  # Law
2
2
 
3
- Protocol stays cascade/overview; domain fills this.
3
+ Protocol stays overview; domain fills this.
4
4
 
5
5
  ## Skills naming
6
6
 
7
- Reserved (do not reuse in consumer custom skills): `ask` `auto` `browser` `cascade` `commit` `commit-and-push` `commit-push` `commit-push-deploy` `commit-push-release` `explain` `handoff` `implement-plan` `parent` `pickup` `solo` `tmp` `write-plan`.
7
+ Reserved (do not reuse in consumer custom skills): `ask` `auto` `browser` `clasp` `commit` `commit-and-push` `commit-push` `commit-push-deploy` `commit-push-release` `explain` `google-workspace` `handoff` `implement-plan` `listen` `pickup` `speak` `tmp` `write-plan`.
8
8
 
9
- Override: same name → one SSOT path (`.rulesync/skills/<name>/`). Re-init force-refresh overwrites grunt-owned names; consumer extras kept. Maps `origin` badge ≠ content picker.
9
+ Override: same name → one SSOT path (`.rulesync/skills/<name>/`). Re-init / `grunt upgrade` force-refresh overwrites grunt-owned names; consumer extras kept. Maps `origin` badge ≠ content picker.
10
+
11
+ Upgrade copies the current package trees and product scripts, then deletes cumulative retired grunt-owned names (skills `parent` `solo` `cascade`; agents `implementer` `thinker`; scripts `telemetry.mjs` `grunt-config.mjs`; paths `.grok/parent.md` `.grok/skills/shared` `.rulesync/grunt.config.jsonc` `.rulesync/grunt.config.local.jsonc` `.rulesync/grunt.config.local.jsonc.example`) and any reserved skill dir this package no longer ships. `fs.cpSync` does not remove dest extras; prune is what drops them. Consumer skills/refs/scripts not on those lists stay.
@@ -0,0 +1,80 @@
1
+ ---
2
+ tags: [listen]
3
+ ---
4
+
5
+ # Listen
6
+
7
+ Speech-to-text from the session. Input only. Not TTS. Not a live voice agent. Not MCP.
8
+
9
+ ```
10
+ node scripts/listen.mjs whoami
11
+ node scripts/listen.mjs devices
12
+ node scripts/listen.mjs rec [--seconds 8] [--device D] [--clip]
13
+ node scripts/listen.mjs start [--device D]
14
+ node scripts/listen.mjs stop [--clip]
15
+ node scripts/listen.mjs toggle [--clip]
16
+ node scripts/listen.mjs status
17
+ node scripts/listen.mjs file --path clip.wav [--clip]
18
+ node scripts/listen.mjs latest
19
+ ```
20
+
21
+ `rec` records then transcribes (default 8s, cap 120s). `toggle` is the hotkey verb: first run starts, second run stops and prints the transcript. Audio and `latest.txt` live under `.tmp/grunt/listen/`. `--cwd /path/to/repo` when the hotkey does not already run in the repo.
22
+
23
+ ## Auth and capture
24
+
25
+ Handheld (any OS): `node scripts/setup.mjs listen` or `npm exec grunt setup` → listen. Prints OS install commands for ffmpeg / whisper-cli (does not run them), optional ggml download into `~/.grunt/whisper/`, OpenAI fallback key if local STT is missing.
26
+
27
+ If ffmpeg, whisper-cli, a ggml model, or `OPENAI_API_KEY` is missing, the CLI prints `setup: node scripts/setup.mjs listen` and exits 1. Agents should show that line, not a stack or JSON. Do not invent a key.
28
+
29
+ STT prefers **local whisper.cpp**. Install the binary; the first `listen` downloads `ggml-base.en.bin` (~142MB) into `~/.grunt/whisper/`. No API cost after that. If the binary or download is missing, it falls back to OpenAI `whisper-1` (`OPENAI_API_KEY` or `~/.grunt/speak.json`). Force with `LISTEN_STT=local` or `LISTEN_STT=openai`. Never commit keys.
30
+
31
+ | | env | `~/.grunt/speak.json` |
32
+ | --- | --- | --- |
33
+ | Local model | `WHISPER_MODEL` | `listen.whisperModel` |
34
+ | Force engine | `LISTEN_STT` | `listen.stt` (`auto` / `local` / `openai`) |
35
+ | OpenAI key | `OPENAI_API_KEY` | `openai.apiKey` |
36
+ | OpenAI model | `LISTEN_MODEL` | `listen.model` (default `whisper-1`) |
37
+ | Device | `LISTEN_DEVICE` | `listen.device` |
38
+ | Seconds | `LISTEN_SECONDS` | `listen.seconds` |
39
+
40
+ ### Local Whisper (preferred)
41
+
42
+ One install:
43
+
44
+ - mac: `brew install whisper-cpp` (provides `whisper-cli`)
45
+ - linux: build https://github.com/ggml-org/whisper.cpp (`whisper-cli` on PATH)
46
+ - win: whisper.cpp release `whisper-cli.exe` on PATH
47
+
48
+ Then `node scripts/listen.mjs whoami` or `rec`. The first run fetches `ggml-base.en.bin` to `~/.grunt/whisper/`. Do not pip-install OpenAI Whisper. Do not curl the model yourself unless the auto-download fails.
49
+
50
+ Larger models: put another `ggml-*.bin` in that folder or set `WHISPER_MODEL`. Doctor reports `whisper-cli` as optional. `whoami` prints `stt=local` or `stt=openai`.
51
+
52
+ ### ffmpeg (mic only)
53
+
54
+ - mac: `brew install ffmpeg`
55
+ - linux: `sudo apt install ffmpeg`
56
+ - win: `winget install Gyan.FFmpeg`
57
+
58
+ `file` and `latest` work without a mic. Doctor reports ffmpeg as optional.
59
+
60
+ `rec` detaches ffmpeg and does not attach it to the IDE TTY. AVFoundation can stall forever on a VS Code / Electron PTY even when Visual Studio Code already has Microphone access.
61
+
62
+ Default devices: mac `:0` (AVFoundation audio 0), linux Pulse `default` (ALSA if the id is `hw:…`), Windows requires `--device` or `LISTEN_DEVICE` from `listen devices`.
63
+
64
+ ## Hotkeys
65
+
66
+ Bind one key to toggle. Include `--clip` so the transcript is on the clipboard as well as `latest.txt`.
67
+
68
+ ```
69
+ node /ABS/grunt/scripts/listen.mjs toggle --clip --cwd /ABS/grunt
70
+ ```
71
+
72
+ Replace `/ABS/grunt` with the repo root.
73
+
74
+ - **mac:** Shortcuts (Run Shell Script) or skhd: `hyper - r : node /ABS/grunt/scripts/listen.mjs toggle --clip --cwd /ABS/grunt`
75
+ - **win:** PowerToys Keyboard Manager or AutoHotkey: `^!r:: Run, node C:\ABS\grunt\scripts\listen.mjs toggle --clip --cwd C:\ABS\grunt, C:\ABS\grunt, Hide`
76
+ - **linux:** desktop custom shortcut or sxhkd to the same command.
77
+
78
+ No daemon. Each keypress is one CLI. First press records; second press transcribes.
79
+
80
+ `--clip` uses `pbcopy` (mac), `clip` (win), or `wl-copy` / `xclip` / `xsel` (linux).