@parallel-cli/parallel 0.4.6 → 0.4.7

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/CHANGELOG.md CHANGED
@@ -2,6 +2,34 @@
2
2
 
3
3
  All notable changes to Parallel are documented here.
4
4
 
5
+ ## 0.4.7 - 2026-06-24
6
+
7
+ ### 0.4.7 Added
8
+
9
+ - Added file revision safety for shared-tree co-editing so stale `write_file` retries and `edit_file` calls must re-read and merge concurrent work before mutating.
10
+ - Added immediate agent-to-agent note nudging with duplicate-note suppression, active-agent checks, and rate-limit safeguards.
11
+ - Added visible coordination signals in the Hub, `/board`, `/diff`, and timelines for claims, work-map warnings, notes, approvals, and questions.
12
+ - Added `/review [agent|all] [prompt]`, a lightweight ask-mode reviewer that returns `APPROVE`, `REVISE`, or `BLOCK` with risks, tests to run, and files to inspect.
13
+ - Added Cursor-style per-agent progress steps through `update_steps`, visible in the Hub and attached terminals.
14
+ - Added batched read-only inspection tools (`read_many`, `inspect_project`) plus lightweight performance counters for model turns, tool calls, shell commands, and context usage.
15
+
16
+ ### 0.4.7 Changed
17
+
18
+ - Reworked `/board` into a coordination surface with Work map warnings first, agent/path/time metadata, and suggestions to inspect `/focus` or `/diff`.
19
+ - Prioritized incoming notes and work-map context in agent live context so coordination updates are handled before ordinary activity.
20
+ - Updated product messaging around shared awareness: agents work like a live team on one working tree, not isolated background jobs.
21
+ - Reworked agent rows to keep the Hub compact with cropped summaries, cream bullet recaps capped at four lines, mode badges, and visible `full /focus aN` plus `term /attach aN` shortcuts.
22
+ - Reworked dedicated agent terminals with a launch header, hidden raw launch noise in normal mode, append-only final results, and a small live status region so native scrollback remains usable.
23
+ - Tuned agent prompts by mode so `/ask`, `/task`, `/plan`, and `/review` use clearer contracts, early progress steps, batched inspection, and less redundant shell micro-commanding.
24
+
25
+ ### 0.4.7 Fixed
26
+
27
+ - Fixed the previous collision retry weakness where a stale writer could receive an adaptation diff and then overwrite without a real re-read.
28
+ - Fixed `edit_file` allowing targeted edits on a stale file as long as `old_string` still existed.
29
+ - Fixed timeline narration being hardcoded in French by routing narration through i18n.
30
+ - Fixed `claim_files` appearing as generic file activity instead of coordination activity.
31
+ - Fixed completed attached terminals repainting large dynamic result panels that could trap mouse-wheel scroll at the top.
32
+
5
33
  ## 0.4.6 - 2026-06-24
6
34
 
7
35
  ### 0.4.6 Added
package/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # Parallel
2
2
 
3
- Real-time multi-agent coding from one terminal control room.
3
+ Real-time coding agents that work like a live team, not isolated background jobs.
4
4
 
5
- Parallel lets you run several AI coding agents on the same repository at the same time. Each agent has its own task, mode, live activity timeline, model, and shared session context. The TUI stays keyboard-first so you can launch work, inspect progress, answer approvals, steer agents, and review changes without leaving the terminal.
5
+ Parallel lets several AI coding agents co-edit the same repository at the same time with shared awareness injected before every model action. Each agent has its own task, mode, live activity timeline, model, and visible coordination context. The TUI stays keyboard-first so you can launch work, inspect progress, answer approvals, steer agents, review risks, and reconcile changes without leaving the terminal.
6
6
 
7
- > One hub. Many agents. Shared context. Human in control.
7
+ > One working tree. Many agents. Shared awareness. Human in control.
8
8
 
9
9
  [![npm version](https://img.shields.io/npm/v/@parallel-cli/parallel?color=blue)](https://www.npmjs.com/package/@parallel-cli/parallel)
10
10
  ![node version](https://img.shields.io/node/v/@parallel-cli/parallel)
@@ -13,14 +13,18 @@ Parallel lets you run several AI coding agents on the same repository at the sam
13
13
 
14
14
  ## Highlights
15
15
 
16
- - Run multiple agents in parallel on one project.
17
- - Choose explicit modes: `/ask`, `/task`, and `/plan`.
16
+ - Run multiple agents as a live team on one shared working tree.
17
+ - Choose explicit modes: `/ask`, `/task`, `/plan`, and `/review`.
18
18
  - Type plain text to launch a task agent immediately.
19
19
  - Use context-aware input in the hub, focus view, and attached agent terminals.
20
20
  - Steer one agent with `@a1 ...` or broadcast with `@all ...`.
21
21
  - Open dedicated agent terminals with native scrollback.
22
22
  - Use a cleaner Codex-like hub with a framed header, focused prompt bar, and quieter empty state.
23
23
  - Review agents, notes, file activity, diffs, cost, skills, specialists, and saved sessions from the TUI.
24
+ - Use `/review [agent|all]` to spawn a lightweight ask-mode reviewer with verdict, risks, tests, and files to inspect.
25
+ - Avoid lost work with file revision safety: stale `write_file` and `edit_file` calls must re-read and merge before retrying.
26
+ - Nudge agents immediately when another agent posts a targeted note, with dedupe and rate-limit safeguards.
27
+ - See overlapping claims and repeated co-edit conflicts in the Hub, `/board`, `/diff`, and agent timelines.
24
28
  - Track shell-created file mutations in the same live diff feed as agent edits.
25
29
  - Configure OpenAI-compatible providers through a guided wizard and settings panel.
26
30
  - Use 29 provider presets across Western, Chinese, Gateway, Inference, and Local categories.
@@ -86,6 +90,7 @@ Use explicit modes when intent matters:
86
90
  /ask Reviewer: should we split the CLI parser?
87
91
  /plan Migration: propose the safest rollout for the config change
88
92
  /task Builder: implement the approved plan
93
+ /review all before we commit
89
94
  ```
90
95
 
91
96
  Steer a running agent:
@@ -102,11 +107,36 @@ Broadcast to every agent:
102
107
 
103
108
  `@all` steers active agents in real time. Finished, stopped, or errored agents are not relaunched by a broadcast.
104
109
 
110
+ ## Best Use Case: Coupled Work
111
+
112
+ Parallel is strongest when the work is too coupled for isolated fan-out and too large for one agent.
113
+
114
+ Example live-team flow:
115
+
116
+ ```text
117
+ /task API: define the new billing quote contract in src/api/quotes.ts
118
+ /task Client: build the UI client against the quote contract
119
+ /task Tests: write integration coverage for quote creation and validation
120
+ ```
121
+
122
+ The API agent can claim `src/api`, post a note with the proposed signature, and update the contract. The client agent sees that note and the diff before its next model action, re-reads the file, and adapts without inventing a second interface. The tests agent watches both sides, adds coverage, and can ask for clarification before the three agents collide.
123
+
124
+ Before committing:
125
+
126
+ ```text
127
+ /review all verify the API contract, client usage, and tests agree
128
+ ```
129
+
130
+ The reviewer is ask-only: it does not edit, does not gate the session globally, and returns a structured verdict with risks and validation steps.
131
+
105
132
  ## Agent Modes
106
133
 
107
134
  - `/ask`: questions, reviews, audits, and tradeoffs. The agent answers and advises; mutating tools and shell commands are blocked.
108
- - `/task`: implementation work. The agent can execute, edit, validate, and summarize.
135
+ - `/task`: implementation work. The agent can execute, edit, validate, and summarize. It may also conclude that no file change is needed when the task is a verification.
109
136
  - `/plan`: risky or unclear work. The agent inspects first, presents a plan, then edits only after explicit approval. A timeout does not approve the plan.
137
+ - `/review`: lightweight reviewer around `/ask`. It inspects the current shared-tree work and returns `APPROVE`, `REVISE`, or `BLOCK` with risks, tests to run, and files to inspect.
138
+
139
+ Task and plan agents maintain a small Cursor-style checklist with one active step at a time. The runtime also encourages batched inspection through `read_many` and `inspect_project` so agents avoid slow chains of tiny read-only shell commands.
110
140
 
111
141
  Aliases:
112
142
 
@@ -118,7 +148,7 @@ Plain text is equivalent to `/task`.
118
148
 
119
149
  ## Control Room
120
150
 
121
- The main TUI is the Parallel hub. The default view stays intentionally quiet: a Codex-like framed header, cream-toned accents, a focused prompt block, and detailed status moved into explicit views.
151
+ The main TUI is the Parallel hub. The default view stays intentionally quiet: a Codex-like framed header, cream-toned accents, a focused prompt block, compact cropped agent rows, and detailed status moved into explicit views.
122
152
 
123
153
  It is designed to answer:
124
154
 
@@ -128,6 +158,11 @@ It is designed to answer:
128
158
  - what changed in the project
129
159
  - what model, provider, shell mode, and cost are active
130
160
 
161
+ Agent rows stay compact even when summaries are long. Use the row shortcuts to expand the right level of detail:
162
+
163
+ - `full /focus a1`: open the full in-Hub transcript and result for one agent.
164
+ - `term /attach a1`: reopen that agent's dedicated terminal.
165
+
131
166
  Input has three explicit contexts:
132
167
 
133
168
  - Hub: plain text launches a new `/task` agent. Slash suggestions show hub commands and agent arguments autocomplete for `/focus`, `/send`, `/attach`, `/pause`, `/resume`, `/stop`, `/restore`, and `/commit`.
@@ -146,6 +181,8 @@ Common hub commands:
146
181
  - `/agents`: agent overview.
147
182
  - `/focus a1`: inspect and steer one agent.
148
183
  - `/raw`: toggle raw detail in focus view.
184
+ - `/attach a1`: open or reopen an agent's dedicated terminal.
185
+ - `/review all`: ask-mode reviewer with verdict, risks, tests, and files to inspect.
149
186
  - `/board`: shared blackboard, claims, notes, and file activity.
150
187
  - `/diff`: live diff history.
151
188
  - `/cost`: token and cost breakdown.
@@ -180,8 +217,10 @@ parallel attach a1 --root .
180
217
 
181
218
  Attached terminals show:
182
219
 
220
+ - a launch header with agent, mode, model, and task
183
221
  - the selected agent's live timeline
184
222
  - native terminal scrollback
223
+ - append-only final results after `done`, `error`, or `stopped`
185
224
  - model, elapsed time, context, and cost
186
225
  - other agents' current state
187
226
  - approval and question prompts for that agent
@@ -197,6 +236,7 @@ plain text sends a message to this agent
197
236
  /task Tests: write parser regression tests
198
237
  /ask Reviewer: is this result safe to merge?
199
238
  /plan Migration: prepare a migration plan
239
+ /review all before commit
200
240
  /raw
201
241
  /quit
202
242
  ```
@@ -265,6 +305,7 @@ If the update succeeds, restart Parallel to run the new version. Use `parallel -
265
305
  - `/ask [Name:] <question> [--model=m]`: launch an ask-only agent.
266
306
  - `/task [Name:] <task> [--model=m] [#skill]`: launch a task agent. Plain text does the same.
267
307
  - `/plan [Name:] <task> [--model=m]`: launch a plan-first agent. It cannot mutate files or run risky shell commands until you manually approve the plan.
308
+ - `/review [agent|all] [prompt]`: launch a lightweight ask-mode reviewer for one agent or the whole shared tree.
268
309
  - `/issue <n>`: spawn a task from a GitHub issue. Requires the `gh` CLI, a GitHub repository, and `gh auth login`.
269
310
  - `/specialist <name> <task>`: spawn with a specialist persona.
270
311
  - `/specialist new <name> [global]`: create a specialist template.
@@ -293,7 +334,7 @@ If the update succeeds, restart Parallel to run the new version. Use `parallel -
293
334
  ### Views And Sessions
294
335
 
295
336
  - `/agents`: agent overview.
296
- - `/board`: shared blackboard, file activity, claims, and notes.
337
+ - `/board`: shared blackboard, work-map warnings, claims, file activity, and notes.
297
338
  - `/notes`: full notes history.
298
339
  - `/diff`: live diff history.
299
340
  - `/cost`: token and cost breakdown.
@@ -375,15 +416,21 @@ When an agent writes a file:
375
416
 
376
417
  1. Parallel checks whether the file changed since that agent last read it.
377
418
  2. If the file is unchanged, the write proceeds.
378
- 3. If another agent changed it, the write is rejected once.
379
- 4. The agent receives the other change as context, re-reads the file, merges both intentions, and retries.
419
+ 3. If another agent or shell command changed it, the write is rejected with an adaptation diff.
420
+ 4. The stale baseline is not silently synchronized. The agent must call `read_file`, merge both intentions on top of the current revision, and retry.
380
421
 
381
- This keeps agents moving without allowing silent overwrites.
422
+ The same stale-read guard applies to `edit_file`, even when `old_string` still exists. This keeps agents moving without allowing silent overwrites.
382
423
 
383
424
  Commands run through `run_command` are also snapshotted before and after execution. If a shell command edits, creates, or deletes tracked project files, Parallel records those mutations in `/diff`, `/board`, and `/commit` ownership just like tool-based edits.
384
425
 
385
426
  The work map is advisory, not a lock. Agents can declare claims with `claim_files`; Parallel detects overlapping claims and repeated conflicts, then shows non-blocking warnings in `/board` and injects them into agent context so agents can coordinate before collisions become expensive.
386
427
 
428
+ ## Shared-Tree Vs Isolated Agents
429
+
430
+ Use Parallel's shared-tree mode when agents need to negotiate live contracts: API and client, schema and tests, parser and docs, or any change where one agent's edit should affect another agent's next step.
431
+
432
+ Use isolated agents or separate worktrees for embarrassingly parallel work: unrelated files, independent chores, or experiments you only want to merge after review. Parallel's identity is the shared-tree team workflow; isolation is a future complement, not the default.
433
+
387
434
  ## Headless Mode
388
435
 
389
436
  For CI and scripts, run without the TUI:
@@ -19,12 +19,14 @@ AGENT MODE: ${mode}
19
19
  ${mode === 'ask'
20
20
  ? `ASK MODE:
21
21
  - You are advisory only. Do not modify files.
22
- - You may inspect with list_files/read_file/search and safe read-only commands when useful.
22
+ - Prefer search/read_file/read_many/inspect_project over shell. Use safe read-only commands only when internal tools are insufficient.
23
+ - Keep the investigation short and targeted. Do not run heavy validation loops unless the user explicitly asks.
23
24
  - Do not run mutating commands, write files, edit files, claim files, or commit.
24
25
  - Finish with task_complete using this user-facing structure in ${userLang}: "Réponse courte", "Recommandation", "Pourquoi", "Prochaines étapes".`
25
26
  : mode === 'plan'
26
27
  ? `PLAN MODE:
27
28
  - Explore first with read-only tools.
29
+ - Batch independent reads/searches with read_many or inspect_project. Keep exploration broad enough to be correct but bounded.
28
30
  - Before modifying any file or running mutating commands, call ask_user with a concrete implementation plan.
29
31
  - The plan must include steps, files you expect to touch, risks, and validation.
30
32
  - Use options ["Approve", "Revise"], recommended "Revise" so timeout never approves changes.
@@ -32,7 +34,8 @@ ${mode === 'ask'
32
34
  - Finish with task_complete using this user-facing structure in ${userLang}: "Plan appliqué", "Ce que j’ai modifié", "Validation", "Risques restants".`
33
35
  : `TASK MODE:
34
36
  - Execute the user's objective end-to-end.
35
- - Explore, edit, validate, and summarize.
37
+ - Use this loop: create visible steps, batch inspect, act, batch validate, summarize.
38
+ - If the task is a verification/audit and the correct outcome is no file changes, that is valid task work. Say explicitly in task_complete that no modification was necessary and why.
36
39
  - Ask the user only when blocked or when a risky product decision cannot be inferred.
37
40
  - Finish with task_complete using this user-facing structure in ${userLang}: "Ce que j’ai fait", "Ce que j’ai vérifié", "Résultat", "Détails techniques".`}
38
41
  ${skillsList
@@ -59,13 +62,16 @@ PARALLEL'S PHILOSOPHY — REAL-TIME CO-EDITING, NEVER ANY BLOCKING:
59
62
  8. MAKE THE SHARED AWARENESS VISIBLE: when another agent's work influenced a decision of yours (you reused their function, adapted to their diff, avoided their work area), SAY IT explicitly — in a post_note to them ("I saw you changed X, so I did Y") and in your task_complete summary (name the agent and what you built on). The user must be able to SEE that you worked as a team, not as isolated bots.
60
63
 
61
64
  WORK METHOD:
62
- - Explore first (list_files, read_file, search) before modifying.
65
+ - For non-trivial work, call update_steps early with 3-6 concrete steps. Keep exactly one step active and mark steps done as you complete them.
66
+ - Explore first before modifying. Decide all independent reads/searches you need, then batch them with read_many or inspect_project instead of calling tools one by one.
67
+ - Use run_command for builds/tests/validation and genuinely useful shell scripts. Do NOT spend many turns running grep/head/tail/wc/awk cascades; batch independent shell checks into one labelled command or use inspect_project.
63
68
  - Declare your work area with claim_files when you start (and when it changes): it prevents collisions without ever locking anything.
64
69
  - If you discover a durable, non-obvious fact about the project (convention, decision, pitfall), save it with remember(fact) for future agents.
65
70
  - wait_for_agent exists for hard dependencies only — prefer progressing on another part of your task over waiting.
66
71
  - Prefer edit_file (targeted changes) over write_file (full rewrite): targeted edits coexist better in parallel.
67
72
  - Make minimal changes; do not rewrite what already works.
68
73
  - Verify your work when relevant (run_command for tests/build), then finish with task_complete.
74
+ - Performance discipline: minimize model turns. If multiple tool calls are independent, make them in the same assistant turn. If several shell checks are independent, run one labelled command.
69
75
  - The task_complete summary is user-facing. Make it structured and specific in ${userLang}, not just "done":
70
76
  1. What I did — concrete outcome in 1-2 sentences.
71
77
  2. Files changed or inspected — mention paths when relevant.
@@ -76,6 +82,29 @@ WORK METHOD:
76
82
  LANGUAGE: write notes addressed to "user" and your task_complete summary in ${userLang}. Notes to other agents and code stay in English.`;
77
83
  /** Assumed context window (tokens) when the provider does not advertise one. */
78
84
  const CONTEXT_WINDOW = 128_000;
85
+ const EMPTY_PERF = {
86
+ modelTurns: 0,
87
+ toolCalls: 0,
88
+ shellCommands: 0,
89
+ shellMs: 0,
90
+ readOnlyShellCommands: 0,
91
+ };
92
+ function noChangeTaskLine() {
93
+ switch (getLang()) {
94
+ case 'fr':
95
+ return 'Mode task: vérification sans changement de fichier nécessaire.';
96
+ case 'es':
97
+ return 'Modo task: verificación sin cambios de archivos necesarios.';
98
+ case 'zh':
99
+ return 'Task 模式:已完成验证,无需修改文件。';
100
+ case 'en':
101
+ default:
102
+ return 'Task mode: verification completed with no file changes needed.';
103
+ }
104
+ }
105
+ function isReadOnlyShell(command) {
106
+ return /\b(grep|rg|head|tail|wc|awk|sed|cat|ls|find)\b/.test(command) && !/[>|;]/.test(command);
107
+ }
79
108
  export class Agent {
80
109
  opts;
81
110
  id;
@@ -90,6 +119,7 @@ export class Agent {
90
119
  stopped = false;
91
120
  lastNoteId = 0;
92
121
  lastChangeId = 0;
122
+ readOnlyShellStreak = 0;
93
123
  constructor(opts) {
94
124
  this.opts = opts;
95
125
  this.id = opts.id;
@@ -114,6 +144,8 @@ export class Agent {
114
144
  cost: opts.price ? 0 : null,
115
145
  startedAt: Date.now(),
116
146
  specialist: opts.specialist?.name,
147
+ progressSteps: [],
148
+ perf: { ...EMPTY_PERF },
117
149
  };
118
150
  this.board.registerAgent(info);
119
151
  // Skip notes/changes that existed before this agent was born
@@ -165,9 +197,13 @@ export class Agent {
165
197
  * A note addressed to this agent just arrived: interrupt the current model
166
198
  * call so the next turn (which injects unread notes) starts immediately.
167
199
  */
168
- nudge() {
200
+ nudge(reason = 'reading team update') {
201
+ if (this.finished || this.stopped || this.paused)
202
+ return false;
169
203
  this.steered = true;
204
+ this.board.setAgentState(this.id, 'listening', reason);
170
205
  this.llmAbort?.abort();
206
+ return true;
171
207
  }
172
208
  /**
173
209
  * Append a message to the in-memory history AND to the conversation file
@@ -189,6 +225,18 @@ export class Agent {
189
225
  await new Promise((r) => setTimeout(r, 300));
190
226
  }
191
227
  }
228
+ updatePerf(delta) {
229
+ const current = this.board.agents.get(this.id)?.perf ?? EMPTY_PERF;
230
+ this.board.updateAgent(this.id, {
231
+ perf: {
232
+ modelTurns: current.modelTurns + (delta.modelTurns ?? 0),
233
+ toolCalls: current.toolCalls + (delta.toolCalls ?? 0),
234
+ shellCommands: current.shellCommands + (delta.shellCommands ?? 0),
235
+ shellMs: current.shellMs + (delta.shellMs ?? 0),
236
+ readOnlyShellCommands: current.readOnlyShellCommands + (delta.readOnlyShellCommands ?? 0),
237
+ },
238
+ });
239
+ }
192
240
  /**
193
241
  * Build the live context injected before EVERY model call:
194
242
  * other agents' status + their fresh diffs + unread notes.
@@ -197,6 +245,15 @@ export class Agent {
197
245
  liveContext() {
198
246
  let hasNews = false;
199
247
  const parts = ['[REAL TIME]', this.board.snapshotFor(this.id)];
248
+ const notes = this.board.notesFor(this.name, this.lastNoteId);
249
+ if (notes.length > 0) {
250
+ this.lastNoteId = notes[notes.length - 1].id;
251
+ hasNews = true;
252
+ parts.push('\n[PRIORITY NOTES RECEIVED — take them into account now]');
253
+ for (const n of notes) {
254
+ parts.push(` • from ${n.from}: ${n.content}`);
255
+ }
256
+ }
200
257
  const changes = this.board.changesSince(this.id, this.lastChangeId);
201
258
  if (changes.length > 0) {
202
259
  this.lastChangeId = changes[changes.length - 1].id;
@@ -219,15 +276,6 @@ export class Agent {
219
276
  }
220
277
  parts.push('Analyze these diffs: if any of them touches your work area, re-read the affected file and adapt. NEVER undo these changes.');
221
278
  }
222
- const notes = this.board.notesFor(this.name, this.lastNoteId);
223
- if (notes.length > 0) {
224
- this.lastNoteId = notes[notes.length - 1].id;
225
- hasNews = true;
226
- parts.push('\n[NOTES RECEIVED — take them into account now]');
227
- for (const n of notes) {
228
- parts.push(` • from ${n.from}: ${n.content}`);
229
- }
230
- }
231
279
  parts.push('\nContinue your task taking the above into account. Use tools, or task_complete if finished.');
232
280
  return { text: parts.join('\n'), hasNews };
233
281
  }
@@ -322,6 +370,7 @@ export class Agent {
322
370
  this.llmAbort = null;
323
371
  }
324
372
  this.steered = false;
373
+ this.updatePerf({ modelTurns: 1 });
325
374
  const a = this.board.agents.get(this.id);
326
375
  if (a) {
327
376
  // Real-time financial view: accrue the cost of this round immediately.
@@ -378,11 +427,40 @@ export class Agent {
378
427
  this.board.log(this.id, 'tool', label);
379
428
  }
380
429
  this.board.updateAgent(this.id, { currentAction: label.slice(0, 80) });
430
+ const shellStartedAt = tc.function.name === 'run_command' ? Date.now() : 0;
381
431
  const result = await this.executor.execute(tc.function.name, args);
432
+ const shellMs = shellStartedAt ? Date.now() - shellStartedAt : 0;
433
+ const readOnlyShell = tc.function.name === 'run_command' && isReadOnlyShell(String(args.command ?? ''));
434
+ this.updatePerf({
435
+ toolCalls: 1,
436
+ shellCommands: tc.function.name === 'run_command' ? 1 : 0,
437
+ shellMs,
438
+ readOnlyShellCommands: readOnlyShell ? 1 : 0,
439
+ });
440
+ if (readOnlyShell) {
441
+ this.readOnlyShellStreak++;
442
+ if (this.readOnlyShellStreak >= 3) {
443
+ this.record({
444
+ role: 'user',
445
+ content: '[PERFORMANCE CORRECTION] You are using several read-only shell micro-commands. Batch the next inspection with read_many/inspect_project or a single labelled shell command, then continue.',
446
+ });
447
+ this.readOnlyShellStreak = 0;
448
+ }
449
+ }
450
+ else if (tc.function.name !== 'update_status' && tc.function.name !== 'update_steps') {
451
+ this.readOnlyShellStreak = 0;
452
+ }
382
453
  if (result === '__TASK_COMPLETE__') {
383
454
  completed = true;
384
455
  const summary = String(args.summary ?? 'Task complete.');
385
- this.board.updateAgent(this.id, { lastResult: summary });
456
+ const changedByThisAgent = this.board.changes.filter((c) => c.agentId === this.id).length;
457
+ const noChangePrefix = this.opts.mode === 'task' && changedByThisAgent === 0
458
+ ? `${noChangeTaskLine()}\n\n`
459
+ : '';
460
+ this.board.updateAgent(this.id, {
461
+ lastResult: `${noChangePrefix}${summary}`,
462
+ progressSteps: (this.board.agents.get(this.id)?.progressSteps ?? []).map((s) => ({ ...s, status: 'done' })),
463
+ });
386
464
  // ONE short headline note (the full summary lives in lastResult and
387
465
  // is rendered as the agent's recap) — no duplicated walls of text.
388
466
  const headline = summary.split('\n').find((l) => l.trim())?.trim() ?? 'Task complete.';
@@ -419,6 +497,8 @@ export class Agent {
419
497
  switch (name) {
420
498
  case 'read_file':
421
499
  return `📖 read ${args.path}`;
500
+ case 'read_many':
501
+ return `📚 read ${Array.isArray(args.paths) ? args.paths.slice(0, 3).join(', ') : 'files'}`;
422
502
  case 'write_file':
423
503
  return `✏ write ${args.path}`;
424
504
  case 'edit_file':
@@ -427,12 +507,16 @@ export class Agent {
427
507
  return `📁 ls ${args.path ?? '.'}`;
428
508
  case 'search':
429
509
  return `🔍 search /${args.pattern}/`;
510
+ case 'inspect_project':
511
+ return `🔎 inspect project`;
430
512
  case 'run_command':
431
513
  return `$ ${args.command}`;
432
514
  case 'post_note':
433
515
  return `✉ note → ${args.to}`;
434
516
  case 'update_status':
435
517
  return `📢 ${args.status}`;
518
+ case 'update_steps':
519
+ return `☑ update steps`;
436
520
  case 'ask_user':
437
521
  return `❓ ${String(args.question ?? '').slice(0, 60)}`;
438
522
  case 'load_skill':