@crouton-kit/crouter 0.3.3 → 0.3.11

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 (57) hide show
  1. package/README.md +2 -2
  2. package/dist/builtin-skills/skills/crouter-development/marketplaces/SKILL.md +1 -1
  3. package/dist/builtin-skills/skills/crouter-development/plugins/SKILL.md +3 -3
  4. package/dist/cli.js +16 -26
  5. package/dist/commands/__tests__/skill.test.js +24 -28
  6. package/dist/commands/agent.d.ts +6 -0
  7. package/dist/commands/agent.js +585 -0
  8. package/dist/commands/debug.d.ts +1 -1
  9. package/dist/commands/debug.js +20 -7
  10. package/dist/commands/human.js +51 -19
  11. package/dist/commands/job.d.ts +9 -0
  12. package/dist/commands/job.js +100 -385
  13. package/dist/commands/{flow.d.ts → mode.d.ts} +1 -1
  14. package/dist/commands/mode.js +231 -0
  15. package/dist/commands/pkg.js +5 -0
  16. package/dist/commands/plan.d.ts +1 -1
  17. package/dist/commands/plan.js +24 -11
  18. package/dist/commands/skill.js +130 -107
  19. package/dist/commands/spec.d.ts +1 -1
  20. package/dist/commands/spec.js +24 -11
  21. package/dist/commands/sys.js +5 -0
  22. package/dist/core/__tests__/job.test.js +38 -74
  23. package/dist/core/__tests__/jobs.test.d.ts +1 -0
  24. package/dist/core/__tests__/jobs.test.js +98 -0
  25. package/dist/core/__tests__/resolver.test.d.ts +1 -0
  26. package/dist/core/__tests__/resolver.test.js +181 -0
  27. package/dist/core/__tests__/spawn.test.d.ts +1 -0
  28. package/dist/core/__tests__/spawn.test.js +138 -0
  29. package/dist/core/__tests__/subagents.test.d.ts +1 -0
  30. package/dist/core/__tests__/subagents.test.js +75 -0
  31. package/dist/core/__tests__/unknown-path.test.d.ts +1 -0
  32. package/dist/core/__tests__/unknown-path.test.js +52 -0
  33. package/dist/core/bootstrap.d.ts +2 -0
  34. package/dist/core/bootstrap.js +66 -0
  35. package/dist/core/command.d.ts +58 -2
  36. package/dist/core/command.js +62 -14
  37. package/dist/core/config.js +20 -2
  38. package/dist/core/frontmatter.d.ts +10 -0
  39. package/dist/core/frontmatter.js +24 -9
  40. package/dist/core/help.d.ts +39 -8
  41. package/dist/core/help.js +64 -32
  42. package/dist/core/jobs.d.ts +33 -13
  43. package/dist/core/jobs.js +259 -47
  44. package/dist/core/resolver.d.ts +1 -2
  45. package/dist/core/resolver.js +111 -47
  46. package/dist/core/spawn.d.ts +150 -10
  47. package/dist/core/spawn.js +493 -41
  48. package/dist/core/subagents.d.ts +18 -0
  49. package/dist/core/subagents.js +163 -0
  50. package/dist/prompts/agent.d.ts +12 -3
  51. package/dist/prompts/agent.js +51 -18
  52. package/dist/prompts/debug.js +14 -7
  53. package/dist/prompts/skill.js +16 -16
  54. package/dist/types.d.ts +22 -1
  55. package/dist/types.js +5 -2
  56. package/package.json +2 -2
  57. package/dist/commands/flow.js +0 -24
@@ -0,0 +1,231 @@
1
+ // `crtr mode` umbrella — modes of operation: spec, plan, implement, review, debug.
2
+ //
3
+ // Collects the workflow-oriented commands:
4
+ // spec / plan / debug — the artifact and root-cause workflows (from their
5
+ // own files); planner, implementer, reviewer — the
6
+ // handoff-spawn leaves previously under `agent new`.
7
+ //
8
+ // The spawn primitives (agent new / fork) and subagent management remain under
9
+ // `crtr agent`. Results from spawned workers are collected at `crtr job`.
10
+ import { defineBranch, defineLeaf } from '../core/command.js';
11
+ import { InputError } from '../core/io.js';
12
+ import { existsSync } from 'node:fs';
13
+ import { createJob, appendEvent, recordJobPane } from '../core/jobs.js';
14
+ import { spawnAndDetach, spawnAgent } from '../core/spawn.js';
15
+ import { planHandoffPrompt, implementHandoffPrompt, reviewerHandoffPrompt, } from '../prompts/agent.js';
16
+ import { assertTmux, resolveMaxPanes, followUpResult, } from './agent.js';
17
+ import { registerSpec } from './spec.js';
18
+ import { registerPlan } from './plan.js';
19
+ import { registerDebug } from './debug.js';
20
+ const DEFAULT_KILL_SECS = 2;
21
+ // ---------------------------------------------------------------------------
22
+ // mode planner
23
+ // ---------------------------------------------------------------------------
24
+ const newPlanner = defineLeaf({
25
+ name: 'planner',
26
+ help: {
27
+ name: 'mode planner',
28
+ summary: 'launch a planning agent for an approved spec; closes the originating pane after handoff',
29
+ params: [
30
+ { kind: 'positional', name: 'spec_path', type: 'path', required: true, constraint: 'Absolute path to the spec file.' },
31
+ { kind: 'flag', name: 'cwd', type: 'path', required: false, constraint: 'Working directory. Defaults to process.cwd().' },
32
+ { kind: 'flag', name: 'name', type: 'string', required: true, constraint: 'Display name passed to the agent CLI (`-n`); surfaces in pane title and resume picker.' },
33
+ ],
34
+ output: [
35
+ { name: 'job_id', type: 'string', required: true, constraint: 'Use with `crtr job read *` and `crtr job cancel`.' },
36
+ { name: 'follow_up', type: 'string', required: true, constraint: 'Your own next call — run it and report the worker\'s result; do not relay it to the user.' },
37
+ ],
38
+ outputKind: 'object',
39
+ effects: [
40
+ 'Spawns a planner agent in a sibling tmux pane.',
41
+ 'Closes the originating pane after a short delay.',
42
+ 'Creates a job entry and result sidecar.',
43
+ ],
44
+ },
45
+ run: async (input) => {
46
+ assertTmux();
47
+ const specPath = input['spec_path'];
48
+ const cwd = typeof input['cwd'] === 'string' ? input['cwd'] : process.cwd();
49
+ const name = input['name'];
50
+ if (!existsSync(specPath)) {
51
+ throw new InputError({
52
+ error: 'not_found',
53
+ message: `spec not found: ${specPath}`,
54
+ field: 'spec_path',
55
+ next: 'Provide an absolute path to an existing spec file.',
56
+ });
57
+ }
58
+ const { jobId } = createJob('planner', { cwd });
59
+ const result = spawnAndDetach({
60
+ prompt: planHandoffPrompt(specPath, jobId),
61
+ cwd,
62
+ jobId,
63
+ placement: 'split-h',
64
+ killAfterSeconds: DEFAULT_KILL_SECS,
65
+ name,
66
+ });
67
+ if (result.status === 'not-in-tmux') {
68
+ throw new InputError({ error: 'not_in_tmux', message: result.message, next: 'Run inside a tmux session.' });
69
+ }
70
+ if (result.status === 'spawn-failed') {
71
+ throw new InputError({ error: 'spawn_failed', message: result.message, next: 'Check tmux is running and try again.' });
72
+ }
73
+ if (result.paneId !== undefined)
74
+ recordJobPane(jobId, result.paneId);
75
+ const plannerPaneLabel = result.paneId !== undefined ? result.paneId : 'unknown';
76
+ appendEvent(jobId, { level: 'info', event: 'worker_started', message: `planner pane ${plannerPaneLabel} spawned` });
77
+ return { job_id: jobId, follow_up: followUpResult(jobId) };
78
+ },
79
+ });
80
+ // ---------------------------------------------------------------------------
81
+ // mode implementer
82
+ // ---------------------------------------------------------------------------
83
+ const newImplementer = defineLeaf({
84
+ name: 'implementer',
85
+ help: {
86
+ name: 'mode implementer',
87
+ summary: 'launch an implementation agent for an approved plan; closes the originating pane after handoff',
88
+ params: [
89
+ { kind: 'positional', name: 'plan_path', type: 'path', required: true, constraint: 'Absolute path to the plan file.' },
90
+ { kind: 'flag', name: 'cwd', type: 'path', required: false, constraint: 'Working directory. Defaults to process.cwd().' },
91
+ { kind: 'flag', name: 'name', type: 'string', required: true, constraint: 'Display name passed to the agent CLI (`-n`); surfaces in pane title and resume picker.' },
92
+ ],
93
+ output: [
94
+ { name: 'job_id', type: 'string', required: true, constraint: 'Use with `crtr job read *` and `crtr job cancel`.' },
95
+ { name: 'follow_up', type: 'string', required: true, constraint: 'Your own next call — run it and report the worker\'s result; do not relay it to the user.' },
96
+ ],
97
+ outputKind: 'object',
98
+ effects: [
99
+ 'Spawns an implementer agent in a sibling tmux pane.',
100
+ 'Closes the originating pane after a short delay.',
101
+ 'Creates a job entry and result sidecar.',
102
+ ],
103
+ },
104
+ run: async (input) => {
105
+ assertTmux();
106
+ const planPath = input['plan_path'];
107
+ const cwd = typeof input['cwd'] === 'string' ? input['cwd'] : process.cwd();
108
+ const name = input['name'];
109
+ if (!existsSync(planPath)) {
110
+ throw new InputError({
111
+ error: 'not_found',
112
+ message: `plan not found: ${planPath}`,
113
+ field: 'plan_path',
114
+ next: 'Provide an absolute path to an existing plan file.',
115
+ });
116
+ }
117
+ const { jobId } = createJob('implementer', { cwd });
118
+ const result = spawnAndDetach({
119
+ prompt: implementHandoffPrompt(planPath, jobId),
120
+ cwd,
121
+ jobId,
122
+ placement: 'split-h',
123
+ killAfterSeconds: DEFAULT_KILL_SECS,
124
+ name,
125
+ });
126
+ if (result.status === 'not-in-tmux') {
127
+ throw new InputError({ error: 'not_in_tmux', message: result.message, next: 'Check tmux is running and try again.' });
128
+ }
129
+ if (result.status === 'spawn-failed') {
130
+ throw new InputError({ error: 'spawn_failed', message: result.message, next: 'Check tmux is running and try again.' });
131
+ }
132
+ if (result.paneId !== undefined)
133
+ recordJobPane(jobId, result.paneId);
134
+ const implPaneLabel = result.paneId !== undefined ? result.paneId : 'unknown';
135
+ appendEvent(jobId, { level: 'info', event: 'worker_started', message: `implementer pane ${implPaneLabel} spawned` });
136
+ return { job_id: jobId, follow_up: followUpResult(jobId) };
137
+ },
138
+ });
139
+ // ---------------------------------------------------------------------------
140
+ // mode reviewer
141
+ // ---------------------------------------------------------------------------
142
+ const newReviewer = defineLeaf({
143
+ name: 'reviewer',
144
+ help: {
145
+ name: 'mode reviewer',
146
+ summary: 'launch a reviewer agent for a plan or spec artifact; the originating pane stays alive to collect the verdict',
147
+ params: [
148
+ { kind: 'positional', name: 'artifact_path', type: 'path', required: true, constraint: 'Absolute path to the artifact to review.' },
149
+ { kind: 'flag', name: 'kind', type: 'enum', choices: ['plan', 'spec'], required: true, constraint: 'Artifact kind to review.' },
150
+ { kind: 'flag', name: 'spec-path', type: 'path', required: false, constraint: 'Absolute path to the spec, for plan reviews. Omit for spec reviews.' },
151
+ { kind: 'flag', name: 'cwd', type: 'path', required: false, constraint: 'Working directory. Defaults to process.cwd().' },
152
+ { kind: 'flag', name: 'name', type: 'string', required: true, constraint: 'Display name passed to the agent CLI (`-n`); surfaces in pane title and resume picker.' },
153
+ ],
154
+ output: [
155
+ { name: 'job_id', type: 'string', required: true, constraint: 'Use with `crtr job read *` and `crtr job cancel`.' },
156
+ { name: 'follow_up', type: 'string', required: true, constraint: 'Your own next call — run it and report the worker\'s result; do not relay it to the user.' },
157
+ ],
158
+ outputKind: 'object',
159
+ effects: [
160
+ 'Spawns a reviewer agent in a sibling tmux pane.',
161
+ 'The originating pane stays alive — wait on the result and act on the verdict.',
162
+ 'Creates a job entry and result sidecar.',
163
+ ],
164
+ },
165
+ run: async (input) => {
166
+ assertTmux();
167
+ const artifactPath = input['artifact_path'];
168
+ const artifactKind = input['kind'];
169
+ const specPath = typeof input['specPath'] === 'string' ? input['specPath'] : undefined;
170
+ const cwd = typeof input['cwd'] === 'string' ? input['cwd'] : process.cwd();
171
+ const name = input['name'];
172
+ if (!existsSync(artifactPath)) {
173
+ throw new InputError({
174
+ error: 'not_found',
175
+ message: `artifact not found: ${artifactPath}`,
176
+ field: 'artifact_path',
177
+ next: 'Provide an absolute path to an existing artifact file.',
178
+ });
179
+ }
180
+ const { jobId } = createJob('reviewer', { cwd });
181
+ // The reviewer is a subordinate the caller waits on (verdict → revise or
182
+ // hand off), NOT a handoff successor. Use spawnAgent so the originating
183
+ // pane (planner/orchestrator) stays alive to collect the result; do not
184
+ // self-kill the caller the way planner/implementer handoffs do.
185
+ const result = spawnAgent({
186
+ prompt: reviewerHandoffPrompt(artifactPath, artifactKind, specPath !== undefined ? specPath : null, jobId),
187
+ cwd,
188
+ jobId,
189
+ maxPanesPerWindow: resolveMaxPanes(),
190
+ name,
191
+ });
192
+ if (result.status === 'not-in-tmux') {
193
+ throw new InputError({ error: 'not_in_tmux', message: result.message, next: 'Run inside a tmux session.' });
194
+ }
195
+ if (result.status === 'spawn-failed') {
196
+ throw new InputError({ error: 'spawn_failed', message: result.message, next: 'Check tmux is running and try again.' });
197
+ }
198
+ if (result.paneId !== undefined)
199
+ recordJobPane(jobId, result.paneId);
200
+ const reviewerPaneLabel = result.paneId !== undefined ? result.paneId : 'unknown';
201
+ appendEvent(jobId, { level: 'info', event: 'worker_started', message: `reviewer pane ${reviewerPaneLabel} spawned` });
202
+ return { job_id: jobId, follow_up: followUpResult(jobId) };
203
+ },
204
+ });
205
+ // ---------------------------------------------------------------------------
206
+ // mode (root umbrella)
207
+ // ---------------------------------------------------------------------------
208
+ export function registerMode() {
209
+ return defineBranch({
210
+ name: 'mode',
211
+ rootEntry: {
212
+ concept: 'modes of operation: spec → plan → implement → review → debug. Workflow commands for the full agentic development lifecycle',
213
+ desc: 'spec, plan, implement, review, debug workflows',
214
+ useWhen: 'running any structured workflow phase — writing a spec, decomposing into a plan, handing off to an implementer or reviewer, or root-causing a bug. These are the "what to do next" commands; `crtr agent new` is the raw spawn primitive.',
215
+ },
216
+ help: {
217
+ name: 'mode',
218
+ summary: 'modes of operation: spec, plan, implement, review, debug',
219
+ model: 'Full agentic development lifecycle in one subtree. spec captures requirements; plan decomposes them into executable steps; planner/implementer/reviewer are the handoff-spawn leaves that delegate each phase to a fresh worker and return a job handle; debug root-causes failures with a reproduce-first workflow. Spawned workers register as jobs — monitor and collect at `crtr job`.',
220
+ children: [
221
+ { name: 'spec', desc: 'create, read, list specifications', useWhen: 'capturing requirements before planning' },
222
+ { name: 'plan', desc: 'create, read, list plans', useWhen: 'shaping or inspecting work' },
223
+ { name: 'debug', desc: 'reproduce-first root-cause workflow', useWhen: 'a bug, test failure, or unexpected behavior needs root-causing' },
224
+ { name: 'planner', desc: 'planning agent for an approved spec', useWhen: 'handing off spec → plan decomposition to a fresh agent' },
225
+ { name: 'implementer', desc: 'implementation agent for an approved plan', useWhen: 'handing off plan → code implementation to a fresh agent' },
226
+ { name: 'reviewer', desc: 'review agent for a plan or spec artifact', useWhen: 'launching a review of a plan or spec artifact' },
227
+ ],
228
+ },
229
+ children: [registerSpec(), registerPlan(), registerDebug(), newPlanner, newImplementer, newReviewer],
230
+ });
231
+ }
@@ -1008,6 +1008,11 @@ const marketBranch = defineBranch({
1008
1008
  export function registerPkg() {
1009
1009
  return defineBranch({
1010
1010
  name: 'pkg',
1011
+ rootEntry: {
1012
+ concept: 'plugins and marketplaces that supply skills',
1013
+ desc: 'manage plugins and marketplaces',
1014
+ useWhen: 'installing or browsing skill collections',
1015
+ },
1011
1016
  help: {
1012
1017
  name: 'pkg',
1013
1018
  summary: 'manage plugins and plugin marketplaces',
@@ -1,4 +1,4 @@
1
- export declare const PLAN_NEW_GUIDE = "## Planning workflow\n\nBuild and save an implementation plan: a map another agent can execute without\nre-discovering context. Work through these phases before saving.\n\n### Phase 1: Understand\n\nBuild a full picture of the request and the code. Search for reusable\nfunctions, patterns, and existing implementations before proposing new ones.\n\nLaunch up to 3 Explore subagents IN PARALLEL (single message, multiple tool\ncalls). Use 1 agent for isolated, small-scope tasks; use more when scope is\nuncertain or multiple subsystems are involved. Give each a distinct focus so\nthey don't duplicate work.\n\n### Phase 2: Design\n\nDesign the implementation from Phase 1 findings. Default to launching at least\n1 Plan agent to validate your understanding and surface alternatives. Skip only\nfor trivially small tasks (typo fixes, single-line renames). Use up to 3 agents\nfor large refactors or architectural changes.\n\nIn the Plan agent prompt: include file paths, code-path traces, requirements,\nand constraints from Phase 1. Request a detailed implementation plan.\n\n### Phase 3: Review findings\n\nRead the critical files identified by agents. Confirm the plan aligns with the\nuser's request. Use AskUserQuestion ONLY to clarify requirements or choose\nbetween approaches \u2014 never to ask \"is this okay?\" or \"should I proceed?\".\n\n### Phase 4: Compose the plan body\n\nQuality bar \u2014 every item below is cheap to satisfy and saves the implementer\nfrom re-deciding:\n\n- Every decision pinned. No \"if X then Y\" branches, no \"investigate whether\u2026\",\n no deferred choices. If you don't know, find out or ask now.\n- No timelines, no fallbacks, no magic values, no \"for now\" shortcuts.\n- Where the plan creates a new interface, schema, or contract, write the actual\n shape, not \"design a Foo type.\"\n\nRequired sections:\n\n # Plan: <one-line title>\n\n ## Context\n <why this change is being made \u2014 the problem, what prompted it, intended outcome>\n\n ## Recommended approach\n <your chosen approach only. Concise enough to scan, detailed enough to execute.>\n\n ## Files to modify / create\n - `path/to/file.ts` \u2014 <what changes>\n\n ## Existing utilities to reuse\n - `functionName` from `path/to/file.ts:LL` \u2014 <why it fits>\n\n ## Verification\n <how to test end-to-end \u2014 run the code, run tests, etc.>\n\nFor plans touching 4+ files across distinct concerns, structure parallel tasks:\n\n ## Tasks\n - **Task 1**: <name>\n - Files: `a.ts`, `b.ts` (disjoint from other tasks)\n - Depends on: (none) | Task N\n - Integration: <shared types/APIs with exact shape>\n - Changes: <bullets>\n\nSkip the Tasks structure for small plans; it's noise when there's no\nparallelism to unlock.\n\n### Phase 5: Save\n\nRun `crtr flow plan new`:\n\n echo '<plan markdown>' | crtr flow plan new <kebab-case-name> [--spec <spec-name>]\n\n- NAME: short kebab-case slug. Nested names become subdirectories\n (e.g. `auth/jwt-refresh`).\n- Pipe the full plan markdown composed in Phase 4 on stdin.\n- `--spec` (optional): name of the spec this plan implements. Enables alignment\n check by the reviewer.\n\nOutput: `{path, follow_up}`. The `follow_up` field names the exact next call\n\u2014 run it.\n\n### Phase 6: Oversize check\n\nIf `follow_up` contains an oversize advisory (plan exceeds 200 lines), split\ninto a short index plan plus nested part plans, each under the threshold.\nRe-save. The implementer executes parts one at a time; long monolithic plans\nare under-decomposed.\n\n### Phase 7: Done\n\nAfter the reviewer approves the plan, your turn ends. Do not summarize in chat.\nFor a human gate, optionally put the plan in front of a person with `crtr\nhuman review` (anchored comments) and gate the handoff with `crtr human\napprove`. This complements \u2014 it does not replace \u2014 `crtr job start reviewer`.\nIf the user is ready to build, ask once whether to hand off; if yes, run:\n`crtr job start implementer` with the plan path.";
1
+ export declare const PLAN_NEW_GUIDE = "## Planning workflow\n\nBuild and save an implementation plan: a map another agent can execute without\nre-discovering context. Work through these phases before saving.\n\n### Phase 1: Understand\n\nBuild a full picture of the request and the code. Search for reusable\nfunctions, patterns, and existing implementations before proposing new ones.\n\nLaunch up to 3 Explore subagents IN PARALLEL (single message, multiple tool\ncalls). Use 1 agent for isolated, small-scope tasks; use more when scope is\nuncertain or multiple subsystems are involved. Give each a distinct focus so\nthey don't duplicate work.\n\n### Phase 2: Design\n\nDesign the implementation from Phase 1 findings. Default to launching at least\n1 Plan agent to validate your understanding and surface alternatives. Skip only\nfor trivially small tasks (typo fixes, single-line renames). Use up to 3 agents\nfor large refactors or architectural changes.\n\nIn the Plan agent prompt: include file paths, code-path traces, requirements,\nand constraints from Phase 1. Request a detailed implementation plan.\n\n### Phase 3: Review findings\n\nRead the critical files identified by agents. Confirm the plan aligns with the\nuser's request. Use AskUserQuestion ONLY to clarify requirements or choose\nbetween approaches \u2014 never to ask \"is this okay?\" or \"should I proceed?\".\n\n### Phase 4: Compose the plan body\n\nQuality bar \u2014 every item below is cheap to satisfy and saves the implementer\nfrom re-deciding:\n\n- Every decision pinned. No \"if X then Y\" branches, no \"investigate whether\u2026\",\n no deferred choices. If you don't know, find out or ask now.\n- No timelines, no fallbacks, no magic values, no \"for now\" shortcuts.\n- Where the plan creates a new interface, schema, or contract, write the actual\n shape, not \"design a Foo type.\"\n\nRequired sections:\n\n # Plan: <one-line title>\n\n ## Context\n <why this change is being made \u2014 the problem, what prompted it, intended outcome>\n\n ## Recommended approach\n <your chosen approach only. Concise enough to scan, detailed enough to execute.>\n\n ## Files to modify / create\n - `path/to/file.ts` \u2014 <what changes>\n\n ## Existing utilities to reuse\n - `functionName` from `path/to/file.ts:LL` \u2014 <why it fits>\n\n ## Verification\n <how to test end-to-end \u2014 run the code, run tests, etc.>\n\nFor plans touching 4+ files across distinct concerns, structure parallel tasks:\n\n ## Tasks\n - **Task 1**: <name>\n - Files: `a.ts`, `b.ts` (disjoint from other tasks)\n - Depends on: (none) | Task N\n - Integration: <shared types/APIs with exact shape>\n - Changes: <bullets>\n\nSkip the Tasks structure for small plans; it's noise when there's no\nparallelism to unlock.\n\n### Phase 5: Save\n\nRun `crtr mode plan new`:\n\n echo '<plan markdown>' | crtr mode plan new <kebab-case-name> [--spec <spec-name>]\n\n- NAME: short kebab-case slug. Nested names become subdirectories\n (e.g. `auth/jwt-refresh`).\n- Pipe the full plan markdown composed in Phase 4 on stdin.\n- `--spec` (optional): name of the spec this plan implements. Enables alignment\n check by the reviewer.\n\nOutput: `{path, follow_up}`. The `follow_up` field names the exact next call\n\u2014 run it.\n\n### Phase 6: Oversize check\n\nIf `follow_up` contains an oversize advisory (plan exceeds 200 lines), split\ninto a short index plan plus nested part plans, each under the threshold.\nRe-save. The implementer executes parts one at a time; long monolithic plans\nare under-decomposed.\n\n### Phase 7: Done\n\nAfter the reviewer approves the plan, your turn ends. Do not summarize in chat.\nFor a human gate, optionally put the plan in front of a person with `crtr\nhuman review` (anchored comments) and gate the handoff with `crtr human\napprove`. This complements \u2014 it does not replace \u2014 `crtr mode reviewer`.\nIf the user is ready to build, ask once whether to hand off; if yes, run:\n`crtr mode implementer` with the plan path.";
2
2
  export declare const PLAN_SHOW_GUIDE = "";
3
3
  import type { BranchDef } from '../core/command.js';
4
4
  export declare function registerPlan(): BranchDef;
@@ -1,4 +1,4 @@
1
- // `crtr flow plan` subtree — plan new / show / list handlers.
1
+ // `crtr mode plan` subtree — plan new / show / list handlers.
2
2
  export const PLAN_NEW_GUIDE = `## Planning workflow
3
3
 
4
4
  Build and save an implementation plan: a map another agent can execute without
@@ -74,9 +74,9 @@ parallelism to unlock.
74
74
 
75
75
  ### Phase 5: Save
76
76
 
77
- Run \`crtr flow plan new\`:
77
+ Run \`crtr mode plan new\`:
78
78
 
79
- echo '<plan markdown>' | crtr flow plan new <kebab-case-name> [--spec <spec-name>]
79
+ echo '<plan markdown>' | crtr mode plan new <kebab-case-name> [--spec <spec-name>]
80
80
 
81
81
  - NAME: short kebab-case slug. Nested names become subdirectories
82
82
  (e.g. \`auth/jwt-refresh\`).
@@ -99,9 +99,9 @@ are under-decomposed.
99
99
  After the reviewer approves the plan, your turn ends. Do not summarize in chat.
100
100
  For a human gate, optionally put the plan in front of a person with \`crtr
101
101
  human review\` (anchored comments) and gate the handoff with \`crtr human
102
- approve\`. This complements — it does not replace — \`crtr job start reviewer\`.
102
+ approve\`. This complements — it does not replace — \`crtr mode reviewer\`.
103
103
  If the user is ready to build, ask once whether to hand off; if yes, run:
104
- \`crtr job start implementer\` with the plan path.`;
104
+ \`crtr mode implementer\` with the plan path.`;
105
105
  export const PLAN_SHOW_GUIDE = '';
106
106
  import { defineBranch, defineLeaf } from '../core/command.js';
107
107
  import { saveArtifact, readArtifact, listArtifacts, OVERSIZE_WARN_LINES } from '../core/artifact.js';
@@ -110,7 +110,7 @@ export function registerPlan() {
110
110
  const planNew = defineLeaf({
111
111
  name: 'new',
112
112
  help: {
113
- name: 'plan new',
113
+ name: 'mode plan new',
114
114
  summary: 'draft a plan from intent and optional spec alignment',
115
115
  guide: PLAN_NEW_GUIDE,
116
116
  params: [
@@ -146,7 +146,7 @@ export function registerPlan() {
146
146
  name: 'follow_up',
147
147
  type: 'string',
148
148
  required: true,
149
- constraint: 'Recommended next call (reviewer job start).',
149
+ constraint: 'Recommended next call (reviewer spawn via `crtr mode reviewer`).',
150
150
  },
151
151
  ],
152
152
  outputKind: 'object',
@@ -163,7 +163,7 @@ export function registerPlan() {
163
163
  if (spec !== undefined)
164
164
  meta['spec'] = spec;
165
165
  const { path, oversize, lineCount } = saveArtifact('plans', name, body, meta);
166
- let follow_up = `Review it: crtr job start reviewer --artifact-path ${path} --artifact-kind plan (returns {job_id}), then crtr job read result <job_id> --wait.`;
166
+ let follow_up = `Review it: crtr mode reviewer ${path} --kind plan (returns {job_id}), then crtr job read result <job_id> --wait.`;
167
167
  follow_up +=
168
168
  ` Optional human gate (complements, does not replace the agent reviewer): crtr human review --file ${path} for anchored comments, then gate handoff with crtr human approve --title "Approve this plan?".`;
169
169
  if (oversize) {
@@ -176,7 +176,7 @@ export function registerPlan() {
176
176
  const planShow = defineLeaf({
177
177
  name: 'show',
178
178
  help: {
179
- name: 'plan show',
179
+ name: 'mode plan show',
180
180
  summary: 'read a plan artifact by name',
181
181
  params: [
182
182
  {
@@ -225,7 +225,7 @@ export function registerPlan() {
225
225
  const planList = defineLeaf({
226
226
  name: 'list',
227
227
  help: {
228
- name: 'plan list',
228
+ name: 'mode plan list',
229
229
  summary: 'paginated list of plan artifacts, sorted ascending by name',
230
230
  params: [
231
231
  {
@@ -295,7 +295,7 @@ export function registerPlan() {
295
295
  return defineBranch({
296
296
  name: 'plan',
297
297
  help: {
298
- name: 'plan',
298
+ name: 'mode plan',
299
299
  summary: 'create and read plan artifacts',
300
300
  model: 'Lifecycle: draft -> active -> handed-off.',
301
301
  children: [
@@ -304,6 +304,19 @@ export function registerPlan() {
304
304
  { name: 'list', desc: 'enumerate plans', useWhen: 'discovering what plans exist' },
305
305
  ],
306
306
  },
307
+ slash: {
308
+ name: 'plan',
309
+ description: 'Plan mode — decompose intent (and an optional spec) into an executable plan.',
310
+ argumentHint: '[what to plan]',
311
+ body: `You are entering **plan mode**: decompose work into an executable plan.
312
+
313
+ 1. Run \`crtr mode plan new -h\` to load the planning workflow and output schema.
314
+ 2. Follow it to draft the plan, then save by piping the markdown to \`crtr mode plan new <name>\` on stdin (pass \`--spec <path>\` if an approved spec exists).
315
+
316
+ The request: $ARGUMENTS
317
+
318
+ If no request was given, ask the user what to plan before starting.`,
319
+ },
307
320
  children: [planNew, planShow, planList],
308
321
  });
309
322
  }