squadrant 0.9.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.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +268 -0
  3. package/dist/index.js +9154 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/squadrantd.js +3928 -0
  6. package/dist/squadrantd.js.map +1 -0
  7. package/package.json +68 -0
  8. package/plugin/.claude-plugin/plugin.json +5 -0
  9. package/plugin/skills/add-pick-crew-rule/SKILL.md +88 -0
  10. package/plugin/skills/captain-ops/SKILL.md +390 -0
  11. package/plugin/skills/command-ops/SKILL.md +157 -0
  12. package/plugin/skills/config-doctor/SKILL.md +46 -0
  13. package/plugin/skills/daily-log/SKILL.md +44 -0
  14. package/plugin/skills/karpathy-principles/SKILL.md +82 -0
  15. package/plugin/skills/set-effort/SKILL.md +59 -0
  16. package/plugin/skills/side-session/SKILL.md +113 -0
  17. package/plugin/skills/squadrant-effort/SKILL.md +8 -0
  18. package/plugin/skills/squadrant-new-project/SKILL.md +67 -0
  19. package/plugin/skills/squadrant-register-project/SKILL.md +60 -0
  20. package/plugin/skills/where-i-am/SKILL.md +102 -0
  21. package/plugin/skills/wiki-ops/SKILL.md +96 -0
  22. package/plugin/skills/wim/SKILL.md +8 -0
  23. package/scripts/acceptance-interactive-codex.sh +56 -0
  24. package/scripts/capture-skill.sh +32 -0
  25. package/scripts/claude-iv-smoke.mjs +133 -0
  26. package/scripts/fix-skill.sh +39 -0
  27. package/scripts/gen-codex-types.sh +18 -0
  28. package/scripts/mailbox-injector-smoke.mjs +124 -0
  29. package/scripts/mark-learning-useful.sh +22 -0
  30. package/scripts/migrate-to-squadrant.sh +158 -0
  31. package/scripts/notify-relay-placement-smoke.mjs +59 -0
  32. package/scripts/read-handoff.sh +22 -0
  33. package/scripts/record-learning.sh +31 -0
  34. package/scripts/record-side-handoff.sh +32 -0
  35. package/scripts/smoke-push-notify.mjs +147 -0
  36. package/scripts/spawn-crew-pane.sh +17 -0
  37. package/scripts/spawn-workspace.sh +206 -0
  38. package/scripts/wiki-ingest.sh +121 -0
  39. package/scripts/wiki-log.sh +20 -0
  40. package/scripts/wiki-query.sh +36 -0
  41. package/scripts/write-handoff.sh +31 -0
  42. package/templates/captain.claude.md +44 -0
  43. package/templates/captain.generic.md +45 -0
  44. package/templates/command.claude.md +32 -0
  45. package/templates/crew.claude.md +64 -0
  46. package/templates/crew.generic.md +51 -0
  47. package/templates/crew.opencode.md +51 -0
  48. package/templates/learnings.claude.md +40 -0
  49. package/templates/side.debug.claude.md +78 -0
  50. package/templates/side.research.claude.md +63 -0
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "squadrant",
3
+ "packageManager": "pnpm@10.30.3",
4
+ "version": "0.9.0",
5
+ "description": "Multi-project orchestration for your coding agents (Claude, Codex, opencode, Gemini)",
6
+ "type": "module",
7
+ "bin": {
8
+ "squadrant": "./dist/index.js",
9
+ "squad": "./dist/index.js"
10
+ },
11
+ "files": [
12
+ "dist/",
13
+ "plugin/",
14
+ "scripts/",
15
+ "templates/"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc -b --force packages/shared packages/core packages/agents packages/workspaces packages/web packages/cli && tsup",
19
+ "dev": "tsup --watch",
20
+ "test": "vitest",
21
+ "lint": "tsc --noEmit",
22
+ "codex:gen-types": "bash scripts/gen-codex-types.sh"
23
+ },
24
+ "keywords": [
25
+ "squadrant",
26
+ "multi-agent",
27
+ "agent",
28
+ "orchestration",
29
+ "cmux",
30
+ "obsidian"
31
+ ],
32
+ "author": "",
33
+ "license": "MIT",
34
+ "engines": {
35
+ "node": ">=18"
36
+ },
37
+ "dependencies": {
38
+ "chalk": "^5.4.0",
39
+ "commander": "^13.0.0",
40
+ "gray-matter": "^4.0.3",
41
+ "jsonc-parser": "^3.3.1"
42
+ },
43
+ "devDependencies": {
44
+ "@squadrant/cli": "workspace:*",
45
+ "@squadrant/core": "workspace:*",
46
+ "@squadrant/agents": "workspace:*",
47
+ "@squadrant/shared": "workspace:*",
48
+ "@squadrant/workspaces": "workspace:*",
49
+ "@squadrant/web": "workspace:*",
50
+ "@types/node": "^22.0.0",
51
+ "tsup": "^8.5.1",
52
+ "typescript": "^5.7.0",
53
+ "vitest": "^3.0.0"
54
+ },
55
+ "pnpm": {
56
+ "onlyBuiltDependencies": [
57
+ "esbuild"
58
+ ]
59
+ },
60
+ "repository": {
61
+ "type": "git",
62
+ "url": "git+https://github.com/tu11aa/squadrant.git"
63
+ },
64
+ "homepage": "https://github.com/tu11aa/squadrant#readme",
65
+ "bugs": {
66
+ "url": "https://github.com/tu11aa/squadrant/issues"
67
+ }
68
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "squadrant",
3
+ "description": "Skills for Squadrant agent orchestration roles (captain, command, crew)",
4
+ "skills": "./skills/"
5
+ }
@@ -0,0 +1,88 @@
1
+ ---
2
+ name: add-pick-crew-rule
3
+ description: Add, edit, or remove a leveled crew routing rule in config.json without hand-editing JSON. Routing rules map task-text keywords to a tier → {agent, model}.
4
+ ---
5
+
6
+ # Manage Crew Routing Rules
7
+
8
+ Crew routing rules live in `defaults.crewRouting.rules` inside `~/.config/squadrant/config.json`.
9
+ Each rule has the shape:
10
+
11
+ ```jsonc
12
+ {
13
+ "tier": "<label>", // human label, e.g. "extreme" / "hard" / "daily"
14
+ "match": "<regex>", // case-insensitive regex tested against the task text
15
+ "agent": "claude|codex|gemini|opencode",
16
+ "model": "opus|sonnet" // omit for codex/opencode (they use their own defaults)
17
+ }
18
+ ```
19
+
20
+ Rules are evaluated in order; the **first match wins**.
21
+
22
+ ## Adding a rule
23
+
24
+ 1. Read the current config:
25
+ ```bash
26
+ cat ~/.config/squadrant/config.json
27
+ ```
28
+
29
+ 2. Identify the `defaults.crewRouting.rules` array. If it is absent, add it.
30
+
31
+ 3. Build the new rule object. Validate:
32
+ - `tier` is a non-empty string
33
+ - `match` is a valid regex (test it mentally against a sample task string)
34
+ - `agent` is one of `claude`, `codex`, `gemini`, `opencode`
35
+ - `model` is only set for claude rules (`opus` or `sonnet`); omit for other agents
36
+
37
+ 4. Insert the rule at the correct position — **rules are evaluated in order**.
38
+ Higher-priority / more specific tiers (e.g. "extreme") belong before broader ones
39
+ (e.g. "hard"). Append low-priority catch-alls last.
40
+
41
+ 5. Write the updated config back via the existing save path:
42
+ ```typescript
43
+ // The saveConfig helper in src/config.ts handles atomic write + newline.
44
+ // If editing the live file directly, use JSON.stringify(config, null, 2) + "\n".
45
+ ```
46
+
47
+ 6. Verify the rule fires as expected:
48
+ ```bash
49
+ # Quick smoke-test (no live crew spawned):
50
+ node -e "
51
+ const {loadConfig} = require(process.env.HOME + '/.config/squadrant/node_modules/...');
52
+ // or just log the matching rule manually
53
+ const rules = require(process.env.HOME + '/.config/squadrant/config.json')
54
+ .defaults?.crewRouting?.rules ?? [];
55
+ const task = 'YOUR TEST TASK HERE';
56
+ const hit = rules.find(r => new RegExp(r.match,'i').test(task));
57
+ console.log(hit ?? 'no match');
58
+ "
59
+ ```
60
+
61
+ ## Editing an existing rule
62
+
63
+ Read → locate the rule by `tier` or `match` → update the field(s) → write back.
64
+
65
+ ## Removing a rule
66
+
67
+ Read → filter out the rule by `tier` or `match` → write back.
68
+
69
+ ## Precedence reminder
70
+
71
+ - Explicit `--agent` / `--model` on `squadrant crew spawn` **always** override routing.
72
+ - If no rule matches, the spawn falls through to `defaults.roles.crew` behavior (unchanged from pre-routing behavior).
73
+
74
+ ## Example rules
75
+
76
+ ```jsonc
77
+ // Route deep-reasoning work to the strongest model
78
+ { "tier": "extreme", "match": "redesign|architect|rewrite|from scratch|deep reasoning", "agent": "claude", "model": "opus" }
79
+
80
+ // Route standard feature/refactor work to a faster model
81
+ { "tier": "hard", "match": "refactor|migrate|implement|feature|daemon|control-plane", "agent": "claude", "model": "sonnet" }
82
+
83
+ // Route mobile tasks to codex (no model — uses codex default)
84
+ { "tier": "mobile", "match": "mobile|ios|swift|android|kotlin|react native", "agent": "codex" }
85
+
86
+ // Route trivial edits to opencode (cheapest path)
87
+ { "tier": "daily", "match": "typo|rename|bump|docs|comment|lint|format", "agent": "opencode" }
88
+ ```
@@ -0,0 +1,390 @@
1
+ ---
2
+ name: captain-ops
3
+ description: Complete captain playbook — session startup, crew spawning, status writing, group awareness, and learnings. Use this skill at session start and reference it throughout.
4
+ ---
5
+
6
+ # Captain Operations
7
+
8
+ ## Session Startup
9
+
10
+ 1. Read `~/.config/squadrant/config.json` — match your current working directory. Note your `spokeVault`, `group`, `groupRole`, and `maxCrew` (default: 5).
11
+ 2. **Check for handoff from previous session:**
12
+ ```bash
13
+ ~/.config/squadrant/scripts/read-handoff.sh "{spokeVaultPath}"
14
+ ```
15
+ If a handoff exists (`"exists"` is not false), read the context carefully:
16
+ - `currentState` — what was happening when the last session ended
17
+ - `openBranches` — branches with uncommitted/unmerged work
18
+ - `nextSteps` — what the previous session planned to do next
19
+ - `blockedItems` — unresolved blockers
20
+ - `decisions` — important decisions already made (don't re-decide)
21
+ The handoff file is auto-deleted after reading. Use this as your primary context source.
22
+ 3. Search **claude-mem** (`mem-search` skill) for your project name to get additional continuity.
23
+ 4. Check `{spokeVault}/daily-logs/` — read the most recent log if one exists.
24
+ 5. Check `{spokeVault}/learnings/` — **selectively** load relevant learnings (see "Selective Loading" section below). Do NOT read all files — grep by task keywords and tags.
25
+ 6. Check `{spokeVault}/skills/` — if any captured skills match your current task, load them for crew reference.
26
+ 7. Check `{spokeVault}/wiki/` — query wiki for keywords related to your current task:
27
+ ```bash
28
+ ~/.config/squadrant/scripts/wiki-query.sh "{spokeVaultPath}" "{relevant-keyword}" --titles-only
29
+ ```
30
+ If relevant pages exist, read them for context before starting work.
31
+ 8. Crew lifecycle events (done / blocked / idle) are delivered to your captain pane automatically by the squadrant daemon via daemon-direct cmux delivery (#332). No relay setup required.
32
+
33
+ 9. (Opt-in) Status writes are not required on every event. Only run `~/.config/squadrant/scripts/write-status.sh` when you have a meaningful note worth recording (a blocker, a deliberate "starting work on X", etc.) — not on a schedule.
34
+
35
+ ## Crew Setup
36
+
37
+ You do NOT create an Agent Team. You spawn each crew session on demand as a **new tab** in your workspace via `squadrant crew spawn` (use `--direction right|down|...` to split into a pane instead). The surface is a fresh CLI session with the crew template loaded as system prompt — disposable, restartable, runtime-agnostic.
38
+
39
+ You don't need to create or persist anything up front. Each `squadrant crew spawn` call creates a new surface.
40
+
41
+ ## Task Decomposition with Task Master
42
+
43
+ When you receive a **PRD, large feature request, or multi-step scope** from command, use **Task Master MCP** to decompose it before spawning crew.
44
+
45
+ ### If a PRD file exists in the project:
46
+ ```
47
+ mcp__task-master-ai__parse_prd(input: ".taskmaster/docs/prd.txt", projectRoot: "{projectPath}")
48
+ ```
49
+ This generates `tasks.json` with structured tasks, dependencies, and complexity scores.
50
+
51
+ ### Query tasks:
52
+ ```
53
+ mcp__task-master-ai__get_tasks(projectRoot: "{projectPath}") # List all tasks
54
+ mcp__task-master-ai__next_task(projectRoot: "{projectPath}") # Get highest-priority unblocked task
55
+ mcp__task-master-ai__get_task(id: "1", projectRoot: "{projectPath}") # Get specific task details
56
+ ```
57
+
58
+ ### Update task status as crew works:
59
+ ```
60
+ mcp__task-master-ai__set_task_status(id: "1", status: "in-progress", projectRoot: "{projectPath}")
61
+ mcp__task-master-ai__set_task_status(id: "1", status: "done", projectRoot: "{projectPath}")
62
+ ```
63
+
64
+ ### Expand complex tasks into subtasks:
65
+ ```
66
+ mcp__task-master-ai__expand_task(id: "1", projectRoot: "{projectPath}")
67
+ ```
68
+
69
+ ### Workflow:
70
+ 1. Receive scope from command → **parse PRD** (or manually create tasks if no PRD file)
71
+ 2. **get_tasks** to see the full dependency graph
72
+ 3. **next_task** to find what's unblocked and highest priority
73
+ 4. Spawn crew for that task
74
+ 5. When crew finishes → **set_task_status** to "done" → **next_task** for the next one
75
+ 6. Repeat until all tasks are done
76
+
77
+ **Note:** Task Master requires an AI provider API key (ANTHROPIC_API_KEY) for `parse_prd` and `expand_task`. If unavailable, create tasks manually using the project's task breakdown file (e.g., `pact-network-tasks.md`) and use Task Master only for status tracking.
78
+
79
+ ## Spawning Crew
80
+
81
+ **You MUST spawn a crew session for ANY coding task** — even a one-line change. You are a coordinator. You plan, delegate, review, and merge. You do NOT write code yourself.
82
+
83
+ A crew is an **interactive Claude sub-session** running in a tab inside your workspace, named `crew-1`, `crew-2`, … (or a name you pick). It stays idle between turns waiting for your next message — same model as a Claude Agent Team subagent.
84
+
85
+ ### Spawn a NEW crew
86
+
87
+ ```bash
88
+ squadrant crew spawn <project> "<task description>" \
89
+ [--name <name>] \
90
+ [--direction tab|right|left|up|down] \
91
+ [--agent claude|codex|gemini|opencode]
92
+ ```
93
+
94
+ What it does:
95
+ 1. Opens a new **tab** in the captain workspace (use `--direction right|left|up|down` to split into a pane instead).
96
+ 2. Names the tab `🔧 <project>:<name>` — `--name` is optional; auto-picks the next free `crew-N`.
97
+ 3. Boots an interactive Claude session (no `-p`) with `crew.<agent>.md` loaded as system prompt.
98
+ 4. Sends your task as the first turn. The crew works on it and then **stays idle** waiting for follow-ups.
99
+
100
+ ### Send a FOLLOW-UP to an existing crew
101
+
102
+ DO NOT spawn a new crew for every turn — that's how you get tab pollution. Use `send`:
103
+
104
+ ```bash
105
+ squadrant crew send <project> <name> "<message>"
106
+ ```
107
+
108
+ ### Inspect & shutdown
109
+
110
+ ```bash
111
+ squadrant crew list <project> # see all live crews for the project
112
+ squadrant crew tasks <project> # compact task listing (use --json for verbose)
113
+ squadrant crew tasks <project> --state-only <id> # fast state check (prints one word)
114
+ squadrant crew read <project> <name> # read tail of a crew's screen (~40 lines)
115
+ squadrant crew read <project> <name> --full # entire scrollback (may be large)
116
+ squadrant crew read <project> <name> --lines 100 # custom tail length
117
+ squadrant crew close <project> <name> # shutdown the crew (closes its tab)
118
+ ```
119
+
120
+ ### Examples
121
+
122
+ Spawn a fresh crew (auto-named `crew-1`):
123
+ ```bash
124
+ squadrant crew spawn brove "Add preinstall hook to package.json. Branch: feat/preinstall."
125
+ ```
126
+
127
+ Named crew for a specific work track:
128
+ ```bash
129
+ squadrant crew spawn brove "Refactor src/api/handlers.ts" --name api-refactor --agent codex
130
+ ```
131
+
132
+ Send a follow-up turn:
133
+ ```bash
134
+ squadrant crew send brove crew-1 "Also wire that into the install script"
135
+ ```
136
+
137
+ Open as a side-by-side pane when you want live preview:
138
+ ```bash
139
+ squadrant crew spawn brove "Fix typo in README" --direction right
140
+ ```
141
+
142
+ ### Leveled crew routing
143
+
144
+ When you spawn a crew without an explicit `--agent` or `--model`, squadrant automatically
145
+ consults the routing rules in `defaults.crewRouting.rules` (config.json) and picks the
146
+ right tier for the task:
147
+
148
+ | Tier | Matches | Routes to |
149
+ |------|---------|-----------|
150
+ | extreme | redesign, architect, rewrite, from scratch | claude/opus |
151
+ | hard | refactor, migrate, implement, feature | claude/sonnet |
152
+ | mobile | mobile, ios, swift, android, kotlin | codex |
153
+ | daily | typo, rename, bump, docs, lint | opencode |
154
+
155
+ The chosen route is printed as a dim one-liner before the spawn completes, e.g.:
156
+ ```
157
+ routed: tier=hard → claude/sonnet (rule: "refactor|migrate|implement|feature|daemon|control-plane")
158
+ ```
159
+
160
+ **Override at any time** — explicit flags always win over routing:
161
+ ```bash
162
+ squadrant crew spawn brove "refactor auth" --agent codex # forces codex despite "hard" tier
163
+ squadrant crew spawn brove "fix typo" --model opus # forces opus despite "daily" tier
164
+ ```
165
+
166
+ To add, edit, or remove routing rules: use the `squadrant:add-pick-crew-rule` skill.
167
+
168
+ ### Effort mode
169
+
170
+ Before spawning a crew, read `defaults.effort` from `~/.config/squadrant/config.json` (run `squadrant effort` to check). Apply the following bias to your crew agent/model choice:
171
+
172
+ | Mode | Directive |
173
+ |------|-----------|
174
+ | **max** | Tokens are plentiful. Prefer claude/opus for crew spawns; don't downshift for cost. |
175
+ | **balance** | Normal. Use default crew routing rules unchanged. (Absent field = balance.) |
176
+ | **low** | Conserve tokens. Prefer opencode/sonnet for crews; reserve opus for work that genuinely needs it. |
177
+
178
+ **Effort is crew-only.** Captain, command, and side roles are unaffected — keep them at their configured model regardless of effort.
179
+
180
+ **Effort is the weakest signal.** An explicit `--agent` / `--model` on a spawn always wins. Effort only nudges your default choice when nothing more specific applies.
181
+
182
+ To change the effort dial: `squadrant effort <max|balance|low>` or use the `squadrant:set-effort` skill.
183
+
184
+ ### Rules
185
+
186
+ - **Reuse with `send` before spawning a new one.** Same task track, same crew. New track = new crew.
187
+ - **Close crews you're done with** (`squadrant crew close ...`) so they don't accumulate.
188
+ - Crews run in **isolated worktrees by default** (parallel-safe, branch per crew). Pass `--shared` only for tiny/one-off tasks that don't need branch isolation. Never hand-run `git worktree add` — `squadrant crew spawn` handles it.
189
+ - Do NOT edit source code yourself — always delegate to crew.
190
+ - Respect `maxCrew` — don't exceed the configured concurrent crew count.
191
+ - **For complex multi-step tasks** (3+ steps, multiple files), tell the crew to use GSD inside the task prompt: *"This is a complex task. Use `/gsd:plan-phase` and `/gsd:execute-phase` for wave-based execution with fresh context per step."*
192
+ - **For simple tasks**, don't mention GSD — the crew will handle it directly.
193
+
194
+ > Non-Claude agents (codex / gemini) currently still launch in print-mode (one-shot) rather than as interactive sessions; `send` won't reach them yet. Prefer Claude crews when you want multi-turn dialogue.
195
+
196
+ ## Task Coordination
197
+
198
+ **HARD RULE: Do NOT poll crew screens in a loop.** Crew lifecycle events (idle / done / blocked) are delivered to your captain pane automatically by the squadrant daemon — trust the daemon signal. Polling loops hang indefinitely, exhaust context, and mask real blockers.
199
+
200
+ You don't have an Agent Team or `TaskCreate`/`TaskUpdate` tools — those were Claude-specific. When you need crew status:
201
+ 1. **Wait for the daemon to notify you.** When a crew finishes, signals blocked, or goes idle, the daemon delivers the event to your captain pane via daemon-direct cmux delivery. This is the primary mechanism — do not replace it with polling.
202
+ 2. `squadrant crew read <project> <name>` — **on-demand spot-check only** (a single read when you have a specific reason, e.g. reviewing a finished diff). Never in a loop, never with `until`.
203
+ 3. `squadrant crew tasks <project>` — **on-demand** compact task listing; `--id <prefix>` to filter; `--state-only <id>` for a single-word state check.
204
+ 4. `squadrant crew list <project>` — see all live crews and pick the right one.
205
+ 5. Inspecting the crew tab visually in cmux when you want richer context (you have its surface ref from the spawn output).
206
+ 6. Asking the user to check the dashboard if you need a cross-project view (see issue #44).
207
+
208
+ If you ever need a bounded check (not a loop), use a fixed counter (≤ 3 attempts with a sleep between), or watch the mailbox seq — never an unbounded `until` loop.
209
+
210
+ ### Handling CREW IDLE
211
+
212
+ CREW IDLE is **ambiguous** — the watchdog did not detect a heartbeat, which can happen when:
213
+ - **(a)** The crew finished but never ran `squadrant crew signal done` (issue #278 — common for claude/opencode before the completion-protocol fix).
214
+ - **(b)** The crew is genuinely waiting for the captain (asked a question or needs a decision).
215
+ - **(c)** The crew is still mid-task and the idle pulse was transient.
216
+
217
+ On CREW IDLE, do a **single on-demand spot-check** (allowed — not a polling loop), then classify:
218
+
219
+ | Spot-check shows | Captain action |
220
+ |-----------------|----------------|
221
+ | Completed work (PR opened, commits pushed, results reported) but no CREW DONE | Treat as the #278 case — review; if good, terminalize (`merge` + `crew close`). If not actually done, **re-task**: send the next instruction via `crew send` (the #148 re-open flow). |
222
+ | Crew asked a question or is waiting for a decision | Respond via `crew send`. Do NOT terminalize — it will signal done after the next turn. |
223
+ | Still mid-task / transient idle | Leave it; wait for the next daemon event. |
224
+
225
+ **Do not re-send the original task** if the crew appears to have completed it — that triggers a duplicate run. Read the crew screen or diff first, then decide: terminalize vs re-task vs leave.
226
+
227
+ This is the captain-side backstop: even if the completion-protocol imperative is skipped, the lifecycle still terminalizes because the captain classifies intent instead of letting the task strand at IDLE.
228
+
229
+ When a crew sends you a status message via `squadrant runtime send <project> "<message>"`, it lands in your captain pane. Acknowledge, then update your handoff if a meaningful decision was made.
230
+
231
+ ## When Crew Finishes
232
+
233
+ After a crew task completes:
234
+
235
+ 1. Review the work — read the diff, check the branch.
236
+ 2. Merge their branch if appropriate.
237
+ 3. Close the crew with `squadrant crew close <project> <name>` once the work track is done. (Or let the crew exit itself — the tab closes when the CLI ends.)
238
+ 4. After closing a crew, VERIFY no orphaned processes remain — e.g. `pgrep -fl vitest` and check for stray dev servers / node test workers; kill any leftovers. Do NOT run the full test suite repeatedly or concurrently across worktrees (a single `vitest run` spawns a ~per-CPU worker pool that uses gigabytes; several at once exhaust RAM). Prefer one verification on the authoritative checkout.
239
+ 5. Record learnings if any (see "Recording Learnings" below).
240
+ 6. Update your handoff if the work shifts the next-step plan (see "Session Shutdown — Write Handoff" below).
241
+
242
+ Status writes (`write-status.sh`) are opt-in; you don't need to write status after every event.
243
+
244
+ ## Session Shutdown (Opt-In Writes)
245
+
246
+ End-of-session writes are **opt-in**, not on a schedule. Only write what is meaningful:
247
+
248
+ 1. **Daily log (opt-in):** if you accomplished something worth a daily log, use the `squadrant:daily-log` skill. Skip it if today was uneventful.
249
+ 2. **Wiki promotion (opt-in):** if a learning crystallized into reusable knowledge, promote to a wiki page using `squadrant:wiki-ops`. Otherwise skip.
250
+ 3. **Handoff (opt-in but recommended for in-flight work):** if work is mid-flight, write a handoff so tomorrow's session can resume:
251
+
252
+ ```bash
253
+ ~/.config/squadrant/scripts/write-handoff.sh "{spokeVaultPath}" '{
254
+ "currentState": "Brief description of where things stand",
255
+ "openBranches": ["feat/branch-name — what it contains"],
256
+ "nextSteps": ["First thing to do tomorrow", "Second thing"],
257
+ "blockedItems": ["Any unresolved blockers"],
258
+ "decisions": ["Key decisions made this session that should not be revisited"],
259
+ "activeTasks": "Summary of task progress (e.g., 3/7 done)"
260
+ }'
261
+ ```
262
+
263
+ If everything is shipped and there is no in-flight work, you do not need to write a handoff.
264
+
265
+ 4. (Optional) If a Command session is running and you want to notify it:
266
+ ```bash
267
+ squadrant runtime send --command "Captain {project} ending session — handoff written."
268
+ ```
269
+ Skip this entirely if no Command session is up — Command is on-demand now.
270
+
271
+ **The handoff is your gift to tomorrow's session.** Be specific. "Working on the API" is useless. "Backend routes for /providers and /providers/:id are done, /timeseries endpoint is next, PR #12 is open for review" is useful.
272
+
273
+ ## Group Awareness
274
+
275
+ If your config has `group` / `groupRole`:
276
+ - Read full config to find sibling projects with the same `group`
277
+ - If your change might affect a sibling, **flag it to command** so it can notify the sibling's captain
278
+ - Use **claude-mem** to search for context from sibling projects
279
+ - `primary` role: your changes may need propagation to forks/dependents
280
+
281
+ ## Cross-Project Delegation
282
+
283
+ When a task genuinely belongs to a sibling project in the same group, use **`squadrant group dispatch <to-project> '<task>'`** instead of hand-writing a message. This records a tracked task on the sibling's project and auto-wakes its captain via the mailbox.
284
+
285
+ ### Rules
286
+
287
+ 1. **Same-group only.** `group dispatch` rejects any target whose `group` field differs from yours. Cross-group dispatch is out of scope — use claude-mem / wiki queries for awareness.
288
+ 2. **`acceptDelegations`.** If the sibling's project config has `acceptDelegations: false`, the command rejects with a clear error. The default is `true`.
289
+ 3. **Boot-if-down.** If the sibling's captain workspace is not running, `group dispatch` boots it (`squadrant launch <project>`) and waits for warmup with a bounded poll (30s hard timeout). If warmup fails, the dispatch is rejected (task not recorded).
290
+
291
+ ### Dispatch-and-yield (do NOT poll)
292
+
293
+ Once the task is recorded to the daemon, `group dispatch` **returns immediately**. The sibling's captain auto-accepts (because `acceptDelegations` is true) and spawns a crew. When the task settles — done, blocked, or failed — the daemon fans the outcome back to **your** mailbox automatically. The daemon wakes you up. **You never poll the sibling.**
294
+
295
+ HARD RULE: Do NOT add a polling loop after `group dispatch`. The report-back is event-driven; trust it.
296
+
297
+ ### Report-back format
298
+
299
+ | Settlement | Message |
300
+ |------------|---------|
301
+ | done | `✅ Cross-project task → B: done — <task snippet>` |
302
+ | blocked | `⛔ Cross-project task → B: blocked — <question>` |
303
+ | failed | `⛔ Cross-project task → B: failed — <error>` |
304
+ | stalled | `⚠️ Cross-project task → B: stalled (no heartbeat)` |
305
+
306
+ ### Example
307
+
308
+ ```bash
309
+ # You are captain of "scaffold-stylus". Ask the docs sibling to update docs.
310
+ squadrant group dispatch scaffold-stylus-docs "Document the new --format flag added in PR #42"
311
+ # → "✔ Dispatched to 'scaffold-stylus-docs' (task abc12345)"
312
+ # → (returns immediately; you are notified when settled)
313
+ ```
314
+
315
+ ## Recording Learnings
316
+
317
+ Recording learnings is **opt-in**. Record when something genuinely surprised you or a useful pattern emerged — not on a schedule.
318
+
319
+ Record after tasks complete, unexpected issues, or discovered patterns:
320
+ ```bash
321
+ ~/.config/squadrant/scripts/record-learning.sh "{spokeVaultPath}" "{category}" "{description}" "{tags}"
322
+ ```
323
+ - Categories: `workflow`, `template`, `convention`, `bug`, `insight`
324
+ - Tags: comma-separated keywords for selective loading (e.g., `cairo,escrow,pvp`)
325
+
326
+ ## Wiki Compilation
327
+
328
+ Wiki writes are **opt-in**. Compile knowledge when you have something worth recording — not on a schedule. Use the `squadrant:wiki-ops` skill for full instructions.
329
+
330
+ 1. **After each task**: If you learned how something works, create/update a wiki page
331
+ 2. **During session shutdown**: Review today's learnings — promote useful ones to wiki pages
332
+ 3. **Before starting work**: Query the wiki for relevant context:
333
+ ```bash
334
+ ~/.config/squadrant/scripts/wiki-query.sh "{spokeVaultPath}" "{task-keywords}"
335
+ ```
336
+
337
+ **Learnings vs Wiki**: Learnings are raw observations (quick to record). Wiki pages are compiled, structured knowledge (worth maintaining). Promote a learning when it's been useful 2+ times or represents how a system works.
338
+
339
+ ## Selective Loading (on session start)
340
+
341
+ Do NOT read all learnings. Instead, filter by relevance:
342
+ 1. `grep -rl` your current task keywords in `{spokeVault}/learnings/`
343
+ 2. Also check for learnings tagged with your current branch name or feature area
344
+ 3. Only read the matching files — skip the rest
345
+ 4. For each learning you load, increment its `times_loaded` counter
346
+ 5. If a learning actually helps your current work, run:
347
+ ```bash
348
+ ~/.config/squadrant/scripts/mark-learning-useful.sh "{learning-file-path}"
349
+ ```
350
+
351
+ Learnings with `times_loaded > 5` and `times_useful: 0` are stale — ignore them.
352
+
353
+ ## Capturing Skills (CAPTURED — from OpenSpace)
354
+
355
+ After a crew member completes a task that used a **novel or reusable pattern**, capture it as a skill:
356
+ ```bash
357
+ ~/.config/squadrant/scripts/capture-skill.sh "{spokeVaultPath}" "{skill-name}" "{one-line description}" "{full markdown body}"
358
+ ```
359
+
360
+ **When to capture:**
361
+ - A task required a multi-step workflow that could apply to future tasks
362
+ - A crew member discovered a useful tool chain or command sequence
363
+ - A pattern emerged across 2+ similar tasks
364
+
365
+ **Don't capture** trivial one-off fixes or project-specific config.
366
+
367
+ Captured skills live in `{spokeVault}/skills/{name}/SKILL.md` and can be referenced by future crew members.
368
+
369
+ ## Fixing Skills (FIX — from OpenSpace)
370
+
371
+ When a learning identifies that an existing skill's instructions are **wrong or outdated**:
372
+ ```bash
373
+ ~/.config/squadrant/scripts/fix-skill.sh "{spokeVaultPath}" "{skill-name}" "{corrected markdown body}"
374
+ ```
375
+
376
+ This backs up the old version and writes the fix. Use when:
377
+ - A captured skill led to a failed task
378
+ - Instructions in a skill are now incorrect due to project changes
379
+ - A workaround in a skill is no longer needed
380
+
381
+ ## Quality Tracking
382
+
383
+ Each learning and captured skill tracks:
384
+ - `times_loaded` — how often it was read into context
385
+ - `times_useful` — how often it actually helped (agent marks it)
386
+ - `times_used` / `times_successful` — for captured skills
387
+
388
+ Use these metrics to prune stale knowledge:
389
+ - Learning loaded 5+ times but never useful → skip it
390
+ - Skill used 3+ times but never successful → flag for FIX or removal