@lovrozagar/grunt 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/agents/orchestrator.md +8 -7
- package/.agents/agents/thinker.md +6 -5
- package/.agents/skills/commit-and-push/SKILL.md +3 -3
- package/.agents/skills/explain/SKILL.md +1 -0
- package/.agents/skills/implement-plan/SKILL.md +116 -0
- package/.agents/skills/write-plan/SKILL.md +82 -0
- package/.claude/agents/orchestrator.md +8 -7
- package/.claude/agents/thinker.md +6 -5
- package/.claude/skills/commit-and-push/SKILL.md +3 -3
- package/.claude/skills/explain/SKILL.md +1 -0
- package/.claude/skills/implement-plan/SKILL.md +116 -0
- package/.claude/skills/write-plan/SKILL.md +82 -0
- package/.codex/agents/orchestrator.toml +8 -7
- package/.codex/agents/thinker.toml +6 -5
- package/.grok/agents/orchestrator.md +8 -7
- package/.grok/agents/thinker.md +6 -5
- package/.grok/hooks/orchestrate-parent.js +3 -100
- package/.grok/skills/commit-and-push/SKILL.md +3 -3
- package/.grok/skills/explain/SKILL.md +1 -0
- package/.grok/skills/implement-plan/SKILL.md +45 -17
- package/.grok/skills/write-plan/SKILL.md +11 -11
- package/.rulesync/reference/INDEX.md +43 -0
- package/.rulesync/reference/cascade.md +11 -9
- package/.rulesync/reference/hooks.md +4 -4
- package/.rulesync/reference/law.md +9 -0
- package/.rulesync/reference/map.md +12 -8
- package/.rulesync/reference/output.md +13 -8
- package/{.grok/skills/shared → .rulesync/reference}/plan-format.md +2 -1
- package/.rulesync/reference/refs-map.md +14 -0
- package/.rulesync/reference/skills-map.md +20 -0
- package/.rulesync/rules/CLAUDE.md +13 -11
- package/.rulesync/rules/overview.md +13 -11
- package/.rulesync/skills/commit-and-push/SKILL.md +3 -3
- package/.rulesync/skills/explain/SKILL.md +1 -0
- package/.rulesync/skills/implement-plan/SKILL.md +124 -0
- package/.rulesync/skills/write-plan/SKILL.md +88 -0
- package/.rulesync/subagents/orchestrator.md +8 -7
- package/.rulesync/subagents/thinker.md +6 -5
- package/AGENTS.md +13 -11
- package/CHANGELOG.md +210 -0
- package/CLAUDE.md +13 -11
- package/README.md +37 -16
- package/cli/init.mjs +21 -4
- package/cli/init.test.ts +97 -26
- package/package.json +6 -6
- package/scripts/doctor.mjs +64 -2
- package/scripts/emit-maps.mjs +422 -0
- package/scripts/grunt-job.mjs +0 -9
- package/scripts/guarded-roots.mjs +4 -7
- package/scripts/pipeline.mjs +67 -0
- package/scripts/skill-conflicts.mjs +71 -0
- package/scripts/telemetry.mjs +0 -38
|
@@ -14,8 +14,8 @@ Always-do:
|
|
|
14
14
|
|
|
15
15
|
| signal | next |
|
|
16
16
|
|---|---|
|
|
17
|
-
| create/change product files | grunt facts → thinker plan/recap-stop before writes; default thinker unless prompt-is-spec or small/simple → implementer. Thinker recap ≠ spec-ready; advise-stop until
|
|
18
|
-
| plan/spec ready + file writes remain |
|
|
17
|
+
| create/change product files | grunt facts → thinker plan/recap-stop before writes; default thinker unless prompt-is-spec or small/simple → implementer. Thinker recap ≠ spec-ready; advise-stop until pick1/pick2 / `/implement-plan {n}` / explicit implement (=pick1). Never parent Write/Bash/Skill |
|
|
18
|
+
| plan/spec ready + file writes remain | leftover pick1/pick2 / `/implement-plan {n}` / explicit implement (=pick1) only. pick1 = spawn implementer + last [thinker] recap as spec; no `.tmp/plans`; no write-plan; no implement-plan. pick2 = write-plan persist then implement-plan one-shot skip pause (`plan=/abs/...`; no user slash). slash `/write-plan` ≠ pick2. `ok`/`yes`/`y`/`continue` ≠ either. Thinker recap alone = recap-stop |
|
|
19
19
|
| tools/facts/git/test/mechanical write | spawn grunt |
|
|
20
20
|
| world fact | spawn grunt `job:web` |
|
|
21
21
|
| write defined solution | spawn implementer; **blocked if advise-class stems present** unless prompt-is-spec / obvious comment-spec false+ |
|
|
@@ -33,12 +33,13 @@ Always-do:
|
|
|
33
33
|
| `/solo` | session escape only; stamp grunt-off-{sid}; else spawn-first |
|
|
34
34
|
| `/cascade` | unlink solo stamp; spawn-first |
|
|
35
35
|
|
|
36
|
-
Precedence: slash → obvious fact/false+/reuse → advise-class row → prompt-is-spec → write. Advise-class + write-class → thinker first; implementer only after spec / `/implement-plan`.
|
|
36
|
+
Precedence: slash → obvious fact/false+/reuse → advise-class row → prompt-is-spec → write. Advise-class + write-class → thinker first; implementer only after spec / pick1 / pick2 / `/implement-plan {n}`.
|
|
37
37
|
False+: I think terraform plan /implement-plan /solo source tokens one-cmd how- last-log why.
|
|
38
|
-
Advise
|
|
39
|
-
1.
|
|
40
|
-
2.
|
|
41
|
-
|
|
38
|
+
Advise leftover: numbered pick each on own line after tagged recap:
|
|
39
|
+
1. Implementer with verbal plan
|
|
40
|
+
2. Implementer with file plan
|
|
41
|
+
3. Tweak
|
|
42
|
+
Match number or full leftover label (or unique tail `verbal plan` / `file plan`). Always-do leftover match; not Skill-name (`2` ≠ write-plan). 1 / that label / explicit implement → spawn implementer; paste last [thinker] recap as spec; no plan file; no write-plan; no implement-plan. Bare `implement`/`implementer` → pick1 only (shared prefix; do not substring-match both). 2 / that label → persist `.tmp/plans/{n}` then spawn implementer `plan=/abs/...` (write-plan then implement-plan one-shot; skip inspect pause; no user slash). 3 / Tweak → stay advise; extra text = revision notes → thinker; bare 3/Tweak = stop wait notes. `/write-plan` persist-only inspect-pause; remainder `/implement-plan {n}` (ask); ≠ leftover pick 2. `/implement-plan {n}` disk/file ≠ verbal. `ok`/`yes`/`y`/`continue` ≠ either implement path.
|
|
42
43
|
You do not talk. First token = spawn. Illegal tools (never consider never call): Read read_file Grep grep Glob list_dir Bash run_terminal_command view_file grep_search run_command. Not in toolkit. Hook deny = backstop not UX. Next=spawn not retry. Only /solo (stamp grunt-off-{sid} this session) escapes spawn workflow. /explain=voice+post-child recap never parent Read. No try-then-spawn. No parent probe. No skip-spawn. No trivia/cheap. User-visible = legal tag + **one-line** recap; advise leftover numbered pick on following lines not crammed. Table = routing; echo = report not command. Siblings still run: `[grunt]:` echo. Facts/search/trees → grunt, never thinker.
|
|
43
44
|
Spawn only `grunt` | `implementer` | `thinker`. Omit `model`. Isolation `none` unless asked. Never spawn `orchestrator`. Children never spawn.
|
|
44
45
|
grunt ← tools. World fact → grunt `job: web`. Never memory. implementer ← specified solution or prompt-is-spec or small/simple; blocked if advise-class. thinker ← think/plan/advise/recommend/how/why/explain (default product change; no implementer this turn).
|
package/.grok/agents/thinker.md
CHANGED
|
@@ -12,11 +12,12 @@ Voice: `.rulesync/reference/output.md` — must follow.
|
|
|
12
12
|
Plan/advise/recommend/how/why/explain. Deep reason. Never spawn. Never implement (implementer agent). Never run for simple tool usage (grunt agent).
|
|
13
13
|
Read-only. No bash. Named-file Read of SSOT paths in the prompt only; investigate/search/trees → immediate `need:` for grunt. Fat facts (search|exec|web|test; world=`job:web` never memory/browse) → stop `need:` JSON; parent fans grunt; `resume_from` + `verdict:`.
|
|
14
14
|
Return the spec/plan. Flag edge cases/pitfalls.
|
|
15
|
-
First line =
|
|
16
|
-
Advise
|
|
17
|
-
1.
|
|
18
|
-
2.
|
|
19
|
-
|
|
15
|
+
First line = recap. Recap **must** be `{decided}. {how-capsule}. {why-clause}`. Why-clause = rejected alt + constraint (not dump not “because”). Labels optional (`Why:` / em-dash OK); do not mandate `## Why`. Body may expand How/Why/edges — not parent-echoed. Advice ≠ completed product work. `need:` JSON still JSON-only (no why mix).
|
|
16
|
+
Advise leftover: numbered pick each on own line after recap:
|
|
17
|
+
1. Implementer with verbal plan
|
|
18
|
+
2. Implementer with file plan
|
|
19
|
+
3. Tweak
|
|
20
|
+
Parent matches leftover. Thinker does not spawn. `ok`/`yes`/`y`/`continue` ≠ implement.
|
|
20
21
|
|
|
21
22
|
Fat dump → stop on this JSON only (≤4/batch; no serial known-parallel):
|
|
22
23
|
|
|
@@ -17,11 +17,9 @@ import {
|
|
|
17
17
|
import {
|
|
18
18
|
denyResponse,
|
|
19
19
|
fatHookOutput,
|
|
20
|
-
fileSizeBytes,
|
|
21
20
|
isWorkspaceGruntJob,
|
|
22
21
|
isParentOrchestrator,
|
|
23
22
|
processFatTools,
|
|
24
|
-
resolveReadPath,
|
|
25
23
|
rewriteGruntScratchPath,
|
|
26
24
|
subagentTypeOf,
|
|
27
25
|
} from "../../scripts/gate-fat-tools.mjs";
|
|
@@ -29,8 +27,8 @@ import { persistPlan } from "../../scripts/persist-plan.mjs";
|
|
|
29
27
|
import { persistHandoff } from "../../scripts/persist-handoff.mjs";
|
|
30
28
|
import { parseNeed } from "../../scripts/parse-need.mjs";
|
|
31
29
|
import { resolveJobCwd, runJob } from "../../scripts/grunt-job.mjs";
|
|
32
|
-
import { logTelemetry, ORCHESTRATOR_LOGS_DIR } from "../../scripts/telemetry.mjs";
|
|
33
30
|
|
|
31
|
+
export const ORCHESTRATOR_LOGS_DIR = ".tmp/orchestrator-logs";
|
|
34
32
|
export const DENY_REASON =
|
|
35
33
|
"First action=spawn implementer|grunt|thinker. Deny expected. Only /solo this session escapes.";
|
|
36
34
|
export const STOP_REASONS = [
|
|
@@ -70,7 +68,6 @@ const PARENT_SKILLS = new Set([
|
|
|
70
68
|
"write-plan",
|
|
71
69
|
"implement-plan",
|
|
72
70
|
]);
|
|
73
|
-
const READ_TOOLS = new Set(["readfile", "read"]);
|
|
74
71
|
const INTERCEPT_JOBS = new Set(["search", "exec"]);
|
|
75
72
|
const MAX_STOP = 3;
|
|
76
73
|
const MAX_INTERCEPT = 3;
|
|
@@ -104,7 +101,6 @@ function preToolUse(data) {
|
|
|
104
101
|
const toolKey = eventKey(toolName);
|
|
105
102
|
let toolInput = data.toolInput;
|
|
106
103
|
if (toolInput == null) toolInput = data.tool_input;
|
|
107
|
-
logPreTool(data, toolKey, toolInput);
|
|
108
104
|
|
|
109
105
|
const sub = subagentTypeOf(data);
|
|
110
106
|
if (sub || !isParentOrchestrator(data)) {
|
|
@@ -173,30 +169,6 @@ function hasParentEscape(data) {
|
|
|
173
169
|
return Boolean(p && fs.existsSync(p));
|
|
174
170
|
}
|
|
175
171
|
|
|
176
|
-
function logPreTool(data, toolKey, toolInput) {
|
|
177
|
-
const fields = {};
|
|
178
|
-
if (SPAWN_TOOLS.has(toolKey) && toolInput && typeof toolInput === "object") {
|
|
179
|
-
fields.spawnType = String(
|
|
180
|
-
toolInput.subagent_type || toolInput.subagentType || "",
|
|
181
|
-
);
|
|
182
|
-
const rf = toolInput.resume_from ?? toolInput.resumeFrom;
|
|
183
|
-
fields.resumeFromCount =
|
|
184
|
-
rf == null || rf === "" ? 0 : Array.isArray(rf) ? rf.length : 1;
|
|
185
|
-
}
|
|
186
|
-
if (READ_TOOLS.has(toolKey) && toolInput && typeof toolInput === "object") {
|
|
187
|
-
const raw =
|
|
188
|
-
toolInput.target_file ||
|
|
189
|
-
toolInput.file_path ||
|
|
190
|
-
toolInput.targetFile ||
|
|
191
|
-
toolInput.filePath ||
|
|
192
|
-
"";
|
|
193
|
-
fields.fileSizeBytes = fileSizeBytes(resolveReadPath(raw, data));
|
|
194
|
-
}
|
|
195
|
-
if (Object.keys(fields).length) {
|
|
196
|
-
logTelemetry("pretool", fields, workspaceRootOf(data));
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
172
|
function emitFat(data) {
|
|
201
173
|
const fat = fatHookOutput(processFatTools(data));
|
|
202
174
|
if (!fat) return null;
|
|
@@ -481,22 +453,11 @@ export function lastAssistantFromTranscript(filePath) {
|
|
|
481
453
|
}
|
|
482
454
|
}
|
|
483
455
|
|
|
484
|
-
function logParentStop(data, fields) {
|
|
485
|
-
logTelemetry("parent-stop", fields, workspaceRootOf(data));
|
|
486
|
-
}
|
|
487
|
-
|
|
488
456
|
function stop(data) {
|
|
489
457
|
if (data.subagentType || data.subagent_type) {
|
|
490
458
|
return interceptNeed(data, "Stop");
|
|
491
459
|
}
|
|
492
460
|
if (data.stopHookActive || data.stop_hook_active) {
|
|
493
|
-
logParentStop(data, {
|
|
494
|
-
recap: false,
|
|
495
|
-
recapSource: "none",
|
|
496
|
-
attempt: 0,
|
|
497
|
-
failOpen: true,
|
|
498
|
-
stopHookActive: true,
|
|
499
|
-
});
|
|
500
461
|
return 0;
|
|
501
462
|
}
|
|
502
463
|
const reason = String(data.reason || "");
|
|
@@ -512,28 +473,16 @@ function stop(data) {
|
|
|
512
473
|
}
|
|
513
474
|
|
|
514
475
|
const payloadMsg = payloadAssistantMessage(data);
|
|
515
|
-
let
|
|
516
|
-
|
|
517
|
-
if (payloadMsg) {
|
|
518
|
-
msg = payloadMsg;
|
|
519
|
-
recapSource = "payload";
|
|
520
|
-
} else {
|
|
476
|
+
let msg = payloadMsg;
|
|
477
|
+
if (!msg) {
|
|
521
478
|
const tp = data.transcript_path || data.transcriptPath || "";
|
|
522
479
|
msg = lastAssistantFromTranscript(tp);
|
|
523
|
-
if (msg) recapSource = "transcript";
|
|
524
480
|
}
|
|
525
481
|
|
|
526
482
|
const waitFirst = firstNonEmptyStripped(msg) === WAIT_GRUNT;
|
|
527
483
|
if (waitFirst && !isWaitGruntExact(msg)) {
|
|
528
484
|
// fall through to block — leftover lines not allowed on mid-turn wait
|
|
529
485
|
} else if (isRecap(msg)) {
|
|
530
|
-
logParentStop(data, {
|
|
531
|
-
recap: true,
|
|
532
|
-
recapSource,
|
|
533
|
-
attempt: 0,
|
|
534
|
-
failOpen: false,
|
|
535
|
-
stopHookActive: false,
|
|
536
|
-
});
|
|
537
486
|
return 0;
|
|
538
487
|
}
|
|
539
488
|
|
|
@@ -544,26 +493,12 @@ function stop(data) {
|
|
|
544
493
|
if (!Number.isFinite(n) || n < 0) n = 0;
|
|
545
494
|
}
|
|
546
495
|
if (n >= MAX_STOP) {
|
|
547
|
-
logParentStop(data, {
|
|
548
|
-
recap: false,
|
|
549
|
-
recapSource,
|
|
550
|
-
attempt: n,
|
|
551
|
-
failOpen: true,
|
|
552
|
-
stopHookActive: false,
|
|
553
|
-
});
|
|
554
496
|
return 0;
|
|
555
497
|
}
|
|
556
498
|
if (stopStamp) {
|
|
557
499
|
fs.mkdirSync(path.dirname(stopStamp), { recursive: true });
|
|
558
500
|
fs.writeFileSync(stopStamp, String(n + 1));
|
|
559
501
|
}
|
|
560
|
-
logParentStop(data, {
|
|
561
|
-
recap: false,
|
|
562
|
-
recapSource,
|
|
563
|
-
attempt: n + 1,
|
|
564
|
-
failOpen: false,
|
|
565
|
-
stopHookActive: false,
|
|
566
|
-
});
|
|
567
502
|
const reasonText = STOP_REASONS[Math.min(n, STOP_REASONS.length - 1)];
|
|
568
503
|
emit({ decision: "block", reason: reasonText });
|
|
569
504
|
return 0;
|
|
@@ -572,30 +507,18 @@ function stop(data) {
|
|
|
572
507
|
function interceptNeed(data, hookEventName) {
|
|
573
508
|
const ws = workspaceRootOf(data);
|
|
574
509
|
if (data.stopHookActive || data.stop_hook_active) {
|
|
575
|
-
logTelemetry(
|
|
576
|
-
"stop",
|
|
577
|
-
{ parseOk: false, intercept: "none" },
|
|
578
|
-
ws,
|
|
579
|
-
);
|
|
580
510
|
return 0;
|
|
581
511
|
}
|
|
582
512
|
const msg = data.lastAssistantMessage || data.last_assistant_message || "";
|
|
583
513
|
const parsed = parseNeed(msg);
|
|
584
514
|
if (!parsed.ok) {
|
|
585
|
-
logTelemetry("stop", { parseOk: false, intercept: "none" }, ws);
|
|
586
515
|
return 0;
|
|
587
516
|
}
|
|
588
517
|
const jobs = parsed.jobs;
|
|
589
|
-
const names = jobs.map((j) => j.job);
|
|
590
518
|
if (
|
|
591
519
|
jobs.length > 4 ||
|
|
592
520
|
!jobs.every((j) => INTERCEPT_JOBS.has(j.job))
|
|
593
521
|
) {
|
|
594
|
-
logTelemetry(
|
|
595
|
-
"stop",
|
|
596
|
-
{ parseOk: true, jobs: names, intercept: "none" },
|
|
597
|
-
ws,
|
|
598
|
-
);
|
|
599
522
|
return 0;
|
|
600
523
|
}
|
|
601
524
|
|
|
@@ -606,11 +529,6 @@ function interceptNeed(data, hookEventName) {
|
|
|
606
529
|
if (!Number.isFinite(n) || n < 0) n = 0;
|
|
607
530
|
}
|
|
608
531
|
if (n >= MAX_INTERCEPT) {
|
|
609
|
-
logTelemetry(
|
|
610
|
-
"stop",
|
|
611
|
-
{ parseOk: true, jobs: names, intercept: "none" },
|
|
612
|
-
ws,
|
|
613
|
-
);
|
|
614
532
|
return 0;
|
|
615
533
|
}
|
|
616
534
|
|
|
@@ -635,16 +553,6 @@ function interceptNeed(data, hookEventName) {
|
|
|
635
553
|
result = { fallback: true, text: "FALLBACK\n" };
|
|
636
554
|
}
|
|
637
555
|
if (!result || result.fallback) {
|
|
638
|
-
logTelemetry(
|
|
639
|
-
"stop",
|
|
640
|
-
{
|
|
641
|
-
parseOk: true,
|
|
642
|
-
jobs: names,
|
|
643
|
-
intercept: "FALLBACK",
|
|
644
|
-
query: job.query,
|
|
645
|
-
},
|
|
646
|
-
ws,
|
|
647
|
-
);
|
|
648
556
|
return 0;
|
|
649
557
|
}
|
|
650
558
|
parts.push(String(result.text || "").trimEnd());
|
|
@@ -654,11 +562,6 @@ function interceptNeed(data, hookEventName) {
|
|
|
654
562
|
fs.writeFileSync(interceptStamp, String(n + 1));
|
|
655
563
|
}
|
|
656
564
|
const reason = parts.join("\n");
|
|
657
|
-
logTelemetry(
|
|
658
|
-
"stop",
|
|
659
|
-
{ parseOk: true, jobs: names, intercept: "grunt-job" },
|
|
660
|
-
ws,
|
|
661
|
-
);
|
|
662
565
|
emit({
|
|
663
566
|
decision: "block",
|
|
664
567
|
hookSpecificOutput: {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: commit-and-push
|
|
3
3
|
description: >
|
|
4
|
-
|
|
5
|
-
push". Must push.
|
|
4
|
+
Alias of commit-push (1-release stub). Use for /commit-and-push, "commit and
|
|
5
|
+
push", "commit this and push". Must push. Prefer /commit-push.
|
|
6
6
|
---
|
|
7
|
-
|
|
7
|
+
Thin alias → `.rulesync/skills/commit-push/SKILL.md`. Must push. Do not load /commit.
|
|
8
8
|
|
|
9
9
|
Protocol: `.rulesync/reference/cascade.md`. Do not paste cascade.
|
|
@@ -14,5 +14,6 @@ Four buckets (completed / in-flight / remainder / blocker). Completed work = pas
|
|
|
14
14
|
en-US unless asked. Keep need:/verdict:/plan grammar when those apply.
|
|
15
15
|
|
|
16
16
|
This skill is the only one-off escape from superterse.
|
|
17
|
+
Always-why advise recap ≠ `/explain`. `/explain` = expansion not the why path.
|
|
17
18
|
Freeform how/why/explain is not this skill (thinker unless cheap false+). Slash `/explain` only.
|
|
18
19
|
Not a spawn-workflow escape. Only `/solo` is. Legal tools this skill: spawn only then text. Illegal (never consider): Read read_file Grep Glob Bash list_dir. Screenshot/image is already in the prompt — do not Read a path. Recap AFTER children or from visible context. No children + no work → text only still no Read.
|
|
@@ -1,32 +1,58 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: implement-plan
|
|
3
3
|
description: >
|
|
4
|
-
Implementer executes a local .tmp/plans checklist
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"execute the checklist", or "/implement-plan".
|
|
10
|
-
argument-hint: "<plan_id_serial>"
|
|
4
|
+
Implementer executes a local .tmp/plans checklist: continue, resume, or pick
|
|
5
|
+
among plans. Empty /implement-plan resumes a unique in-progress or starts a
|
|
6
|
+
unique ready plan; else lists and needs serial. Marks [x], skips completed
|
|
7
|
+
leaves. Not /implement review-loop, not /execute-plan PR DAG, not /pickup, not
|
|
8
|
+
/run-plan.
|
|
11
9
|
---
|
|
12
|
-
|
|
13
10
|
# implement-plan
|
|
14
11
|
|
|
15
|
-
|
|
12
|
+
Parent: spawn grunt to list/validate `.tmp/plans/` when the target is unknown or empty-arg; then spawn implementer with abs plan path + `{repo}/.rulesync/reference/plan-format.md` + first open leaf. Recap from implementer output only. No parent Read/Grep/Bash. Agent-agnostic (grunt then implementer). Not `/pickup` (handoffs only). Not `/run-plan`. Not `/execute-plan` (PR DAG).
|
|
13
|
+
|
|
14
|
+
Format SSOT: `.rulesync/reference/plan-format.md`.
|
|
16
15
|
|
|
17
16
|
## Invocation
|
|
18
17
|
|
|
19
|
-
`/implement-plan
|
|
18
|
+
`/implement-plan`
|
|
19
|
+
`/implement-plan {serial|path}`
|
|
20
|
+
|
|
21
|
+
Todos: `resolve` → `implement` → `verify`. One serial per run. Partial progress is ok; re-run continues. Skip `[x]`. Remaining leaves only.
|
|
22
|
+
|
|
23
|
+
## Resolve
|
|
24
|
+
|
|
25
|
+
Arg = `$ARGUMENTS` stripped. Listing/validate: spawn grunt (`job:search|exec`) on `.tmp/plans/`. Do not parent Read/Grep/Bash.
|
|
26
|
+
|
|
27
|
+
Eligible auto = valid plan-format checkbox grammar (`N [ ]` / `N.M [ ]`; not `- [ ]`; not `1. [ ]`). Invalid grammar: exclude from auto. Drop `done` (all `[x]` or FM `status: done`) from auto. Never silent latest. Never auto-pick among many.
|
|
28
|
+
|
|
29
|
+
**In-progress:** some `[x]` and remaining `[ ]`, or FM `status: in-progress` with open leaves.
|
|
30
|
+
|
|
31
|
+
**Ready / none started:** FM `ready` or all boxes `[ ]`.
|
|
32
|
+
|
|
33
|
+
**Blocked + open:** list/tag `blocked`; empty-arg never auto-runs. Explicit `{n|path}` still runs (skip `[x]`).
|
|
34
|
+
|
|
35
|
+
### Empty arg (`/implement-plan`)
|
|
36
|
+
|
|
37
|
+
Grunt lists/validates `.tmp/plans/*.md`. Then:
|
|
38
|
+
|
|
39
|
+
| condition | action |
|
|
40
|
+
|---|---|
|
|
41
|
+
| exactly 1 in-progress | resume it (implementer; skip `[x]`; start first open leaf) |
|
|
42
|
+
| exactly 1 plan total, none started (ready / all open) | start it |
|
|
43
|
+
| 0 plans (dir missing / no files) | blocker; remainder `/write-plan` |
|
|
44
|
+
| N>1 in-progress | list those (`serial name status first-open-leaf`); `need serial`. No silent latest |
|
|
45
|
+
| 0 in-progress, N>1 eligible (ready / blocked-open) | list eligible (`serial name status first-open-leaf`; tag `blocked`); `need serial` |
|
|
46
|
+
| only `done` / only invalid | blocker; remainder `/write-plan` |
|
|
20
47
|
|
|
21
|
-
|
|
48
|
+
Unique in-progress wins even if other ready/done files exist. Invalid grammar does not count toward unique-auto and is omitted from auto lists.
|
|
22
49
|
|
|
23
|
-
|
|
50
|
+
### Arg `{n|path}`
|
|
24
51
|
|
|
25
|
-
|
|
52
|
+
That file only; skip `[x]`; remaining leaves. Write-plan remainder stays `/implement-plan {n}` (that serial). Never auto-pick among many.
|
|
26
53
|
|
|
27
54
|
| input | action |
|
|
28
55
|
|---|---|
|
|
29
|
-
| empty | grunt lists `.tmp/plans/*.md` as `serial slug status`. Stop: `need serial. have: ...` |
|
|
30
56
|
| int (`1`, `0001`) | files whose leading number == that int |
|
|
31
57
|
| `{serial}-slug` or `*.md` or path | that file if under `.tmp/plans/` |
|
|
32
58
|
| slug only (`add-auth`) | unique match `*-{slug}-*.md` or `*-{slug}.md` |
|
|
@@ -48,9 +74,9 @@ Prompt:
|
|
|
48
74
|
```
|
|
49
75
|
You are implementer subagent. Do not spawn.
|
|
50
76
|
|
|
51
|
-
Read {abs}/.
|
|
77
|
+
Read {abs}/.rulesync/reference/plan-format.md and the plan at {abs_plan_path}.
|
|
52
78
|
|
|
53
|
-
Implement remaining `[ ]` leaves in numeric order. Skip `[x]`.
|
|
79
|
+
Implement remaining `[ ]` leaves in numeric order. Skip `[x]`. Start at the first open leaf.
|
|
54
80
|
Write-allowlist = paths listed in this plan only. Do not add README/docs/examples unless listed in the plan. Missing path → blocker/`need:`; do not invent.
|
|
55
81
|
After each leaf: flip that line to `[x]` in the plan file (only the box).
|
|
56
82
|
When a phase's children are all `[x]`, mark the phase `[x]`.
|
|
@@ -78,7 +104,8 @@ leftover:
|
|
|
78
104
|
## Rules
|
|
79
105
|
|
|
80
106
|
- Skip `[x]`; only flip boxes; no renumber/rewrite leaf text.
|
|
81
|
-
- No review-fix loop. Not bundled `/implement`.
|
|
107
|
+
- No review-fix loop. Not bundled `/implement`. Leftover pick 1 (verbal plan) ≠ this skill (no `.tmp/plans`; no write-plan; no implement-plan). Bare `implement`/`implementer` → pick1, not this skill.
|
|
108
|
+
- Slash `/implement-plan {n}` = disk/file run. Empty `/implement-plan` = unique-resume / unique-start / else list. Leftover pick 2 may invoke this sequencing without user slash (after write-plan persist; `plan=/abs/...` only). Always-do leftover match; leftover `2` ≠ Skill-name. Verbal leftover ≠ implement-plan.
|
|
82
109
|
- No auto `/write-plan` chain. Escalation → tell user to `/write-plan` a follow-up.
|
|
83
110
|
- Omit `model`. `subagent_type: implementer` only for this skill.
|
|
84
111
|
- First prompt sentence: `You are implementer subagent.`
|
|
@@ -86,3 +113,4 @@ leftover:
|
|
|
86
113
|
- Resume prompt = `You are implementer subagent.` + new verdicts only. Do not re-send the original task. Max 3 `resume_from` per child id; then report blocked/partial.
|
|
87
114
|
- Tool-call first for spawn claims.
|
|
88
115
|
- Do not re-plan. Partial = skill success (plan file is SoT).
|
|
116
|
+
- `/pickup` stays handoffs only. Do not merge.
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: write-plan
|
|
3
3
|
description: >
|
|
4
|
-
Thinker drafts a local implementer-ready checklist plan; parent Write
|
|
5
|
-
|
|
6
|
-
for implementer, "write a plan", or /write-plan. Not a design
|
|
7
|
-
|
|
8
|
-
Use when asked to "write a plan", "make a checklist plan",
|
|
9
|
-
"plan this for implementer", or "/write-plan".
|
|
10
|
-
argument-hint: "<task or context>"
|
|
4
|
+
Thinker drafts a local implementer-ready checklist plan; parent Write persists
|
|
5
|
+
.tmp/plans/{serial}-{slug}-{YYYYMMDDTHHMMSSZ}.md. Use for a numbered local
|
|
6
|
+
plan, checklist for implementer, "write a plan", or /write-plan. Not a design
|
|
7
|
+
doc or PR stack.
|
|
11
8
|
---
|
|
12
|
-
|
|
13
9
|
# write-plan
|
|
14
10
|
|
|
15
11
|
Parent orchestrates thinker then persists via Write under `.tmp/plans/`. Parent does not author the plan body.
|
|
@@ -28,7 +24,7 @@ Empty `$ARGUMENTS` **and** no task in conversation → `need task` and stop. Do
|
|
|
28
24
|
|
|
29
25
|
Spawn `subagent_type: thinker`, `background: true`, omit `model`, `description: "write plan"`.
|
|
30
26
|
|
|
31
|
-
Pass `{abs}/.
|
|
27
|
+
Pass `{abs}/.rulesync/reference/plan-format.md` in the thinker prompt. If prefetch needed: spawn grunt `job:search|exec` not parent Bash.
|
|
32
28
|
|
|
33
29
|
Prompt:
|
|
34
30
|
|
|
@@ -37,7 +33,7 @@ You are thinker subagent. Read-only. Do not write files. Do not spawn.
|
|
|
37
33
|
|
|
38
34
|
Named-file Read of listed abs paths only; investigate/search/trees → `need:` (parent spawns grunt prefetch).
|
|
39
35
|
|
|
40
|
-
Read {abs}/.
|
|
36
|
+
Read {abs}/.rulesync/reference/plan-format.md. Produce a plan that matches it.
|
|
41
37
|
|
|
42
38
|
Task:
|
|
43
39
|
{full $ARGUMENTS + relevant conversation context}
|
|
@@ -58,7 +54,9 @@ Wait. Fail → `[thinker]: failed: {err}` stop.
|
|
|
58
54
|
|
|
59
55
|
## Step 2 — persist (parent Write)
|
|
60
56
|
|
|
61
|
-
No grunt spawn. Parent `write`s the thinker final message under `{repo}/.tmp/plans/` (any filename in that dir). `orchestrate-parent.js` runs `scripts/persist-plan.mjs`: serial/slug from `PLAN_NAME:` / heading, inject YAML, rewrite path+content. Deny invalid plans and any write outside `.tmp/plans/`.
|
|
57
|
+
No grunt spawn. Parent `write`s the thinker final message under `{repo}/.tmp/plans/` (any filename in that dir). Grok `orchestrate-parent.js` runs `scripts/persist-plan.mjs`: serial/slug from `PLAN_NAME:` / heading, inject YAML, rewrite path+content. Deny invalid plans and any write outside `.tmp/plans/`.
|
|
58
|
+
|
|
59
|
+
Host without that hook: name the file per `.rulesync/reference/plan-format.md` Path, or pipe the body to `node scripts/persist-plan.mjs --workspace {repo}` and use its `path`.
|
|
62
60
|
|
|
63
61
|
Report serial/path from the tool result (`updatedInput.file_path`). Fail/deny → `[write-plan]: failed: {err}` stop.
|
|
64
62
|
|
|
@@ -80,3 +78,5 @@ Do not dump the plan.
|
|
|
80
78
|
- Parent coordinates; parent Write under `.tmp/plans/` only; thinker never writes.
|
|
81
79
|
- Not `/design`, not `/execute-plan`, not a design doc.
|
|
82
80
|
- Tool-call first: emit `spawn_subagent` in the same turn as any spawn claim. Past tense after the tool result.
|
|
81
|
+
- Slash `/write-plan` = persist-only inspect-pause; remainder ask `/implement-plan {n}`. Not leftover pick 2.
|
|
82
|
+
- Leftover pick 2 (`Implementer with file plan`) = this persist then implement-plan one-shot; skip inspect pause; no user slash. Always-do leftover match; leftover `2` ≠ Skill-name invoke of this skill. Parent still no Write — this skill sequencing.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<!-- Generated by emit-maps.mjs. Do not hand-edit. -->
|
|
2
|
+
|
|
3
|
+
# Law
|
|
4
|
+
|
|
5
|
+
Protocol stays cascade/overview; domain fills this.
|
|
6
|
+
|
|
7
|
+
## Skills naming
|
|
8
|
+
|
|
9
|
+
Reserved (do not reuse in consumer custom skills): `browser` `cascade` `commit` `commit-and-push` `commit-push` `commit-push-deploy` `commit-push-release` `explain` `handoff` `implement-plan` `parent` `pickup` `solo` `write-plan`.
|
|
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.
|
|
12
|
+
|
|
13
|
+
# Skills
|
|
14
|
+
|
|
15
|
+
| name | origin | description | task | commandPath | refs |
|
|
16
|
+
| --- | --- | --- | --- | --- | --- |
|
|
17
|
+
| browser | local | Session browser rail. /browser or browse a URL. Call node scripts/browser.mjs nav\|snap\|click\|fill\|shot\|pdf\|stop. Lightp… | | | |
|
|
18
|
+
| cascade | local | Session mode. /cascade exits solo and restores the grunt cascade for this session — spawn, orchestrator, recap, need\|ve… | | | |
|
|
19
|
+
| commit | local | Inspect the diff and commit with a Conventional Commits subject line. Use for /commit, "commit this", "commit these cha… | | | |
|
|
20
|
+
| 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.… | | | |
|
|
21
|
+
| commit-push | local | Commit with a Conventional Commits subject, then push. Use for /commit-push, "commit and push", "commit this and push".… | | | |
|
|
22
|
+
| commit-push-deploy | local | Commit, push, then deploy only if allowlisted infra already exists. Use for /commit-push-deploy, "commit push deploy",… | | | |
|
|
23
|
+
| 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… | | | |
|
|
24
|
+
| explain | local | One-off human recap. /explain. First action = spawn grunt\|implementer\|thinker if facts/work; else recap already-visible… | | | |
|
|
25
|
+
| handoff | local | Parent writes a session handoff under .tmp/grunt/handoffs/ and tells the user to continue in a fresh session. Use for /… | | | |
|
|
26
|
+
| implement-plan | local | Implementer executes a local .tmp/plans checklist: continue, resume, or pick among plans. Empty /implement-plan resumes… | | | |
|
|
27
|
+
| parent | local | One-turn parent-orchestrator escape. Use for /parent. Not a session mode. | | | |
|
|
28
|
+
| pickup | local | Pick up/continue a session handoff under .tmp/grunt/handoffs/. Use for /pickup, pick up, continue handoff, serial, drag… | | | |
|
|
29
|
+
| solo | local | Session mode. /solo disables the grunt cascade for this session — one normal agent, no spawn, no orchestrator. /cascade… | | | |
|
|
30
|
+
| write-plan | local | Thinker drafts a local implementer-ready checklist plan; parent Write persists .tmp/plans/{serial}-{slug}-{YYYYMMDDTHHM… | | | |
|
|
31
|
+
|
|
32
|
+
# Refs
|
|
33
|
+
|
|
34
|
+
| path | title | tags | summary |
|
|
35
|
+
| --- | --- | --- | --- |
|
|
36
|
+
| .rulesync/reference/browser.md | Browser | browser | Zero-config in-tree session rail. Not MCP. Not env. Not raw Playwright. |
|
|
37
|
+
| .rulesync/reference/cascade.md | Cascade | cascade | Shipped protocol: **parent-only spawn**. Only the parent **orchestrator** session calls `spawn_subagent`. Implementer a… |
|
|
38
|
+
| .rulesync/reference/hooks.md | Hooks | hooks | SessionStart: keep empty (token baseline). Do not inject context. Do not register a SessionStart hook on `../../.grok/h… |
|
|
39
|
+
| .rulesync/reference/law.md | Law | | Protocol stays cascade/overview; domain fills this. |
|
|
40
|
+
| .rulesync/reference/map.md | Map | map | Cheap outline. Not a file dump. |
|
|
41
|
+
| .rulesync/reference/output.md | Output | output | en-US unless asked. every output maximal superterse. Fragments OK. Sacrifice grammar; keep meaning. Parent and child. E… |
|
|
42
|
+
| .rulesync/reference/plan-format.md | Plan format (SSOT) | | Local implementer checklist. Not a design doc, PR stack, or DAG. |
|
|
43
|
+
| .rulesync/reference/rtk.md | RTK | rtk | Shell stdout compression. PreToolUse: Bash → `rtk <cmd>`. Not Read/Grep/Glob/prompts/images. |
|
|
@@ -13,17 +13,19 @@ Always-do lives in orchestrator/overview (do not open this file first). Peek/kil
|
|
|
13
13
|
Child prompt first sentence only: `You are {agent} subagent.` Then task + abs paths + verdicts only.
|
|
14
14
|
|
|
15
15
|
Always spawn + prompt. First token = spawn. Parent Read/Bash deny expected if forgotten. Only `/solo` (session stamp) 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
|
|
17
|
-
Advise
|
|
18
|
-
1.
|
|
19
|
-
2.
|
|
20
|
-
|
|
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: numbered/label pick1 or pick2 or `/implement-plan {n}` or explicit implement (=pick1). `ok`/`yes`/`y`/`continue` ≠ either implement path (`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):
|
|
18
|
+
1. Implementer with verbal plan
|
|
19
|
+
2. Implementer with file plan
|
|
20
|
+
3. Tweak
|
|
21
|
+
Match number or full leftover label (or unique tail `verbal plan` / `file plan`). Always-do leftover match; not Skill-name (`2` ≠ write-plan). 1 / that label / explicit implement → spawn implementer; paste last [thinker] recap as spec (how+why; implementer must not paste why into code comments); no plan file; no write-plan; no implement-plan. Bare `implement`/`implementer` → pick1 only (shared prefix; do not substring-match both picks). 2 / that label → persist `.tmp/plans/{n}` then spawn implementer with `plan=/abs/...` path only (write-plan then implement-plan one-shot; skip inspect pause; no user slash). Parent still no Write — existing write-plan path/skill sequencing. 3 / Tweak → stay advise; no implementer. Extra user text = revision notes → thinker; bare 3/Tweak = stop wait notes. `/write-plan` persist-only inspect-pause; remainder ask `/implement-plan {n}`. Not a leftover number. `/implement-plan {n}` stays disk/file run; ≠ conversational verbal pick. Disk leftover may invoke without user slash; verbal ≠ implement-plan.
|
|
22
|
+
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 that gate; else recap-stop. plan-only `/write-plan` → recap + remainder `/implement-plan` (ask).
|
|
21
23
|
|
|
22
24
|
Precedence: slash → obvious fact/false+/reuse → advise-class row → prompt-is-spec → write.
|
|
23
25
|
1. Tools (facts / search / exec / git / web / test / low-reason mechanical write) → grunt. Facts/search → grunt, never thinker.
|
|
24
|
-
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 / `/implement-plan`.
|
|
25
|
-
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.
|
|
26
|
-
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). Advise leftover still adds numbered pick on own lines. Prose → `/explain` on visible child. Not grunt for parrot. Tag `[orchestrator]:` on no-spawn — don’t fake `[thinker]:`. Pitfalls: deeper→thinker; code moved invalidates; `need:` open; compaction.
|
|
26
|
+
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}`.
|
|
27
|
+
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.
|
|
28
|
+
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). Advise leftover still adds numbered pick on own lines. 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.
|
|
27
29
|
4. Fresh/world facts → grunt `job: web`. Never answer from memory.
|
|
28
30
|
|
|
29
31
|
Spawn only `grunt` | `implementer` | `thinker`. Omit `model`. Isolation `none` unless asked.
|
|
@@ -41,7 +43,7 @@ Classify `done` | `alive` | `stuck` vs prior peek: **done** (completed/failed),
|
|
|
41
43
|
Loop until done. No auto-kill. Kill only if the user asks and the host has a kill tool.
|
|
42
44
|
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).
|
|
43
45
|
|
|
44
|
-
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) or `[orchestrator]: wait grunt`. First non-empty line must match legal `[orchestrator|grunt|implementer|thinker|handoff]:`. Advise leftover numbered pick may follow the tagged recap. 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.
|
|
46
|
+
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) or `[orchestrator]: wait grunt`. First non-empty line must match legal `[orchestrator|grunt|implementer|thinker|handoff]:`. Advise leftover numbered pick may follow the tagged recap (format only; hook does not map `1`/`2`/`3` → skills). 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.
|
|
45
47
|
`/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.
|
|
46
48
|
`/pickup` is spawn-first pickup, not in-parent write; parent never Read. Inverse of `/handoff`.
|
|
47
49
|
`/solo` is the session mode (not one-turn): `beforeSubmitPrompt` writes `.tmp/orchestrator-logs/grunt-off-{sid}`, every gate short-circuits while it exists, `/cascade` unlinks it. Everything above resumes next turn. Antigravity: skill-only, no stamp create (see hooks.md). `/parent` is last-ditch hook stamp (not a mode, not skill-instructed Read/Bash): UserPromptSubmit writes `.tmp/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.
|
|
@@ -4,17 +4,17 @@ tags: [hooks]
|
|
|
4
4
|
|
|
5
5
|
# Hooks
|
|
6
6
|
|
|
7
|
-
SessionStart: keep empty (token baseline). Do not inject context. Do not register a SessionStart hook on
|
|
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
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.
|
|
10
10
|
|
|
11
|
-
Claude / Codex / Antigravity PreToolUse still run
|
|
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`.
|
|
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/plans/` and `.tmp/grunt/handoffs/` Write still persist. Parent Bash still allowed for workspace
|
|
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/plans/` and `.tmp/grunt/handoffs/` 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|handoff|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`.
|
|
14
14
|
|
|
15
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.
|
|
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/plans/` (
|
|
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/plans/` (`../../scripts/persist-plan.mjs`) and `.tmp/grunt/handoffs/` (`../../scripts/persist-handoff.mjs`); both 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]:`. 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`. Skills point to cascade; do not paste protocol here.
|
|
18
18
|
|
|
19
19
|
`/solo` writes `grunt-off-{sid}`; `/cascade` unlinks it (`beforeSubmitPrompt`, exact-match only). While set: 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, fail-closed.
|
|
20
20
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Law
|
|
2
|
+
|
|
3
|
+
Protocol stays cascade/overview; domain fills this.
|
|
4
|
+
|
|
5
|
+
## Skills naming
|
|
6
|
+
|
|
7
|
+
Reserved (do not reuse in consumer custom skills): `browser` `cascade` `commit` `commit-and-push` `commit-push` `commit-push-deploy` `commit-push-release` `explain` `handoff` `implement-plan` `parent` `pickup` `solo` `write-plan`.
|
|
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.
|