@dpeek/codeless 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,8 +12,11 @@ consumer application code. Its tests use independent temporary repositories.
12
12
 
13
13
  ## Installation
14
14
 
15
- Codeless requires Bun, Git, Herdr, and Pi. The scoped package is configured for
16
- public npm access. Once published, install it with either package manager:
15
+ Codeless requires Bun, Git, Herdr, and Pi. Planner activation requires Herdr's
16
+ official Pi lifecycle integration; install it with `herdr integration install pi`
17
+ and restart existing Pi processes after updating it. The managed launch and
18
+ session-replacement contract is verified against Herdr 0.8.2 and Pi 0.85.1.
19
+ The scoped package is configured for public npm access. Once published, install it with either package manager:
17
20
 
18
21
  ```sh
19
22
  bun add --global @dpeek/codeless
@@ -91,20 +94,30 @@ The configured prompt directory provides `change.md`, `implement.md`,
91
94
 
92
95
  Path arguments are JSON-quoted. Each direction is `<directions>/<slug>.md`.
93
96
  The project owns prompt contents, approval rules, review criteria, and the
94
- transition from review to commit. Required prompts and directions must exist;
95
- the runner does not generate or copy project instructions.
97
+ transition from review to commit. `codeless init` creates missing copies of the
98
+ package's four generic starters, but never replaces existing prompt bytes.
99
+ Review and commit those local prompt edits in the invoking checkout, then bring
100
+ that commit onto the configured integration branch before creating streams.
101
+ Required prompts and directions must exist for stream creation and opening.
96
102
 
97
103
  The package-owned planner extension activates every planner session. Before its
98
- first project prompt, it requires the exact `<slug>-planner` Pi name, establishes
99
- and verifies the `<slug>_planner` Herdr identity, and confirms `approve_stream_change`,
100
- `dispatch_stream_implementer`, and `next_stream_change` are active. Missing or
104
+ first project prompt, it requires the exact `<slug>-planner` Pi name and verifies
105
+ the `<slug>_planner` Herdr identity, managed interactive readiness, foreground
106
+ worktree, and matching native session reference from Herdr's Pi lifecycle
107
+ integration. It confirms `approve_stream_change`,
108
+ `dispatch_stream_implementer`, `rework_stream_implementer`, `finish_stream_implementer`, and `next_stream_change` are active. Missing or
101
109
  incompatible activation, identity mismatch, or inactive tools stops before
102
- `/change`; global Pi extension installation is unnecessary.
110
+ `/change`. During session replacement, activation allows a brief bounded wait for
111
+ an otherwise-valid Herdr identity to publish the current native Pi reference;
112
+ it never waits on a wrong name, process, lifecycle source, or worktree. Global
113
+ installation of Codeless's extension is unnecessary.
103
114
  The approval tool has no arguments. Its extension derives the active
104
115
  `<slug>-planner` Pi session and passes it to the backing CLI, which requires it
105
- to match the worktree and branch. The CLI validates the clean current-integration
106
- baseline and proposal, exclusively creates the next monotonic `changes/NNN.md`,
107
- and records one hash-backed journal approval. Exact retries reconcile a missing
116
+ to match the clean stream worktree and branch. That stream commit is the
117
+ proposal's base; approval does not compare it with a concurrently advancing
118
+ integration branch. The CLI validates the proposal, exclusively creates the next
119
+ monotonic `changes/NNN.md`, and records one hash-backed journal approval. Landing
120
+ later owns locked synchronization and any required rebase onto integration. Exact retries reconcile a missing
108
121
  file or journal step; conflicting state stops. Approval returns the numbered path
109
122
  but does not dispatch it. Dispatch uses the package executable, inherits the
110
123
  planner's worktree, and queues review only on success. Pi loads the extension
@@ -121,7 +134,7 @@ sending `/change` after resources reload. The previous conversation is not copie
121
134
  journal and project files carry context.
122
135
 
123
136
  This uses Pi's `newSession({ setup, withSession })` command API, verified with
124
- Pi 0.84.3. Only the replacement context activates the selection and sends the
137
+ Pi 0.85.1. Only the replacement context activates the selection and sends the
125
138
  new prompt. Configuration changes take effect at the next role-session boundary,
126
139
  not during an active planner or implementer. Review and remediation therefore
127
140
  continue with their existing session's selection. Duplicate requests
@@ -157,8 +170,15 @@ planners or worktree shells are running.
157
170
  metrics/<slug>/NNN.json # dispatch/landing times and deduplicated implementer attempts
158
171
  ```
159
172
 
160
- Run `codeless init` once after configuring a project. It creates the shared state
161
- layout and the dedicated integration worktree at
173
+ Run `codeless init` once after configuring a project. It creates missing generic
174
+ `change.md`, `implement.md`, `review.md`, and `commit.md` starters in the
175
+ configured in-project prompt directory, reporting each as created or preserved.
176
+ Existing prompt files are never replaced; review and commit generated files from
177
+ the editable invoking checkout, then bring that commit onto the configured
178
+ integration branch before creating streams. Init refuses to generate missing
179
+ prompts when invoked from the dedicated integration checkout.
180
+
181
+ It also creates the shared state layout and dedicated integration worktree at
162
182
  `<workspace>/worktree/<integration-branch>` without requiring Herdr. For the
163
183
  default workspace it adds only `/.codeless/state/` to the primary checkout's
164
184
  `.gitignore`; an absolute workspace override does not modify repository ignores.
@@ -172,36 +192,56 @@ inspect its targets before using it.
172
192
 
173
193
  ## Commands
174
194
 
175
- Run creation, opening, and planner launch from a Herdr-managed shell. Landing
176
- needs no Herdr session.
195
+ Run creation and opening from a Herdr-managed operator shell outside the target
196
+ planner/implementer panes. Herdr requires an available interactive shell in the
197
+ target pane before it can start Pi. Landing needs no Herdr session.
177
198
 
178
199
  ```sh
179
200
  codeless init
180
201
  codeless create <slug>
181
202
  codeless open <slug>
182
- codeless planner <slug>
183
203
  codeless approve <planner-session>
184
204
  codeless dispatch <numbered-change-file>
205
+ codeless rework <numbered-change-file> <feedback>
206
+ codeless finish <numbered-change-file>
185
207
  codeless land <slug>
186
208
  codeless next <numbered-change-file> <landed-commit>
187
209
  codeless metrics
188
210
  ```
189
211
 
190
212
  Slugs are lowercase kebab-case, at most 24 characters. `init` validates the
191
- existing configuration and integration branch, reports the branch, primary
192
- checkout, workspace, and integration worktree, then creates only the shared
193
- state directories and canonical integration worktree when absent. All other
213
+ existing configuration and integration branch, validates all configured prompt
214
+ destinations before mutation, reports created or preserved starters plus the
215
+ branch, primary checkout, workspace, and integration worktree, then creates the
216
+ shared state directories and canonical integration worktree when absent. All other
194
217
  commands validate their prerequisites and never bootstrap this setup. `create` starts
195
218
  `stream/<slug>` from the integration branch and creates its local documents;
196
- it refuses existing streams. `open` resumes a stream. Both run the configured
197
- install command, then validate and open a planner beside an idle shell. `planner`
198
- starts Pi in an existing stream's lone shell after the same role preflight. Its
199
- activation establishes the same identity as creation and reopening.
219
+ it refuses existing streams. `open` reuses the existing stream workspace and
220
+ one- or two-pane layout. It focuses an existing managed planner without installing
221
+ dependencies, sending another prompt, or replacing its conversation. To restart,
222
+ exit Pi deliberately, leave both stream panes at their shell prompts in the
223
+ stream worktree, then run `codeless open <slug>` from another Herdr shell.
224
+
225
+ When a planner must be started, creation/opening validates the available shells,
226
+ runs the configured install command and role preflight, adds a right-hand shell
227
+ only when absent, and uses `herdr agent start` for named, readiness-checked Pi
228
+ startup. It verifies the result before sending activation. An occupied or
229
+ mismatched pane, unmanaged agent, ambiguous layout, or failed startup stops;
230
+ Codeless never takes over an existing agent. Pi's display name is separate from
231
+ Herdr's managed agent name. Activation verifies names and native session binding;
232
+ it never renames an unmanaged process. There is no direct `planner` command.
233
+
200
234
  Dispatch validates the implementer selection before touching the planner's
201
235
  right-hand pane, starts a fresh ephemeral implementer with Codeless's reporting
202
- extension and its explicit Pi extension flag, and waits for completion. Its JSON
203
- result is a normalized attempt report, which the planner tool exposes before
204
- queueing review. It includes the actual settled model/thinking selection,
236
+ extension and its explicit Pi extension flag, and waits for completion. Rework verifies
237
+ that same change's idle implementer and worktree, invokes one package-owned Pi command
238
+ that verifies its immutable stream/change scope, arms reporting, and submits one feedback
239
+ turn with the same one-hour limit, records a `rework`
240
+ attempt, and returns it before review is queued again. Finish verifies that identity,
241
+ gracefully exits it, and waits for the right pane's stream-worktree shell. Neither operation
242
+ replaces the agent, changes its selection, retries, or continues after a mismatch, timeout,
243
+ blocked agent, or ambiguous pane. Its JSON result is a normalized attempt report, which the
244
+ planner tool exposes before queueing review. It includes the actual settled model/thinking selection,
205
245
  terminal text and outcome, full-session Pi usage and available Pi cost estimate,
206
246
  timestamps, and tool/error counts; prompts, source, thinking, credentials, and
207
247
  transcripts are not retained.
@@ -216,11 +256,17 @@ integration fast-forward, Codeless records the landed time and commit on that
216
256
  change's canonical record, creating a landed record without elapsed time when
217
257
  dispatch collection was unavailable; collection warnings never alter dispatch or
218
258
  landing.
219
- `codeless metrics` prints every recorded stream and a project total. Its elapsed
220
- columns are dispatch-to-land wall-clock time; among landed changes, records
259
+ `codeless metrics` prints every recorded stream and a project total. Its first
260
+ table reports dispatch-to-land wall-clock time; among landed changes, records
221
261
  without a measured duration are explicitly unavailable. Dispatched-but-unlanded
222
- changes remain a separate count. Metrics are prospective local observations, not
223
- journal state or a recovery mechanism.
262
+ changes remain a separate count. Its second table reports implementer attempts:
263
+ distinct changes with rework, initial and rework turns, incomplete collection,
264
+ exact stored terminal outcomes, and tool errors. Usage and cost coverage count
265
+ measured attempts separately from unavailable collection; token totals include
266
+ only measured usage, and cost totals remain grouped by recorded currency without
267
+ conversion. These counts do not establish implementation quality or review
268
+ success. Metrics are prospective local observations, not journal state or a
269
+ recovery mechanism.
224
270
 
225
271
  Landing requires clean stream and integration worktrees and exactly one stream
226
272
  commit outside their merge base. It acquires `.land-lock` atomically, recording
@@ -248,8 +294,8 @@ control Pi itself. Preparation can be repeated safely after inspecting a failure
248
294
 
249
295
  If validation or session replacement fails, the planner stops for operator
250
296
  attention. Landing is already complete, and any preparation fast-forward remains
251
- applied. There is no background retry; restarting the planner recovers from the
252
- journal and Git state.
297
+ applied. There is no background retry; exit Pi and reopen the stream from another
298
+ Herdr shell to recover from the journal and Git state.
253
299
 
254
300
  ## Package development
255
301
 
@@ -74,23 +74,89 @@ function write(path, value) {
74
74
  export default function implementerReportingExtension(pi) {
75
75
  pi.registerFlag("codeless-attempt", { type: "string" });
76
76
  let configuration;
77
+ let startupScope;
78
+ let rearm;
77
79
  let startedAt;
80
+ let entryOffset = 0;
78
81
  let toolCalls = 0;
79
82
  let errorCount = 0;
83
+
84
+ function configure(value, offset = 0) {
85
+ if (
86
+ typeof value?.path !== "string" ||
87
+ typeof value?.id !== "string" ||
88
+ typeof value?.stream !== "string" ||
89
+ typeof value?.change !== "string" ||
90
+ !["initial", "rework"].includes(value?.kind)
91
+ )
92
+ throw new Error("Codeless attempt configuration is invalid");
93
+ return { value, offset };
94
+ }
80
95
  pi.on("session_start", () => {
81
96
  try {
82
97
  const value = JSON.parse(pi.getFlag("codeless-attempt") ?? "");
83
- if (
84
- typeof value?.path === "string" &&
85
- typeof value?.id === "string" &&
86
- typeof value?.stream === "string" &&
87
- typeof value?.change === "string"
88
- )
89
- configuration = value;
98
+ configuration = configure(value).value;
99
+ startupScope = { stream: configuration.stream, change: configuration.change };
90
100
  } catch {}
91
101
  });
102
+ function requireScope(value) {
103
+ if (
104
+ startupScope === undefined ||
105
+ value?.stream !== startupScope.stream ||
106
+ value?.change !== startupScope.change
107
+ )
108
+ throw new Error("Codeless stream/change scope does not match this implementer session");
109
+ }
110
+
111
+ pi.registerCommand("codeless-rework", {
112
+ description: "Submit one scope-verified Codeless implementer rework turn",
113
+ handler: async (args, ctx) => {
114
+ let value;
115
+ try {
116
+ value = JSON.parse(args);
117
+ } catch {
118
+ throw new Error("Codeless rework requires one JSON-quoted request");
119
+ }
120
+ requireScope(value);
121
+ if (typeof value?.feedback !== "string" || value.feedback.trim().length === 0)
122
+ throw new Error("Codeless rework requires concise non-empty feedback");
123
+ const next = configure(value, ctx.sessionManager.getEntries().length);
124
+ if (next.value.kind !== "rework") throw new Error("Codeless rework attempt must be rework");
125
+ configuration = undefined;
126
+ rearm = next;
127
+ try {
128
+ pi.sendUserMessage(`Review feedback: ${value.feedback.trim()}`, { deliverAs: "followUp" });
129
+ } catch (error) {
130
+ rearm = undefined;
131
+ throw error;
132
+ }
133
+ },
134
+ });
135
+
136
+ pi.registerCommand("codeless-finish", {
137
+ description: "Gracefully finish a scope-verified Codeless implementer",
138
+ handler: async (args, ctx) => {
139
+ let value;
140
+ try {
141
+ value = JSON.parse(args);
142
+ } catch {
143
+ throw new Error("Codeless finish requires one JSON-quoted scope");
144
+ }
145
+ requireScope(value);
146
+ await ctx.shutdown();
147
+ },
148
+ });
92
149
  pi.on("agent_start", () => {
93
- startedAt ??= new Date().toISOString();
150
+ if (rearm !== undefined) {
151
+ configuration = rearm.value;
152
+ entryOffset = rearm.offset;
153
+ rearm = undefined;
154
+ startedAt = new Date().toISOString();
155
+ toolCalls = 0;
156
+ errorCount = 0;
157
+ } else {
158
+ startedAt ??= new Date().toISOString();
159
+ }
94
160
  });
95
161
  pi.on("tool_execution_end", (event) => {
96
162
  toolCalls += 1;
@@ -100,9 +166,10 @@ export default function implementerReportingExtension(pi) {
100
166
  if (configuration === undefined) return;
101
167
  const report = configuration;
102
168
  configuration = undefined;
103
- const settledMessages = messages(ctx.sessionManager.getEntries());
169
+ const entries = ctx.sessionManager.getEntries().slice(entryOffset);
170
+ const settledMessages = messages(entries);
104
171
  const final = [...settledMessages].reverse().find((message) => message.role === "assistant");
105
- const totals = sessionUsage(ctx.sessionManager.getEntries());
172
+ const totals = sessionUsage(entries);
106
173
  const model = final?.responseModel ?? final?.model ?? ctx.model?.id;
107
174
  const provider = final?.provider ?? ctx.model?.provider;
108
175
  const selection =
@@ -123,6 +190,7 @@ export default function implementerReportingExtension(pi) {
123
190
  stream: report.stream,
124
191
  change: report.change,
125
192
  role: "implementer",
193
+ kind: report.kind,
126
194
  startedAt: startedAt ?? new Date().toISOString(),
127
195
  endedAt: new Date().toISOString(),
128
196
  ...(selection === undefined ? {} : { selection }),
@@ -1,11 +1,16 @@
1
1
  import { fileURLToPath } from "node:url";
2
+ import { resolve } from "node:path";
2
3
  import { validAttempt } from "../src/attempt.ts";
3
4
 
4
5
  const codeless = fileURLToPath(new URL("../bin/codeless", import.meta.url));
5
6
  const thinkingLevels = new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
7
+ const nativeSessionAttempts = 20;
8
+ const nativeSessionRetryDelayMs = 50;
6
9
  const requiredTools = [
7
10
  "approve_stream_change",
8
11
  "dispatch_stream_implementer",
12
+ "rework_stream_implementer",
13
+ "finish_stream_implementer",
9
14
  "next_stream_change",
10
15
  ];
11
16
 
@@ -91,24 +96,47 @@ export default function plannerExtension(pi) {
91
96
  throw new Error("Herdr returned an invalid planner identity response");
92
97
  }
93
98
  };
94
- let agent = await plannerIdentity();
95
- if (agent?.name === "pi") {
96
- const renamed = await pi.exec("herdr", ["agent", "rename", pane, expectedPlanner], {
97
- timeout: 30_000,
98
- });
99
- if (renamed.code !== 0) {
99
+ const attempts = activation ? nativeSessionAttempts : 1;
100
+ for (let attempt = 0; attempt < attempts; attempt += 1) {
101
+ const agent = await plannerIdentity();
102
+ if (agent?.name !== expectedPlanner) {
100
103
  throw new Error(
101
- renamed.stderr.trim() ||
102
- renamed.stdout.trim() ||
103
- "Codeless could not establish Herdr planner identity",
104
+ `Codeless planner identity is ${agent?.name ?? "missing"}, expected ${expectedPlanner}; exit this agent and run codeless open ${match[1]} from another Herdr shell`,
104
105
  );
105
106
  }
106
- agent = await plannerIdentity();
107
- }
108
- if (agent?.name !== expectedPlanner) {
109
- throw new Error(
110
- `Codeless planner identity is ${agent?.name ?? "missing"}, expected ${expectedPlanner}`,
111
- );
107
+ if (agent.agent !== "pi" || agent.interactive_ready !== true) {
108
+ throw new Error("Codeless requires a Herdr-managed Pi planner started by codeless open");
109
+ }
110
+ if (
111
+ typeof agent.foreground_cwd !== "string" ||
112
+ resolve(agent.foreground_cwd) !== resolve(ctx.cwd)
113
+ ) {
114
+ throw new Error("Codeless planner worktree does not match Herdr's foreground cwd");
115
+ }
116
+ const session = agent.agent_session;
117
+ const expectedSession =
118
+ session?.kind === "path"
119
+ ? ctx.sessionManager.getSessionFile()
120
+ : session?.kind === "id"
121
+ ? ctx.sessionManager.getSessionId()
122
+ : undefined;
123
+ if (
124
+ agent.screen_detection_skipped !== true ||
125
+ session?.source !== "herdr:pi" ||
126
+ session.agent !== "pi" ||
127
+ !expectedSession
128
+ ) {
129
+ throw new Error(
130
+ "Codeless planner native session does not match Herdr's Pi lifecycle integration",
131
+ );
132
+ }
133
+ if (session.value === expectedSession) break;
134
+ if (attempt === attempts - 1) {
135
+ throw new Error(
136
+ "Codeless planner native session does not match Herdr's Pi lifecycle integration",
137
+ );
138
+ }
139
+ await new Promise((resolveDelay) => setTimeout(resolveDelay, nativeSessionRetryDelayMs));
112
140
  }
113
141
  const activeTools = ctx.getSystemPromptOptions().selectedTools ?? [];
114
142
  const missing = requiredTools.filter((tool) => !activeTools.includes(tool));
@@ -290,6 +318,98 @@ export default function plannerExtension(pi) {
290
318
  },
291
319
  });
292
320
 
321
+ pi.registerTool({
322
+ name: "rework_stream_implementer",
323
+ label: "Remediate stream implementation",
324
+ description:
325
+ "Reuse the idle implementer for this approved change, submit one actionable feedback turn, collect its rework attempt, and queue review again.",
326
+ promptSnippet: "Send one concise remediation request to the existing stream implementer",
327
+ promptGuidelines: [
328
+ "Call rework_stream_implementer only when review finds actionable defects in the approved change. Use its approved changePath and concise feedback; never reproduce Herdr commands.",
329
+ "The tool queues review only after a settled rework attempt. Stop on any error and do not retry automatically.",
330
+ ],
331
+ parameters: {
332
+ type: "object",
333
+ properties: {
334
+ changePath: {
335
+ type: "string",
336
+ description: "Absolute path to the approved changes/NNN.md file",
337
+ },
338
+ feedback: { type: "string", description: "Concise actionable review feedback" },
339
+ },
340
+ required: ["changePath", "feedback"],
341
+ additionalProperties: false,
342
+ },
343
+ async execute(_toolCallId, params, signal) {
344
+ const changePath = params.changePath.replace(/^@/, "");
345
+ const execution = await pi.exec("bun", [codeless, "rework", changePath, params.feedback], {
346
+ signal,
347
+ timeout: 3_700_000,
348
+ });
349
+ const output = [execution.stdout.trim(), execution.stderr.trim()]
350
+ .filter(Boolean)
351
+ .join("\n");
352
+ if (execution.code !== 0)
353
+ throw new Error(output || `codeless rework failed with exit code ${execution.code}`);
354
+ let attempt;
355
+ try {
356
+ attempt = JSON.parse(execution.stdout);
357
+ } catch {
358
+ throw new Error("Codeless returned an invalid rework attempt");
359
+ }
360
+ if (!validAttempt(attempt, attempt?.stream, attempt?.change) || attempt.kind !== "rework")
361
+ throw new Error("Codeless returned an invalid rework attempt");
362
+ pi.sendUserMessage(`/review ${JSON.stringify(changePath)}`, {
363
+ deliverAs: "steer",
364
+ expandPromptTemplates: true,
365
+ });
366
+ return {
367
+ content: [{ type: "text", text: attempt.text || "Implementer rework settled." }],
368
+ details: { changePath, attempt },
369
+ };
370
+ },
371
+ });
372
+
373
+ pi.registerTool({
374
+ name: "finish_stream_implementer",
375
+ label: "Finish stream implementer",
376
+ description:
377
+ "Gracefully exit the verified idle implementer after review approval and confirm its right-hand pane returned to the stream shell.",
378
+ promptSnippet: "Finish the approved stream implementer before commit and landing",
379
+ promptGuidelines: [
380
+ "Call finish_stream_implementer exactly once after recording review approval and before following commit-and-land instructions.",
381
+ "Stop on failure; do not use Herdr commands or continue to commit and land.",
382
+ ],
383
+ parameters: {
384
+ type: "object",
385
+ properties: {
386
+ changePath: {
387
+ type: "string",
388
+ description: "Absolute path to the approved changes/NNN.md file",
389
+ },
390
+ },
391
+ required: ["changePath"],
392
+ additionalProperties: false,
393
+ },
394
+ async execute(_toolCallId, params, signal) {
395
+ const changePath = params.changePath.replace(/^@/, "");
396
+ const execution = await pi.exec("bun", [codeless, "finish", changePath], {
397
+ signal,
398
+ timeout: 35_000,
399
+ });
400
+ const output = [execution.stdout.trim(), execution.stderr.trim()]
401
+ .filter(Boolean)
402
+ .join("\n");
403
+ if (execution.code !== 0)
404
+ throw new Error(output || `codeless finish failed with exit code ${execution.code}`);
405
+ return {
406
+ content: [
407
+ { type: "text", text: "Implementer exited and its pane returned to the stream shell." },
408
+ ],
409
+ };
410
+ },
411
+ });
412
+
293
413
  pi.registerTool({
294
414
  name: "dispatch_stream_implementer",
295
415
  label: "Dispatch stream implementer",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dpeek/codeless",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "An attended planner and implementer workflow for parallel capability development",
5
5
  "homepage": "https://github.com/dpeek/codeless#readme",
6
6
  "bugs": {
@@ -17,6 +17,7 @@
17
17
  "files": [
18
18
  "bin",
19
19
  "extension",
20
+ "prompts",
20
21
  "src",
21
22
  "README.md",
22
23
  "spec"
@@ -0,0 +1,40 @@
1
+ ---
2
+ description: Propose and coordinate the next small change for a stream
3
+ argument-hint: "<stream-directory> <direction-file>"
4
+ ---
5
+
6
+ You are the planner for the stream at `$1`. The current working directory is the stream's repository worktree.
7
+
8
+ Read the repository guidance, `.codeless/config.json`, `$1/planner.md`, every numbered Markdown file in `$1/changes/`, `$2`, its related contracts, and the current implementation relevant to the stream. Resolve the integration branch from that configuration.
9
+
10
+ Before proposing, inspect the branch, recent commits, and worktree. If changes are not explained as an active approved change in `planner.md`, stop and show the operator the evidence. Never discard work automatically.
11
+
12
+ If the latest numbered change is approved but uncommitted, resume it. If it is committed but unlanded on the configured integration branch, resume review or landing. Otherwise require a clean worktree with no commits outside the configured integration branch, fast-forward to that branch, and reread the direction and affected contracts. Stop on divergence. Once planning begins, keep that stream commit as the proposal's base; do not resynchronize merely because integration advances while the proposal awaits approval. Locked landing owns the later rebase.
13
+
14
+ Propose exactly one small, complete change and write it to `$1/change.md`:
15
+
16
+ ```markdown
17
+ # <short outcome>
18
+
19
+ ## Why
20
+
21
+ ## Change
22
+
23
+ ## Acceptance
24
+
25
+ ## Decisions
26
+ ```
27
+
28
+ Under `Decisions`, record only choices that matter now; write `None` when there are none.
29
+
30
+ Present the proposal and wait for the operator:
31
+
32
+ - `go`: call `approve_stream_change` exactly once. It validates and promotes the proposal, records one approval, and returns its number, title, and absolute numbered change path. After it succeeds, call `dispatch_stream_implementer` exactly once with that returned change path.
33
+ - `no`: append the rejected proposal and reason to `planner.md`; do not allocate a numbered change.
34
+ - other feedback: revise `change.md`, recheck the relevant state, and present it again.
35
+
36
+ Approval is separate from dispatch. Do not edit approval state by hand or reproduce the dispatch tool's worktree, pane, or agent operations. If dispatch returns an error, stop and show the operator the exact error; do not retry automatically.
37
+
38
+ After the implementer settles, follow the queued `/review <absolute-numbered-change-path>` instruction. Do not finish after merely reporting that implementation settled. Keep this implementer alive for every remediation round belonging to the same numbered change.
39
+
40
+ The implementation updates code, focused tests, owning contracts, and the direction; remove satisfied todo intentions. If no worthwhile work remains, say so.
@@ -0,0 +1,37 @@
1
+ ---
2
+ description: Commit one reviewed stream change
3
+ argument-hint: "<numbered-change-file>"
4
+ ---
5
+
6
+ Commit the reviewed implementation of `$1` on the current stream branch.
7
+
8
+ Before committing or landing:
9
+
10
+ - confirm `planner.md` records review approval for this change;
11
+ - inspect the complete diff for unrelated edits;
12
+ - confirm every acceptance criterion is met;
13
+ - run the relevant checks if their passing result is not current;
14
+ - determine whether this reviewed change already has its one commit because a previous landing attempt stopped.
15
+
16
+ If the change is not committed, create exactly one commit. Use an imperative subject that describes the resulting behavior. Add a short body only for a non-obvious design decision. If the reviewed change already has its one unlanded commit, do not create another.
17
+
18
+ Read `.codeless/config.json` to resolve the configured integration branch. Derive `<slug>` from the numbered change path and land it with:
19
+
20
+ ```sh
21
+ codeless land <slug>
22
+ ```
23
+
24
+ Replace the placeholder with the literal stream slug and do not include angle brackets. This command owns the shared integration lock, rebases the one stream commit when the configured integration branch advanced, runs the configured checks, and fast-forwards the dedicated integration checkout. It does not modify other branches or checkouts.
25
+
26
+ If landing succeeds, append the full commit hash and subject plus a `landed on <configured-integration-branch>` note to the stream's `planner.md`. Include any decisions the next planner needs before resetting the session.
27
+
28
+ Then call `next_stream_change` exactly once with `changePath` set to the absolute path of `$1` and `landedCommit` set to that full hash. Finish this turn after requesting the handoff. The tool validates the completed landing, fast-forwards the stream to the current configured integration branch, and starts a fresh planner session with the project's `/change` prompt. Do not propose the next change in this session or send `/new` through shell keystrokes.
29
+
30
+ The next planner proposes one change and waits for the operator's `go`; this handoff does not approve further implementation. If no worthwhile work remains, it reports that and stops. If handoff validation fails or the reset is cancelled, stop and report the state; do not retry automatically. Landing remains complete even if the handoff fails.
31
+
32
+ There are two expected landing stops:
33
+
34
+ - If another stream owns the integration slot, leave this stream committed where it is, report the owner, and wait. Do not poll, queue, or retry automatically.
35
+ - If this stream owns the slot and the rebase conflicts, keep the slot. Resolve the conflicts in this worktree so both the current configured integration branch and the approved change are preserved, stage the resolutions, and continue the rebase with `GIT_EDITOR=true git rebase --continue`. Repeat until the rebase completes, run the relevant checks, then run `codeless land <slug>` again to finish. The slot prevents another automated landing from moving the integration branch while you resolve it.
36
+
37
+ For any other failure while this stream owns the slot, report the exact state and wait for the operator. The slot remains held for deliberate recovery; never remove the workspace's landing lock automatically or on guesswork.
@@ -0,0 +1,17 @@
1
+ ---
2
+ description: Implement one approved stream change
3
+ argument-hint: "<numbered-change-file>"
4
+ ---
5
+
6
+ You are the implementer. Implement only the approved change in `$1` in the current worktree.
7
+
8
+ Read the numbered change, repository guidance, and the smallest relevant part of the codebase. Preserve unrelated work.
9
+
10
+ - Do not edit the planner journal, current proposal, or numbered changes beside `$1`.
11
+ - Do not commit, rebase, merge, switch branches, or reset files.
12
+ - Update the owning contracts and todo with the implementation.
13
+ - Add or update focused tests for changed behavior.
14
+ - Run the smallest useful checks.
15
+ - If the change cannot be completed safely, stop and explain the blocker with evidence.
16
+
17
+ When finished, report what changed, checks run and their results, and assumptions or remaining concerns.
@@ -0,0 +1,20 @@
1
+ ---
2
+ description: Review the worktree against one approved stream change
3
+ argument-hint: "<numbered-change-file>"
4
+ ---
5
+
6
+ You are the planner reviewing the implementation of `$1`.
7
+
8
+ Read the approved change and repository guidance. Inspect the complete worktree diff and relevant surrounding code. Review for correctness and regressions, unmet acceptance criteria, missing or weak tests, accidental scope growth, and consistency with the repository's domain model and style.
9
+
10
+ Run focused checks when the implementation report is insufficient evidence.
11
+
12
+ If remediation is required, call `rework_stream_implementer` once with `$1` as `changePath` and a concise actionable feedback list. The tool reuses the verified idle implementer, waits for its one feedback turn, returns its rework attempt, and queues review again. Do not reproduce agent operations or retry automatically.
13
+
14
+ If operator judgment is required, stop and ask one concrete question. If the change is ready:
15
+
16
+ 1. append a compact approval and verification summary to the stream's `planner.md`;
17
+ 2. call `finish_stream_implementer` once with `$1` as `changePath`; it gracefully exits the verified implementer and confirms its pane returned to the stream shell;
18
+ 3. only after that tool succeeds, read `.codeless/config.json`, resolve its `prompts` directory, and immediately follow that directory's `commit.md` instructions for `$1`.
19
+
20
+ Do not finish the implementer before approval because remediation for this numbered change retains its context. If the finish tool fails, stop and report its error.