@crouton-kit/crouter 0.3.14 → 0.3.15

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 (220) hide show
  1. package/dist/build-root.d.ts +8 -0
  2. package/dist/build-root.js +30 -0
  3. package/dist/builtin-personas/design/base.md +3 -7
  4. package/dist/builtin-personas/design/orchestrator.md +4 -3
  5. package/dist/builtin-personas/developer/base.md +3 -7
  6. package/dist/builtin-personas/developer/orchestrator.md +5 -4
  7. package/dist/builtin-personas/explore/base.md +3 -7
  8. package/dist/builtin-personas/explore/orchestrator.md +1 -5
  9. package/dist/builtin-personas/general/base.md +2 -4
  10. package/dist/builtin-personas/general/orchestrator.md +2 -4
  11. package/dist/builtin-personas/lifecycle/resident.md +2 -0
  12. package/dist/builtin-personas/lifecycle/terminal.md +6 -0
  13. package/dist/builtin-personas/orchestration-kernel.md +42 -3
  14. package/dist/builtin-personas/plan/base.md +3 -5
  15. package/dist/builtin-personas/plan/orchestrator.md +5 -4
  16. package/dist/builtin-personas/plan/reviewers/architecture-fit/base.md +9 -0
  17. package/dist/builtin-personas/plan/reviewers/code-smells/base.md +9 -0
  18. package/dist/builtin-personas/plan/reviewers/pattern-consistency/base.md +9 -0
  19. package/dist/builtin-personas/plan/reviewers/requirements-coverage/base.md +9 -0
  20. package/dist/builtin-personas/plan/reviewers/security/base.md +9 -0
  21. package/dist/builtin-personas/review/base.md +3 -5
  22. package/dist/builtin-personas/review/orchestrator.md +2 -6
  23. package/dist/builtin-personas/runtime-base.md +3 -19
  24. package/dist/builtin-personas/spec/base.md +3 -5
  25. package/dist/builtin-personas/spec/orchestrator.md +4 -3
  26. package/dist/builtin-personas/spine/has-manager.md +10 -0
  27. package/dist/builtin-personas/spine/no-manager.md +2 -0
  28. package/dist/builtin-skills/skills/crouter-development/personas/SKILL.md +96 -0
  29. package/dist/builtin-skills/skills/crouter-development/personas/base-prompt/SKILL.md +49 -0
  30. package/dist/builtin-skills/skills/crouter-development/personas/orchestrator-prompt/SKILL.md +49 -0
  31. package/dist/builtin-skills/skills/planning/SKILL.md +1 -1
  32. package/dist/builtin-skills/skills/spec/SKILL.md +2 -2
  33. package/dist/cli.js +6 -29
  34. package/dist/commands/attention.js +76 -7
  35. package/dist/commands/canvas-prune.d.ts +2 -0
  36. package/dist/commands/canvas-prune.js +66 -0
  37. package/dist/commands/canvas.js +5 -8
  38. package/dist/commands/chord.d.ts +2 -0
  39. package/dist/commands/chord.js +143 -0
  40. package/dist/commands/daemon.js +8 -5
  41. package/dist/commands/dashboard.js +2 -0
  42. package/dist/commands/human/prompts.js +28 -27
  43. package/dist/commands/human/queue.js +30 -14
  44. package/dist/commands/human/shared.d.ts +26 -21
  45. package/dist/commands/human/shared.js +44 -66
  46. package/dist/commands/human.js +4 -14
  47. package/dist/commands/node.d.ts +11 -0
  48. package/dist/commands/node.js +221 -98
  49. package/dist/commands/pkg/market-inspect.js +6 -4
  50. package/dist/commands/pkg/market-manage.js +10 -6
  51. package/dist/commands/pkg/market.js +2 -4
  52. package/dist/commands/pkg/plugin-inspect.js +6 -4
  53. package/dist/commands/pkg/plugin-manage.js +12 -7
  54. package/dist/commands/pkg/plugin.js +2 -4
  55. package/dist/commands/pkg.js +0 -4
  56. package/dist/commands/push.js +178 -15
  57. package/dist/commands/revive.js +5 -3
  58. package/dist/commands/skill/author.js +6 -4
  59. package/dist/commands/skill/find.js +8 -5
  60. package/dist/commands/skill/read.js +2 -0
  61. package/dist/commands/skill/state.js +6 -4
  62. package/dist/commands/skill.js +0 -6
  63. package/dist/commands/sys/config.js +21 -7
  64. package/dist/commands/sys/doctor.js +2 -0
  65. package/dist/commands/sys/update.js +4 -0
  66. package/dist/commands/sys.js +0 -6
  67. package/dist/commands/tmux-spread.d.ts +2 -0
  68. package/dist/commands/tmux-spread.js +130 -0
  69. package/dist/core/__tests__/canvas-inbox-watcher.test.js +25 -0
  70. package/dist/core/__tests__/child-followup.test.d.ts +1 -0
  71. package/dist/core/__tests__/child-followup.test.js +83 -0
  72. package/dist/core/__tests__/close.test.d.ts +1 -0
  73. package/dist/core/__tests__/close.test.js +148 -0
  74. package/dist/core/__tests__/context-intro.test.d.ts +1 -0
  75. package/dist/core/__tests__/context-intro.test.js +196 -0
  76. package/dist/core/__tests__/daemon-boot.test.d.ts +1 -0
  77. package/dist/core/__tests__/daemon-boot.test.js +93 -0
  78. package/dist/core/__tests__/daemon-liveness.test.d.ts +1 -0
  79. package/dist/core/__tests__/daemon-liveness.test.js +223 -0
  80. package/dist/core/__tests__/focuses.test.d.ts +1 -0
  81. package/dist/core/__tests__/focuses.test.js +259 -0
  82. package/dist/core/__tests__/fork.test.d.ts +1 -0
  83. package/dist/core/__tests__/fork.test.js +91 -0
  84. package/dist/core/__tests__/home-session.test.d.ts +1 -0
  85. package/dist/core/__tests__/home-session.test.js +153 -0
  86. package/dist/core/__tests__/human-cancel-guard.test.d.ts +1 -0
  87. package/dist/core/__tests__/human-cancel-guard.test.js +49 -0
  88. package/dist/core/__tests__/keystone.test.d.ts +1 -0
  89. package/dist/core/__tests__/keystone.test.js +185 -0
  90. package/dist/core/__tests__/kickoff.test.d.ts +1 -0
  91. package/dist/core/__tests__/kickoff.test.js +89 -0
  92. package/dist/core/__tests__/lifecycle.test.d.ts +1 -0
  93. package/dist/core/__tests__/lifecycle.test.js +178 -0
  94. package/dist/core/__tests__/listing-completeness.test.d.ts +1 -0
  95. package/dist/core/__tests__/listing-completeness.test.js +31 -0
  96. package/dist/core/__tests__/memory.test.d.ts +1 -0
  97. package/dist/core/__tests__/memory.test.js +152 -0
  98. package/dist/core/__tests__/migration.test.d.ts +1 -0
  99. package/dist/core/__tests__/migration.test.js +238 -0
  100. package/dist/core/__tests__/pane-column.test.d.ts +1 -0
  101. package/dist/core/__tests__/pane-column.test.js +153 -0
  102. package/dist/core/__tests__/passive-subscription.test.js +24 -1
  103. package/dist/core/__tests__/persona-compose.test.d.ts +1 -0
  104. package/dist/core/__tests__/persona-compose.test.js +53 -0
  105. package/dist/core/__tests__/persona-subkind.test.d.ts +1 -0
  106. package/dist/core/__tests__/persona-subkind.test.js +62 -0
  107. package/dist/core/__tests__/persona.test.d.ts +1 -0
  108. package/dist/core/__tests__/persona.test.js +107 -0
  109. package/dist/core/__tests__/placement-focus.test.d.ts +1 -0
  110. package/dist/core/__tests__/placement-focus.test.js +244 -0
  111. package/dist/core/__tests__/placement-reconcile.test.d.ts +1 -0
  112. package/dist/core/__tests__/placement-reconcile.test.js +212 -0
  113. package/dist/core/__tests__/placement-revive.test.d.ts +1 -0
  114. package/dist/core/__tests__/placement-revive.test.js +238 -0
  115. package/dist/core/__tests__/placement-teardown.test.d.ts +1 -0
  116. package/dist/core/__tests__/placement-teardown.test.js +183 -0
  117. package/dist/core/__tests__/prune.test.d.ts +1 -0
  118. package/dist/core/__tests__/prune.test.js +116 -0
  119. package/dist/core/__tests__/push-final-guard.test.d.ts +1 -0
  120. package/dist/core/__tests__/push-final-guard.test.js +71 -0
  121. package/dist/core/__tests__/relaunch.test.d.ts +1 -0
  122. package/dist/core/__tests__/relaunch.test.js +328 -0
  123. package/dist/core/__tests__/reset.test.js +26 -7
  124. package/dist/core/__tests__/revive.test.d.ts +1 -0
  125. package/dist/core/__tests__/revive.test.js +217 -0
  126. package/dist/core/__tests__/spawn-root.test.d.ts +1 -0
  127. package/dist/core/__tests__/spawn-root.test.js +73 -0
  128. package/dist/core/__tests__/steer-note.test.d.ts +1 -0
  129. package/dist/core/__tests__/steer-note.test.js +39 -0
  130. package/dist/core/__tests__/stop-guard.test.d.ts +1 -0
  131. package/dist/core/__tests__/stop-guard.test.js +82 -0
  132. package/dist/core/__tests__/subcommand-tier.test.js +35 -33
  133. package/dist/core/__tests__/tmux-surface.test.d.ts +1 -0
  134. package/dist/core/__tests__/tmux-surface.test.js +106 -0
  135. package/dist/core/__tests__/unknown-path.test.js +8 -2
  136. package/dist/core/canvas/attention.d.ts +10 -0
  137. package/dist/core/canvas/attention.js +40 -0
  138. package/dist/core/canvas/canvas.d.ts +66 -7
  139. package/dist/core/canvas/canvas.js +209 -21
  140. package/dist/core/canvas/db.d.ts +8 -0
  141. package/dist/core/canvas/db.js +206 -4
  142. package/dist/core/canvas/focuses.d.ts +22 -0
  143. package/dist/core/canvas/focuses.js +80 -0
  144. package/dist/core/canvas/index.d.ts +3 -0
  145. package/dist/core/canvas/index.js +3 -0
  146. package/dist/core/canvas/labels.d.ts +27 -0
  147. package/dist/core/canvas/labels.js +36 -0
  148. package/dist/core/canvas/render.js +25 -10
  149. package/dist/core/canvas/telemetry.d.ts +14 -0
  150. package/dist/core/canvas/telemetry.js +35 -0
  151. package/dist/core/canvas/types.d.ts +115 -12
  152. package/dist/core/command.d.ts +25 -1
  153. package/dist/core/command.js +23 -15
  154. package/dist/core/config.js +36 -2
  155. package/dist/core/feed/feed.js +3 -3
  156. package/dist/core/feed/inbox.d.ts +3 -1
  157. package/dist/core/feed/inbox.js +45 -5
  158. package/dist/core/feed/passive.js +24 -11
  159. package/dist/core/help.d.ts +26 -13
  160. package/dist/core/help.js +44 -37
  161. package/dist/core/personas/index.d.ts +1 -1
  162. package/dist/core/personas/index.js +1 -1
  163. package/dist/core/personas/loader.d.ts +40 -1
  164. package/dist/core/personas/loader.js +63 -1
  165. package/dist/core/personas/resolve.d.ts +13 -6
  166. package/dist/core/personas/resolve.js +46 -34
  167. package/dist/core/runtime/bearings.d.ts +20 -0
  168. package/dist/core/runtime/bearings.js +92 -0
  169. package/dist/core/runtime/close.d.ts +14 -0
  170. package/dist/core/runtime/close.js +151 -0
  171. package/dist/core/runtime/demote.js +27 -10
  172. package/dist/core/runtime/front-door.js +1 -1
  173. package/dist/core/runtime/kickoff.d.ts +23 -6
  174. package/dist/core/runtime/kickoff.js +92 -36
  175. package/dist/core/runtime/launch.d.ts +24 -12
  176. package/dist/core/runtime/launch.js +75 -19
  177. package/dist/core/runtime/lifecycle.d.ts +13 -0
  178. package/dist/core/runtime/lifecycle.js +86 -0
  179. package/dist/core/runtime/memory.d.ts +43 -0
  180. package/dist/core/runtime/memory.js +165 -0
  181. package/dist/core/runtime/naming.d.ts +22 -0
  182. package/dist/core/runtime/naming.js +166 -0
  183. package/dist/core/runtime/nodes.d.ts +32 -1
  184. package/dist/core/runtime/nodes.js +60 -10
  185. package/dist/core/runtime/persona.d.ts +25 -0
  186. package/dist/core/runtime/persona.js +139 -0
  187. package/dist/core/runtime/placement.d.ts +287 -0
  188. package/dist/core/runtime/placement.js +663 -0
  189. package/dist/core/runtime/presence.d.ts +7 -15
  190. package/dist/core/runtime/presence.js +90 -66
  191. package/dist/core/runtime/promote.d.ts +14 -7
  192. package/dist/core/runtime/promote.js +57 -67
  193. package/dist/core/runtime/reset.d.ts +47 -4
  194. package/dist/core/runtime/reset.js +223 -52
  195. package/dist/core/runtime/revive.d.ts +26 -2
  196. package/dist/core/runtime/revive.js +166 -39
  197. package/dist/core/runtime/spawn.d.ts +20 -5
  198. package/dist/core/runtime/spawn.js +163 -43
  199. package/dist/core/runtime/stop-guard.d.ts +1 -1
  200. package/dist/core/runtime/stop-guard.js +18 -8
  201. package/dist/core/runtime/tmux.d.ts +100 -14
  202. package/dist/core/runtime/tmux.js +201 -28
  203. package/dist/core/spawn.js +15 -0
  204. package/dist/daemon/crtrd.d.ts +12 -1
  205. package/dist/daemon/crtrd.js +152 -34
  206. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.d.ts +1 -0
  207. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +266 -0
  208. package/dist/pi-extensions/canvas-commands.js +16 -13
  209. package/dist/pi-extensions/canvas-context-intro.d.ts +70 -0
  210. package/dist/pi-extensions/canvas-context-intro.js +164 -0
  211. package/dist/pi-extensions/canvas-goal-capture.d.ts +3 -0
  212. package/dist/pi-extensions/canvas-goal-capture.js +15 -1
  213. package/dist/pi-extensions/canvas-inbox-watcher.js +11 -0
  214. package/dist/pi-extensions/canvas-nav.d.ts +12 -4
  215. package/dist/pi-extensions/canvas-nav.js +586 -262
  216. package/dist/pi-extensions/canvas-stophook.d.ts +16 -0
  217. package/dist/pi-extensions/canvas-stophook.js +344 -228
  218. package/dist/types.d.ts +28 -0
  219. package/dist/types.js +16 -0
  220. package/package.json +1 -1
@@ -0,0 +1,96 @@
1
+ ---
2
+ name: crouter-development/personas
3
+ type: playbook
4
+ description: How to define a custom node kind (persona) for crtr — base/orchestrator files, the frontmatter contract, scope resolution and overrides, and how to write the prose. Use when adding a new `--kind`, overriding a builtin agent, or debugging persona resolution.
5
+ keywords: [persona, node kind, --kind, orchestrator, base, system prompt]
6
+ ---
7
+
8
+ # Authoring crtr personas (custom node kinds)
9
+
10
+ A **persona** is what `--kind` resolves to: the markdown that becomes a node's system prompt plus the launch knobs (model/tools/extensions/lifecycle). Defining one adds a new spawnable agent type to the canvas.
11
+
12
+ Audience: LLM agents creating or overriding a crtr node kind.
13
+
14
+ ## When to add a kind (vs reuse a builtin)
15
+
16
+ Builtins cover the common shapes: `explore spec design plan developer review general`.
17
+
18
+ - **Reuse a builtin** when the work fits one. Don't fork `developer` to tweak one sentence.
19
+ - **Add a kind** for a recurring specialist with its own deliverable + reporting contract that no builtin matches — e.g. `researcher`, `migration`, `release`.
20
+ - **Override a builtin** by creating a same-named dir at user/project scope — it *shadows* the builtin (precedence below), it doesn't edit the shipped file.
21
+
22
+ Never edit `src/builtin-personas/` for a local need — that ships to everyone. Override at scope instead.
23
+
24
+ ## Layout
25
+
26
+ ```
27
+ <root>/personas/
28
+ ├── <kind>/
29
+ │ ├── base.md # worker persona (mode=base)
30
+ │ └── orchestrator.md # orchestrator persona (mode=orchestrator) — optional
31
+ ├── orchestration-kernel.md # shared; @include-d by orchestrator files
32
+ └── runtime-base.md # shared; prepended to EVERY persona automatically
33
+ ```
34
+
35
+ A kind exists once `<kind>/` holds a `base.md` **or** `orchestrator.md`. `crtr node new --kind <x>` validates against the discovered set and errors with the valid list — your fast existence check.
36
+
37
+ ## Scope + precedence
38
+
39
+ Resolution is **project > user > builtin**, resolved per file:
40
+
41
+ | Scope | Path |
42
+ |---|---|
43
+ | project | `<project>/.crouter/personas/<kind>/` — checked into the repo |
44
+ | user | `~/.crouter/personas/<kind>/` — personal, all your projects |
45
+ | builtin | ships with the CLI |
46
+
47
+ Personas are **scope-root content, not plugin content** — they don't ship via plugins or marketplaces (the loader only searches `<scope>/personas/`). To share a kind, commit it to a repo's `.crouter/personas/` (project) or copy it into `~/.crouter/personas/` (user).
48
+
49
+ ## The two files
50
+
51
+ **`base.md`** — the worker. Second person. State scope → method → deliverable, and end by reporting via `crtr push final`. Default lifecycle `terminal` (finishes in one window). → how to write one: `[[crouter-development/personas/base-prompt]]`.
52
+
53
+ **`orchestrator.md`** — the owner that delegates to children and never does the work itself. Name the child kinds it drives and set per-phase exit criteria. **Must end with `@include orchestration-kernel.md`** — the loader inlines it; without it the orchestrator boots with no fan-out protocol. Default lifecycle `resident`. → how to write one: `[[crouter-development/personas/orchestrator-prompt]]`.
54
+
55
+ If a kind has only `base.md`, `--mode orchestrator` composes `base.md body + kernel` and forces `resident` — so write `orchestrator.md` only when the worker and owner prose genuinely differ.
56
+
57
+ ## Frontmatter contract
58
+
59
+ YAML frontmatter on either file supplies launch knobs; the body is the system prompt.
60
+
61
+ | Field | Type | Effect |
62
+ |---|---|---|
63
+ | `lifecycle` | `terminal`\|`resident` | terminal = finishes + reaps; resident = interactive/long-lived. Defaults: base→terminal, orchestrator→resident. |
64
+ | `model` | string | pi model override (normalized). Omit to inherit the default. |
65
+ | `tools` | string[] | pi tool allowlist. Omit for all tools. |
66
+ | `extensions` | string[] | pi extensions, **added after** the always-on canvas extensions. |
67
+ | `skills` | string[] | skills attached at launch. |
68
+ | `roadmapSkill` | string | orchestrator only — a skill whose body is injected as roadmap-shaping guidance when the node runs as an orchestrator. |
69
+
70
+ `resolve()` never throws: a missing/empty persona falls back to `"You are a <kind> agent…"` defaults, so a node always boots. `runtime-base.md` (the push/finish/delegate/feed/ask protocol) is prepended to every persona — **don't restate it in the body.**
71
+
72
+ ## @include
73
+
74
+ `@include <filename>` inlines another persona-root file, resolved through the same project>user>builtin chain. Used for `orchestration-kernel.md`; drop an `orchestration-kernel.md` at user/project scope to change orchestrator protocol fleet-wide.
75
+
76
+ ## Dev loop
77
+
78
+ ```bash
79
+ mkdir -p ~/.crouter/personas/researcher
80
+ $EDITOR ~/.crouter/personas/researcher/base.md # frontmatter + prose
81
+ crtr node new --kind researcher "map the auth flow" # spawn; a bad --kind prints the valid kinds
82
+ ```
83
+
84
+ No scaffold command — create the dir + files by hand. Copy a builtin (`explore/base.md`, `developer/orchestrator.md`) as a starting template.
85
+
86
+ ## Failure modes
87
+
88
+ - **Orchestrator with no `@include orchestration-kernel.md`** — boots without the fan-out protocol; can't delegate. Always include it.
89
+ - **Restating runtime-base** — the push/finish/delegate protocol is already prepended. Duplicating it wastes context and drifts out of sync.
90
+ - **`lifecycle: resident` on a worker `base.md`** — the node never finishes. Reserve `resident` for interactive/long-lived kinds.
91
+ - **Editing `src/builtin-personas/` for a local need** — ships to everyone. Override at user/project scope.
92
+ - **Kind not listed after creating the dir** — neither `base.md` nor `orchestrator.md` is present, or the filename is wrong. The dir alone doesn't register a kind.
93
+
94
+ ## Related
95
+
96
+ `[[crouter-development/plugins]]` packages *skills* for distribution — personas are distributed differently (committed to a scope's `personas/`), so a kind is never part of a plugin.
@@ -0,0 +1,49 @@
1
+ ---
2
+ name: crouter-development/personas/base-prompt
3
+ type: playbook
4
+ description: How to write a base persona prompt (base.md) — the system prompt for a single-window worker node. Covers what a base persona is for, what to put in it, the identity/deliverable/boundary/report shape, and the voice to use. Use when writing or revising a <kind>/base.md.
5
+ keywords: [base persona, base.md, worker prompt, system prompt, terminal node]
6
+ ---
7
+
8
+ # Writing a base persona prompt
9
+
10
+ `base.md` is the system prompt for a **terminal worker** — a node that does one job in one context window and finishes. Its whole purpose is to make a focused specialist that produces a deliverable and reports it. This skill is the philosophy of what belongs in a base persona; for file mechanics and frontmatter, see `[[crouter-development/personas]]`.
11
+
12
+ Audience: LLM agents writing a `<kind>/base.md`.
13
+
14
+ ## What a base persona is for
15
+
16
+ A base worker **does the work itself and ends.** It is not a manager. The persona points a fresh, capable model at one kind of task and makes it produce the right artifact without supervision. Everything in the body serves that: who it is, what good output looks like, what's out of bounds, and how it hands the result back.
17
+
18
+ A base persona is a **system prompt**, not a task. Write the durable role — the identity and standards that hold for *every* task of this kind — and let the spawn-time prompt carry the specific task. Never bake one task's details into the persona.
19
+
20
+ ## The four things to put in it
21
+
22
+ In order. Most base personas are 1–3 short paragraphs total.
23
+
24
+ 1. **Identity — one line, second person.** Open `"You are a <role> agent."` This is a system-prompt identity declaration; `"You are X"` is correct here (it would be wrong in a task prompt). Name the role sharply — "fast codebase exploration agent", "code review agent" — so the model knows which hat it wears.
25
+
26
+ 2. **The deliverable and its shape.** State *what good output is*, not a step-by-step procedure. Name the artifact and its structure: design names its sections, review names its severity tiers, explore demands `file:line` citations. You set the target the model steers toward — describe the target, not a checklist of moves to reach it. Fix the *what*; delegate the *how* to the model's judgment.
27
+
28
+ 3. **The boundaries that keep it in its lane.** One or two constraints that carve this kind out from its neighbors: explore is "read-only — do not modify"; design and plan "do not implement"; developer "throw errors early, no silent fallbacks". These earn their negative framing because the model has a real prior toward crossing the line — a design agent *will* start writing code if you don't fence it off. Keep them to genuine lane boundaries; don't pile on don'ts the model wouldn't trip over anyway.
29
+
30
+ 4. **The report.** Close by stating the deliverable is reported via `crtr push final` — the one runtime rule worth reinforcing in the body, because stopping without it is the most common worker failure. Everything else in the protocol (delegating, the feed, escalating) is already prepended by `runtime-base.md`; do not re-teach it.
31
+
32
+ ## Keep it shallow
33
+
34
+ A base worker may spawn a helper or two for a targeted sub-task, but most of the work must be its own. If a kind's job routinely needs broad fan-out, it isn't a base worker — it's an orchestrator (`[[crouter-development/personas/orchestrator-prompt]]`). The base persona should make a do-er, not a delegator; say so explicitly when the kind is tempting to over-delegate (developer: "keep the delegation shallow").
35
+
36
+ ## Voice
37
+
38
+ - **Second person + imperative.** "You are X." "Answer the question." "Do not modify files." Direct instruction for a direct worker.
39
+ - **Positive framing for standards.** Describe the output you want, not a list of failures to avoid — "quote concrete `file:line` references" beats "don't be vague".
40
+ - **Reserve hard rules.** CAPS / MUST only for the genuine non-negotiable — usually the finish rule and the lane boundary. If everything is critical, nothing is.
41
+ - **Density.** This loads as the system prompt on *every* spawn of the kind. No preamble, no fluff — every line is the identity, the deliverable, a boundary, or the report.
42
+
43
+ ## Failure modes
44
+
45
+ - **Procedure instead of target.** A numbered how-to ages badly and fights the model's judgment. State the deliverable's shape; let it choose the path.
46
+ - **Restating runtime-base.** Re-teaching delegation/feed/escalation duplicates the prepended protocol and drifts out of sync. Reference only `push final`, as the deliverable.
47
+ - **Task leakage.** Specifics of one task baked into the persona make every future spawn wear yesterday's job. Keep the body to the durable role.
48
+ - **No report close.** A base persona that never names `crtr push final` produces workers that go quiet and get re-prompted. Always close on the deliverable.
49
+ - **A manager in worker's clothing.** If the body spends more ink on delegation than on doing, you've written an orchestrator — split it.
@@ -0,0 +1,49 @@
1
+ ---
2
+ name: crouter-development/personas/orchestrator-prompt
3
+ type: playbook
4
+ description: How to write an orchestrator persona prompt (orchestrator.md) — the system prompt for a resident coordinator node. Covers the kernel-vs-kind split, what belongs in the per-kind body, naming the child pipeline, the roadmapSkill pointer, and the @include rule. Use when writing or revising a <kind>/orchestrator.md.
5
+ keywords: [orchestrator persona, orchestrator.md, orchestration-kernel, roadmapSkill, resident node]
6
+ ---
7
+
8
+ # Writing an orchestrator persona prompt
9
+
10
+ `orchestrator.md` is the system prompt for a **resident coordinator** — a long-lived node that owns a goal too large for one window and delivers it by decomposing, delegating, integrating, and surviving context refreshes. This skill is the philosophy of what belongs in an orchestrator persona; for file mechanics and frontmatter, see `[[crouter-development/personas]]`.
11
+
12
+ Audience: LLM agents writing a `<kind>/orchestrator.md`.
13
+
14
+ ## The one rule that shapes everything: kernel vs kind
15
+
16
+ Every orchestrator persona ends with `@include orchestration-kernel.md`. The kernel already teaches the **universal orchestrator protocol** — the wake loop, the roadmap structure and discipline, long-term memory, working in phases, delegating outcomes, steering what comes back, engaging the human, and the pre-finish checklist. It is long and complete.
17
+
18
+ So your `orchestrator.md` body carries **only the delta** — what is specific to this kind. If a line you're about to write is true of orchestrators in general, the kernel already says it; cut it. Subtract before you add: the body is usually 1–3 short paragraphs *on top of* the kernel, not a re-derivation of how to orchestrate.
19
+
20
+ ## What the per-kind body puts in
21
+
22
+ 1. **Identity — the kind's ownership.** Open `"You are a **<kind> orchestrator** — …"` and say what this kind *owns*: a feature-sized goal (developer), a specification effort (spec), a review surface (review), a research question (explore). Bold the role. One sentence on what "owning it" means here.
23
+
24
+ 2. **The child kinds it drives, and the pipeline.** Name the specialists this orchestrator delegates to and the order it runs them: developer drives `explore → spec → plan → developer → review` as a "spec → plan → implement → review → fix → validate" pipeline; spec runs `SHAPE → DESIGN → REQUIREMENTS` stages; review fans `review` children across units. The flow is the kind's signature — make it explicit so delegation isn't ad hoc.
25
+
26
+ 3. **A pointer to the methodology skill — don't inline it.** Set `roadmapSkill: <skill>` in frontmatter and tell the body to read `crtr skill read <kind>` before shaping the roadmap. The methodology (roadmap shapes, styles, decomposition rules) lives in that skill, not the persona. The persona points; the skill teaches.
27
+
28
+ 4. **The kind's quality bar.** State the domain-specific exit criteria the kernel can't: developer's "implementation is done when provably correct against the spec, review done when a non-implementer cleared all Major/Critical findings, validation done end-to-end in the real runtime." This is where you set the ceiling for *this* kind of work.
29
+
30
+ 5. **What integration means here.** Every orchestrator's deliverable is the *synthesis*, never the child transcripts — but say what synthesis looks like for this kind: explore reconciles findings into one architecture answer; review deduplicates and severity-normalises into one verdict; design verifies every contract is honored on both sides. "Integrate, don't concatenate," made concrete.
31
+
32
+ ## The recurring sizing rule
33
+
34
+ When a unit is itself too big for one window, the orchestrator creates that child **directly as `--mode orchestrator`**, not a base worker it counts on to self-promote. This appears in nearly every orchestrator persona because it's domain-flavored — *which* child kind gets promoted differs by orchestrator. State it for yours; a node born an orchestrator is strictly more capable than one hoping to become one.
35
+
36
+ ## Voice
37
+
38
+ - **Second person identity, then operations.** "You are a **developer orchestrator**…" then "Run the build as a delegation pipeline…".
39
+ - **Positive, concrete framing.** Name the pipeline and the exit criteria; don't enumerate things not to do. The one earned negative is the load-bearing boundary — "never by writing the code yourself" — which counters a real model prior to just do the work.
40
+ - **Reserve hard rules** for genuine non-negotiables (the no-self-execution boundary, the no-self-promotion sizing rule). Density matters: this loads on every revive.
41
+ - **End with the include.** `@include orchestration-kernel.md` on its own line, last. Without it the orchestrator boots with no protocol and cannot run the loop.
42
+
43
+ ## Failure modes
44
+
45
+ - **Re-teaching the kernel.** Re-explaining the wake loop, roadmap sections, yielding, or memory duplicates the kernel and drifts. If it's universal, delete it.
46
+ - **Missing `@include`.** No kernel = no loop, no roadmap discipline, no finish checklist. Always include it, last.
47
+ - **Inlining the methodology.** Roadmap shapes belong in the `roadmapSkill`, not the persona. Point at it.
48
+ - **No named pipeline.** An orchestrator that doesn't name its child kinds and their order produces scattershot delegation. The flow is the value.
49
+ - **Forgetting the no-self-execution rule.** Without an explicit boundary, the model drifts into doing the work itself and exhausts its context with the goal half-met — the exact failure orchestrators exist to avoid.
@@ -12,7 +12,7 @@ Every planning effort produces either a flat plan or a decomposed plan (index +
12
12
 
13
13
  **Use a flat plan** when the work is a single coherent domain, involves fewer than ~6 files, and can be written at consistent task granularity without exceeding roughly 150–200 lines. A flat plan has an overview, ordered phases, and a verification section. No sub-plans. One file.
14
14
 
15
- **Use a decomposed plan** when the change spans multiple domains (e.g., data layer, API surface, UI), involves 6+ files, or would require a master plan that cannot be written at consistent granularity without ballooning. In this case: produce an index plan (the navigable master) and delegate each domain slice to a `plan`-kind child node, giving each child its slice scope, the relevant portion of the spec, and its place in the dependency graph. The index plan is the synthesis artifact — it lists all sub-plans by path, defines phases and their dependencies, and contains a task table the implementation orchestrator can execute directly. Detail lives in sub-plans; the master is not allowed to carry it.
15
+ **Use a decomposed plan** when the change spans multiple domains (e.g., data layer, API surface, UI), involves 6+ files, or would require a master plan that cannot be written at consistent granularity without ballooning. In this case: produce an index plan (the navigable master) and delegate each domain slice to a `plan`-kind child node, giving each child its slice scope, the relevant portion of the spec, and its place in the dependency graph. A slice that itself decomposes further — multiple sub-domains, more than one window's worth of planning — goes to a `plan` sub-orchestrator created directly (`crtr node new --kind plan --mode orchestrator`), not a base child relied on to promote itself. The index plan is the synthesis artifact — it lists all sub-plans by path, defines phases and their dependencies, and contains a task table the implementation orchestrator can execute directly. Detail lives in sub-plans; the master is not allowed to carry it.
16
16
 
17
17
  **The decomposition trigger is domain boundary, not size alone.** Three backend files and three frontend files are two domains even if the total count is modest — plan them separately and synthesize, because the integration seam is where bugs live and one agent reading both halves won't catch them as cleanly as two agents each going deep.
18
18
 
@@ -20,7 +20,7 @@ Gate: human confirms readiness to proceed to design.
20
20
 
21
21
  Design produces the blueprint: components and their topology, end-to-end flows, files and directories affected, locked decisions, and open questions resolved. The altitude is infra/services — no function signatures, no algorithm descriptions, no implementation ordering. Design answers "what shape does this take?" — planning answers "how is it built?"
22
22
 
23
- Small or simple design work (one surface, clear scope, few components) can be done by a single `design`-kind child node. Large or complex design work — multi-surface features, multiple interacting subsystems, significant architectural choices — must be delegated to a **design orchestrator** (a resident `design`-kind node), which decomposes the design internally and returns a finished artifact. The trigger for spawning a design orchestrator rather than a base design node: if the design effort has more than one distinct phase or more than ~5 interacting components, use an orchestrator.
23
+ Small or simple design work (one surface, clear scope, few components) can be done by a single `design`-kind child node. Large or complex design work — multi-surface features, multiple interacting subsystems, significant architectural choices — must be delegated to a **design orchestrator** (a `design`-kind node created directly with `--mode orchestrator`), which decomposes the design internally and returns a finished artifact. The trigger for spawning a design orchestrator rather than a base design node: if the design effort has more than one distinct phase or more than ~5 interacting components, use an orchestrator.
24
24
 
25
25
  Gate: human approves the rendered design artifact.
26
26
 
@@ -64,7 +64,7 @@ After yield-and-revive, `## Strategy / phases` plus `## Active context` must let
64
64
 
65
65
  Spawn a base `design` node (terminal) when: the design surface is bounded, one component or subsystem, no multi-phase structure required. The node produces `context/design.md` and `context/design.json` and returns.
66
66
 
67
- Spawn a `design` orchestrator (resident) when: the feature spans multiple subsystems, has distinct implementation phases that need separate design treatment, or the design effort is itself likely to fill one context window before it's finished. Pass it the shape brief as its goal; it owns the decomposition and integration internally and reports a finished design artifact when done.
67
+ Spawn a `design` orchestrator (resident) when: the feature spans multiple subsystems, has distinct implementation phases that need separate design treatment, or the design effort is itself likely to fill one context window before it's finished. Create it directly as an orchestrator — `crtr node new --kind design --mode orchestrator` — rather than spawning a base design node and counting on it to promote itself once it discovers the surface is too big; self-promotion is unreliable, and a node born an orchestrator is strictly more capable than one hoping to become one. Pass it the shape brief as its goal; it owns the decomposition and integration internally and reports a finished design artifact when done.
68
68
 
69
69
  In either case, the spec orchestrator waits for the design to land and the human to approve it before proceeding.
70
70
 
package/dist/cli.js CHANGED
@@ -1,36 +1,13 @@
1
1
  #!/usr/bin/env node
2
- import { defineRoot, runCli } from './core/command.js';
3
- import { registerSkill } from './commands/skill.js';
4
- import { registerPkg } from './commands/pkg.js';
5
- import { registerHuman } from './commands/human.js';
6
- import { registerSys } from './commands/sys.js';
7
- import { registerPush, registerFeed } from './commands/push.js';
8
- import { registerNode } from './commands/node.js';
9
- import { registerCanvas } from './commands/canvas.js';
2
+ import { runCli } from './core/command.js';
3
+ import { buildRoot } from './build-root.js';
10
4
  import { maybeBootRoot } from './core/runtime/front-door.js';
11
5
  import { maybeAutoUpdate } from './core/auto-update.js';
12
6
  import { ensureBootSkill, ensureOfficialMarketplace, ensureProjectScope, ensureSlashCommands } from './core/bootstrap.js';
13
- // Root owns only the tagline and globals. Every subtree's concept line,
14
- // selection rubric, and any dynamic block it contributes to root -h are
15
- // declared on the subtree itself (its rootEntry) and assembled here by
16
- // defineRoot. Add a subtree to this list and it appears at root; nothing about
17
- // it is restated here.
18
- const root = defineRoot({
19
- tagline: 'crtr: agentic planning runtime.',
20
- globals: [
21
- { name: '-h', desc: 'print help for any node — append to any subcommand path' },
22
- ],
23
- subtrees: [
24
- registerSkill(),
25
- registerPkg(),
26
- registerHuman(),
27
- registerSys(),
28
- registerNode(),
29
- registerPush(),
30
- registerFeed(),
31
- registerCanvas(),
32
- ],
33
- });
7
+ // The full command tree is assembled in build-root.ts (shared with the
8
+ // listing-completeness test). Root owns only the tagline; every subtree
9
+ // declares its own representation.
10
+ const root = buildRoot();
34
11
  // The front door: bare `crtr` (or `crtr [dir] ["prompt"]`) boots a resident
35
12
  // root node and execs pi in this terminal. Recognized subcommands fall through
36
13
  // to the normal dispatcher. Must run before anything that assumes a subcommand.
@@ -13,13 +13,15 @@
13
13
  // Exported as a branch; `crtr canvas` (canvas.ts) mounts it.
14
14
  import { defineBranch, defineLeaf } from '../core/command.js';
15
15
  import { InputError } from '../core/io.js';
16
- import { getNode } from '../core/canvas/index.js';
17
- import { countAsks, pendingAsksForView, asksAcrossCanvas, } from '../core/canvas/attention.js';
16
+ import { getNode, view } from '../core/canvas/index.js';
17
+ import { countAsks, pendingAsksForView, asksAcrossCanvas, asksForNodes, } from '../core/canvas/attention.js';
18
18
  // ---------------------------------------------------------------------------
19
19
  // attention count
20
20
  // ---------------------------------------------------------------------------
21
21
  const attentionCount = defineLeaf({
22
22
  name: 'count',
23
+ description: 'total pending ask count (machine-parseable stdout.count)',
24
+ whenToUse: 'getting a single pending-ask count for a script or nav chrome to read (stdout.count is machine-parseable); scope with --node or --view, or default to canvas-wide',
23
25
  help: {
24
26
  name: 'canvas attention count',
25
27
  // stdout.count is parsed directly by the nav chrome — keep the contract.
@@ -90,6 +92,8 @@ const attentionCount = defineLeaf({
90
92
  // ---------------------------------------------------------------------------
91
93
  const attentionList = defineLeaf({
92
94
  name: 'list',
95
+ description: 'itemised list of cwds with pending asks',
96
+ whenToUse: 'finding which agents are blocked waiting on a human — an itemised list of the cwds with pending asks, oldest first, so you know where to go answer. Scope to a sub-DAG with --view or list canvas-wide. Use `canvas attention count` instead when a script just needs the number, or `canvas attention map` for per-node counts to label a UI',
93
97
  help: {
94
98
  name: 'canvas attention list',
95
99
  summary: 'list nodes with pending human asks, grouped by cwd, oldest first',
@@ -135,18 +139,83 @@ const attentionList = defineLeaf({
135
139
  },
136
140
  });
137
141
  // ---------------------------------------------------------------------------
142
+ // attention map
143
+ // ---------------------------------------------------------------------------
144
+ const attentionMap = defineLeaf({
145
+ name: 'map',
146
+ description: 'per-node ask counts for a visible set, batched in one pass',
147
+ whenToUse: 'labelling every node in a UI with its pending-ask count in one batched pass — the form nav chrome polls (one process, one JSON blob) instead of N count shell-outs',
148
+ help: {
149
+ name: 'canvas attention map',
150
+ summary: 'per-node pending-ask counts for a visible set of nodes in ONE pass — the batched form the nav chrome polls (one process, one JSON blob) instead of N count shell-outs',
151
+ params: [
152
+ {
153
+ kind: 'flag',
154
+ name: 'view',
155
+ type: 'string',
156
+ required: false,
157
+ constraint: 'Include this node and its whole sub-DAG (root + reports recursively). Union with --nodes. At least one of --view/--nodes is required.',
158
+ },
159
+ {
160
+ kind: 'flag',
161
+ name: 'nodes',
162
+ type: 'string',
163
+ required: false,
164
+ constraint: 'Comma-separated explicit node ids to include (e.g. ancestry + peers). Union with --view.',
165
+ },
166
+ ],
167
+ output: [
168
+ {
169
+ name: 'counts',
170
+ type: 'object',
171
+ required: true,
172
+ constraint: 'Map of node_id → pending ask count. Every requested id is present (0 when none).',
173
+ },
174
+ ],
175
+ outputKind: 'object',
176
+ effects: ['Read-only: scans each distinct cwd\'s humanloop interaction dir once.'],
177
+ },
178
+ run: async (input) => {
179
+ const viewId = input['view'];
180
+ const nodesRaw = input['nodes'];
181
+ if (viewId === undefined && (nodesRaw === undefined || nodesRaw.trim() === '')) {
182
+ throw new InputError({
183
+ error: 'missing_scope',
184
+ message: 'at least one of --view <id> or --nodes <a,b,c> is required',
185
+ next: 'Pass --view <root> to cover a sub-DAG, --nodes <a,b,c> for an explicit set, or both.',
186
+ });
187
+ }
188
+ const ids = new Set();
189
+ if (viewId !== undefined) {
190
+ if (getNode(viewId) === null) {
191
+ throw new InputError({
192
+ error: 'not_found',
193
+ message: `no node: ${viewId}`,
194
+ next: 'List nodes with `crtr node inspect list`.',
195
+ });
196
+ }
197
+ ids.add(viewId);
198
+ for (const id of view(viewId))
199
+ ids.add(id);
200
+ }
201
+ if (nodesRaw !== undefined) {
202
+ for (const id of nodesRaw.split(',').map((s) => s.trim()).filter((s) => s !== ''))
203
+ ids.add(id);
204
+ }
205
+ return { counts: asksForNodes([...ids]) };
206
+ },
207
+ });
208
+ // ---------------------------------------------------------------------------
138
209
  // Export — mounted under `crtr canvas`
139
210
  // ---------------------------------------------------------------------------
140
211
  export const attentionBranch = defineBranch({
141
212
  name: 'attention',
213
+ description: 'count/list pending human asks across the graph',
214
+ whenToUse: 'checking whether any agent on the canvas is blocked waiting on a human, and where: count the pending asks, list the cwds that have them, or map per-node counts. Scope with --node or --view, or go canvas-wide. Use `canvas dashboard` instead for the graph SHAPE, or `node inspect list` for a plain node roster',
142
215
  help: {
143
216
  name: 'canvas attention',
144
217
  summary: 'aggregate pending human asks across the canvas',
145
218
  model: 'Human asks are stored per-cwd by humanloop. `count` returns a single integer (stdout.count is parsed by nav chrome); `list` returns itemised entries. Scope with --node (one node) or --view (sub-DAG) — default is canvas-wide.',
146
- children: [
147
- { name: 'count', desc: 'total pending ask count (machine-parseable stdout.count)', useWhen: 'polling from a script or nav chrome' },
148
- { name: 'list', desc: 'itemised list of cwds with pending asks', useWhen: 'finding which agents need a human response' },
149
- ],
150
219
  },
151
- children: [attentionCount, attentionList],
220
+ children: [attentionCount, attentionList, attentionMap],
152
221
  });
@@ -0,0 +1,2 @@
1
+ import type { LeafDef } from '../core/command.js';
2
+ export declare const canvasPruneLeaf: LeafDef;
@@ -0,0 +1,66 @@
1
+ // `crtr canvas prune` — bounded retention for the node graph.
2
+ //
3
+ // The canvas never deleted a node before this: dead/done/canceled rows + their
4
+ // `nodes/<id>/` dirs accumulated without limit. `prune` is the retention sweep —
5
+ // remove TERMINAL nodes (dead | done | canceled) older than a TTL; the edges→nodes
6
+ // FK (ON DELETE CASCADE) GCs their edges, and each node's dir is removed too.
7
+ // Live nodes (active | idle, the daemon's domain) are never touched.
8
+ //
9
+ // Exported as a leaf; `crtr canvas` (canvas.ts) mounts it.
10
+ import { defineLeaf } from '../core/command.js';
11
+ import { pruneNodes } from '../core/canvas/index.js';
12
+ const DEFAULT_TTL_DAYS = 14;
13
+ export const canvasPruneLeaf = defineLeaf({
14
+ name: 'prune',
15
+ description: 'remove terminal nodes (dead/done/canceled) older than a TTL',
16
+ whenToUse: 'you want to bound the canvas\u2019s on-disk growth \u2014 sweep away nodes that are finished (done), crashed (dead), or closed (canceled) and older than a retention window, reclaiming their rows, edges (cascade-deleted by the schema), and `nodes/<id>/` dirs. Run it as an operator/cron chore; live nodes (active/idle) are never touched. Pass `--dry-run` first to see exactly what would go, `--ttl <days>` to widen or tighten the window',
17
+ help: {
18
+ name: 'canvas prune',
19
+ summary: 'delete terminal nodes older than a TTL (edges cascade, dirs removed); --dry-run to preview',
20
+ params: [
21
+ {
22
+ kind: 'flag',
23
+ name: 'ttl',
24
+ type: 'int',
25
+ required: false,
26
+ default: DEFAULT_TTL_DAYS,
27
+ constraint: `Retention window in days: only dead/done/canceled nodes created more than this many days ago are pruned. Default: ${DEFAULT_TTL_DAYS}.`,
28
+ },
29
+ {
30
+ kind: 'flag',
31
+ name: 'dry-run',
32
+ type: 'bool',
33
+ required: false,
34
+ default: false,
35
+ constraint: 'Report what WOULD be pruned without deleting anything.',
36
+ },
37
+ ],
38
+ output: [
39
+ { name: 'pruned', type: 'integer', required: true, constraint: 'How many nodes were pruned (0 under --dry-run since nothing is deleted; the candidate count is in `nodes`).' },
40
+ { name: 'dryRun', type: 'boolean', required: true, constraint: 'True when nothing was deleted (preview only).' },
41
+ { name: 'ttlDays', type: 'integer', required: true, constraint: 'The retention window used.' },
42
+ { name: 'nodes', type: 'object[]', required: true, constraint: 'One per pruned (or, under --dry-run, prunable) node: {node_id,status,created}.' },
43
+ ],
44
+ outputKind: 'object',
45
+ effects: [
46
+ 'Deletes matching `nodes` rows; their edges cascade-delete via the FK; each node\u2019s `nodes/<id>/` dir is removed.',
47
+ 'No-op on live nodes (active/idle) and on terminal nodes newer than the TTL.',
48
+ 'Under --dry-run: read-only, deletes nothing.',
49
+ ],
50
+ },
51
+ run: async (input) => {
52
+ const ttlDays = input['ttl'] ?? DEFAULT_TTL_DAYS;
53
+ const dryRun = input['dryRun'] ?? false;
54
+ const result = pruneNodes({ ttlDays, dryRun });
55
+ return {
56
+ pruned: dryRun ? 0 : result.pruned.length,
57
+ dryRun,
58
+ ttlDays,
59
+ nodes: result.pruned.map((p) => ({
60
+ node_id: p.node_id,
61
+ status: p.status,
62
+ created: p.created,
63
+ })),
64
+ };
65
+ },
66
+ });
@@ -11,6 +11,9 @@ import { dashboardLeaf } from './dashboard.js';
11
11
  import { reviveLeaf } from './revive.js';
12
12
  import { attentionBranch } from './attention.js';
13
13
  import { daemonBranch } from './daemon.js';
14
+ import { tmuxSpreadLeaf } from './tmux-spread.js';
15
+ import { chordLeaf } from './chord.js';
16
+ import { canvasPruneLeaf } from './canvas-prune.js';
14
17
  export function registerCanvas() {
15
18
  return defineBranch({
16
19
  name: 'canvas',
@@ -22,14 +25,8 @@ export function registerCanvas() {
22
25
  help: {
23
26
  name: 'canvas',
24
27
  summary: 'observe and supervise the whole agent graph',
25
- model: 'Canvas-wide operations, distinct from per-node work (`node`) and a node\'s own spine I/O (`push`/`feed`). `dashboard` renders the subscription forest as a tree; `attention` aggregates pending human asks across the graph; `revive` reopens a window for a done/idle/dead node; `daemon` manages the thin crtrd supervisor that auto-revives nodes on window exit.',
26
- children: [
27
- { name: 'dashboard', desc: 'render the canvas as a subscription tree', useWhen: 'inspecting the whole graph at a glance' },
28
- { name: 'attention', desc: 'count/list pending human asks across the graph', useWhen: 'checking whether any agent is blocked on a human' },
29
- { name: 'revive', desc: 'reopen a window for a done/idle/dead node', useWhen: 'manually waking a node (the daemon does this automatically)' },
30
- { name: 'daemon', desc: 'manage the crtrd supervisor process', useWhen: 'starting, checking, or stopping background supervision' },
31
- ],
28
+ model: 'Canvas-wide operations, distinct from per-node work (`node`) and a node\'s own spine I/O (`push`/`feed`). `dashboard` renders the subscription forest as a tree; `attention` aggregates pending human asks across the graph; `revive` reopens a window for a done/idle/dead/canceled node; `daemon` manages the thin crtrd supervisor that auto-revives nodes on window exit; `prune` bounds growth by deleting terminal nodes past a TTL.',
32
29
  },
33
- children: [dashboardLeaf, attentionBranch, reviveLeaf, daemonBranch],
30
+ children: [dashboardLeaf, attentionBranch, reviveLeaf, tmuxSpreadLeaf, daemonBranch, chordLeaf, canvasPruneLeaf],
34
31
  });
35
32
  }
@@ -0,0 +1,2 @@
1
+ import type { LeafDef } from '../core/command.js';
2
+ export declare const chordLeaf: LeafDef;