@aragon-agent/cli 0.6.24 → 0.6.25

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 (37) hide show
  1. package/CHANGELOG.md +1835 -1786
  2. package/README.md +2578 -2562
  3. package/dist/agent/controller.d.ts +49 -3
  4. package/dist/agent/controller.js +78 -3
  5. package/dist/agent/conversation-reset.d.ts +91 -0
  6. package/dist/agent/conversation-reset.js +66 -0
  7. package/dist/agent/model-probe-limits.d.ts +39 -0
  8. package/dist/agent/model-probe-limits.js +25 -0
  9. package/dist/agent/model-probe.d.ts +104 -0
  10. package/dist/agent/model-probe.js +391 -0
  11. package/dist/agent/reducer.js +45 -13
  12. package/dist/commands/builtins.js +14 -34
  13. package/dist/commands/clear-command.d.ts +27 -0
  14. package/dist/commands/clear-command.js +107 -0
  15. package/dist/commands/registry.d.ts +20 -1
  16. package/dist/config/model-profiles.d.ts +8 -0
  17. package/dist/config/model-profiles.js +10 -0
  18. package/dist/session/clear-archive.d.ts +51 -0
  19. package/dist/session/clear-archive.js +160 -0
  20. package/dist/todo/types.d.ts +5 -3
  21. package/dist/ui/App.js +39 -7
  22. package/dist/ui/entries/CompactionCard.d.ts +5 -4
  23. package/dist/ui/entries/CompactionCard.js +5 -4
  24. package/dist/ui/overlays/HelpOverlay.js +8 -2
  25. package/dist/ui/overlays/ModelDiscoveryList.d.ts +23 -0
  26. package/dist/ui/overlays/ModelDiscoveryList.js +161 -0
  27. package/dist/ui/overlays/ModelProfileEditor.d.ts +18 -1
  28. package/dist/ui/overlays/ModelProfileEditor.js +117 -68
  29. package/dist/ui/overlays/SettingsScreen.d.ts +8 -0
  30. package/dist/ui/overlays/SettingsScreen.js +34 -2
  31. package/dist/ui/overlays/model-probe-view.d.ts +128 -0
  32. package/dist/ui/overlays/model-probe-view.js +225 -0
  33. package/dist/ui/overlays/model-profile-state.d.ts +9 -1
  34. package/dist/ui/overlays/model-profile-state.js +10 -0
  35. package/dist/ui/overlays/use-model-probe.d.ts +30 -0
  36. package/dist/ui/overlays/use-model-probe.js +109 -0
  37. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,1786 +1,1835 @@
1
- # Changelog
2
-
3
- All notable changes to `@aragon-agent/cli` are documented here. Entries at
4
- `0.4.x` and earlier refer to the package by its former name, `@argon-agent/cli`
5
- — those releases really were published under that name, so they are left as they
6
- were written.
7
-
8
- ## Unreleased
9
-
10
- ### Fixed
11
-
12
- - **`Ctrl+I` was dead on Windows.** The win32-input-mode translator only
13
- recognised the chord when the console reported it as `VK_TAB` (vk 9) with
14
- ctrl - a record shape no real console was ever probed for. Physical
15
- Ctrl+I keeps the LETTER vk (0x49, the same Ctrl+letter rule that reports
16
- Ctrl+A as vk 65 and Ctrl+J as vk 74 in the Shift+Enter probe captures)
17
- while `char` carries the Tab byte, so the record fell through to the
18
- generic Ctrl-combo branch, came out as plain Tab, and the keybinding
19
- silently did completion instead of opening the index confirm. The
20
- translator now tells Ctrl+I apart from Tab by `char === 0x09 && ctrl`
21
- whatever vk it rides, with Shift still mapping to Shift+Tab; both record
22
- shapes are pinned by regression rows in `win32-input-mode.test.ts`.
23
-
24
- ### Team dispatch supervisor (team-overseer)
25
-
26
- - **A time ceiling on a subagent is now an inspection trigger, not a death
27
- sentence.** With the supervisor on (new key `team.overseer`, default
28
- `true`, needs the fast tier), two soft timers per child - event silence at
29
- `idleTimeoutMs` and a wall clock at `subagentTimeoutMs` (or 5 minutes when
30
- no ceiling is configured) - fire one bounded fast-tier inspection. The
31
- supervisor decides wait / nudge / replace / abandon; the runtime applies,
32
- funnelling every lifecycle change through the worker loop that awaits the
33
- child, so a replacement is never built for nobody.
34
- - **A nudge is steering; a replace is a rebuild with an amended brief.**
35
- Guidance is queued at core's safe top-of-loop checkpoint; a replacement
36
- carries the supervisor's reason, the dead child's `filesTouched`, and the
37
- original brief bounded to the same prompt budget. A post-mortem inspection
38
- diagnoses a child that died silently (watchdog death, stream loss) and may
39
- re-assign it once.
40
- - **Budgets are structural, not settings**: 4 inspections and 1 replacement
41
- per child per dispatch; past them the child runs under its own (lengthened
42
- while supervised) idle watchdog and the supervisor goes quiet. An
43
- unparseable or failing supervision call always becomes `wait` -
44
- supervision must never kill a healthy child.
45
- - Every applied decision is visible three ways: the report's Supervisor
46
- section (`[silence 30s] a1: nudge - ...`), the team panel and the `-p`
47
- stderr line, and a `debug` log event. `aragon exec` emits it as an
48
- additive `team` subtype `overseer` (`EXEC_SCHEMA_VERSION` unchanged).
49
- - New command `/team overseer on|off` (refused mid-dispatch, like every
50
- other `/team` setting) and new config key `team.overseer`, also settable
51
- as `aragon config set team.overseer false`. With the supervisor off - or
52
- no fast tier - every path is byte-for-byte the pre-feature regime:
53
- `subagentTimeoutMs` is a hard abort and silence is the child's own
54
- watchdog.
55
-
56
- ### 启动与缩窗不再误报 Frame diff lost sync
57
-
58
- - 启动即现的 "Frame diffing lost sync with the terminal and fell back to a
59
- full repaint … `--no-diff-render`" 警告已消除:Ink 挂载/卸载经渲染 stdout 写出的
60
- 光标隐藏/恢复序列(`ESC[?25l` / `ESC[?25h`)由帧写入器直接透传——不进差分、
61
- 不失效缓存、不计 fallback,也不再消耗会话的首写豁免。启动序列恢复
62
- "种子帧透传 → 首帧全量 → 之后纯 diff"。
63
- - 终端高度缩小(拖小窗口、改字号、面板重排)不再触发同一条警告:Ink 的
64
- `clearTerminal` 整帧写入被差分器识别为 Ink 自身写法,透传并失效缓存但不计
65
- fallback;该控制写同样不消耗首写豁免,其后的首个 log-update 帧仍按种子帧豁免,
66
- 下一帧自然全量重绘。
67
- - `/perf` 的 `fallbacks` 重新从 0 起步,"健康会话 fallbacks === 0" 的诊断信号
68
- (AC-11)恢复可判。
69
-
70
- ### Consistent TUI styling
71
-
72
- - Interactive sessions always use Unicode and default to truecolor, including
73
- PowerShell sessions without terminal or UTF locale markers. Ink's actual color
74
- output follows the same policy, with renderer state restored on exit.
75
- - Explicit color opt-outs keep Unicode borders and icons; the opening logo now
76
- depends only on available space. Headless terminal detection is unchanged.
77
- - Reloading model settings preserves session display preferences. Syntax
78
- highlighting follows the same color policy, and status icons use consistent
79
- single-column glyphs to prevent narrow-frame overflow.
80
- - Hiding the editor caret while scrolling preserves draft geometry, preventing
81
- a layout update loop when entering text above the full startup logo.
82
- - Register exit cleanup before mounting the application, so immediate exits and
83
- initial render failures restore terminal and color state reliably. Failed
84
- mounts no longer mark an auto-installed build as healthy.
85
-
86
- ### Model context window
87
-
88
- - Discover context limits at startup and after connection changes without blocking
89
- input. The status bar and compaction use the discovered limit; `/context` names
90
- API versus catalog metadata. Unknown windows show `?`, not a fabricated 128k
91
- capacity or percentage. Manual `contextWindow` overrides retain precedence.
92
- - Window overrides now apply to tail relief and compaction progress as well as
93
- the gauge. Workers on different models/endpoints do not inherit the lead's
94
- override. API-key changes refresh metadata, and ending a session cancels its
95
- pending model queries. `/context` also hides unknown capacities/percentages.
96
-
97
- ### TUI 输入与排队可靠性
98
-
99
- - Shift+Enter 与粘贴按输入顺序处理;普通 Enter 保持弹层兼容,混合输入最多提交一次,
100
- 余稿及拒绝提交的正文保留。结束输入流时完整排空,不泄漏内部控制标记。
101
- - 超限粘贴拒绝同一外部输入块的正文和 Enter,避免误提交旧稿;未闭合粘贴继续按正文消费。
102
- - 拖选后仅 Ctrl+C 复制;文字变化与丢失鼠标释放时取消无效高亮,避免卡住视口。
103
- - 固定 Queue 状态行按消息 ID 回执更新,支持窄屏、暂停与多条消息计数。
104
- - 保存和退出保留所有未发送全文;恢复先验证存档,旧 queued 作为警告展示且不自动重放。
105
-
106
- ### Removed
107
-
108
- - Removed the inline terminal UI and its automatic downgrade rules. Interactive
109
- sessions now always use the full-screen UI; small windows show a resize notice.
110
- - Removed `--fullscreen`, `--no-fullscreen`, `ARAGON_FULLSCREEN`, and the
111
- `fullscreen` config setting. Old flags are rejected and old stored preferences
112
- are ignored. Headless commands and piped input retain their existing behavior.
113
- - Interactive-only screens now reject non-TTY input/output with exit code 2.
114
-
115
- ### Added
116
-
117
- - **`system/init` now lists what this build can do.** A new optional
118
- `capabilities: string[]` field, carrying `["interrupt"]` for this release.
119
-
120
- A wrapper cannot tell by observation whether an interrupt will settle
121
- gracefully or kill the process outright, and guessing wrong costs the user
122
- their conversation. Rather than have callers compare version numbers — which
123
- breaks on forks, prereleases, and version shapes nobody anticipated — the
124
- build now says so itself, in an event that already arrives on every start.
125
- Absent on older builds, and absence should be read as "no", never as
126
- "probably".
127
-
128
- Additive, so `schemaVersion` does not move. Consumers that do not know the
129
- field ignore it, exactly as the schema contract asks.
130
-
131
- - **The composer understands pasting.** Until now it did not have the concept at
132
- all: every byte the terminal delivered on stdin was a keystroke, and a
133
- clipboard block is thousands of bytes arriving in an unpredictable number of
134
- chunks. Three separate failures fell out of that one omission, and on Windows
135
- you hit all three at once.
136
-
137
- A carriage return that landed alone in a chunk **sent the half-finished
138
- message** — a fifteen-line paste could arrive as a dozen separate messages,
139
- interleaved with the agent's replies. A carriage return in the middle of a
140
- chunk was inserted into the draft as a literal `\r`, which the terminal obeyed
141
- by **overwriting the row it was drawn on**. And a paste that survived both grew
142
- the composer to the height of the pasted text, pushing the transcript out of a
143
- frame whose row accounting still believed the composer was three rows tall.
144
-
145
- Pasting now works the way it reads:
146
-
147
- - **A paste never submits.** Line breaks become buffer newlines, exactly one
148
- per source line break, `CRLF` and lone `CR` alike.
149
- - **A short paste appears verbatim.** At or below 6 lines and 400 characters it
150
- is inserted as-is, indentation intact, and renders exactly like typed text.
151
- - **A large paste collapses to a placeholder** — `[Pasted text #1 +218 lines]`
152
- — which occupies one line, carries its own size in its label, deletes as a
153
- single unit (one `Backspace`, and `Ctrl+W` / `Ctrl+U` / `Ctrl+K` cannot leave
154
- half of one behind), and expands back to the full text the moment you send.
155
- The model receives every byte; the composer never has to draw them.
156
- - **No pasted byte is executed as a terminal control.** `\r`, `\x1b`, NUL, DEL
157
- and the C1 range are stripped from the payload — never from your keystrokes,
158
- so `Ctrl+A` and Escape are untouched.
159
- - **The composer has a ceiling.** A draft of any length occupies at most 3 / 6 /
160
- 10 rows depending on terminal height, scrolls internally to keep the caret
161
- visible, shows how many rows are hidden above and below, and reports its true
162
- height to the layout budget. Four hundred presses of `Shift+Enter` were
163
- already able to destroy the frame; they no longer are.
164
- - **A submitted message cannot make the transcript unresponsive.** A user entry
165
- renders at most 40 rows plus a `... +N more lines` tail. The full text is kept
166
- and the exit transcript is uncapped.
167
-
168
- On terminals that support it, detection is **exact**: aragon asks for bracketed
169
- paste (`DECSET 2004`) in full-screen mode and reads the markers the terminal
170
- wraps your paste in. Where that is unavailable — inline mode, an old Windows
171
- console — a heuristic on chunk shape catches the same cases, and it needs no
172
- cooperation from the terminal at all. Both feed one code path.
173
-
174
- Turn it off with `--no-paste`, `ARAGON_PASTE=0`, or
175
- `aragon config set paste false`; the input path is then byte-for-byte what
176
- 0.6.2 did.
177
-
178
- ### Fixed
179
-
180
- - **The right-edge scrollbar no longer disappears while output streams.** The
181
- differential renderer ended every repainted row with `CSI K` (erase to end of
182
- line). The scrollbar fills the last column of every viewport row, and on
183
- terminals that keep the cursor on the last column after writing it (Windows
184
- console hosts) that erase blanked the cell that had just been drawn, so the
185
- scrollbar vanished whenever a row was redrawn. Rows that already fill the
186
- terminal width are now repainted without the erase; narrower rows are
187
- unchanged. `--no-diff-render` was never affected. `/perf` gained a `scrollbar:`
188
- line for diagnosing visibility and drag problems.
189
-
190
- - **`{"type":"interrupt"}` now really does settle the run — on every platform.**
191
- The stdin interrupt frame used to raise a SIGINT at our own process. On POSIX
192
- that reaches the runner's terminator and the run winds down properly: it
193
- breaks out of the loop, persists the session, and emits `result` with the
194
- usage and cost. On Windows, Node does not deliver a self-directed SIGINT to
195
- its own handlers — the process simply terminated with exit code 1, having run
196
- none of it.
197
-
198
- For anyone using `aragon exec` interactively that difference was invisible,
199
- because an interrupt there is usually the last thing that happens. It is not
200
- invisible to a **wrapper** that interrupts a turn and then respawns on the same
201
- `--session-id` to keep the conversation going: on Windows it silently got back
202
- a session missing everything since the previous save. `exec/index.ts` has
203
- carried a comment about that caller for some time ("PERSIST FIRST, ANNOUNCE
204
- SECOND … a caller that reads `result` and immediately respawns with the same
205
- `--session-id` must not race the writer"), so the intent was there; the path
206
- just could not be reached on Windows.
207
-
208
- The frame now calls the runner directly instead of going through a signal.
209
- POSIX behaviour is byte-for-byte unchanged — the same code runs, with the same
210
- `stopReason`, the same exit code 130, and the same two-second window in which a
211
- second signal still forces an immediate exit.
212
-
213
- - **A pasted API key is stored correctly again.** Ink broadcasts each stdin chunk
214
- to every mounted input handler, so the settings screen, the question overlay
215
- and the plan-review feedback field all see what the composer sees. Without
216
- this, a ~100-character key pasted into Settings would have been stored wrapped
217
- in invisible framing bytes, masked on screen by the password dots, and would
218
- have failed to authenticate on every request afterwards with nothing anywhere
219
- explaining why.
220
-
221
- - **`--no-mouse` still writes no mouse sequence.** Paste support installs a
222
- stdin filter, and `paste` defaults to on, so the filter now exists in sessions
223
- that disabled the mouse. Whether the mouse is on is a separate question from
224
- whether the stream is wrapped, and the four places that used to conflate them
225
- now ask the right one: `aragon --no-mouse` writes no `?1000h`, no `?1006h` and
226
- no `?1002h`, leaves your terminal's own click-drag selection alone, and reports
227
- `/mouse` as off — while pasting still works.
228
-
229
- ### Changed
230
-
231
- - **The run status row moved above the input box and carries the `steer` hint.**
232
- While a run is active, the spinner, the phrase and `steer / interrupt / exit`
233
- share one row directly above the input, in place of the idle hint row below it
234
- (the footer keeps its height). It scrolls with the input; when it leaves the
235
- viewport the fixed bottom row shows the animation instead, so there is never
236
- more than one spinner. Terminals under 20 rows and `--no-hints` keep the old
237
- fixed row. The update notice is also held back for the whole run.
238
-
239
- - **Auto-compaction no longer reports compactions that did not happen.** A long
240
- unattended run used to print a red `context not compacted #2: nothing_to_drop`
241
- card into the transcript. The card was accurate; nobody had asked for it.
242
- Auto-compaction evaluates itself at every turn boundary, and a checkpoint that
243
- looks at the history and finds nothing worth dropping has changed nothing,
244
- called nothing and spent nothing — a smoke alarm announcing "no fire" twice an
245
- hour, in error colours, with a machine reason attached.
246
-
247
- A compaction now announces itself **if and only if it commits to doing work**.
248
- That is a position in the control flow, not a list of reason strings: everything
249
- decided before the first spend is silent, and everything decided after it —
250
- including every failure, the truncation fallback, an Esc, and a host fault — is
251
- as loud as it ever was. A declined `pressure` checkpoint is now
252
- indistinguishable from a turn on which the threshold was never crossed.
253
-
254
- **`/compact` and overflow recovery are unchanged.** A compaction you asked for
255
- is owed an answer, and a reactive compaction running after the provider has
256
- already refused your request is the one moment the diagnosis matters most. Both
257
- still report on every outcome.
258
-
259
- **Quiet, not unrecorded.** Every attempt is still written to the diagnostic log
260
- (its `compaction` line gains an `announced` field, so `announced: false` is one
261
- grep), still charged to the anti-loop guards, and still counted by
262
- `/compact status` — which now reads
263
- `This session: 1 compaction (2 checkpoints declined), 94.2k tokens reclaimed`
264
- when checkpoints declined, and is byte-identical to before when none did. If
265
- declines keep happening, the self-disable notice still says so out loud, once,
266
- naming the cause and the remedies. Card numbers are also contiguous again: `#N`
267
- counts compactions that ran, not checkpoints that fired.
268
-
269
- **Behaviour change for wrapper scripts.** A declined `pressure` compaction no
270
- longer emits a `{ type: 'compaction', subtype: 'start' | 'end' }` pair on the
271
- `--output-format json` stream, and no longer prints `[compaction] skipped:` on
272
- `-p` stderr. The pairs stay balanced, so only consumers counting *attempts* are
273
- affected; the diagnostic log reports those more accurately.
274
-
275
- ### Added
276
-
277
- - **Context compaction, hardened — the trigger now counts the whole history, the
278
- recent turns can no longer wedge a run, sub-agents get the same protection, and
279
- a compaction is no longer irreversible.**
280
-
281
- **The trigger was systematically late.** It fired on the provider's reported
282
- usage for the PREVIOUS request, read at a checkpoint that runs AFTER the current
283
- turn's tool results were appended — and tool results are the largest single
284
- increment in this loop (100 KB per call, several per turn, ~25 k tokens each).
285
- A session reading 88 % could be sending 110 %. Occupancy is now the measured
286
- base PLUS an estimate of everything appended since that measurement, and the
287
- status gauge reads the same number the trigger does, on every turn — including
288
- the turns where a guard declines to compact, which is exactly when the number
289
- matters most.
290
-
291
- **The recent turns can no longer wedge a run.** Every previous rung of the
292
- ladder operated on the head of the conversation. When the RETAINED tail was what
293
- did not fit, each rung reported success or "nothing to drop" while the history
294
- stayed un-sendable and the run died. Oversized `tool_result` bodies inside the
295
- retained turns are now clipped, oldest first, only when the alternative is a
296
- request the provider cannot accept. Nothing is removed — no message, no
297
- tool-call id, no role — so a valid history stays valid. Every clip is announced
298
- in the text the model reads, at the exact place the data went, and on the card,
299
- in `/compact status`, on the JSON stream and in the archive.
300
-
301
- **Sub-agents compact their own history** (`compaction.subagents`, default
302
- `true`). A `task` child is bounded by 24 turns and fifteen minutes, and when one
303
- overflowed its entire history was discarded and the dispatch reached the lead as
304
- one partial sentence. Children run under tighter bounds than the lead: two
305
- retained turns, at most two compactions, the fast tier preferred, and failure
306
- forced to truncate because nobody is watching a background worker. No transcript
307
- card — the lead's transcript describes the lead's context. Set
308
- `compaction.subagents: false` to restore the previous behaviour exactly.
309
-
310
- **A compaction is no longer irreversible** (`compaction.archive`, default
311
- `true`). The dropped messages are written verbatim to `~/.aragon/compaction/`
312
- before the splice is adopted. `/compact history` lists this run's archives,
313
- `/compact show <n>` prints one's metadata and summary — never message bodies.
314
- The directory is shared by every `aragon` on the machine, so files carry a
315
- per-process run id and retention is two-tier: 20 files per run by count, plus a
316
- seven-day sweep across all runs, so one session can never prune a live
317
- neighbour's work. Writing is best-effort: a failure is logged and never affects
318
- the compaction. This is deliberately **not** undo — restoring an over-full
319
- history restores the condition that triggered the compaction.
320
-
321
- **The long moment is legible.** The live card counts elapsed seconds and says
322
- `esc to cancel`, which `AgentController.abort()` has always made true and no
323
- surface has ever stated. A compaction that could only clip says so and names no
324
- model, because none was called.
325
-
326
- Two new config keys (`compaction.subagents`, `compaction.archive`), two new
327
- environment variables (`ARAGON_COMPACTION_SUBAGENTS`,
328
- `ARAGON_COMPACTION_ARCHIVE`), two new `/compact` verbs (`history`, `show <n>`),
329
- and two new settings-screen rows. No flags were added.
330
-
331
- - **Context compaction — a long run no longer dies when the window fills, and it
332
- is ON by default.** A session's conversation only grows: nothing anywhere
333
- removed a message, so a 40-turn tool-heavy run had exactly one ending available
334
- to it once the context window filled — an HTTP 400 and a banner reading
335
- *"Context length exceeded — start a new conversation with /reset."* The
336
- product's answer to running out of context was "throw away everything you were
337
- doing."
338
-
339
- Now, at **90 %** occupancy, the run pauses at a turn boundary, hands the older
340
- part of the history to a summarizer, and swaps it for a structured record. Your
341
- original task stays **verbatim**, the most recent turns stay **verbatim**, and
342
- the run continues in the same loop with the same tools, the same todo list and
343
- the same working directory.
344
-
345
- **This changes behaviour for existing users, in the direction of not dying.**
346
- `--no-compaction`, or `compaction.enabled: false`, restores the old behaviour
347
- exactly: no manager is constructed, nothing is subscribed, no registry is
348
- allocated, and a full window ends the run as it did before. Both flag forms are
349
- declared, so a stored `false` survives a run that passes no flags.
350
-
351
- Three ways it fires. **Proactively** on measured occupancy — the case that
352
- happens almost every time. **Reactively** when the provider returns
353
- `context_overflow` anyway, because the model is not in the static window table
354
- or you are pointed at a proxy in front of a smaller one: one compaction, one
355
- re-send, run continues. And **manually**, via `/compact`, which runs
356
- immediately when idle and queues to the next turn boundary when running.
357
-
358
- The trigger has two terms. 90 % of a 200 k window leaves 20 k, which is plenty;
359
- 90 % of a 32 k window leaves 3.2 k, which is less than a single `max_tokens` of
360
- 8192 — the request is already impossible. So compaction also fires whenever the
361
- remaining headroom drops below one full response.
362
-
363
- **The default summarizer is your own model, and that costs real money.**
364
- `compaction.useFastTier` is `true`, but it is a *preference*: the fast tier is
365
- off unless you configured it, so out of the box the first compaction is a
366
- ~30 k-token call on the session's own model. It happens at most 5 times per
367
- run, the alternative is losing the run entirely, and the spend is visible — in
368
- the session total, priced with the summarizer's own table, and reported as
369
- `pricing unknown` rather than `$0.00` when that table has never seen the model.
370
- Configure the fast tier to make it cheap.
371
-
372
- Summarization fails sometimes. The ladder is one retry (on your **main** model
373
- if the first attempt used the fast tier), then a **truncation** that says so on
374
- the card, on the JSON event stream, and inside the block the model itself
375
- reads. `compaction.onFailure: "stop"` makes the other trade.
376
-
377
- Four guards stop it looping on your money: never two on consecutive turns,
378
- never more than 5 per run, a progress requirement, and a self-disable after two
379
- no-progress attempts with a notice naming the cause and the fix. The guards are
380
- **trigger-aware** — the reactive path stays armed even after a self-disable,
381
- because a compaction answering a request the provider has already refused is
382
- the difference between a live run and a dead one.
383
-
384
- Three UI surfaces: `Compacting context…` on the activity row while it runs, a
385
- `compacting` chip plus threshold-aligned gauge colours as state, and a
386
- transcript card with the before/after counts, the summarizer, the duration and
387
- an expandable summary as the record. The gauge falls **immediately** rather
388
- than waiting for the next turn. `/compact status` is the guaranteed surface at
389
- any width.
390
-
391
- New: `compaction` config section (6 keys), `--compaction` / `--no-compaction` /
392
- `--compaction-threshold`, `ARAGON_COMPACTION*` (3 vars), `/compact` (6 forms),
393
- three settings-screen rows, a `compaction` event on the `aragon exec` JSON
394
- stream (`EXEC_SCHEMA_VERSION` **unchanged** — adding an event type never bumps
395
- it), and two stderr lines under `-p`.
396
-
397
- ### Changed
398
-
399
- - **The context gauge now counts cache tokens**, through the same
400
- `occupiedTokens` the compaction trigger reads. Anthropic reports `input_tokens`
401
- *excluding* cached tokens and puts them in two separate fields, so the old
402
- `inputTokens + outputTokens` silently under-reported occupancy for anyone
403
- behind a caching gateway. That was already a defect in the number on the status
404
- bar; it becomes a much worse one the moment a trigger fires on a different
405
- number from the one you are watching.
406
-
407
- - **`context_overflow` now names `/compact` alongside `/reset`.** That remedy
408
- list was complete until this release, because throwing the conversation away
409
- really was the only exit.
410
-
411
- ### Known limitation
412
-
413
- - **A summarizer that is 90 % faithful will, eventually, drop something the run
414
- needed,** and no amount of prompt engineering closes that. The design bounds it
415
- — verbatim task, verbatim recent turns, a block that tells the model the record
416
- is partial, and three surfaces that make it visible so a human can step in —
417
- but it does not eliminate it. That is inherent to compaction as a technique, it
418
- is the same trade Claude Code and Codex make, and it is preferable by a wide
419
- margin to the previous behaviour, which was to lose the entire run.
420
-
421
- ## 0.6.0
422
-
423
- ### Added
424
-
425
- - **`aragon exec` — a second, machine-facing face on the same binary.** The
426
- package already installed from npm and already ran from a terminal, so "it has
427
- a CLI" was true. It was nonetheless not *callable* by another program:
428
- everything it exposed was shaped for a person, and a build script, a CI job, a
429
- web backend or a second agent had to spawn it, capture free text, and guess.
430
- There was no way to read the answer without also reading the narration, no way
431
- to carry a conversation across two invocations, no way to say "you may read but
432
- not write" when there is no human to answer `--confirm`, and no way to bound
433
- what a run may spend.
434
-
435
- `aragon exec` adds a **contract** rather than a feature: a versioned JSON event
436
- schema on stdout, a session identifier the caller may mint itself, a tool
437
- permission policy enforced at the tool boundary, caller-set budgets with their
438
- own exit code, and a discovery command so a wrapper can ask what it just
439
- installed before depending on it. Everything underneath is reused unchanged —
440
- the same controller, the same tools, the same config resolution, the same
441
- skills, teams, todo and fast-tier subsystems.
442
-
443
- - `--output-format text | json | stream-json`. `stream-json` is NDJSON: one
444
- object per line, `system/init` first, exactly one `result` last, on every
445
- exit path including error, budget and signal. `text` is byte-identical to
446
- `aragon -p`, because it **delegates** to the same renderer rather than
447
- reimplementing it.
448
- - `--session-id` / `--resume` / `--continue`, backed by `~/.aragon-agent/
449
- sessions/` and an exclusive lock, so two runs cannot interleave and lose a
450
- turn. A second run on a held id exits 2 with `session_busy` rather than
451
- blocking.
452
- - `--permission-mode auto|plan|strict` plus `--allow-tool` / `--deny-tool`.
453
- A denied tool is **not registered at all**, so the model never sees it and
454
- never plans around it — and the policy reaches subagents, so one `task` call
455
- cannot bypass it.
456
- - `--max-turns` / `--max-duration`, both aborting through the same path `Esc`
457
- uses, both reporting `isError: false` and exit **3**: a budget firing is not
458
- a malfunction, but it is not a complete answer either, and a shell script has
459
- to be able to tell without parsing JSON.
460
- - `--append-system-prompt` / `--append-system-prompt-file`. Appending only;
461
- there is deliberately no full `--system-prompt` replacement, because the
462
- builtin prompt carries tool discipline, todo planning, the skills catalog and
463
- the plan-mode block, and replacing it silently disables half the product.
464
- - `--input-format stream-json`, so one process can serve several turns from a
465
- pipe. A malformed line is skipped with a non-fatal `error` event; an unknown
466
- message type is ignored.
467
- - **`aragon sessions`** (`list` / `show` / `rm` / `prune` / `path`),
468
- **`aragon info [--json]`** and **`aragon doctor [--json] [--probe]`**.
469
-
470
- Documented in full under
471
- [Use it from another project](./README.md#use-it-from-another-project),
472
- including an honest Limits section: there is no filesystem sandbox, process
473
- exit is terminal on Windows whether or not a `result` arrived, an exec session
474
- resumed in the TUI shows no scrollback, and `sessions prune` shares a directory
475
- with the TUI's `/save`.
476
-
477
- ### Changed
478
-
479
- - **Exit code `3` is new, and the signal row is now stated as `128 + signo`.**
480
- `3` means "stopped by a budget you set" and is reachable only from
481
- `aragon exec`. The signal codes are unchanged in behaviour — this CLI has
482
- always exited `128 + signo`, so `SIGTERM` has always been `143` — but the
483
- README previously simplified all of them to `130`, which is fine for prose
484
- about a CLI a human interrupts and not good enough for a wire contract.
485
- - `interrupt` handling now settles the run before exiting when `aragon exec`
486
- owns it, so a wrapper reading NDJSON gets a final `result` on Ctrl-C instead of
487
- having to time out to learn the run ended. `aragon`, `aragon -p` and every
488
- other subcommand keep the previous bare-exit behaviour byte for byte.
489
-
490
- ### Unchanged, and asserted rather than claimed
491
-
492
- - `aragon`, `aragon -p`, every existing flag, every slash command and every byte
493
- of their output. `aragon exec --output-format text` and `runHeadless` are
494
- compared for byte equality on **both** stdout and stderr by a regression test,
495
- and `createBuiltinTools` with no permission policy is proven by object identity
496
- to return the tools it returned before.
497
-
498
- ## Unreleased
499
-
500
- ### Project index on Ctrl+I (bundled `project-indexer` skill)
501
-
502
- - The `project-indexer` skill now ships **bundled** with the package
503
- (`<pkg>/skills/project-indexer`, read-only, alongside `skill-creator`): it
504
- generates the `.claude-index/` navigation map and injects the Google-style
505
- Clean Code Guidelines section into `CLAUDE.md`, adapted from the standalone
506
- Claude Code skill (ask_user instead of AskUserQuestion; body condensed under
507
- the 30 KB invocation budget with the four templates bundled as files).
508
- - New keybinding `Ctrl+I`: opens a Yes/No confirm that names every write
509
- target, then dispatches `/skill:project-indexer` through the ordinary
510
- command path - the indexing run is a normal agent turn whose tool calls
511
- stream into the transcript. While a run is in flight the key warns instead
512
- of queueing; with skills disabled or the skill shadowed it explains instead
513
- of failing silently.
514
- - `Ctrl+I` is legacy-encoded as the Tab byte, so the stdin filter's two
515
- translators (win32-input-mode on Windows, kitty CSI-u / modifyOtherKeys
516
- elsewhere) now emit a distinct NUL-delimited `INDEX_KEY_FRAME` for it -
517
- the same framing technique `Shift+Enter` uses. On terminals with neither
518
- protocol the key keeps its legacy Tab meaning (completion).
519
- - The header names the key next to the detail toggle: `^I Index` collapsed,
520
- `^I build index` in the `Ctrl+G` expanded state; hidden below 72 columns and
521
- while an overlay is open. `/skill:project-indexer` and `/project-indexer`
522
- remain available as typed commands.
523
-
524
- ### Added
525
-
526
- - **Drag the mouse to select text, and release to copy it.** Full-screen mode
527
- takes the alternate screen, turns on mouse reporting so the wheel can scroll a
528
- transcript the terminal no longer knows how to scroll, and draws every row
529
- itself. Each of those is right on its own; together they took your terminal's
530
- own drag-to-select away and put nothing in its place. The only thing shipped
531
- in its place was a one-line notice naming a bypass key that is Shift on some
532
- emulators, Fn on others and a preference elsewhere — a workaround, told once,
533
- in a line that scrolls away.
534
-
535
- Press the left button and drag: the cells you drag across are highlighted as
536
- you go, and releasing copies exactly them. The copy goes out over **OSC 52**
537
- first, so it reaches the clipboard of the machine you are *sitting at* rather
538
- than the one you are ssh'd into, with the platform clipboard binary attempted
539
- alongside it for terminals that ignore the sequence. Neither mechanism is
540
- detectable, so the toast names what was sent rather than claiming a success it
541
- cannot verify. `/copy` now goes through the same path and gained ssh support on
542
- the way.
543
-
544
- The highlight is painted in the frame pipeline rather than in React, so a drag
545
- costs one to three re-addressed rows instead of a re-render of the whole tree,
546
- and the text that is copied is read from the same mirrored rows the highlight
547
- was painted over — what you see is what you get by construction, not by a
548
- staleness check that can be wrong.
549
-
550
- Two switches, both reversible without a restart: `/mouse off` hands the mouse
551
- back to your terminal for the session (and says plainly that the wheel goes
552
- inert while it is off), `/mouse on` takes it back, and
553
- `aragon config set mouseSelect false` keeps wheel scrolling while leaving
554
- drag-select off — which also stops the CLI asking the terminal for motion
555
- reports at all, so that session puts exactly the bytes on the wire that it did
556
- before this release. `--no-mouse` remains the switch that captures nothing.
557
-
558
- ### Changed
559
-
560
- - **Scrolling up now actually stops the transcript.** The viewport followed the
561
- newest output by holding a *fixed distance from the bottom*, so scrolling up
562
- during a run did not pause anything: twelve new rows of output moved the
563
- window twelve rows down, and whatever you had scrolled up to read slid off the
564
- top while you were reading it. The faster the agent talked, the faster your
565
- reading position ran away.
566
-
567
- While you are scrolled up, the transcript is now anchored to the **content**:
568
- new output accumulates below the window instead of dragging the window along
569
- with it, and the rows on screen hold still. After five seconds with no
570
- scrolling the viewport returns to the newest line by itself — but only if
571
- something actually arrived while you were paused, so reading a *finished*
572
- transcript is never interrupted by a jump to a bottom that has not moved.
573
- Every gesture restarts the countdown, a selection drag suspends it, and
574
- `aragon config set scrollResumeMs 0` turns the return off entirely
575
- (`ARAGON_SCROLL_RESUME_MS` sets it too).
576
-
577
- The number the hint shows means something sharper as a result: it is now
578
- literally "rows of newer output below your reading position", which is what
579
- `PgDn` traverses and what the status bar's `↑N` has always shown.
580
-
581
- - **The "N new lines · PgDn" hint moved inside the input box.** It used to be
582
- rendered as the viewport's own last row, which spent a line of your transcript
583
- on chrome at exactly the moment the transcript was longest — and, because the
584
- hint's presence shrank the viewport, it fed back into the very number it was
585
- displaying. It is now a right-aligned chip on the composer's input row, inside
586
- the border, where it costs no rows at all. The chip sits in a fixed-width cell
587
- so the number gaining a digit cannot re-wrap a draft, it never truncates (the
588
- draft wraps first), and unlike the teaching row below the box it neither fades
589
- with experience nor disappears on a short terminal: how far behind you are is
590
- state, not a tutorial.
591
-
592
- ### Fixed
593
-
594
- - **The working spinner no longer disappears when an ack takes its row.** Steer a
595
- run, approve a plan, or press `Ctrl+T` while the agent is working, and the row
596
- above the composer traded its spinner for the acknowledgement — and for that
597
- ack's full two and a half seconds, nothing anywhere on screen moved. The status
598
- bar still read `running` and the tool card still read `running`, so no
599
- information had left the frame; only the evidence that the process was alive
600
- had, during exactly the long tool calls where "is it stuck?" is the question you
601
- are already asking. Consecutive acks extended the window, and steering is
602
- something the composer invites on every run.
603
-
604
- That row was made the sole owner of animation in this same release, and
605
- everything else on screen holds still for as long as the row is believed to be
606
- showing one. Believed, not checked: an ack won the row outright, so the belief
607
- and the frame disagreed, and the disagreement was invisible to every test
608
- because no component was wrong on its own.
609
-
610
- The ack still owns the row and keeps every word of its text. The spinner now
611
- rides beside it as a bare glyph — no phrase, no clock — so there is exactly one
612
- animation at every instant of a run, with an ack up or without one: never none,
613
- and never the several this release set out to remove. Terminals without Unicode
614
- and anyone running with `reducedMotion` come out byte for byte unchanged; they
615
- had no animation to lose, and nothing is prefixed to their acks.
616
-
617
- - **`/clear` now takes the todo panel with it.** Finish a plan, type `/clear`,
618
- and the transcript emptied while the `7/7 done` rail stayed exactly where it
619
- was — on a screen you had just asked to be cleared. It stayed until your next
620
- real message, which is precisely the pause you take after clearing to decide
621
- what to ask next, so essentially everyone met it.
622
-
623
- This was deliberate once. The list is a projection of what the model believes,
624
- and `/clear` wipes the transcript rather than the conversation, so the model
625
- still believed in the plan and a panel contradicting the model was judged worse
626
- than no panel. That reasoning holds for everything the CLI does on its own; it
627
- does not hold against you typing the command. An explicit instruction was
628
- always this rule's exception — `/todo clear` has used the same door from the
629
- start — and `/clear` now goes through it.
630
-
631
- The list itself is cleared, not just the pixels, so `/save`, `/todo status`,
632
- `/todo continue` and auto follow-through all agree with the screen: no plan is
633
- written into a saved session, nothing offers to continue one, and nothing spends
634
- a follow-through on it. `/reset` is unchanged and still the only command that
635
- clears the conversation. Nothing is stranded either way — the model's next
636
- `todo_write` is a full replacement, so the panel comes back the moment there is
637
- a plan to show.
638
-
639
- ### Added
640
-
641
- - **An update that will not start is undone automatically.** The updater shipped
642
- in this same release could install a version that fails to *import* — an
643
- undeclared dependency, a Node API that moved, a syntax error past the transpile
644
- target — and the only recovery was to know the package name and type
645
- `npm i -g @aragon-agent/cli@<some older version>` from memory. None of those
646
- failures reach any line inside `main()`, so no amount of care there helps.
647
-
648
- The `aragon` command is now a small launcher that runs **before** the CLI. It
649
- reads one ~300-byte file, and on every launch except the first one after an
650
- auto-update that is all it does — no write at all. But if the version it is
651
- about to start is one **this updater installed**, and that version has already
652
- exited non-zero twice, it reinstalls the version that was running before the
653
- update and marks the bad one so nothing puts it back:
654
-
655
- ```
656
- aragon 0.6.0 failed to start twice; rolling back to 0.5.9.
657
- ```
658
-
659
- It boots anyway. If the crash was transient, refusing to start would lock you
660
- out of a working CLI on our guess; the reinstall is detached and finishes
661
- either way. The next session says once what happened and then stops. A **newer**
662
- release clears the mark and installs normally — you were never opted out of
663
- updates, only out of the loop.
664
-
665
- It never touches a version **you** installed yourself, and it does not try to
666
- detect a release that starts and is merely wrong. `aragon update --rollback` is
667
- the same mechanism run deliberately, for the case a human spots in one second
668
- and a heuristic would get wrong on a bad day. Exit `4` means there was nothing
669
- recorded to roll back to.
670
-
671
- **`update.mode: off` disables this too.** The guard is armed only by an
672
- auto-install, so a machine that never auto-installs never arms it — the kill
673
- switch turns off the whole subsystem, recovery included.
674
-
675
- - **A blocked install now says what is actually blocking it.** Every install
676
- failure used to print the same line: `update failed · npm i -g
677
- @aragon-agent/cli`. On Windows the commonest cause is that the shim which
678
- launched us is held open by the shell running it, so that advice hits the same
679
- handle and fails identically — the one visible failure was also a wrong
680
- instruction. Failures are now classified, and three of them name the real
681
- remedy and appear immediately rather than after three strikes, because each is
682
- something you can fix and none of them fixes itself:
683
-
684
- ```
685
- ! update blocked · close other aragon windows, then: npm i -g @aragon-agent/cli
686
- ! update failed · no disk space
687
- ! update needs write access · npm i -g @aragon-agent/cli
688
- ```
689
-
690
- Network failures are deliberately **not** in that set: you cannot fix the
691
- registry and the next check may well succeed, so they stay silent and back off.
692
-
693
- - **Updates work behind a corporate proxy.** Node's `fetch` ignores `HTTP_PROXY`,
694
- so on a proxied machine the check failed silently forever. When the direct
695
- request fails, `aragon` now asks the npm you already have instead, which
696
- honours `proxy`, `https-proxy` and your `.npmrc`. It runs *only* after a
697
- request that has already failed, so on an ordinary machine it never runs.
698
- `/update status` shows `probe: npm` when this is what answered. No credentials
699
- are read or forwarded — we run the command you could have typed.
700
-
701
- - `/update status` gained `rollback`, `lastgood` and `probe` lines, so what the
702
- guard did and what `--rollback` would reinstall are answerable without reading
703
- the log.
704
-
705
- ### Changed
706
-
707
- - **`aragon update` exit codes: a blocked install is now `2`, not `1`.** This is
708
- the one change here a script can notice. `1` means "try again later" and `2`
709
- means "this machine will never auto-update, run the command we printed" — and
710
- for `EPERM` / `EBUSY` / `ENOSPC` the second is the accurate one: waiting does
711
- not unblock a held file handle or an empty disk. A caller shaped like
712
- `aragon update || sleep 300 && retry` changes behaviour. `0`, and `1` for an
713
- ordinary failed check or install, are unchanged.
714
-
715
- - `bin.aragon` now points at `dist/launcher.js` rather than `dist/cli.js`.
716
- `dist/cli.js` is unchanged, keeps its shebang and stays executable, so
717
- `npm start` and any script invoking it directly keep working — only the mapping
718
- moved.
719
-
720
- - **`aragon` keeps itself up to date.** Until now the installed copy was frozen
721
- forever: nothing in the CLI ever looked at the registry, so someone who
722
- installed 0.4.x eighteen releases ago was still running it and the only signal
723
- that anything had moved was a README they were never going to re-read.
724
-
725
- There is now a background updater. At most once every four hours, and at most
726
- once per machine per interval, it asks npm what the `latest` dist-tag resolves
727
- to; if that version is genuinely newer, stable, not deprecated and runnable on
728
- this Node, it installs it silently into the same global installation you
729
- already have and says so on **one line above the composer**:
730
-
731
- ```
732
- * 0.6.0 installed - restart aragon to apply
733
- ```
734
-
735
- **The running process is never mutated in any way it can observe.** The new
736
- version lands on disk and takes effect on the *next* launch. A restart in the
737
- middle of a turn would destroy a live run, a subagent dispatch and an open plan
738
- review, so the line waits and the human decides when.
739
-
740
- The notice does not get its own row — it shares the row the toast stack and the
741
- working line already share, behind both of them. A toast is a response to
742
- something you did and wins outright; the working line is transient and would be
743
- lost if deferred; the update line is persistent and loses nothing by waiting.
744
- The practical effect is that **someone who is actually working never sees the
745
- updater until they stop.**
746
-
747
- It only ever runs `npm i -g` for one kind of installation: a global one where
748
- no project manifest claims to own the version. pnpm, yarn, bun and volta are
749
- each detected and get the correct command for *that* manager printed instead
750
- of a command run on their behalf; `npx`, a project's `node_modules` and a
751
- clone of this repo produce no line at all, because none of them is out of date
752
- in any sense the user can act on. A global directory that cannot be written is
753
- detected before anything is spawned, and npm exiting `0` into a *different*
754
- prefix — which happens on any machine with `prefix=` in `.npmrc` or two Node
755
- installations — is caught by re-reading the version from the directory we
756
- classified, rather than being believed.
757
-
758
- Every failure is silent: it logs, backs off exponentially, and says nothing
759
- until the third consecutive one, at which point it says something actionable.
760
- Four config keys (`update.mode`, `update.checkIntervalMs`, `update.registry`,
761
- `update.distTag`), the flags `--update` / `--no-update`, the environment
762
- variables `ARAGON_UPDATE` and `ARAGON_UPDATE_REGISTRY`, the slash command
763
- `/update [status|now|skip|off]`, and a foreground `aragon update
764
- [--check] [--to <version>] [--json]` for headless users. `update.mode: off`
765
- and `ARAGON_UPDATE=0` are kill switches, and with either set the CLI executes
766
- zero lines of update code.
767
-
768
- Auto-update widens the window in which a compromised release reaches users
769
- without a human decision. The README says so plainly, along with what is and
770
- is not mitigated. No credentials are ever attached to the check.
771
-
772
- - **A running command shows what it is doing.** `bash` is the only tool here that
773
- can run for minutes — `npm test`, a `git clone`, a training job — and while it
774
- ran, its card was one line of text that never changed. Nothing in that frame
775
- distinguished a test suite at 40% from a child process blocked forever on a
776
- password prompt this CLI will never show. Its card now carries the last eight
777
- lines of what the command is printing, plus one footer row that reads
778
- `(running)` or, once the child has been quiet for ten seconds,
779
- `no output for 45s` — with the seconds advancing.
780
-
781
- A `\r`-driven progress bar (npm, pip, curl, docker) is *one* line rewritten a
782
- thousand times, and it renders as **one row counting up in place** rather than
783
- a thousand rows of nearly the same string — including the ordinary case where
784
- the bar emits no newline at all for its entire run.
785
-
786
- Everything the tail shows is **stripped, not interpreted**: ANSI colour, cursor
787
- motion, `\r`, `\b`, tabs and every other control byte are removed at the
788
- boundary before a row is stored, so nothing can move a cursor inside a frame
789
- the renderer believes it owns. It is bounded twice by construction — eight rows
790
- per call, sixteen concurrent calls — so a command that writes 400 MB to stdout
791
- costs a fixed number of retained rows.
792
-
793
- It is a **display and nothing else**. The text the model receives is
794
- byte-for-byte what it was; `Ctrl+O` does nothing while a command runs, because
795
- expansion is a promise about stored content and there is no stored rest of a
796
- 400 MB stream; `/save` during a run writes no tail, since a resumed one would
797
- describe a process that died with the session; and at settle the card is
798
- replaced by the authoritative result exactly as before.
799
-
800
- New config key `liveToolOutput`, defaulting to **`true`** — unlike
801
- `showThinking` below, this adds information rather than hiding it.
802
- `aragon config set liveToolOutput false` (or `--no-live-tool-output`, or
803
- `ARAGON_LIVE_TOOL_OUTPUT=0`, or the **Live output** row in `/settings`) turns it
804
- off, and with it off no store is allocated and no recorder is attached: `bash`
805
- is byte-identical to the build before this entry.
806
-
807
- - **The working line stops guessing while a tool runs.** It reads
808
- `⠙ Running bash` instead of rotating thinking-words. `running` covers the whole
809
- turn, including the minutes the model is idle and a child process is doing the
810
- work, so "Pondering" during a build was not calm — it was wrong. One row, no
811
- digits, no clock: everything the row already promised still holds.
812
-
813
- ### Changed
814
-
815
- - **Reasoning blocks are now hidden by default.** `showThinking` is a new
816
- top-level config key and it defaults to `false`. If you have been reading
817
- thinking every day, this is the entry that concerns you: `Ctrl+T` still shows
818
- it for the session exactly as before, `aragon config set showThinking true`
819
- (or `--show-thinking`, or `ARAGON_SHOW_THINKING=1`) restores the old behaviour
820
- permanently, and `/settings` has a **Show thinking** row directly under
821
- **Thinking**.
822
-
823
- Nothing is hidden silently. A settled turn that thought leaves one muted row
824
- where the block used to be — `✱ thought for 12s · ctrl+t to show` — so the fact
825
- that reasoning happened, how long it took, and how to see it are all still on
826
- screen. In **inline** mode that row omits the key hint and the toast reads
827
- `Thinking shown for new output.`, because a settled entry there has already
828
- been printed into your terminal's scrollback and cannot be repainted; the
829
- toggle applies to the live entry and to everything drawn after it.
830
-
831
- `thinkingLevel` is untouched and means what it always did — the effort the
832
- provider is asked to spend. `showThinking` is only whether the terminal draws
833
- what came back. They are one word apart in the config file, which is why the
834
- flag is `--show-thinking` rather than the shorter name.
835
-
836
- ### Added
837
-
838
- - **A live working line while a run is in flight.** One row above the composer,
839
- carrying a spinner and a word that rotates every four seconds:
840
- `⠋ Percolating…`. Take reasoning off the screen and the gap between submitting
841
- and the first token is otherwise completely blank, which reads as dead rather
842
- than as busy — the two changes are one change.
843
-
844
- It carries no clock and no token count, deliberately: the status bar one row
845
- below already renders both, under the same running condition and driven by the
846
- same 200 ms ticker this row reuses. Under `reducedMotion` the spinner is a
847
- static glyph and the word is chosen once and holds, because rotating text is
848
- motion too. An idle frame is unchanged, and so is the viewport's row budget —
849
- the line shares the row the toast strip already owned rather than adding one.
850
-
851
- - **`write_file` and `edit_file` render a real diff.** Hunks with old/new line
852
- numbers, a `+N -M` summary, add/remove/context colouring, and `(truncated)` or
853
- a `binary` / `too-large` / `unreadable` note when the old side could not be
854
- read. Diffs collapse at 12 rows behind the existing `Ctrl+O` — no new
855
- keybinding. A resumed session written by an older build, or a card whose patch
856
- the bounded store already evicted, falls back to the previous text preview;
857
- nothing renders blank.
858
-
859
- `write_file` previously reported creating a 300-line file as
860
- `Wrote 8214 bytes to path`, and `edit_file`'s diff trimmed the common prefix
861
- and suffix and rendered *everything* in between as one removed block followed
862
- by one added block — for a `replace_all` touching line 40 and line 900, that
863
- was 860 removed rows followed by 860 nearly identical added ones.
864
-
865
- **The model's input got smaller, not larger.** The structured patch reaches the
866
- screen on a CLI-local channel rather than through the tool result, and the text
867
- the model reads gained a 4 000-character ceiling it did not have before (its
868
- only previous bound was the executor's 100 KB backstop). A single-region edit
869
- is byte-for-byte what it was plus one `@@` header; a multi-region edit is
870
- strictly smaller. `write_file`'s result text is unchanged.
871
-
872
- ### Changed
873
-
874
- - **A stream that stops mid-answer is now a loud failure instead of a silent
875
- truncated one.** All three provider adapters used to end their SSE loop by
876
- yielding "done" with whatever had arrived, so a connection closed cleanly
877
- half-way through an answer — a proxy idle cut, a load-balancer timeout, an
878
- HTTP/2 GOAWAY — was indistinguishable from a completed reply. You got a
879
- truncated answer and were told nothing.
880
-
881
- Each adapter now reports the truncation, which is what lets it be retried and
882
- recovered. An **abort** is explicitly excluded and still completes normally, and
883
- a model that legitimately says nothing and stops is still a success.
884
-
885
- This is deliberately **not** behind `--no-retry`: an adapter that reports a
886
- truncated stream honestly should do so whether or not retry is enabled. A switch
887
- that also disabled telling you the truth would be a mute button, not a kill
888
- switch.
889
-
890
- - **The mouse wheel now only ever scrolls.** A notch scrolls the transcript
891
- three rows (a page with `Shift`), or the open overlay when there is one, no
892
- matter where the pointer is sitting. Prompt history is recalled by `↑` / `↓`
893
- alone, exactly as in Claude Code and Codex.
894
-
895
- **This supersedes the 0.5.0 entry below**, which said the wheel "scrolls what
896
- is under the pointer" and stepped prompt history one entry per notch when the
897
- pointer was over the input box. That turned out to be wrong in use rather than
898
- in principle: the pointer is not an instrument you aim in a TUI — it rests
899
- wherever you last left it, which in a chat-shaped app is next to the thing you
900
- type into. So the ordinary "scroll back and see what just happened" gesture
901
- landed on the composer and replaced the draft with an old prompt, with no
902
- error, no undo and nothing visibly connecting the gesture to the outcome. The
903
- band that decided this was invisible too: its boundary was a measured row that
904
- moved as the toast row, the hint row and the completion popup came and went, so
905
- the same gesture could do two different things a second apart.
906
-
907
- Nothing else about the wheel changes — same three rows per notch, same
908
- `Shift`+wheel page, same `--no-mouse` / `ARAGON_MOUSE=0` / `mouse: false`
909
- escape hatches, same `Shift`+drag for selecting text.
910
-
911
- - **A long session stays as fast as a short one.** The TUI used to get slower as
912
- a session grew and, past a threshold, stopped making progress at all. That was
913
- structural rather than incidental: Ink has no output caching, so every frame
914
- re-walked the entire mounted tree, re-measured every text node and
915
- re-serialised the frame. The per-frame cost was therefore proportional to every
916
- character the session had ever produced — and `transcriptWindow` bounded the
917
- entry *count*, which bounds nothing when one entry can be fifty thousand lines.
918
-
919
- Entries outside the visible band are no longer mounted. The viewport renders
920
- what you can see plus a couple either side and replaces the rest with two
921
- spacers of the right height, so the frame costs what the screen costs.
922
- Scrolling, the `↑N` readout and the wheel routing are untouched. Because the
923
- horizon is no longer a rendering budget, `transcriptWindow` rises from 300 to
924
- 1000 and its ceiling from 2000 to 20000; an existing setting is still valid
925
- and still clamps.
926
-
927
- Syntax highlighting and markdown parsing are memoised on their input, so a
928
- 200-line code block is tokenised once rather than thirty times a second for as
929
- long as it stays on screen. Only the *parsed* form is cached and never a themed
930
- one, so `/theme` still takes effect on the next frame.
931
-
932
- Under genuine load the streaming interval widens — 33 ms up to a 320 ms
933
- ceiling — so keystrokes and `Ctrl+C` do not queue behind renders. This is
934
- visible rather than silent: a muted **`eco`** chip appears in the status bar
935
- while it is in effect, because a user who cannot see why the stream got
936
- chunkier will conclude the model got slower. `--no-render-governor`,
937
- `renderGovernor: false` or `ARAGON_RENDER_GOVERNOR=0` turns it off;
938
- `--max-render-interval 33` flattens the ladder without disabling the mechanism.
939
-
940
- - **A live thinking block no longer grows without limit.** While an answer is
941
- streaming, visible thinking is clamped to its newest 24 rows behind a
942
- `... N earlier lines` marker, and the whole block renders again the moment the
943
- answer settles. Thinking is scratch reasoning you read from its newest end, and
944
- an unbounded one was the easiest way for a single live entry to fill the
945
- viewport on its own.
946
-
947
- ### Fixed
948
-
949
- - **Inline mode could hard-freeze the terminal, and now cannot.** Once a live
950
- entry grew taller than the terminal, Ink took a branch that writes
951
- `clearTerminal` plus the *entire accumulated session history* on every
952
- subsequent frame — bypassing both of its own dedupe gates, and growing without
953
- bound for the rest of the session. Any inline user (`--no-fullscreen`,
954
- `TERM=dumb`, CI, a terminal under 12 rows or 40 columns) whose model wrote a
955
- long answer could reach it. The live region is now clamped below that
956
- threshold, with a `... N earlier lines` marker naming what is deferred. Nothing
957
- is lost: the entry prints in full into the terminal's own scrollback the moment
958
- it settles.
959
-
960
- - **The view state no longer grows without a ceiling.** A single assistant answer
961
- is capped at 256 KiB in the view (thinking at 64 KiB, streamed tool arguments
962
- at 16 KiB) by eliding the MIDDLE, so both the opening and the live cursor
963
- survive; a marker states how many characters went. `transcriptRetain`
964
- (default 1000) caps the entries kept in memory, and what it removed is counted
965
- and reported both by `/perf` and at the top of the exit replay. A model that
966
- emits five megabytes no longer makes every later frame a five-megabyte scan.
967
-
968
- ### Added
969
-
970
- - **A fast model tier: a second, cheaper model you can delegate to and be
971
- reviewed by.** Off by default — with `fast.enabled: false` the system prompt,
972
- the `task` schema, the transcript and the request payloads are byte-identical
973
- to a build without it — and it does two things once you turn it on.
974
-
975
- **Delegation.** `task` gains one optional field per subagent, `model: "fast"`.
976
- A child marked that way runs on the fast model and is otherwise identical:
977
- same tools, same working directory, same `--confirm` gate, same plan-mode
978
- gate, same skills ceiling. Delegating to a cheaper model is a *model* choice,
979
- never a permission boundary. It is where "not complicated, but very expensive
980
- in context" gets paid for — a child that reads nine files and reports four
981
- sentences moves the file bodies out of the lead's window and onto a model that
982
- costs a fraction as much per token.
983
-
984
- **Periodic review.** Every few turns a small digest of what the lead has been
985
- doing goes to the fast model with one question — is this still on track? — and
986
- a critique that is not "on track" is injected into the running loop as a
987
- `<fast_review>` block, so the lead sees a second opinion while it can still
988
- act on it:
989
-
990
- ```
991
- fast review #2 · claude-haiku-4-5 · turn 12 · 1.4s
992
- You have edited config/schema.ts three times without running the tests.
993
- ```
994
-
995
- The digest is built from a bounded ring of recent turns and **never** from the
996
- message history: sending a session's accumulated file bodies to the "cheap"
997
- model would make a review cost more than the turn it reviews, which is the
998
- inversion the whole feature exists to prevent.
999
-
1000
- Spend is attributed **per tier** — a fast child's tokens are priced at the
1001
- fast model's table, not the lead's, and the dispatch report states the two
1002
- separately. A model the built-in price table has never seen is reported as
1003
- `unknown` rather than as `$0.00`, because a feature that looks free while it
1004
- is spending money is worse than one that admits it does not know.
1005
-
1006
- Turn it on with `/fast model <id>` then `/fast on`, with
1007
- `aragon config set fast.enabled true`, with `--fast --fast-model <id>`, or with
1008
- `ARAGON_FAST=1 ARAGON_FAST_MODEL=<id>`. `/fast status` is the guaranteed
1009
- readout: the resolved model, the budget, and this session's reviews, delegated
1010
- children, tokens and cost. Eleven `fast.*` config keys, four flags, four
1011
- environment variables and five settings-screen rows; see the README.
1012
-
1013
- **The review has a session budget.** A session is not one run — it is one run
1014
- per message you send — so a cadence bounds the pace and nothing bounds the
1015
- total. `fast.reviewMaxPerSession` (default **40**, raisable live with
1016
- `/fast budget <n>`) is the number of reviews a session may *start*; reaching it
1017
- prints one `info` notice that names the remedy and says delegation is
1018
- unaffected, and `/fast status` reads `12/40` from the first review rather than a
1019
- bare count you can only size after the fact. It is denominated in **reviews,
1020
- not currency**, because the fast tier is exactly where a model the price table
1021
- has never seen lives — a dollar ceiling would silently never fire for the
1022
- configuration that most needs one. Delegation is never budgeted: it is spend the
1023
- lead chose in service of a message you sent, it is already bounded by `team.*`,
1024
- and it exists to *reduce* total cost.
1025
-
1026
- **The review also fails fast, so it cannot compete with you.** It calls through
1027
- its own provider registry with **one** retry rather than the ten
1028
- `retry.maxRetries` defaults to for the lead, and it observes neither `retry.*`
1029
- nor `/retry` — that policy says how hard to fight for *your* answer, and
1030
- inheriting it for an unrequested background call is how an advisory ends up
1031
- spending a rate-limited provider's quota on itself. Its own wall-clock bound
1032
- is 20 s.
1033
-
1034
- Two failure modes are handled out loud rather than silently. If the tier stops
1035
- resolving mid-session — you switch the main provider and `fast.provider` was
1036
- inheriting it — `model:"fast"` is downgraded to the main model, **counted, and
1037
- stated in the report**, because an agent that silently gets an expensive child
1038
- has no way to learn its cost model is wrong. And three consecutive
1039
- *misconfiguration* failures disable the reviewer for the session with exactly
1040
- one warning, while a merely busy provider (rate-limited or overloaded) is
1041
- treated as transient and never counts — that condition fixes itself, and a
1042
- session-long silent shutdown over it would not. A review you *cancelled* is
1043
- neither: Esc, a run that ends first, or quitting leaves a `cancelled` card and
1044
- no strike against the tier.
1045
-
1046
- Reviews log under their own `fast` scope rather than under `agent`, so
1047
- `fast_review_*` records filter cleanly away from the lead's.
1048
-
1049
- - **API calls are retried with backoff, and the waiting is legible.** A transient
1050
- provider failure — HTTP 429, 529, 5xx, 408, or a dropped connection — used to end
1051
- the turn. One red notice, an idle prompt, and forty tool calls of work thrown
1052
- away. It is now retried up to **10 times** with an increasing interval
1053
- (1 s → 2 → 4 → 8 → 16 → 30 s, equal-jittered, 30 s per wait at most) under a
1054
- 4-minute budget measured from the first failure.
1055
-
1056
- What you see while it waits is **one line, rewritten in place** — never ten
1057
- notices — carrying what failed, which attempt this is, and a countdown to the
1058
- next one:
1059
-
1060
- ```
1061
- ↻ Provider overloaded · retry 3/10 in 7s Esc to cancel
1062
- ↻ recovered after 3 retries · 12.4s
1063
- ```
1064
-
1065
- plus a `retry 3/10 7s` chip on the status bar (`[r3]` on a narrow terminal). The
1066
- card settles into the transcript as history — `recovered`, `gave up`, or
1067
- `interrupted` — and shows up in the exit replay, because a turn that spent three
1068
- minutes retrying is exactly the kind of cost an exported transcript should
1069
- account for.
1070
-
1071
- **Esc ends the wait within a frame**, not at the end of the countdown, and it
1072
- never produces a fabricated error: an aborted request is silent. That is the one
1073
- detail everything else here depends on, because the provider layer marks an
1074
- `AbortError` as retryable — so the signal is checked *before* the error, and a
1075
- user pressing Esc can never be mistaken for a timeout worth retrying.
1076
-
1077
- Never retried: `auth_error` (401/403), `invalid_request`, `context_overflow`.
1078
- Ten retries of a bad API key is three minutes of looking broken.
1079
-
1080
- `Retry-After` is honoured as a **floor**, never a replacement — a `Retry-After: 1`
1081
- on the ninth retry does not undo eight retries of backoff — and a stated wait
1082
- longer than a minute is surfaced immediately with the provider's own number
1083
- rather than silently wedging the terminal.
1084
-
1085
- A connection that dies **mid-answer** is also covered, and this is the case that
1086
- needed more than a retry loop: the partial text is discarded, the affected tool
1087
- cards are removed, and the answer restarts from the top. Nothing is duplicated,
1088
- because the engine only writes history on a completed turn.
1089
-
1090
- - **`/retry [show|on|off|max <n>]`, `--retry` / `--no-retry`, `--retry-max <n>`,
1091
- `ARAGON_RETRY`, `ARAGON_RETRY_MAX`, and a `retry` config section** with nine
1092
- keys (`aragon config set retry.*`). `/retry off` takes effect **in the running
1093
- session** — subagents included, since they share the lead's provider registry —
1094
- not only at the next launch. `retry.maxRetries: 0` is the kill switch and is a
1095
- real value at every one of those entry points. `/settings` gains one read-only
1096
- `API retries` row.
1097
-
1098
- - **A subagent's retry is visible on the team card.** A child in backoff reports
1099
- `retry 3/10` on its own row. Children inherit the retry policy for free, but
1100
- their events never reach the lead's view, so without this a subagent spending
1101
- three minutes waiting looked exactly like a hung dispatch.
1102
-
1103
- - **Retry lines in `-p` mode go to stderr, never stdout.** `[retry 3/10]
1104
- overloaded — waiting 7s` and `[retry] recovered after 3 retries` are on stderr,
1105
- so `aragon -p … | jq` stays valid; a discarded partial answer is announced there
1106
- too, because a piped consumer otherwise cannot tell a replay from a model that
1107
- repeated itself. They are not suppressed by `--quiet`: a three-minute pause with
1108
- no explanation is not a compact run, it is a hang.
1109
-
1110
- - **`/perf`.** Reports what the renderer is actually doing: the frame interval
1111
- and the last commit cost, how many entries exist / are retained / were dropped
1112
- / are mounted, height-cache and render-cache occupancy, and the viewport
1113
- geometry. `/perf reset` clears the caches and returns the governor to its
1114
- fastest rung. Silent degradation is the one thing a claim of robustness cannot
1115
- afford, and this is the place that names it.
1116
-
1117
- - **Three configuration keys**, each with a flag and an environment override:
1118
- `transcriptRetain` (`--transcript-retain`, `ARAGON_TRANSCRIPT_RETAIN`),
1119
- `renderGovernor` (`--render-governor` / `--no-render-governor`,
1120
- `ARAGON_RENDER_GOVERNOR`) and `maxRenderIntervalMs`
1121
- (`--max-render-interval`, `ARAGON_MAX_RENDER_INTERVAL_MS`). No migration and no
1122
- config version bump: a file written before they existed loads unchanged.
1123
- `transcriptRetain` is raised to `transcriptWindow` when the two conflict —
1124
- retaining less than you can scroll to would make part of the horizon
1125
- unreachable — and a startup notice names both numbers, because overriding a
1126
- value you typed and saying nothing is the one thing none of this may do.
1127
-
1128
- - **Following the plan through, on a budget you can do arithmetic on.** A run
1129
- that ended with steps outstanding used to print one sentence and stop. It now
1130
- asks three questions the CLI already knew the answers to — did you abort it,
1131
- did it error, did the list move — and does one of three things.
1132
-
1133
- With the default `notify` the sentence is unchanged, except that a run **you**
1134
- cancelled with `Esc` now says nothing at all: being told what you just
1135
- interrupted is the CLI answering a question nobody asked.
1136
-
1137
- With `/todo follow auto` it continues the plan itself, after announcing
1138
- `Continuing with 4 remaining steps in 3s - Esc to stop.` Auto-continuation was
1139
- refused last release as "an unbounded cost loop wearing a helpful hat", and
1140
- that judgement stands — what changed is that the loop is now bounded first.
1141
- A continuation that completes no step buys exactly one more attempt; a single
1142
- plan is continued at most 25 times however productive it looks; and a re-plan
1143
- forgives the first counter but never the second, so a model that reshapes its
1144
- list every turn cannot lift the ceiling. A run that ended with an error never
1145
- auto-continues in any mode. `Esc` cancels, and so does typing anything.
1146
-
1147
- Whatever sends the continuation — the timer or `/todo continue` — now sends
1148
- the numbered list of open steps rather than the words "continue with the
1149
- remaining todo items", so a plan whose `todo_write` has scrolled out of the
1150
- context window is still followed exactly. Neither path records that text in
1151
- your prompt history any more; it is not something you typed.
1152
-
1153
- Under `-p` there is no grace window, because there is nobody there to use it,
1154
- which is precisely why the two counters rather than the human are the
1155
- protection there. `[todo] continuing (3 steps left)` and
1156
- `[todo] 3 steps unfinished` go to stderr, suppressed by `--quiet`, and an
1157
- unfinished plan still never changes the exit code.
1158
-
1159
- New surfaces: `/todo follow <notify|auto|off>`; `--todo-follow <mode>`;
1160
- `ARAGON_TODO_FOLLOW`; and `todo.followThrough` in `config.json`. The default
1161
- is `notify`, so a session that does not ask for any of this behaves as it did.
1162
-
1163
- - **A plan strip for inline mode.** Inline mode has no fixed frame and so no
1164
- rail, which left every pipe, every `CI=1`, every `TERM=dumb` terminal and
1165
- every window under twelve rows able to see `todo 3/7` but not *which* step was
1166
- running. There is now a one-row strip under the transcript —
1167
- `todo 3/7 > Adding the rail to AppShell +2 done` — windowed on the
1168
- same step the rail would have anchored on. It truncates rather than wrapping
1169
- and is exactly one row at every width, so the composer does not move.
1170
- `--no-todo-panel` hides it along with the rail.
1171
-
1172
- ### Changed
1173
-
1174
- - `npm run typecheck` now covers the test tree in both packages. `tsconfig.json`
1175
- excludes `__tests__` so the build never emits fixtures, and vitest transpiles
1176
- without typechecking — between the two, a widened required field could break
1177
- ten test files while `npm run build` and `npm test` were both green. Twelve
1178
- such errors had accumulated; all twelve were fixture drift and all twelve are
1179
- repaired, with no suppressions and no production type relaxed to accommodate a
1180
- fixture.
1181
-
1182
- - **TODO planning, and a rail to watch it in.** For work with three or more
1183
- distinct steps the agent now keeps a visible plan: it writes a checklist with
1184
- a new `todo_write` tool, marks exactly one item in progress, and ticks it off
1185
- before starting the next. In full-screen mode the list is rendered as a
1186
- right-hand rail about a fifth of the terminal wide, windowed around the step
1187
- being worked on rather than sliced from the top. Ask for something small and
1188
- nothing appears — the prompt tells the model not to plan work it can finish in
1189
- one or two steps, and a one-item list against an empty plan is refused
1190
- outright, so a session that never plans has byte-identical layout to a build
1191
- without this feature.
1192
-
1193
- The list is a projection of what the model believes, and that single rule
1194
- decides everything else: `/clear` keeps it (the conversation is still there),
1195
- `/reset` drops it, `/save` writes it and `/resume` restores it — and resuming
1196
- a session that carries no list CLEARS the current one rather than leaving a
1197
- plan on screen whose conversation has just been replaced. A finished plan
1198
- survives to the start of your next message so you get to see `7/7 done`; an
1199
- unfinished one survives "continue" and "now do the rest", then expires after
1200
- three unrelated turns rather than holding a fifth of the screen for the rest
1201
- of the session. A run that ends with items left over produces a notice and
1202
- `/todo continue`; nothing auto-continues on your behalf.
1203
-
1204
- "One step at a time" is enforced by structure rather than asked for in a
1205
- prompt: any payload with two in-progress items is repaired down to one, and a
1206
- list with none promotes the first unfinished item. Whatever the model sends,
1207
- the panel has exactly one current row.
1208
-
1209
- New surfaces: the `todo_write` tool; `/todo [status|on|off|panel on|off|clear|
1210
- continue]`; `--todo` / `--no-todo` and `--todo-panel` / `--no-todo-panel`;
1211
- `ARAGON_TODO=0`; and `todo.enabled` / `todo.panel` in `config.json` (a third
1212
- key, `todo.followThrough`, arrived with the follow-through entry above).
1213
- `panel` is
1214
- separate from `enabled` on purpose — a screen-reader user wants the planning
1215
- discipline without the column, and the system prompt varies one sentence to
1216
- match. Under `-p` the plan goes to stderr as `[todo] 3/7 <step>` lines,
1217
- suppressed by `--quiet`. Below 80 columns, behind an overlay, in inline mode
1218
- or on a short terminal the rail is not mounted and the counter appears in the
1219
- status bar instead; the transcript keeps at least 62 columns at every width.
1220
-
1221
- - **Output token limits that cannot themselves fail a run.** Every model and
1222
- every provider now defaults to 64000 output tokens, and that number is
1223
- configurable from the TUI, from a flag, from `ARAGON_MAX_TOKENS`, and by hand
1224
- in `~/.aragon-agent/config.json`. Leave it alone and it stays 64000.
1225
-
1226
- What is new is that the number is an *ambition*. `gpt-4o` caps at 16384 and
1227
- `gemini-1.5-pro` at 8192; sending 64000 to either is an HTTP 400 that ends the
1228
- turn with a raw provider string in the transcript. The cap is now clamped down
1229
- to whatever the target model actually accepts, from a per-model table plus
1230
- whatever the provider's own model list reports. For a model nothing knows — a
1231
- proxy, a `--base-url` endpoint, something that shipped last week — the request
1232
- goes out at 64000, and if the provider objects, `aragon` reads the real ceiling
1233
- out of the error text, repairs the request, sends it exactly once more, and
1234
- remembers the answer for the rest of the session. One warning line; the run
1235
- continues.
1236
-
1237
- Two combinations that were a guaranteed 400 on every request are fixed with
1238
- it: `--thinking xhigh` asks for a 65536-token budget while Anthropic requires
1239
- `max_tokens` to be strictly greater than it, and OpenAI's reasoning family
1240
- (`o1`, `o3`, `gpt-5`) rejects the `max_tokens` parameter name outright in
1241
- favour of `max_completion_tokens`.
1242
-
1243
- New surfaces: `/max-tokens [<n>|auto|default]`, which with no argument reports
1244
- the setting *and* the effective cap for the live model; an `Effective:` line
1245
- under the settings screen's `Max tokens` field, so a value the model will not
1246
- honour is visible before you save it; `--max-tokens auto`; and
1247
- `aragon config set maxTokens <n|auto|default>`, which echoes the value that was
1248
- actually stored rather than the one you typed.
1249
-
1250
- - **Team subagents.** The agent can now hand independent parts of a job to up to
1251
- five short-lived subagents that run in parallel, then read one combined report
1252
- of what each of them found. It decides for itself whether to delegate, so a
1253
- session that never calls the new `task` tool is byte-for-byte the session that
1254
- existed before. On by default; `--no-team` or `team.enabled: false` turns it
1255
- off, and `aragon config set team.maxSubagents <n>` sets the width (1-10; the
1256
- 10 is a hard ceiling no config file can raise).
1257
-
1258
- A subagent is a full agent with the same tools and working directory but no
1259
- memory of your conversation, so its brief has to be self-contained. It cannot
1260
- delegate further and it cannot ask you anything. Plan mode and a skill's
1261
- `allowed-tools` ceiling both reach one level down, so delegating is never a
1262
- way around either; `--confirm` queues subagent confirmations one at a time and
1263
- labels each with the subagent that is asking.
1264
-
1265
- Subagents can message each other with `team_send` / `team_wait`, delivered by
1266
- attaching the message to the recipient's next tool result rather than
1267
- interrupting it. The limits are deliberate — 6 messages each, one every 15
1268
- seconds, 24 per dispatch — and every refusal is a plain result naming the
1269
- limit rather than an error, because an error invites the retry the limits
1270
- exist to prevent.
1271
-
1272
- While a dispatch runs, a roster sits between the transcript and the composer
1273
- and the status bar carries `agents 3/5`; both disappear when it finishes and
1274
- the transcript keeps a card you can expand with `Ctrl+O`. `Esc` aborts every
1275
- subagent and returns the partial report. Under `-p` the transitions go to
1276
- stderr and the subagents' tokens are folded into the `[usage]` footer, so the
1277
- cost readout cannot under-report what the team spent.
1278
-
1279
- Full documentation, including the limits table and how team mode interacts
1280
- with plan mode, skills and `--confirm`, is in the README.
1281
-
1282
- - **The subagent roster now shows what each subagent is doing, and shows the
1283
- ones that are working.** Where every row used to say `thinking` for minutes at
1284
- a time, it now says `bash: npm test -w cli`, `read: src/api/routes.ts`,
1285
- `waiting for a2`, or the tail of the sentence the subagent is currently
1286
- writing. On a narrow terminal the same row falls back to a file name and a
1287
- program name rather than wrapping, and the elapsed clock keeps its place at
1288
- every width.
1289
-
1290
- The five visible rows are now the five that matter: whatever is running comes
1291
- first, then whatever is queued, then the most recent results. Above five
1292
- subagents the old panel showed the five that had finished first and hid
1293
- everything still working behind `+3 more`, which is the opposite of what the
1294
- roster is for. `+3 more` now says how many of the hidden ones are still going.
1295
-
1296
- - **A subagent no longer waits two minutes for a message nobody can send.**
1297
- `team_wait` now checks whether anyone could actually answer before it blocks:
1298
- if the teammate it named has already finished, does not exist, or is itself
1299
- waiting in a way that cannot be released in time, it returns straight away and
1300
- says which. Nothing is refused that could still have been answered — including
1301
- by a third teammate further down the chain — and the subagent is told what to
1302
- do instead rather than handed an error.
1303
-
1304
- - **A subagent whose very first request dies on a rate limit is retried once.**
1305
- Only a genuine cold start qualifies: no turn completed and no tool ran, so
1306
- there is nothing to undo. It restarts after two seconds, the roster says
1307
- `starting (retry)`, and the report notes `retried 1x`. Pressing `Esc`, a
1308
- timeout, or any subagent that had already begun work is never retried.
1309
-
1310
- ### Changed
1311
-
1312
- - **`"maxTokens": null` in `config.json` now means AUTO** — use each model's own
1313
- ceiling, never above 64000. It previously resolved to 64000 by accident (the
1314
- layered resolver skipped `null`), and there was no way to express AUTO through
1315
- any supported write path. If you have a `null` there today, the only difference
1316
- is a downward clamp on models whose real ceiling is below 64000 — the direction
1317
- that prevents failures rather than causing them. Absent still means 64000, and
1318
- an explicit number still means that number.
1319
-
1320
- - **`config.json` holds settings again.** The prompts you type are no longer
1321
- stored in it. They move to `~/.aragon-agent/prompt-history.jsonl` — one JSON
1322
- object per line, `0600` on POSIX — and the submit counter and the "notice
1323
- already shown" flag move to `~/.aragon-agent/state.json`. `↑` and `↓` behave
1324
- exactly as before.
1325
-
1326
- Two things get better. Opening `config.json` to change your model no longer
1327
- means scrolling past a transcript of your own typing, and copying it to
1328
- another machine no longer carries your prompts along. And submitting a message
1329
- no longer rewrites the file that holds your API keys: `config.json` is written
1330
- when you change a setting, and at no other time.
1331
-
1332
- **Your history and counters are migrated automatically, once, at the next
1333
- launch.** Nothing is printed, because nothing changes for you. The dead
1334
- `recentModels` key — which nothing has ever written — is dropped.
1335
-
1336
- If you go back to 0.5.x after upgrading, that version does not know about the
1337
- new file and `↑` will look empty. Nothing has been lost: the entries are still
1338
- in `prompt-history.jsonl`, and upgrading again brings them back.
1339
-
1340
- ### Added
1341
-
1342
- - **`aragon history`** — `path`, `list` (`-n`, `--json`) and `clear --yes` for
1343
- the prompt history, alongside the existing `aragon logs` commands. Entries are
1344
- stored verbatim, so `clear` is how you erase them; `aragon config set
1345
- historyEnabled false` stops new ones being recorded without deleting or hiding
1346
- what is already there.
1347
-
1348
- - **The mouse wheel scrolls what is under the pointer.** In full-screen mode the
1349
- wheel now scrolls the transcript three rows per notch (a page with `Shift`),
1350
- scrolls an open overlay when the pointer is over one, and steps prompt history
1351
- one entry per notch when the pointer is over the input box — the same code
1352
- path `↑` / `↓` use, so it inherits the rule that an in-progress draft is never
1353
- overwritten. A slim rail on the viewport's right edge shows where you are in
1354
- the conversation.
1355
-
1356
- **This fixes a destructive bug.** Previously the wheel recalled prompt history
1357
- no matter where the pointer was, because the alternate screen makes terminals
1358
- translate each notch into arrow keys. Wheeling while composing a message
1359
- silently replaced the draft with an old prompt, and nothing scrolled.
1360
-
1361
- **Selecting text with the mouse now requires `Shift`+drag** in most terminals.
1362
- That is the standard convention for "an application is tracking the mouse" and
1363
- it applies to everyone, including people who never scroll with the wheel — so
1364
- the first session says so once, in the transcript, and never again. Turn the
1365
- whole feature off with `--no-mouse`, `ARAGON_MOUSE=0`, or
1366
- `aragon config set mouse false`; the wheel then does nothing rather than
1367
- reverting to the old behaviour. Inline mode (`--no-fullscreen`) is untouched:
1368
- your terminal's own scrollback already does the right thing there.
1369
-
1370
- Under `tmux` with `mouse on`, tmux keeps the wheel for itself and the app
1371
- never sees it. `set -g mouse off` hands it back.
1372
-
1373
- ### Changed
1374
-
1375
- - **Your files moved to `~/.aragon-agent/`.** Config, sessions, installed skills
1376
- and the usage counters now live in one directory in your home — on Windows
1377
- `C:\Users\<you>\.aragon-agent\`, and the same path on macOS and Linux. They
1378
- used to be split across `%APPDATA%\aragon-agent-nodejs\Config` and
1379
- `%LOCALAPPDATA%\aragon-agent-nodejs\Data` (or the XDG equivalents), which are
1380
- correct locations and terrible answers to "where do I change the model?".
1381
-
1382
- **The move happens once, automatically, on first launch, and prints a line on
1383
- stderr when it does.** Nothing is deleted: `config.json` is COPIED rather than
1384
- moved, and the old directories are left where they are, so reinstalling 0.5.0
1385
- remains lossless. `aragon config home` prints the new location and names the
1386
- old ones. Once you are satisfied, you can delete them yourself.
1387
-
1388
- `ARAGON_HOME` relocates the whole tree. It has to be a real environment
1389
- variable — the path is resolved before any `.env` is read, so putting it in a
1390
- `.env` will not work. `aragon config home` always prints what is actually in
1391
- use.
1392
-
1393
- ### Added
1394
-
1395
- - **Logging.** Records go to `~/.aragon-agent/logs/aragon-<date>.log` as JSON
1396
- Lines: startup and exit, config writes, turn boundaries with token counts,
1397
- tool names with durations, skill loads, and every uncaught error. Files rotate
1398
- by day and by size (`log.maxFileBytes`, default 5 MiB) and the oldest beyond
1399
- `log.maxFiles` (default 10) are deleted.
1400
-
1401
- **`info`, the default, records no conversation content**, so attaching a log
1402
- to a bug report is safe. `--log-level debug` (or `--verbose`) adds prompts,
1403
- replies and tool arguments truncated to `log.previewChars`; `trace` adds them
1404
- in full. Those two write what you typed — check before sharing one.
1405
-
1406
- API keys are removed at every level by two independent passes: fields whose
1407
- name looks like a credential are blanked whatever they hold, and every string
1408
- is scanned both for known key formats and for the literal keys this process is
1409
- holding — which is what covers a custom endpoint whose key looks like nothing
1410
- in particular. `log.redactSecrets false` turns both off and warns you on
1411
- stdout when you set it.
1412
-
1413
- Nothing is ever uploaded. There is no network path out of this subsystem.
1414
-
1415
- New commands: `aragon logs path | list | tail [-n N] [--follow] [--level lv]
1416
- [--json] | clear --yes | open`, and `/logs` inside the TUI. New flags:
1417
- `--log-level`, `--verbose`, `--log-file` / `--no-log-file`, `--log-dir`. New
1418
- environment variables: `ARAGON_LOG_LEVEL`, `ARAGON_LOG_FILE`, `ARAGON_LOG_DIR`
1419
- — these three, unlike `ARAGON_HOME`, can come from a `.env`.
1420
-
1421
- - **`aragon config get <key>` / `list [--json]` / `edit` / `home`.** `get` and
1422
- `list` mask every secret, `--json` included. `edit` opens `config.json` in
1423
- `$VISUAL` / `$EDITOR` (`notepad` on Windows), takes a `config.json.bak` first,
1424
- and re-parses on exit — an invalid edit is reported immediately, and the
1425
- backup is named in the message.
1426
-
1427
- - **`/reload`** re-reads `config.json` into the running session, for when you
1428
- have edited it in another window. Refused while a run is in progress: swapping
1429
- the model mid-turn would let the second half of an answer come from different
1430
- settings than the first, with nothing afterwards able to explain the result.
1431
-
1432
- - **Log level in the settings screen**, alongside provider / model / thinking.
1433
- The rest of the log settings — and `redactSecrets` above all — stay
1434
- command-line-only, so the one switch that can put credentials on disk cannot
1435
- be flipped with an arrow key.
1436
-
1437
- ### Fixed
1438
-
1439
- - **A malformed `config.json` no longer resets everything in silence.** A stray
1440
- comma used to send the model, theme, timeouts, skills and (as far as you could
1441
- tell) your API key back to defaults, with nothing anywhere explaining it. The
1442
- fallback is unchanged — a bad config still never stops the CLI from starting —
1443
- but it now says so, and records why.
1444
-
1445
- - **Ctrl+C now flushes pending log records in every mode.** The signal handlers
1446
- only existed in the full-screen branch, so `-p`, the inline renderer and every
1447
- subcommand took Node's default termination, which does not run exit handlers.
1448
-
1449
- ### Added
1450
-
1451
- - **Plan mode.** `Shift+Tab` toggles between `BUILD` (everything as before) and
1452
- `PLAN`, a read-only research-and-design posture. `/plan [on|off|status]` is a
1453
- first-class equivalent for terminals that swallow `CSI Z`, and `--plan` /
1454
- `--no-plan` / `ARAGON_PLAN=1` / `planModeDefault` cover the startup case.
1455
-
1456
- In `PLAN`, `write_file`, `edit_file`, `bash`, `skill_install` and
1457
- `skill_create` are refused **at the tool boundary**, so read-only is a
1458
- property of the wiring rather than a promise in a prompt. `bash` is refused in
1459
- full, `git status` included: a shell string cannot be classified reliably, and
1460
- a gate that is right most of the time is worse than one that is always right,
1461
- because you stop trusting the badge. The refusal names `read_file` / `glob` /
1462
- `grep` as the alternatives.
1463
-
1464
- Two tools exist only while a human is attached. `ask_user` renders a
1465
- keyboard-driven wizard - 1-5 questions, 2-4 options each, exactly one marked
1466
- `RECOMMENDED`, plus an `Other...` free-text option - where pressing `Enter`
1467
- through the wizard accepts every recommendation. `submit_plan` renders the
1468
- plan as a scrollable card: `a` approves, `r` sends written feedback (`<-`
1469
- returns to the card), `Esc` dismisses. **Approving flips the session to
1470
- `BUILD` immediately and the same run continues into implementation.**
1471
-
1472
- Dismissing a plan asks for a better one rather than stopping - the agent is
1473
- told to refine and resubmit - so the way out of a run is `Esc` twice: the
1474
- first closes the card, the second aborts the run.
1475
-
1476
- Toggling mid-run is asymmetric on purpose: `build -> plan` applies at once,
1477
- `plan -> build` is deferred to the end of the run (the status bar shows
1478
- `PLAN -> BUILD` meanwhile) so a run launched under a read-only guarantee
1479
- cannot start writing files because of one stray keypress.
1480
-
1481
- `aragon -p --plan "..."` registers no question or plan tool - there is nobody
1482
- to ask - but the read-only gate still applies, so it means "tell me how you
1483
- would do this, and do not touch my repository".
1484
-
1485
- - Three flat config keys: `planModeDefault` (default `false`),
1486
- `planModeMaxAskRounds` (default `4`, clamped `[1, 10]`) and
1487
- `planModeHumanTimeoutMs` (default `1800000`, clamped `[60000, 7200000]`). All
1488
- three are settable with `aragon config set`. Additive, as always: a config
1489
- file written by an earlier version loads unchanged.
1490
-
1491
- ### Fixed
1492
-
1493
- - A `--confirm` prompt no longer races the idle watchdog. Taking longer than
1494
- `idleTimeoutMs` over `Proceed? (y/N)` used to abort the run with no
1495
- explanation; every human wait now suspends the watchdog and restarts it in a
1496
- `finally`.
1497
-
1498
- - Honor an explicit `NODE_TLS_REJECT_UNAUTHORIZED=0` setting in the CLI and the
1499
- official npm release workflow while hiding only Node's standard insecure-TLS
1500
- warning. Other process warnings remain visible.
1501
-
1502
- ## 0.5.0
1503
-
1504
- ### Breaking
1505
-
1506
- - **The package is renamed `@argon-agent/cli` → `@aragon-agent/cli`.** The brand
1507
- was always meant to be *Aragon*, matching AragonMesh; the missing `a` was a
1508
- typo that reached the registry. Install with:
1509
-
1510
- ```
1511
- npm uninstall -g @argon-agent/cli
1512
- npm install -g @aragon-agent/cli
1513
- ```
1514
-
1515
- `@argon-agent/cli` is deprecated and receives no further releases. **The
1516
- executable is still `aragon`** — the command you type does not change.
1517
-
1518
- - **Environment variables are `ARAGON_*`, not `ARGON_*`.** There is no
1519
- compatibility fallback: `ARGON_MODEL`, `ARGON_PROVIDER`, `ARGON_BASE_URL`,
1520
- `ARGON_THINKING`, `ARGON_MAX_TOKENS`, `ARGON_THEME`, `ARGON_FULLSCREEN`,
1521
- `ARGON_SKILLS`, `ARGON_SKILLS_DISABLED`, `ARGON_SKILLS_PATH` and
1522
- `ARGON_REDUCED_MOTION` are all ignored from this release on. Rename them in
1523
- your shell profile and CI. Provider keys (`ANTHROPIC_API_KEY`,
1524
- `OPENAI_API_KEY`, `GOOGLE_API_KEY`, `GEMINI_API_KEY`) are untouched.
1525
-
1526
- - **The project-level skills directory is `.aragon/skills`, not
1527
- `.argon/skills`.** This one lives in your repository, so rename it yourself:
1528
-
1529
- ```
1530
- git mv .argon .aragon
1531
- ```
1532
-
1533
- A config file that already persisted the old default keeps working — an
1534
- explicitly saved `skills.projectDirs` still wins over the default — but the
1535
- shipped default is now `['.aragon/skills', '.claude/skills']`. Update it with
1536
- `aragon config set` if you want the new default.
1537
-
1538
- ### Added
1539
-
1540
- - **Automatic migration of your user-level state.** On first run, 0.5.0 moves
1541
- the `env-paths` config and data directories from `argon-agent` to
1542
- `aragon-agent` — your API key, sessions and installed skills come with it, and
1543
- each installed skill's `.argon-skill.json` manifest is renamed to
1544
- `.aragon-skill.json` so `skills update` and `skills uninstall` still recognise
1545
- it. The migration prints one line to **stderr**, runs once, and is skipped
1546
- entirely if the new directory already exists. If it fails for any reason the
1547
- CLI still starts; the old directory is never deleted when a cross-volume copy
1548
- was needed.
1549
-
1550
- - The opening wordmark now reads `ARAGON` and is 52 columns wide (was 44).
1551
- Terminals between 52 and 55 columns show the single-line banner rather than a
1552
- clipped wordmark.
1553
-
1554
- - **Skills.** A skill is a directory holding a `SKILL.md` (YAML frontmatter +
1555
- Markdown body) plus optional `reference/`, `scripts/` and `assets/`. Skills
1556
- reach the model through three levels of progressive disclosure: a name +
1557
- one-line "when to use" catalog in the system prompt (≤ 6 000 bytes total),
1558
- the full body only when the model calls the `skill` tool, and bundled files
1559
- only when it reads them with `read_file` / `bash`. A skill therefore costs a
1560
- line of context rather than its whole body. How many fit in Level 1 depends on
1561
- description length and language — roughly 30 with terse English descriptions,
1562
- roughly 10 with Chinese ones at the character cap; past that the catalog
1563
- truncates and `skill_find` covers the remainder.
1564
- - Four model-facing tools: `skill` (load), `skill_find` (search installed
1565
- skills), `skill_install` (install from a local directory, git repo, or https
1566
- `SKILL.md` / `.zip`) and `skill_create` (author a new one from a procedure the
1567
- agent just worked out).
1568
- - **`aragon skills update <name> | --all`**, with `--dry-run`, `--force` and
1569
- `--check`. Re-fetches from the source recorded in the install manifest,
1570
- preserving `installedAt` and recording `updatedAt` / `previousVersion`. Refuses
1571
- before downloading anything when the installed copy has local edits, and
1572
- re-validates the source against the *current* `skills.allowedHosts` rather than
1573
- the one in force at install time. Not exposed to the model.
1574
- - **Catalog ranking.** Level 1 entries are ordered by scope, then by how recently
1575
- and often each skill was used, so truncation drops what you do not use rather
1576
- than what sorts last alphabetically. With no usage data the order is unchanged.
1577
- - **`skill_find`**, advertised in the prompt only when the catalog actually
1578
- truncated. Searches installed skills by name, description and keyword; never
1579
- reaches the network, never returns `activation: manual` skills, and tells the
1580
- model to ask for a source rather than invent one when nothing matches.
1581
- - **Cross-process install lock.** Install / create / remove / update take a
1582
- per-directory advisory lock, closing a race in which two concurrent installs
1583
- could interleave their atomic-replace steps and delete a skill with no error.
1584
- Self-expires after 60 s; waits at most 5 s; only ever released by its owner.
1585
- - **Load-time integrity.** Discovery re-checks `SKILL.md` against the sha256
1586
- recorded at install, at no extra I/O. `skills.integrity` selects
1587
- `off` / `warn` (default) / `strict`.
1588
- - **Local usage counters** at `<data>/skill-usage.json` — skill name, count and
1589
- timestamp only, never transmitted, disabled with `skills.usageTracking=false`.
1590
- Automatically injected `activation: always` skills are not counted.
1591
- - Config keys `skills.integrity` and `skills.usageTracking`; `aragon skills list
1592
- --sort=recent` and `/skills list --sort=recent`.
1593
- - Every usable skill also becomes a slash command: `/<skill-name> [args]`, with
1594
- `$ARGUMENTS` / `$1..$9` substitution. On a name clash the built-in command
1595
- always wins and the skill is reachable as `/skill:<name>`.
1596
- - `/skills` management: `list`, `info`, `install`, `remove`, `enable`,
1597
- `disable`, `reload`, `create`, `trust`, `untrust`.
1598
- - `aragon skills …` non-interactive equivalents plus `path` and `doctor`.
1599
- Exit codes follow `config set`: `0` ok, `1` run-time failure, `2` usage.
1600
- - Four discovery scopes in ascending precedence: bundled (`<pkg>/skills`), user
1601
- (`<data>/skills`), project (`<cwd>/.aragon/skills` and, read-only,
1602
- `<cwd>/.claude/skills` for Claude Code interop), and `ARAGON_SKILLS_PATH`.
1603
- - New flags `--no-skills`, `--skill <name>` (repeatable) and `--skills-yes`;
1604
- env `ARAGON_SKILLS`, `ARAGON_SKILLS_PATH`, `ARAGON_SKILLS_DISABLED`; config keys
1605
- `skills.enabled`, `skills.requireApproval`, `skills.catalogMaxBytes`,
1606
- `skills.bodyMaxBytes`.
1607
- - One bundled skill, `skill-creator`, documenting how to write a good one.
1608
- - New runtime dependency: `fflate` (~30 KB, MIT, zero transitive deps) for zip
1609
- extraction. `@aragon-agent/core` gains no dependency.
1610
- - **Release tooling for the scope change.** `npm run verify:brand` scans every
1611
- file that `npm pack` would put in the tarball — README and `dist/` included —
1612
- and blocks the release on any surviving `argon` reference, with only the four
1613
- documented exceptions (the two CHANGELOGs and the legacy-state migration
1614
- module, which hold the old names by definition). `packages/cli` also gains a
1615
- `prepublishOnly: npm run build`, so a publish that bypasses
1616
- `publish-latest.ps1` can no longer ship a `dist/` that is out of step with the
1617
- sources. `deprecate-legacy.ps1` retires `@argon-agent/*` on the registry, and
1618
- refuses to do so until the replacements are actually published.
1619
-
1620
- ### Changed
1621
-
1622
- - The globally installed executable is now `aragon`. The previous `argon` and
1623
- `argon-agent` aliases are no longer installed.
1624
- - `config/store.ts` now deep-merges the `skills` section on both read and write,
1625
- the same treatment `apiKeys` already received. Without it a partial patch such
1626
- as the one `/skills disable` sends would replace the whole section and
1627
- silently discard `trustedProjectDirs`, `allowedHosts` and `requireApproval`.
1628
- - `slashSuggestions` accepts `-` and `:`, so kebab-case and `skill:`-namespaced
1629
- commands autocomplete. Previously `/my-sk` produced no popup at all.
1630
- - `AgentController` now has a single `agent.setSystemPrompt()` call site, so a
1631
- `/cwd` change can no longer drop the skill catalog out of the prompt.
1632
- - With skills off or none installed, the system prompt and the 7-tool array are
1633
- byte-identical to the previous release.
1634
- - Added a repository-level PowerShell release workflow that automatically
1635
- updates CLI and Core versions, synchronizes their dependency and lockfile,
1636
- verifies both tarballs, and publishes them in dependency order.
1637
-
1638
- ### Security
1639
-
1640
- - Installing a skill requires an explicit human approval that **probes for a
1641
- human first and refuses when there is none**. Under `-p` there is no TUI and
1642
- therefore no approver, so `skill_install` is refused with an actionable
1643
- message rather than writing a third-party directory unattended. Use
1644
- `--skills-yes` (or `skills.requireApproval=false`) to opt out deliberately.
1645
- - Project skill directories require a one-time trust confirmation before they
1646
- are loaded — cloning an unfamiliar repository does not grant it the ability
1647
- to inject instructions into your session.
1648
- - Git is invoked only via `execFile` with an argv array and `shell: false`, and
1649
- owner / repo / ref / subdirectory fragments are whitelisted and refused if
1650
- they begin with `-`. A leading dash matters even with a pure argv array:
1651
- `--upload-pack=<program>` makes git execute that program.
1652
- - Zip extraction is streamed and gated on **actually written** bytes, per-entry
1653
- size, compression ratio and entry count, all of which can abort mid-archive.
1654
- The size a zip *declares* is written by whoever built it and is never trusted.
1655
- Path traversal, absolute entries, symlinks and Windows device names are
1656
- refused, and a rejected archive is removed rather than left half-extracted.
1657
- - Network fetches are `https:` only, restricted to `skills.allowedHosts`,
1658
- re-checked on every redirect (max 3), size-capped, and refuse IP literals and
1659
- loopback.
1660
- - Nothing a skill ships is executed at install time, and the executable bit is
1661
- not preserved. Scripts run only when the model invokes `bash` explicitly.
1662
- There is no sandbox: approval blocks *silent* installation, it does not make
1663
- a skill you approved safe.
1664
-
1665
- ## 0.3.0
1666
-
1667
- A full-screen TUI release. `@argon-agent/core` is untouched, no new runtime
1668
- dependency is added, and the headless/print contract, exit codes, and
1669
- slash-command semantics are unchanged. The 0.2.0 inline renderer remains
1670
- available in full via `--no-fullscreen`.
1671
-
1672
- ### Added
1673
-
1674
- - **Full-screen mode (default).** `aragon` now takes over the terminal's
1675
- alternate screen buffer — the same mechanism `vim` / `htop` / `lazygit` use.
1676
- Your shell history is covered, not erased, and comes back untouched on exit.
1677
- The frame is a fixed `rows - 1` tall, so **the composer and the status bar sit
1678
- at the physical bottom of the screen from the very first frame**: empty
1679
- session, long session, mid-scroll, or overlay open.
1680
- - **Brand region.** A six-row gradient ASCII wordmark on a roomy empty session,
1681
- degrading to a banner, then a single-line bar, then a bare wordmark as space
1682
- runs out. Row 1 always begins with the brand glyph.
1683
- - **Self-drawn scrolling.** `PgUp` / `PgDn` by the page, `Shift+↑` / `Shift+↓` by
1684
- the line. The viewport auto-follows new output while pinned to the bottom;
1685
- scrolling away shows `↑N` in the status bar plus a "N new lines" hint, and
1686
- submitting a message always re-pins.
1687
- - **Exit replay.** After leaving the alternate screen the session is replayed
1688
- into the normal buffer as plain, colorless text, so the conversation does not
1689
- evaporate with the screen. Turn it off with `--no-exit-transcript`.
1690
- - **New flags** `--fullscreen` / `--no-fullscreen` / `--no-exit-transcript`, the
1691
- env var `ARGON_FULLSCREEN=0|1`, and the config keys `fullscreen`,
1692
- `exitTranscript`, and `transcriptWindow`.
1693
- - **Automatic downgrade.** A non-TTY stdout, `TERM=dumb`, CI, and terminals under
1694
- 12 rows / 40 columns fall back to the inline renderer. Only the non-TTY gate is
1695
- un-overridable — `--fullscreen` beats the rest.
1696
-
1697
- ### Changed
1698
-
1699
- - The status bar lost its round border and is now exactly one row; it had been
1700
- spending an eighth of a 24-row terminal framing a single line of text.
1701
- - The toast strip holds a fixed row in full-screen mode, so the transcript no
1702
- longer jumps as toasts appear and expire.
1703
- - The composer is a rounded frame whose border color reports state (idle, has a
1704
- draft, running, blurred by an overlay), with the completion popup above it.
1705
- - `Ctrl+L` repaints the frame instead of writing a clear sequence. Ink dedupes
1706
- identical output at two separate gates, so under a fixed frame the old
1707
- approach erased the screen and then declined to redraw it.
1708
- - `Shift+↑` / `Shift+↓` no longer recall prompt history — they scroll.
1709
- - Full-screen mode routes `console.*` into the transcript as notices rather than
1710
- letting Ink write them straight to stdout, which corrupts the frame's line
1711
- accounting.
1712
-
1713
- ### Known trade-offs
1714
-
1715
- - The terminal's native scrollback and mouse wheel do not scroll the transcript
1716
- in full-screen mode; use `PgUp` / `PgDn`, or run with `--no-fullscreen`.
1717
- - Mouse tracking is deliberately left off: enabling it costs text selection and
1718
- copy in most terminals.
1719
- - Should a crash ever strand your terminal on the alternate screen, `reset`
1720
- restores it. Four independent restore paths exist to prevent that: normal
1721
- exit, `process.exit`, `SIGINT` / `SIGTERM` / `SIGHUP`, and Ink's own signal
1722
- handling.
1723
-
1724
- ## 0.2.0
1725
-
1726
- A design-elevation & HCI-hardening release. No breaking changes: `@argon-agent/core`
1727
- is untouched, no new runtime dependency is added, and the headless/print contract,
1728
- exit codes, config keys, and slash-command semantics from 0.1.0 are unchanged.
1729
-
1730
- ### Added
1731
-
1732
- - **Real theming engine.** Distinct `dark` / `light` palettes with an `auto`
1733
- resolution (`auto → dark`), color degradation across terminal depth
1734
- (truecolor → 256 → 16 → monochrome), and an ASCII glyph fallback for terminals
1735
- without Unicode. Honors `NO_COLOR`, `FORCE_COLOR`, `--no-color`, and
1736
- `TERM=dumb`. Switch live with `/theme <auto|dark|light>` (persisted).
1737
- - **Elegant chrome.** A gradient wordmark header that collapses to a slim sticky
1738
- bar after the first turn, a first-run **Welcome / empty-state** card, and a
1739
- status bar with a colored **context gauge** (threshold colors), a **tokens/sec**
1740
- read-out while running, and a contextual hint.
1741
- - **Legible tool output.** Colored unified diffs (green adds / red removes) and
1742
- per-tool rich previews (`edit_file`/`write_file`/`read_file`/`bash`/`list_dir`/
1743
- `glob`). Long previews collapse to 8 lines and expand with `Ctrl+O` or
1744
- `/expand [n]`.
1745
- - **Autocomplete.** A slash-command palette and `@file` path completion popup
1746
- (`Tab`/`→` to complete, `Up`/`Down` to move, `Esc` to close).
1747
- - **Full line editing.** Home/End, word jump/delete, kill-to-start/end, and
1748
- multi-line vertical cursor navigation, with prompt-history recall at the edges.
1749
- Unknown control/escape sequences are dropped instead of inserted.
1750
- - **Reliability under load.** Ink `<Static>` finalization for settled entries and
1751
- a streaming delta coalescer, so long/fast sessions stay flicker-free.
1752
- - **Calm feedback.** Ephemeral, auto-dismissing **toasts** for transient acks;
1753
- the transcript keeps only durable content (messages, tool cards, run errors).
1754
- - `reducedMotion` config (also `ARGON_REDUCED_MOTION`; implied by `--no-color`)
1755
- replaces spinners with a static glyph.
1756
-
1757
- ### Changed
1758
-
1759
- - History scrollback now uses the **native terminal scrollback** that `<Static>`
1760
- prints into (this supersedes the never-implemented `PgUp`/`PgDn` promise).
1761
-
1762
- ## 0.1.0
1763
-
1764
- Initial release — a Claude-Code / Codex-style interactive terminal UI (TUI) on
1765
- top of `@argon-agent/core`.
1766
-
1767
- ### Added
1768
-
1769
- - **Interactive TUI** (React + Ink): gradient header, streaming transcript with
1770
- markdown + syntax highlighting, collapsible thinking blocks, live tool-call
1771
- cards, a status bar (model / context % / tokens / cost / elapsed), and modal
1772
- overlays (settings, model picker, help, confirm).
1773
- - **Built-in toolset** wired into the core agent at full permission:
1774
- `read_file`, `write_file`, `edit_file`, `list_dir`, `glob`, `grep`, `bash`.
1775
- - **Layered configuration** (defaults → user file → env/`.env` → flags) with
1776
- live in-TUI editing of provider / model / base URL / API keys / thinking level
1777
- / max tokens. Secrets are masked and the config file is written `0600` on POSIX.
1778
- - **One-shot / print mode** (`argon -p`) for scripting and piping, plus
1779
- `argon config` / `argon config set` / `argon config path` / `argon models`.
1780
- - **Session control**: abort (Esc), steer-while-running, follow-up queue,
1781
- double-Ctrl-C exit, `/save` / `/resume` JSON sessions.
1782
- - **Timeout invariant** (`idleTimeout ≥ toolTimeout`) so a long single tool run
1783
- is never killed by the idle watchdog.
1784
- - **Never-silent failures**: pre-flight API-key validation, error-StreamEvent
1785
- rendering, and a guard that surfaces a swallowed agent error instead of a
1786
- blank no-op (headless exits `1`/`2` accordingly).
1
+ # Changelog
2
+
3
+ All notable changes to `@aragon-agent/cli` are documented here. Entries at
4
+ `0.4.x` and earlier refer to the package by its former name, `@argon-agent/cli`
5
+ — those releases really were published under that name, so they are left as they
6
+ were written.
7
+
8
+ ## Unreleased
9
+
10
+ ### Added
11
+
12
+ - **A model profile can be verified where it is written.** The profile editor
13
+ gains two action rows: **Test connection** (`Ctrl+R`) and **Discover models**
14
+ (`Ctrl+F`). A test is one real completion against the UNSAVED draft - the
15
+ provider, model, base URL and the key `keep`/`replace`/`shared` actually
16
+ resolves to - and it answers with a verdict (`OK 812 ms | 18 in / 4 out`) or a
17
+ classified failure plus the one thing to fix (`Key rejected by anthropic (HTTP
18
+ 401).` / `Fix: edit API key, or set Credential mode to Shared.`). A discovery
19
+ lists what the key can really reach, so the model is picked instead of typed.
20
+ Both run against the draft, cost at most one short request (discovery costs no
21
+ tokens), never retry, and never write `ModelRegistry`'s five-minute discovery
22
+ cache. Every result is bound to a target fingerprint, so an `OK` can never
23
+ describe a model, endpoint or key the user has since edited. The progress line
24
+ is static text: no new animated site, so `single-spinner` still holds.
25
+
26
+ ### Fixed
27
+
28
+ - **`/clear` did not clear the context.** It reset the visible transcript and the
29
+ todo panel and left `agent.state.messages` - the history that is actually sent,
30
+ billed, measured by `/context` and compacted - completely untouched. A long
31
+ session looked restarted and behaved like it had never been cleared: the next
32
+ request still carried every old turn, so the model remembered the previous task
33
+ and the occupancy gauge did not move. `/clear` now runs the one real
34
+ new-conversation boundary (`controller.resetConversation()`) in the only safe
35
+ order: interrupt the running turn (`forceStop`, which also drops the events the
36
+ unwinding engine keeps emitting), wait for it to settle inside a bounded budget,
37
+ archive the old conversation, drop both queues, then clear history, compaction
38
+ identity, context measurement and skill activation frames. A reset that cannot
39
+ stop the engine clears **nothing** and says so.
40
+ - **`/reset`'s "cancelled N queued messages" notice is preserved.** `/reset` is now
41
+ an alias of `/clear`, and the count is read **before** the queues are cleared -
42
+ read afterwards it would always be zero, which is a notice that lies.
43
+
44
+ ### Changed
45
+
46
+ - **`/clear` means "start a new conversation"; the old behaviour moved to
47
+ `/clear screen`.** The previous semantics (wipe the transcript and the todo
48
+ panel, keep the history and the queue) are still available, spelled explicitly,
49
+ and are byte-identical to what `/clear` used to do. `/clear` no longer refuses
50
+ while a run is in flight: it interrupts, which removes the dead end where the
51
+ only command that worked mid-run was the one that kept the context.
52
+ - **`/reset` is an alias of `/clear`, one implementation.** Two bodies could drift
53
+ back into "one clears the screen, one clears the session"; one body cannot.
54
+ - **The conversation being cleared is archived first**, to
55
+ `~/.aragon-agent/sessions/cleared/cleared-<yyyyMMdd>-<HHmmss>-<pid>.json`
56
+ (newest 20 kept, `<ARAGON_HOME>` honoured). The path is reported in the
57
+ transcript and restores with `/resume <path>`. The file carries no `meta`, so
58
+ `sessions list` / `sessions prune` and `--continue` are unaffected; a failed
59
+ archive only logs and never blocks the clear.
60
+
61
+ - **`Ctrl+I` was dead on Windows.** The win32-input-mode translator only
62
+ recognised the chord when the console reported it as `VK_TAB` (vk 9) with
63
+ ctrl - a record shape no real console was ever probed for. Physical
64
+ Ctrl+I keeps the LETTER vk (0x49, the same Ctrl+letter rule that reports
65
+ Ctrl+A as vk 65 and Ctrl+J as vk 74 in the Shift+Enter probe captures)
66
+ while `char` carries the Tab byte, so the record fell through to the
67
+ generic Ctrl-combo branch, came out as plain Tab, and the keybinding
68
+ silently did completion instead of opening the index confirm. The
69
+ translator now tells Ctrl+I apart from Tab by `char === 0x09 && ctrl`
70
+ whatever vk it rides, with Shift still mapping to Shift+Tab; both record
71
+ shapes are pinned by regression rows in `win32-input-mode.test.ts`.
72
+
73
+ ### Team dispatch supervisor (team-overseer)
74
+
75
+ - **A time ceiling on a subagent is now an inspection trigger, not a death
76
+ sentence.** With the supervisor on (new key `team.overseer`, default
77
+ `true`, needs the fast tier), two soft timers per child - event silence at
78
+ `idleTimeoutMs` and a wall clock at `subagentTimeoutMs` (or 5 minutes when
79
+ no ceiling is configured) - fire one bounded fast-tier inspection. The
80
+ supervisor decides wait / nudge / replace / abandon; the runtime applies,
81
+ funnelling every lifecycle change through the worker loop that awaits the
82
+ child, so a replacement is never built for nobody.
83
+ - **A nudge is steering; a replace is a rebuild with an amended brief.**
84
+ Guidance is queued at core's safe top-of-loop checkpoint; a replacement
85
+ carries the supervisor's reason, the dead child's `filesTouched`, and the
86
+ original brief bounded to the same prompt budget. A post-mortem inspection
87
+ diagnoses a child that died silently (watchdog death, stream loss) and may
88
+ re-assign it once.
89
+ - **Budgets are structural, not settings**: 4 inspections and 1 replacement
90
+ per child per dispatch; past them the child runs under its own (lengthened
91
+ while supervised) idle watchdog and the supervisor goes quiet. An
92
+ unparseable or failing supervision call always becomes `wait` -
93
+ supervision must never kill a healthy child.
94
+ - Every applied decision is visible three ways: the report's Supervisor
95
+ section (`[silence 30s] a1: nudge - ...`), the team panel and the `-p`
96
+ stderr line, and a `debug` log event. `aragon exec` emits it as an
97
+ additive `team` subtype `overseer` (`EXEC_SCHEMA_VERSION` unchanged).
98
+ - New command `/team overseer on|off` (refused mid-dispatch, like every
99
+ other `/team` setting) and new config key `team.overseer`, also settable
100
+ as `aragon config set team.overseer false`. With the supervisor off - or
101
+ no fast tier - every path is byte-for-byte the pre-feature regime:
102
+ `subagentTimeoutMs` is a hard abort and silence is the child's own
103
+ watchdog.
104
+
105
+ ### 启动与缩窗不再误报 Frame diff lost sync
106
+
107
+ - 启动即现的 "Frame diffing lost sync with the terminal and fell back to a
108
+ full repaint … `--no-diff-render`" 警告已消除:Ink 挂载/卸载经渲染 stdout 写出的
109
+ 光标隐藏/恢复序列(`ESC[?25l` / `ESC[?25h`)由帧写入器直接透传——不进差分、
110
+ 不失效缓存、不计 fallback,也不再消耗会话的首写豁免。启动序列恢复
111
+ "种子帧透传 → 首帧全量 → 之后纯 diff"。
112
+ - 终端高度缩小(拖小窗口、改字号、面板重排)不再触发同一条警告:Ink 的
113
+ `clearTerminal` 整帧写入被差分器识别为 Ink 自身写法,透传并失效缓存但不计
114
+ fallback;该控制写同样不消耗首写豁免,其后的首个 log-update 帧仍按种子帧豁免,
115
+ 下一帧自然全量重绘。
116
+ - `/perf` 的 `fallbacks` 重新从 0 起步,"健康会话 fallbacks === 0" 的诊断信号
117
+ (AC-11)恢复可判。
118
+
119
+ ### Consistent TUI styling
120
+
121
+ - Interactive sessions always use Unicode and default to truecolor, including
122
+ PowerShell sessions without terminal or UTF locale markers. Ink's actual color
123
+ output follows the same policy, with renderer state restored on exit.
124
+ - Explicit color opt-outs keep Unicode borders and icons; the opening logo now
125
+ depends only on available space. Headless terminal detection is unchanged.
126
+ - Reloading model settings preserves session display preferences. Syntax
127
+ highlighting follows the same color policy, and status icons use consistent
128
+ single-column glyphs to prevent narrow-frame overflow.
129
+ - Hiding the editor caret while scrolling preserves draft geometry, preventing
130
+ a layout update loop when entering text above the full startup logo.
131
+ - Register exit cleanup before mounting the application, so immediate exits and
132
+ initial render failures restore terminal and color state reliably. Failed
133
+ mounts no longer mark an auto-installed build as healthy.
134
+
135
+ ### Model context window
136
+
137
+ - Discover context limits at startup and after connection changes without blocking
138
+ input. The status bar and compaction use the discovered limit; `/context` names
139
+ API versus catalog metadata. Unknown windows show `?`, not a fabricated 128k
140
+ capacity or percentage. Manual `contextWindow` overrides retain precedence.
141
+ - Window overrides now apply to tail relief and compaction progress as well as
142
+ the gauge. Workers on different models/endpoints do not inherit the lead's
143
+ override. API-key changes refresh metadata, and ending a session cancels its
144
+ pending model queries. `/context` also hides unknown capacities/percentages.
145
+
146
+ ### TUI 输入与排队可靠性
147
+
148
+ - Shift+Enter 与粘贴按输入顺序处理;普通 Enter 保持弹层兼容,混合输入最多提交一次,
149
+ 余稿及拒绝提交的正文保留。结束输入流时完整排空,不泄漏内部控制标记。
150
+ - 超限粘贴拒绝同一外部输入块的正文和 Enter,避免误提交旧稿;未闭合粘贴继续按正文消费。
151
+ - 拖选后仅 Ctrl+C 复制;文字变化与丢失鼠标释放时取消无效高亮,避免卡住视口。
152
+ - 固定 Queue 状态行按消息 ID 回执更新,支持窄屏、暂停与多条消息计数。
153
+ - 保存和退出保留所有未发送全文;恢复先验证存档,旧 queued 作为警告展示且不自动重放。
154
+
155
+ ### Removed
156
+
157
+ - Removed the inline terminal UI and its automatic downgrade rules. Interactive
158
+ sessions now always use the full-screen UI; small windows show a resize notice.
159
+ - Removed `--fullscreen`, `--no-fullscreen`, `ARAGON_FULLSCREEN`, and the
160
+ `fullscreen` config setting. Old flags are rejected and old stored preferences
161
+ are ignored. Headless commands and piped input retain their existing behavior.
162
+ - Interactive-only screens now reject non-TTY input/output with exit code 2.
163
+
164
+ ### Added
165
+
166
+ - **`system/init` now lists what this build can do.** A new optional
167
+ `capabilities: string[]` field, carrying `["interrupt"]` for this release.
168
+
169
+ A wrapper cannot tell by observation whether an interrupt will settle
170
+ gracefully or kill the process outright, and guessing wrong costs the user
171
+ their conversation. Rather than have callers compare version numbers — which
172
+ breaks on forks, prereleases, and version shapes nobody anticipated — the
173
+ build now says so itself, in an event that already arrives on every start.
174
+ Absent on older builds, and absence should be read as "no", never as
175
+ "probably".
176
+
177
+ Additive, so `schemaVersion` does not move. Consumers that do not know the
178
+ field ignore it, exactly as the schema contract asks.
179
+
180
+ - **The composer understands pasting.** Until now it did not have the concept at
181
+ all: every byte the terminal delivered on stdin was a keystroke, and a
182
+ clipboard block is thousands of bytes arriving in an unpredictable number of
183
+ chunks. Three separate failures fell out of that one omission, and on Windows
184
+ you hit all three at once.
185
+
186
+ A carriage return that landed alone in a chunk **sent the half-finished
187
+ message** — a fifteen-line paste could arrive as a dozen separate messages,
188
+ interleaved with the agent's replies. A carriage return in the middle of a
189
+ chunk was inserted into the draft as a literal `\r`, which the terminal obeyed
190
+ by **overwriting the row it was drawn on**. And a paste that survived both grew
191
+ the composer to the height of the pasted text, pushing the transcript out of a
192
+ frame whose row accounting still believed the composer was three rows tall.
193
+
194
+ Pasting now works the way it reads:
195
+
196
+ - **A paste never submits.** Line breaks become buffer newlines, exactly one
197
+ per source line break, `CRLF` and lone `CR` alike.
198
+ - **A short paste appears verbatim.** At or below 6 lines and 400 characters it
199
+ is inserted as-is, indentation intact, and renders exactly like typed text.
200
+ - **A large paste collapses to a placeholder** — `[Pasted text #1 +218 lines]`
201
+ — which occupies one line, carries its own size in its label, deletes as a
202
+ single unit (one `Backspace`, and `Ctrl+W` / `Ctrl+U` / `Ctrl+K` cannot leave
203
+ half of one behind), and expands back to the full text the moment you send.
204
+ The model receives every byte; the composer never has to draw them.
205
+ - **No pasted byte is executed as a terminal control.** `\r`, `\x1b`, NUL, DEL
206
+ and the C1 range are stripped from the payload — never from your keystrokes,
207
+ so `Ctrl+A` and Escape are untouched.
208
+ - **The composer has a ceiling.** A draft of any length occupies at most 3 / 6 /
209
+ 10 rows depending on terminal height, scrolls internally to keep the caret
210
+ visible, shows how many rows are hidden above and below, and reports its true
211
+ height to the layout budget. Four hundred presses of `Shift+Enter` were
212
+ already able to destroy the frame; they no longer are.
213
+ - **A submitted message cannot make the transcript unresponsive.** A user entry
214
+ renders at most 40 rows plus a `... +N more lines` tail. The full text is kept
215
+ and the exit transcript is uncapped.
216
+
217
+ On terminals that support it, detection is **exact**: aragon asks for bracketed
218
+ paste (`DECSET 2004`) in full-screen mode and reads the markers the terminal
219
+ wraps your paste in. Where that is unavailable — inline mode, an old Windows
220
+ console — a heuristic on chunk shape catches the same cases, and it needs no
221
+ cooperation from the terminal at all. Both feed one code path.
222
+
223
+ Turn it off with `--no-paste`, `ARAGON_PASTE=0`, or
224
+ `aragon config set paste false`; the input path is then byte-for-byte what
225
+ 0.6.2 did.
226
+
227
+ ### Fixed
228
+
229
+ - **The right-edge scrollbar no longer disappears while output streams.** The
230
+ differential renderer ended every repainted row with `CSI K` (erase to end of
231
+ line). The scrollbar fills the last column of every viewport row, and on
232
+ terminals that keep the cursor on the last column after writing it (Windows
233
+ console hosts) that erase blanked the cell that had just been drawn, so the
234
+ scrollbar vanished whenever a row was redrawn. Rows that already fill the
235
+ terminal width are now repainted without the erase; narrower rows are
236
+ unchanged. `--no-diff-render` was never affected. `/perf` gained a `scrollbar:`
237
+ line for diagnosing visibility and drag problems.
238
+
239
+ - **`{"type":"interrupt"}` now really does settle the run — on every platform.**
240
+ The stdin interrupt frame used to raise a SIGINT at our own process. On POSIX
241
+ that reaches the runner's terminator and the run winds down properly: it
242
+ breaks out of the loop, persists the session, and emits `result` with the
243
+ usage and cost. On Windows, Node does not deliver a self-directed SIGINT to
244
+ its own handlers — the process simply terminated with exit code 1, having run
245
+ none of it.
246
+
247
+ For anyone using `aragon exec` interactively that difference was invisible,
248
+ because an interrupt there is usually the last thing that happens. It is not
249
+ invisible to a **wrapper** that interrupts a turn and then respawns on the same
250
+ `--session-id` to keep the conversation going: on Windows it silently got back
251
+ a session missing everything since the previous save. `exec/index.ts` has
252
+ carried a comment about that caller for some time ("PERSIST FIRST, ANNOUNCE
253
+ SECOND … a caller that reads `result` and immediately respawns with the same
254
+ `--session-id` must not race the writer"), so the intent was there; the path
255
+ just could not be reached on Windows.
256
+
257
+ The frame now calls the runner directly instead of going through a signal.
258
+ POSIX behaviour is byte-for-byte unchanged — the same code runs, with the same
259
+ `stopReason`, the same exit code 130, and the same two-second window in which a
260
+ second signal still forces an immediate exit.
261
+
262
+ - **A pasted API key is stored correctly again.** Ink broadcasts each stdin chunk
263
+ to every mounted input handler, so the settings screen, the question overlay
264
+ and the plan-review feedback field all see what the composer sees. Without
265
+ this, a ~100-character key pasted into Settings would have been stored wrapped
266
+ in invisible framing bytes, masked on screen by the password dots, and would
267
+ have failed to authenticate on every request afterwards with nothing anywhere
268
+ explaining why.
269
+
270
+ - **`--no-mouse` still writes no mouse sequence.** Paste support installs a
271
+ stdin filter, and `paste` defaults to on, so the filter now exists in sessions
272
+ that disabled the mouse. Whether the mouse is on is a separate question from
273
+ whether the stream is wrapped, and the four places that used to conflate them
274
+ now ask the right one: `aragon --no-mouse` writes no `?1000h`, no `?1006h` and
275
+ no `?1002h`, leaves your terminal's own click-drag selection alone, and reports
276
+ `/mouse` as off — while pasting still works.
277
+
278
+ ### Changed
279
+
280
+ - **The run status row moved above the input box and carries the `steer` hint.**
281
+ While a run is active, the spinner, the phrase and `steer / interrupt / exit`
282
+ share one row directly above the input, in place of the idle hint row below it
283
+ (the footer keeps its height). It scrolls with the input; when it leaves the
284
+ viewport the fixed bottom row shows the animation instead, so there is never
285
+ more than one spinner. Terminals under 20 rows and `--no-hints` keep the old
286
+ fixed row. The update notice is also held back for the whole run.
287
+
288
+ - **Auto-compaction no longer reports compactions that did not happen.** A long
289
+ unattended run used to print a red `context not compacted #2: nothing_to_drop`
290
+ card into the transcript. The card was accurate; nobody had asked for it.
291
+ Auto-compaction evaluates itself at every turn boundary, and a checkpoint that
292
+ looks at the history and finds nothing worth dropping has changed nothing,
293
+ called nothing and spent nothing — a smoke alarm announcing "no fire" twice an
294
+ hour, in error colours, with a machine reason attached.
295
+
296
+ A compaction now announces itself **if and only if it commits to doing work**.
297
+ That is a position in the control flow, not a list of reason strings: everything
298
+ decided before the first spend is silent, and everything decided after it —
299
+ including every failure, the truncation fallback, an Esc, and a host fault — is
300
+ as loud as it ever was. A declined `pressure` checkpoint is now
301
+ indistinguishable from a turn on which the threshold was never crossed.
302
+
303
+ **`/compact` and overflow recovery are unchanged.** A compaction you asked for
304
+ is owed an answer, and a reactive compaction running after the provider has
305
+ already refused your request is the one moment the diagnosis matters most. Both
306
+ still report on every outcome.
307
+
308
+ **Quiet, not unrecorded.** Every attempt is still written to the diagnostic log
309
+ (its `compaction` line gains an `announced` field, so `announced: false` is one
310
+ grep), still charged to the anti-loop guards, and still counted by
311
+ `/compact status` — which now reads
312
+ `This session: 1 compaction (2 checkpoints declined), 94.2k tokens reclaimed`
313
+ when checkpoints declined, and is byte-identical to before when none did. If
314
+ declines keep happening, the self-disable notice still says so out loud, once,
315
+ naming the cause and the remedies. Card numbers are also contiguous again: `#N`
316
+ counts compactions that ran, not checkpoints that fired.
317
+
318
+ **Behaviour change for wrapper scripts.** A declined `pressure` compaction no
319
+ longer emits a `{ type: 'compaction', subtype: 'start' | 'end' }` pair on the
320
+ `--output-format json` stream, and no longer prints `[compaction] skipped:` on
321
+ `-p` stderr. The pairs stay balanced, so only consumers counting *attempts* are
322
+ affected; the diagnostic log reports those more accurately.
323
+
324
+ ### Added
325
+
326
+ - **Context compaction, hardened — the trigger now counts the whole history, the
327
+ recent turns can no longer wedge a run, sub-agents get the same protection, and
328
+ a compaction is no longer irreversible.**
329
+
330
+ **The trigger was systematically late.** It fired on the provider's reported
331
+ usage for the PREVIOUS request, read at a checkpoint that runs AFTER the current
332
+ turn's tool results were appended — and tool results are the largest single
333
+ increment in this loop (100 KB per call, several per turn, ~25 k tokens each).
334
+ A session reading 88 % could be sending 110 %. Occupancy is now the measured
335
+ base PLUS an estimate of everything appended since that measurement, and the
336
+ status gauge reads the same number the trigger does, on every turn — including
337
+ the turns where a guard declines to compact, which is exactly when the number
338
+ matters most.
339
+
340
+ **The recent turns can no longer wedge a run.** Every previous rung of the
341
+ ladder operated on the head of the conversation. When the RETAINED tail was what
342
+ did not fit, each rung reported success or "nothing to drop" while the history
343
+ stayed un-sendable and the run died. Oversized `tool_result` bodies inside the
344
+ retained turns are now clipped, oldest first, only when the alternative is a
345
+ request the provider cannot accept. Nothing is removed — no message, no
346
+ tool-call id, no role — so a valid history stays valid. Every clip is announced
347
+ in the text the model reads, at the exact place the data went, and on the card,
348
+ in `/compact status`, on the JSON stream and in the archive.
349
+
350
+ **Sub-agents compact their own history** (`compaction.subagents`, default
351
+ `true`). A `task` child is bounded by 24 turns and fifteen minutes, and when one
352
+ overflowed its entire history was discarded and the dispatch reached the lead as
353
+ one partial sentence. Children run under tighter bounds than the lead: two
354
+ retained turns, at most two compactions, the fast tier preferred, and failure
355
+ forced to truncate because nobody is watching a background worker. No transcript
356
+ card — the lead's transcript describes the lead's context. Set
357
+ `compaction.subagents: false` to restore the previous behaviour exactly.
358
+
359
+ **A compaction is no longer irreversible** (`compaction.archive`, default
360
+ `true`). The dropped messages are written verbatim to `~/.aragon/compaction/`
361
+ before the splice is adopted. `/compact history` lists this run's archives,
362
+ `/compact show <n>` prints one's metadata and summary — never message bodies.
363
+ The directory is shared by every `aragon` on the machine, so files carry a
364
+ per-process run id and retention is two-tier: 20 files per run by count, plus a
365
+ seven-day sweep across all runs, so one session can never prune a live
366
+ neighbour's work. Writing is best-effort: a failure is logged and never affects
367
+ the compaction. This is deliberately **not** undo — restoring an over-full
368
+ history restores the condition that triggered the compaction.
369
+
370
+ **The long moment is legible.** The live card counts elapsed seconds and says
371
+ `esc to cancel`, which `AgentController.abort()` has always made true and no
372
+ surface has ever stated. A compaction that could only clip says so and names no
373
+ model, because none was called.
374
+
375
+ Two new config keys (`compaction.subagents`, `compaction.archive`), two new
376
+ environment variables (`ARAGON_COMPACTION_SUBAGENTS`,
377
+ `ARAGON_COMPACTION_ARCHIVE`), two new `/compact` verbs (`history`, `show <n>`),
378
+ and two new settings-screen rows. No flags were added.
379
+
380
+ - **Context compaction — a long run no longer dies when the window fills, and it
381
+ is ON by default.** A session's conversation only grows: nothing anywhere
382
+ removed a message, so a 40-turn tool-heavy run had exactly one ending available
383
+ to it once the context window filled — an HTTP 400 and a banner reading
384
+ *"Context length exceeded — start a new conversation with /reset."* The
385
+ product's answer to running out of context was "throw away everything you were
386
+ doing."
387
+
388
+ Now, at **90 %** occupancy, the run pauses at a turn boundary, hands the older
389
+ part of the history to a summarizer, and swaps it for a structured record. Your
390
+ original task stays **verbatim**, the most recent turns stay **verbatim**, and
391
+ the run continues in the same loop with the same tools, the same todo list and
392
+ the same working directory.
393
+
394
+ **This changes behaviour for existing users, in the direction of not dying.**
395
+ `--no-compaction`, or `compaction.enabled: false`, restores the old behaviour
396
+ exactly: no manager is constructed, nothing is subscribed, no registry is
397
+ allocated, and a full window ends the run as it did before. Both flag forms are
398
+ declared, so a stored `false` survives a run that passes no flags.
399
+
400
+ Three ways it fires. **Proactively** on measured occupancy — the case that
401
+ happens almost every time. **Reactively** when the provider returns
402
+ `context_overflow` anyway, because the model is not in the static window table
403
+ or you are pointed at a proxy in front of a smaller one: one compaction, one
404
+ re-send, run continues. And **manually**, via `/compact`, which runs
405
+ immediately when idle and queues to the next turn boundary when running.
406
+
407
+ The trigger has two terms. 90 % of a 200 k window leaves 20 k, which is plenty;
408
+ 90 % of a 32 k window leaves 3.2 k, which is less than a single `max_tokens` of
409
+ 8192 — the request is already impossible. So compaction also fires whenever the
410
+ remaining headroom drops below one full response.
411
+
412
+ **The default summarizer is your own model, and that costs real money.**
413
+ `compaction.useFastTier` is `true`, but it is a *preference*: the fast tier is
414
+ off unless you configured it, so out of the box the first compaction is a
415
+ ~30 k-token call on the session's own model. It happens at most 5 times per
416
+ run, the alternative is losing the run entirely, and the spend is visible — in
417
+ the session total, priced with the summarizer's own table, and reported as
418
+ `pricing unknown` rather than `$0.00` when that table has never seen the model.
419
+ Configure the fast tier to make it cheap.
420
+
421
+ Summarization fails sometimes. The ladder is one retry (on your **main** model
422
+ if the first attempt used the fast tier), then a **truncation** that says so on
423
+ the card, on the JSON event stream, and inside the block the model itself
424
+ reads. `compaction.onFailure: "stop"` makes the other trade.
425
+
426
+ Four guards stop it looping on your money: never two on consecutive turns,
427
+ never more than 5 per run, a progress requirement, and a self-disable after two
428
+ no-progress attempts with a notice naming the cause and the fix. The guards are
429
+ **trigger-aware** — the reactive path stays armed even after a self-disable,
430
+ because a compaction answering a request the provider has already refused is
431
+ the difference between a live run and a dead one.
432
+
433
+ Three UI surfaces: `Compacting context…` on the activity row while it runs, a
434
+ `compacting` chip plus threshold-aligned gauge colours as state, and a
435
+ transcript card with the before/after counts, the summarizer, the duration and
436
+ an expandable summary as the record. The gauge falls **immediately** rather
437
+ than waiting for the next turn. `/compact status` is the guaranteed surface at
438
+ any width.
439
+
440
+ New: `compaction` config section (6 keys), `--compaction` / `--no-compaction` /
441
+ `--compaction-threshold`, `ARAGON_COMPACTION*` (3 vars), `/compact` (6 forms),
442
+ three settings-screen rows, a `compaction` event on the `aragon exec` JSON
443
+ stream (`EXEC_SCHEMA_VERSION` **unchanged** — adding an event type never bumps
444
+ it), and two stderr lines under `-p`.
445
+
446
+ ### Changed
447
+
448
+ - **The context gauge now counts cache tokens**, through the same
449
+ `occupiedTokens` the compaction trigger reads. Anthropic reports `input_tokens`
450
+ *excluding* cached tokens and puts them in two separate fields, so the old
451
+ `inputTokens + outputTokens` silently under-reported occupancy for anyone
452
+ behind a caching gateway. That was already a defect in the number on the status
453
+ bar; it becomes a much worse one the moment a trigger fires on a different
454
+ number from the one you are watching.
455
+
456
+ - **`context_overflow` now names `/compact` alongside `/reset`.** That remedy
457
+ list was complete until this release, because throwing the conversation away
458
+ really was the only exit.
459
+
460
+ ### Known limitation
461
+
462
+ - **A summarizer that is 90 % faithful will, eventually, drop something the run
463
+ needed,** and no amount of prompt engineering closes that. The design bounds it
464
+ — verbatim task, verbatim recent turns, a block that tells the model the record
465
+ is partial, and three surfaces that make it visible so a human can step in —
466
+ but it does not eliminate it. That is inherent to compaction as a technique, it
467
+ is the same trade Claude Code and Codex make, and it is preferable by a wide
468
+ margin to the previous behaviour, which was to lose the entire run.
469
+
470
+ ## 0.6.0
471
+
472
+ ### Added
473
+
474
+ - **`aragon exec` — a second, machine-facing face on the same binary.** The
475
+ package already installed from npm and already ran from a terminal, so "it has
476
+ a CLI" was true. It was nonetheless not *callable* by another program:
477
+ everything it exposed was shaped for a person, and a build script, a CI job, a
478
+ web backend or a second agent had to spawn it, capture free text, and guess.
479
+ There was no way to read the answer without also reading the narration, no way
480
+ to carry a conversation across two invocations, no way to say "you may read but
481
+ not write" when there is no human to answer `--confirm`, and no way to bound
482
+ what a run may spend.
483
+
484
+ `aragon exec` adds a **contract** rather than a feature: a versioned JSON event
485
+ schema on stdout, a session identifier the caller may mint itself, a tool
486
+ permission policy enforced at the tool boundary, caller-set budgets with their
487
+ own exit code, and a discovery command so a wrapper can ask what it just
488
+ installed before depending on it. Everything underneath is reused unchanged —
489
+ the same controller, the same tools, the same config resolution, the same
490
+ skills, teams, todo and fast-tier subsystems.
491
+
492
+ - `--output-format text | json | stream-json`. `stream-json` is NDJSON: one
493
+ object per line, `system/init` first, exactly one `result` last, on every
494
+ exit path including error, budget and signal. `text` is byte-identical to
495
+ `aragon -p`, because it **delegates** to the same renderer rather than
496
+ reimplementing it.
497
+ - `--session-id` / `--resume` / `--continue`, backed by `~/.aragon-agent/
498
+ sessions/` and an exclusive lock, so two runs cannot interleave and lose a
499
+ turn. A second run on a held id exits 2 with `session_busy` rather than
500
+ blocking.
501
+ - `--permission-mode auto|plan|strict` plus `--allow-tool` / `--deny-tool`.
502
+ A denied tool is **not registered at all**, so the model never sees it and
503
+ never plans around it — and the policy reaches subagents, so one `task` call
504
+ cannot bypass it.
505
+ - `--max-turns` / `--max-duration`, both aborting through the same path `Esc`
506
+ uses, both reporting `isError: false` and exit **3**: a budget firing is not
507
+ a malfunction, but it is not a complete answer either, and a shell script has
508
+ to be able to tell without parsing JSON.
509
+ - `--append-system-prompt` / `--append-system-prompt-file`. Appending only;
510
+ there is deliberately no full `--system-prompt` replacement, because the
511
+ builtin prompt carries tool discipline, todo planning, the skills catalog and
512
+ the plan-mode block, and replacing it silently disables half the product.
513
+ - `--input-format stream-json`, so one process can serve several turns from a
514
+ pipe. A malformed line is skipped with a non-fatal `error` event; an unknown
515
+ message type is ignored.
516
+ - **`aragon sessions`** (`list` / `show` / `rm` / `prune` / `path`),
517
+ **`aragon info [--json]`** and **`aragon doctor [--json] [--probe]`**.
518
+
519
+ Documented in full under
520
+ [Use it from another project](./README.md#use-it-from-another-project),
521
+ including an honest Limits section: there is no filesystem sandbox, process
522
+ exit is terminal on Windows whether or not a `result` arrived, an exec session
523
+ resumed in the TUI shows no scrollback, and `sessions prune` shares a directory
524
+ with the TUI's `/save`.
525
+
526
+ ### Changed
527
+
528
+ - **Exit code `3` is new, and the signal row is now stated as `128 + signo`.**
529
+ `3` means "stopped by a budget you set" and is reachable only from
530
+ `aragon exec`. The signal codes are unchanged in behaviour — this CLI has
531
+ always exited `128 + signo`, so `SIGTERM` has always been `143` — but the
532
+ README previously simplified all of them to `130`, which is fine for prose
533
+ about a CLI a human interrupts and not good enough for a wire contract.
534
+ - `interrupt` handling now settles the run before exiting when `aragon exec`
535
+ owns it, so a wrapper reading NDJSON gets a final `result` on Ctrl-C instead of
536
+ having to time out to learn the run ended. `aragon`, `aragon -p` and every
537
+ other subcommand keep the previous bare-exit behaviour byte for byte.
538
+
539
+ ### Unchanged, and asserted rather than claimed
540
+
541
+ - `aragon`, `aragon -p`, every existing flag, every slash command and every byte
542
+ of their output. `aragon exec --output-format text` and `runHeadless` are
543
+ compared for byte equality on **both** stdout and stderr by a regression test,
544
+ and `createBuiltinTools` with no permission policy is proven by object identity
545
+ to return the tools it returned before.
546
+
547
+ ## Unreleased
548
+
549
+ ### Project index on Ctrl+I (bundled `project-indexer` skill)
550
+
551
+ - The `project-indexer` skill now ships **bundled** with the package
552
+ (`<pkg>/skills/project-indexer`, read-only, alongside `skill-creator`): it
553
+ generates the `.claude-index/` navigation map and injects the Google-style
554
+ Clean Code Guidelines section into `CLAUDE.md`, adapted from the standalone
555
+ Claude Code skill (ask_user instead of AskUserQuestion; body condensed under
556
+ the 30 KB invocation budget with the four templates bundled as files).
557
+ - New keybinding `Ctrl+I`: opens a Yes/No confirm that names every write
558
+ target, then dispatches `/skill:project-indexer` through the ordinary
559
+ command path - the indexing run is a normal agent turn whose tool calls
560
+ stream into the transcript. While a run is in flight the key warns instead
561
+ of queueing; with skills disabled or the skill shadowed it explains instead
562
+ of failing silently.
563
+ - `Ctrl+I` is legacy-encoded as the Tab byte, so the stdin filter's two
564
+ translators (win32-input-mode on Windows, kitty CSI-u / modifyOtherKeys
565
+ elsewhere) now emit a distinct NUL-delimited `INDEX_KEY_FRAME` for it -
566
+ the same framing technique `Shift+Enter` uses. On terminals with neither
567
+ protocol the key keeps its legacy Tab meaning (completion).
568
+ - The header names the key next to the detail toggle: `^I Index` collapsed,
569
+ `^I build index` in the `Ctrl+G` expanded state; hidden below 72 columns and
570
+ while an overlay is open. `/skill:project-indexer` and `/project-indexer`
571
+ remain available as typed commands.
572
+
573
+ ### Added
574
+
575
+ - **Drag the mouse to select text, and release to copy it.** Full-screen mode
576
+ takes the alternate screen, turns on mouse reporting so the wheel can scroll a
577
+ transcript the terminal no longer knows how to scroll, and draws every row
578
+ itself. Each of those is right on its own; together they took your terminal's
579
+ own drag-to-select away and put nothing in its place. The only thing shipped
580
+ in its place was a one-line notice naming a bypass key that is Shift on some
581
+ emulators, Fn on others and a preference elsewhere — a workaround, told once,
582
+ in a line that scrolls away.
583
+
584
+ Press the left button and drag: the cells you drag across are highlighted as
585
+ you go, and releasing copies exactly them. The copy goes out over **OSC 52**
586
+ first, so it reaches the clipboard of the machine you are *sitting at* rather
587
+ than the one you are ssh'd into, with the platform clipboard binary attempted
588
+ alongside it for terminals that ignore the sequence. Neither mechanism is
589
+ detectable, so the toast names what was sent rather than claiming a success it
590
+ cannot verify. `/copy` now goes through the same path and gained ssh support on
591
+ the way.
592
+
593
+ The highlight is painted in the frame pipeline rather than in React, so a drag
594
+ costs one to three re-addressed rows instead of a re-render of the whole tree,
595
+ and the text that is copied is read from the same mirrored rows the highlight
596
+ was painted over — what you see is what you get by construction, not by a
597
+ staleness check that can be wrong.
598
+
599
+ Two switches, both reversible without a restart: `/mouse off` hands the mouse
600
+ back to your terminal for the session (and says plainly that the wheel goes
601
+ inert while it is off), `/mouse on` takes it back, and
602
+ `aragon config set mouseSelect false` keeps wheel scrolling while leaving
603
+ drag-select off — which also stops the CLI asking the terminal for motion
604
+ reports at all, so that session puts exactly the bytes on the wire that it did
605
+ before this release. `--no-mouse` remains the switch that captures nothing.
606
+
607
+ ### Changed
608
+
609
+ - **Scrolling up now actually stops the transcript.** The viewport followed the
610
+ newest output by holding a *fixed distance from the bottom*, so scrolling up
611
+ during a run did not pause anything: twelve new rows of output moved the
612
+ window twelve rows down, and whatever you had scrolled up to read slid off the
613
+ top while you were reading it. The faster the agent talked, the faster your
614
+ reading position ran away.
615
+
616
+ While you are scrolled up, the transcript is now anchored to the **content**:
617
+ new output accumulates below the window instead of dragging the window along
618
+ with it, and the rows on screen hold still. After five seconds with no
619
+ scrolling the viewport returns to the newest line by itself — but only if
620
+ something actually arrived while you were paused, so reading a *finished*
621
+ transcript is never interrupted by a jump to a bottom that has not moved.
622
+ Every gesture restarts the countdown, a selection drag suspends it, and
623
+ `aragon config set scrollResumeMs 0` turns the return off entirely
624
+ (`ARAGON_SCROLL_RESUME_MS` sets it too).
625
+
626
+ The number the hint shows means something sharper as a result: it is now
627
+ literally "rows of newer output below your reading position", which is what
628
+ `PgDn` traverses and what the status bar's `↑N` has always shown.
629
+
630
+ - **The "N new lines · PgDn" hint moved inside the input box.** It used to be
631
+ rendered as the viewport's own last row, which spent a line of your transcript
632
+ on chrome at exactly the moment the transcript was longest — and, because the
633
+ hint's presence shrank the viewport, it fed back into the very number it was
634
+ displaying. It is now a right-aligned chip on the composer's input row, inside
635
+ the border, where it costs no rows at all. The chip sits in a fixed-width cell
636
+ so the number gaining a digit cannot re-wrap a draft, it never truncates (the
637
+ draft wraps first), and unlike the teaching row below the box it neither fades
638
+ with experience nor disappears on a short terminal: how far behind you are is
639
+ state, not a tutorial.
640
+
641
+ ### Fixed
642
+
643
+ - **The working spinner no longer disappears when an ack takes its row.** Steer a
644
+ run, approve a plan, or press `Ctrl+T` while the agent is working, and the row
645
+ above the composer traded its spinner for the acknowledgement — and for that
646
+ ack's full two and a half seconds, nothing anywhere on screen moved. The status
647
+ bar still read `running` and the tool card still read `running`, so no
648
+ information had left the frame; only the evidence that the process was alive
649
+ had, during exactly the long tool calls where "is it stuck?" is the question you
650
+ are already asking. Consecutive acks extended the window, and steering is
651
+ something the composer invites on every run.
652
+
653
+ That row was made the sole owner of animation in this same release, and
654
+ everything else on screen holds still for as long as the row is believed to be
655
+ showing one. Believed, not checked: an ack won the row outright, so the belief
656
+ and the frame disagreed, and the disagreement was invisible to every test
657
+ because no component was wrong on its own.
658
+
659
+ The ack still owns the row and keeps every word of its text. The spinner now
660
+ rides beside it as a bare glyph — no phrase, no clock — so there is exactly one
661
+ animation at every instant of a run, with an ack up or without one: never none,
662
+ and never the several this release set out to remove. Terminals without Unicode
663
+ and anyone running with `reducedMotion` come out byte for byte unchanged; they
664
+ had no animation to lose, and nothing is prefixed to their acks.
665
+
666
+ - **`/clear` now takes the todo panel with it.** Finish a plan, type `/clear`,
667
+ and the transcript emptied while the `7/7 done` rail stayed exactly where it
668
+ was — on a screen you had just asked to be cleared. It stayed until your next
669
+ real message, which is precisely the pause you take after clearing to decide
670
+ what to ask next, so essentially everyone met it.
671
+
672
+ This was deliberate once. The list is a projection of what the model believes,
673
+ and `/clear` wipes the transcript rather than the conversation, so the model
674
+ still believed in the plan and a panel contradicting the model was judged worse
675
+ than no panel. That reasoning holds for everything the CLI does on its own; it
676
+ does not hold against you typing the command. An explicit instruction was
677
+ always this rule's exception — `/todo clear` has used the same door from the
678
+ start — and `/clear` now goes through it.
679
+
680
+ The list itself is cleared, not just the pixels, so `/save`, `/todo status`,
681
+ `/todo continue` and auto follow-through all agree with the screen: no plan is
682
+ written into a saved session, nothing offers to continue one, and nothing spends
683
+ a follow-through on it. `/reset` is unchanged and still the only command that
684
+ clears the conversation. Nothing is stranded either way — the model's next
685
+ `todo_write` is a full replacement, so the panel comes back the moment there is
686
+ a plan to show.
687
+
688
+ ### Added
689
+
690
+ - **An update that will not start is undone automatically.** The updater shipped
691
+ in this same release could install a version that fails to *import* — an
692
+ undeclared dependency, a Node API that moved, a syntax error past the transpile
693
+ target — and the only recovery was to know the package name and type
694
+ `npm i -g @aragon-agent/cli@<some older version>` from memory. None of those
695
+ failures reach any line inside `main()`, so no amount of care there helps.
696
+
697
+ The `aragon` command is now a small launcher that runs **before** the CLI. It
698
+ reads one ~300-byte file, and on every launch except the first one after an
699
+ auto-update that is all it does — no write at all. But if the version it is
700
+ about to start is one **this updater installed**, and that version has already
701
+ exited non-zero twice, it reinstalls the version that was running before the
702
+ update and marks the bad one so nothing puts it back:
703
+
704
+ ```
705
+ aragon 0.6.0 failed to start twice; rolling back to 0.5.9.
706
+ ```
707
+
708
+ It boots anyway. If the crash was transient, refusing to start would lock you
709
+ out of a working CLI on our guess; the reinstall is detached and finishes
710
+ either way. The next session says once what happened and then stops. A **newer**
711
+ release clears the mark and installs normally — you were never opted out of
712
+ updates, only out of the loop.
713
+
714
+ It never touches a version **you** installed yourself, and it does not try to
715
+ detect a release that starts and is merely wrong. `aragon update --rollback` is
716
+ the same mechanism run deliberately, for the case a human spots in one second
717
+ and a heuristic would get wrong on a bad day. Exit `4` means there was nothing
718
+ recorded to roll back to.
719
+
720
+ **`update.mode: off` disables this too.** The guard is armed only by an
721
+ auto-install, so a machine that never auto-installs never arms it — the kill
722
+ switch turns off the whole subsystem, recovery included.
723
+
724
+ - **A blocked install now says what is actually blocking it.** Every install
725
+ failure used to print the same line: `update failed · npm i -g
726
+ @aragon-agent/cli`. On Windows the commonest cause is that the shim which
727
+ launched us is held open by the shell running it, so that advice hits the same
728
+ handle and fails identically — the one visible failure was also a wrong
729
+ instruction. Failures are now classified, and three of them name the real
730
+ remedy and appear immediately rather than after three strikes, because each is
731
+ something you can fix and none of them fixes itself:
732
+
733
+ ```
734
+ ! update blocked · close other aragon windows, then: npm i -g @aragon-agent/cli
735
+ ! update failed · no disk space
736
+ ! update needs write access · npm i -g @aragon-agent/cli
737
+ ```
738
+
739
+ Network failures are deliberately **not** in that set: you cannot fix the
740
+ registry and the next check may well succeed, so they stay silent and back off.
741
+
742
+ - **Updates work behind a corporate proxy.** Node's `fetch` ignores `HTTP_PROXY`,
743
+ so on a proxied machine the check failed silently forever. When the direct
744
+ request fails, `aragon` now asks the npm you already have instead, which
745
+ honours `proxy`, `https-proxy` and your `.npmrc`. It runs *only* after a
746
+ request that has already failed, so on an ordinary machine it never runs.
747
+ `/update status` shows `probe: npm` when this is what answered. No credentials
748
+ are read or forwarded — we run the command you could have typed.
749
+
750
+ - `/update status` gained `rollback`, `lastgood` and `probe` lines, so what the
751
+ guard did and what `--rollback` would reinstall are answerable without reading
752
+ the log.
753
+
754
+ ### Changed
755
+
756
+ - **`aragon update` exit codes: a blocked install is now `2`, not `1`.** This is
757
+ the one change here a script can notice. `1` means "try again later" and `2`
758
+ means "this machine will never auto-update, run the command we printed" — and
759
+ for `EPERM` / `EBUSY` / `ENOSPC` the second is the accurate one: waiting does
760
+ not unblock a held file handle or an empty disk. A caller shaped like
761
+ `aragon update || sleep 300 && retry` changes behaviour. `0`, and `1` for an
762
+ ordinary failed check or install, are unchanged.
763
+
764
+ - `bin.aragon` now points at `dist/launcher.js` rather than `dist/cli.js`.
765
+ `dist/cli.js` is unchanged, keeps its shebang and stays executable, so
766
+ `npm start` and any script invoking it directly keep working — only the mapping
767
+ moved.
768
+
769
+ - **`aragon` keeps itself up to date.** Until now the installed copy was frozen
770
+ forever: nothing in the CLI ever looked at the registry, so someone who
771
+ installed 0.4.x eighteen releases ago was still running it and the only signal
772
+ that anything had moved was a README they were never going to re-read.
773
+
774
+ There is now a background updater. At most once every four hours, and at most
775
+ once per machine per interval, it asks npm what the `latest` dist-tag resolves
776
+ to; if that version is genuinely newer, stable, not deprecated and runnable on
777
+ this Node, it installs it silently into the same global installation you
778
+ already have and says so on **one line above the composer**:
779
+
780
+ ```
781
+ * 0.6.0 installed - restart aragon to apply
782
+ ```
783
+
784
+ **The running process is never mutated in any way it can observe.** The new
785
+ version lands on disk and takes effect on the *next* launch. A restart in the
786
+ middle of a turn would destroy a live run, a subagent dispatch and an open plan
787
+ review, so the line waits and the human decides when.
788
+
789
+ The notice does not get its own row — it shares the row the toast stack and the
790
+ working line already share, behind both of them. A toast is a response to
791
+ something you did and wins outright; the working line is transient and would be
792
+ lost if deferred; the update line is persistent and loses nothing by waiting.
793
+ The practical effect is that **someone who is actually working never sees the
794
+ updater until they stop.**
795
+
796
+ It only ever runs `npm i -g` for one kind of installation: a global one where
797
+ no project manifest claims to own the version. pnpm, yarn, bun and volta are
798
+ each detected and get the correct command for *that* manager printed instead
799
+ of a command run on their behalf; `npx`, a project's `node_modules` and a
800
+ clone of this repo produce no line at all, because none of them is out of date
801
+ in any sense the user can act on. A global directory that cannot be written is
802
+ detected before anything is spawned, and npm exiting `0` into a *different*
803
+ prefix — which happens on any machine with `prefix=` in `.npmrc` or two Node
804
+ installations — is caught by re-reading the version from the directory we
805
+ classified, rather than being believed.
806
+
807
+ Every failure is silent: it logs, backs off exponentially, and says nothing
808
+ until the third consecutive one, at which point it says something actionable.
809
+ Four config keys (`update.mode`, `update.checkIntervalMs`, `update.registry`,
810
+ `update.distTag`), the flags `--update` / `--no-update`, the environment
811
+ variables `ARAGON_UPDATE` and `ARAGON_UPDATE_REGISTRY`, the slash command
812
+ `/update [status|now|skip|off]`, and a foreground `aragon update
813
+ [--check] [--to <version>] [--json]` for headless users. `update.mode: off`
814
+ and `ARAGON_UPDATE=0` are kill switches, and with either set the CLI executes
815
+ zero lines of update code.
816
+
817
+ Auto-update widens the window in which a compromised release reaches users
818
+ without a human decision. The README says so plainly, along with what is and
819
+ is not mitigated. No credentials are ever attached to the check.
820
+
821
+ - **A running command shows what it is doing.** `bash` is the only tool here that
822
+ can run for minutes — `npm test`, a `git clone`, a training job — and while it
823
+ ran, its card was one line of text that never changed. Nothing in that frame
824
+ distinguished a test suite at 40% from a child process blocked forever on a
825
+ password prompt this CLI will never show. Its card now carries the last eight
826
+ lines of what the command is printing, plus one footer row that reads
827
+ `(running)` or, once the child has been quiet for ten seconds,
828
+ `no output for 45s` — with the seconds advancing.
829
+
830
+ A `\r`-driven progress bar (npm, pip, curl, docker) is *one* line rewritten a
831
+ thousand times, and it renders as **one row counting up in place** rather than
832
+ a thousand rows of nearly the same string — including the ordinary case where
833
+ the bar emits no newline at all for its entire run.
834
+
835
+ Everything the tail shows is **stripped, not interpreted**: ANSI colour, cursor
836
+ motion, `\r`, `\b`, tabs and every other control byte are removed at the
837
+ boundary before a row is stored, so nothing can move a cursor inside a frame
838
+ the renderer believes it owns. It is bounded twice by construction — eight rows
839
+ per call, sixteen concurrent calls — so a command that writes 400 MB to stdout
840
+ costs a fixed number of retained rows.
841
+
842
+ It is a **display and nothing else**. The text the model receives is
843
+ byte-for-byte what it was; `Ctrl+O` does nothing while a command runs, because
844
+ expansion is a promise about stored content and there is no stored rest of a
845
+ 400 MB stream; `/save` during a run writes no tail, since a resumed one would
846
+ describe a process that died with the session; and at settle the card is
847
+ replaced by the authoritative result exactly as before.
848
+
849
+ New config key `liveToolOutput`, defaulting to **`true`** — unlike
850
+ `showThinking` below, this adds information rather than hiding it.
851
+ `aragon config set liveToolOutput false` (or `--no-live-tool-output`, or
852
+ `ARAGON_LIVE_TOOL_OUTPUT=0`, or the **Live output** row in `/settings`) turns it
853
+ off, and with it off no store is allocated and no recorder is attached: `bash`
854
+ is byte-identical to the build before this entry.
855
+
856
+ - **The working line stops guessing while a tool runs.** It reads
857
+ `⠙ Running bash` instead of rotating thinking-words. `running` covers the whole
858
+ turn, including the minutes the model is idle and a child process is doing the
859
+ work, so "Pondering" during a build was not calm — it was wrong. One row, no
860
+ digits, no clock: everything the row already promised still holds.
861
+
862
+ ### Changed
863
+
864
+ - **Reasoning blocks are now hidden by default.** `showThinking` is a new
865
+ top-level config key and it defaults to `false`. If you have been reading
866
+ thinking every day, this is the entry that concerns you: `Ctrl+T` still shows
867
+ it for the session exactly as before, `aragon config set showThinking true`
868
+ (or `--show-thinking`, or `ARAGON_SHOW_THINKING=1`) restores the old behaviour
869
+ permanently, and `/settings` has a **Show thinking** row directly under
870
+ **Thinking**.
871
+
872
+ Nothing is hidden silently. A settled turn that thought leaves one muted row
873
+ where the block used to be — `✱ thought for 12s · ctrl+t to show` — so the fact
874
+ that reasoning happened, how long it took, and how to see it are all still on
875
+ screen. In **inline** mode that row omits the key hint and the toast reads
876
+ `Thinking shown for new output.`, because a settled entry there has already
877
+ been printed into your terminal's scrollback and cannot be repainted; the
878
+ toggle applies to the live entry and to everything drawn after it.
879
+
880
+ `thinkingLevel` is untouched and means what it always did — the effort the
881
+ provider is asked to spend. `showThinking` is only whether the terminal draws
882
+ what came back. They are one word apart in the config file, which is why the
883
+ flag is `--show-thinking` rather than the shorter name.
884
+
885
+ ### Added
886
+
887
+ - **A live working line while a run is in flight.** One row above the composer,
888
+ carrying a spinner and a word that rotates every four seconds:
889
+ `⠋ Percolating…`. Take reasoning off the screen and the gap between submitting
890
+ and the first token is otherwise completely blank, which reads as dead rather
891
+ than as busy — the two changes are one change.
892
+
893
+ It carries no clock and no token count, deliberately: the status bar one row
894
+ below already renders both, under the same running condition and driven by the
895
+ same 200 ms ticker this row reuses. Under `reducedMotion` the spinner is a
896
+ static glyph and the word is chosen once and holds, because rotating text is
897
+ motion too. An idle frame is unchanged, and so is the viewport's row budget —
898
+ the line shares the row the toast strip already owned rather than adding one.
899
+
900
+ - **`write_file` and `edit_file` render a real diff.** Hunks with old/new line
901
+ numbers, a `+N -M` summary, add/remove/context colouring, and `(truncated)` or
902
+ a `binary` / `too-large` / `unreadable` note when the old side could not be
903
+ read. Diffs collapse at 12 rows behind the existing `Ctrl+O` — no new
904
+ keybinding. A resumed session written by an older build, or a card whose patch
905
+ the bounded store already evicted, falls back to the previous text preview;
906
+ nothing renders blank.
907
+
908
+ `write_file` previously reported creating a 300-line file as
909
+ `Wrote 8214 bytes to path`, and `edit_file`'s diff trimmed the common prefix
910
+ and suffix and rendered *everything* in between as one removed block followed
911
+ by one added block — for a `replace_all` touching line 40 and line 900, that
912
+ was 860 removed rows followed by 860 nearly identical added ones.
913
+
914
+ **The model's input got smaller, not larger.** The structured patch reaches the
915
+ screen on a CLI-local channel rather than through the tool result, and the text
916
+ the model reads gained a 4 000-character ceiling it did not have before (its
917
+ only previous bound was the executor's 100 KB backstop). A single-region edit
918
+ is byte-for-byte what it was plus one `@@` header; a multi-region edit is
919
+ strictly smaller. `write_file`'s result text is unchanged.
920
+
921
+ ### Changed
922
+
923
+ - **A stream that stops mid-answer is now a loud failure instead of a silent
924
+ truncated one.** All three provider adapters used to end their SSE loop by
925
+ yielding "done" with whatever had arrived, so a connection closed cleanly
926
+ half-way through an answer — a proxy idle cut, a load-balancer timeout, an
927
+ HTTP/2 GOAWAY — was indistinguishable from a completed reply. You got a
928
+ truncated answer and were told nothing.
929
+
930
+ Each adapter now reports the truncation, which is what lets it be retried and
931
+ recovered. An **abort** is explicitly excluded and still completes normally, and
932
+ a model that legitimately says nothing and stops is still a success.
933
+
934
+ This is deliberately **not** behind `--no-retry`: an adapter that reports a
935
+ truncated stream honestly should do so whether or not retry is enabled. A switch
936
+ that also disabled telling you the truth would be a mute button, not a kill
937
+ switch.
938
+
939
+ - **The mouse wheel now only ever scrolls.** A notch scrolls the transcript
940
+ three rows (a page with `Shift`), or the open overlay when there is one, no
941
+ matter where the pointer is sitting. Prompt history is recalled by `↑` / `↓`
942
+ alone, exactly as in Claude Code and Codex.
943
+
944
+ **This supersedes the 0.5.0 entry below**, which said the wheel "scrolls what
945
+ is under the pointer" and stepped prompt history one entry per notch when the
946
+ pointer was over the input box. That turned out to be wrong in use rather than
947
+ in principle: the pointer is not an instrument you aim in a TUI — it rests
948
+ wherever you last left it, which in a chat-shaped app is next to the thing you
949
+ type into. So the ordinary "scroll back and see what just happened" gesture
950
+ landed on the composer and replaced the draft with an old prompt, with no
951
+ error, no undo and nothing visibly connecting the gesture to the outcome. The
952
+ band that decided this was invisible too: its boundary was a measured row that
953
+ moved as the toast row, the hint row and the completion popup came and went, so
954
+ the same gesture could do two different things a second apart.
955
+
956
+ Nothing else about the wheel changes — same three rows per notch, same
957
+ `Shift`+wheel page, same `--no-mouse` / `ARAGON_MOUSE=0` / `mouse: false`
958
+ escape hatches, same `Shift`+drag for selecting text.
959
+
960
+ - **A long session stays as fast as a short one.** The TUI used to get slower as
961
+ a session grew and, past a threshold, stopped making progress at all. That was
962
+ structural rather than incidental: Ink has no output caching, so every frame
963
+ re-walked the entire mounted tree, re-measured every text node and
964
+ re-serialised the frame. The per-frame cost was therefore proportional to every
965
+ character the session had ever produced — and `transcriptWindow` bounded the
966
+ entry *count*, which bounds nothing when one entry can be fifty thousand lines.
967
+
968
+ Entries outside the visible band are no longer mounted. The viewport renders
969
+ what you can see plus a couple either side and replaces the rest with two
970
+ spacers of the right height, so the frame costs what the screen costs.
971
+ Scrolling, the `↑N` readout and the wheel routing are untouched. Because the
972
+ horizon is no longer a rendering budget, `transcriptWindow` rises from 300 to
973
+ 1000 and its ceiling from 2000 to 20000; an existing setting is still valid
974
+ and still clamps.
975
+
976
+ Syntax highlighting and markdown parsing are memoised on their input, so a
977
+ 200-line code block is tokenised once rather than thirty times a second for as
978
+ long as it stays on screen. Only the *parsed* form is cached and never a themed
979
+ one, so `/theme` still takes effect on the next frame.
980
+
981
+ Under genuine load the streaming interval widens — 33 ms up to a 320 ms
982
+ ceiling — so keystrokes and `Ctrl+C` do not queue behind renders. This is
983
+ visible rather than silent: a muted **`eco`** chip appears in the status bar
984
+ while it is in effect, because a user who cannot see why the stream got
985
+ chunkier will conclude the model got slower. `--no-render-governor`,
986
+ `renderGovernor: false` or `ARAGON_RENDER_GOVERNOR=0` turns it off;
987
+ `--max-render-interval 33` flattens the ladder without disabling the mechanism.
988
+
989
+ - **A live thinking block no longer grows without limit.** While an answer is
990
+ streaming, visible thinking is clamped to its newest 24 rows behind a
991
+ `... N earlier lines` marker, and the whole block renders again the moment the
992
+ answer settles. Thinking is scratch reasoning you read from its newest end, and
993
+ an unbounded one was the easiest way for a single live entry to fill the
994
+ viewport on its own.
995
+
996
+ ### Fixed
997
+
998
+ - **Inline mode could hard-freeze the terminal, and now cannot.** Once a live
999
+ entry grew taller than the terminal, Ink took a branch that writes
1000
+ `clearTerminal` plus the *entire accumulated session history* on every
1001
+ subsequent frame — bypassing both of its own dedupe gates, and growing without
1002
+ bound for the rest of the session. Any inline user (`--no-fullscreen`,
1003
+ `TERM=dumb`, CI, a terminal under 12 rows or 40 columns) whose model wrote a
1004
+ long answer could reach it. The live region is now clamped below that
1005
+ threshold, with a `... N earlier lines` marker naming what is deferred. Nothing
1006
+ is lost: the entry prints in full into the terminal's own scrollback the moment
1007
+ it settles.
1008
+
1009
+ - **The view state no longer grows without a ceiling.** A single assistant answer
1010
+ is capped at 256 KiB in the view (thinking at 64 KiB, streamed tool arguments
1011
+ at 16 KiB) by eliding the MIDDLE, so both the opening and the live cursor
1012
+ survive; a marker states how many characters went. `transcriptRetain`
1013
+ (default 1000) caps the entries kept in memory, and what it removed is counted
1014
+ and reported both by `/perf` and at the top of the exit replay. A model that
1015
+ emits five megabytes no longer makes every later frame a five-megabyte scan.
1016
+
1017
+ ### Added
1018
+
1019
+ - **A fast model tier: a second, cheaper model you can delegate to and be
1020
+ reviewed by.** Off by default — with `fast.enabled: false` the system prompt,
1021
+ the `task` schema, the transcript and the request payloads are byte-identical
1022
+ to a build without it — and it does two things once you turn it on.
1023
+
1024
+ **Delegation.** `task` gains one optional field per subagent, `model: "fast"`.
1025
+ A child marked that way runs on the fast model and is otherwise identical:
1026
+ same tools, same working directory, same `--confirm` gate, same plan-mode
1027
+ gate, same skills ceiling. Delegating to a cheaper model is a *model* choice,
1028
+ never a permission boundary. It is where "not complicated, but very expensive
1029
+ in context" gets paid for — a child that reads nine files and reports four
1030
+ sentences moves the file bodies out of the lead's window and onto a model that
1031
+ costs a fraction as much per token.
1032
+
1033
+ **Periodic review.** Every few turns a small digest of what the lead has been
1034
+ doing goes to the fast model with one question — is this still on track? — and
1035
+ a critique that is not "on track" is injected into the running loop as a
1036
+ `<fast_review>` block, so the lead sees a second opinion while it can still
1037
+ act on it:
1038
+
1039
+ ```
1040
+ fast review #2 · claude-haiku-4-5 · turn 12 · 1.4s
1041
+ You have edited config/schema.ts three times without running the tests.
1042
+ ```
1043
+
1044
+ The digest is built from a bounded ring of recent turns and **never** from the
1045
+ message history: sending a session's accumulated file bodies to the "cheap"
1046
+ model would make a review cost more than the turn it reviews, which is the
1047
+ inversion the whole feature exists to prevent.
1048
+
1049
+ Spend is attributed **per tier** — a fast child's tokens are priced at the
1050
+ fast model's table, not the lead's, and the dispatch report states the two
1051
+ separately. A model the built-in price table has never seen is reported as
1052
+ `unknown` rather than as `$0.00`, because a feature that looks free while it
1053
+ is spending money is worse than one that admits it does not know.
1054
+
1055
+ Turn it on with `/fast model <id>` then `/fast on`, with
1056
+ `aragon config set fast.enabled true`, with `--fast --fast-model <id>`, or with
1057
+ `ARAGON_FAST=1 ARAGON_FAST_MODEL=<id>`. `/fast status` is the guaranteed
1058
+ readout: the resolved model, the budget, and this session's reviews, delegated
1059
+ children, tokens and cost. Eleven `fast.*` config keys, four flags, four
1060
+ environment variables and five settings-screen rows; see the README.
1061
+
1062
+ **The review has a session budget.** A session is not one run — it is one run
1063
+ per message you send — so a cadence bounds the pace and nothing bounds the
1064
+ total. `fast.reviewMaxPerSession` (default **40**, raisable live with
1065
+ `/fast budget <n>`) is the number of reviews a session may *start*; reaching it
1066
+ prints one `info` notice that names the remedy and says delegation is
1067
+ unaffected, and `/fast status` reads `12/40` from the first review rather than a
1068
+ bare count you can only size after the fact. It is denominated in **reviews,
1069
+ not currency**, because the fast tier is exactly where a model the price table
1070
+ has never seen lives — a dollar ceiling would silently never fire for the
1071
+ configuration that most needs one. Delegation is never budgeted: it is spend the
1072
+ lead chose in service of a message you sent, it is already bounded by `team.*`,
1073
+ and it exists to *reduce* total cost.
1074
+
1075
+ **The review also fails fast, so it cannot compete with you.** It calls through
1076
+ its own provider registry with **one** retry rather than the ten
1077
+ `retry.maxRetries` defaults to for the lead, and it observes neither `retry.*`
1078
+ nor `/retry` — that policy says how hard to fight for *your* answer, and
1079
+ inheriting it for an unrequested background call is how an advisory ends up
1080
+ spending a rate-limited provider's quota on itself. Its own wall-clock bound
1081
+ is 20 s.
1082
+
1083
+ Two failure modes are handled out loud rather than silently. If the tier stops
1084
+ resolving mid-session — you switch the main provider and `fast.provider` was
1085
+ inheriting it — `model:"fast"` is downgraded to the main model, **counted, and
1086
+ stated in the report**, because an agent that silently gets an expensive child
1087
+ has no way to learn its cost model is wrong. And three consecutive
1088
+ *misconfiguration* failures disable the reviewer for the session with exactly
1089
+ one warning, while a merely busy provider (rate-limited or overloaded) is
1090
+ treated as transient and never counts — that condition fixes itself, and a
1091
+ session-long silent shutdown over it would not. A review you *cancelled* is
1092
+ neither: Esc, a run that ends first, or quitting leaves a `cancelled` card and
1093
+ no strike against the tier.
1094
+
1095
+ Reviews log under their own `fast` scope rather than under `agent`, so
1096
+ `fast_review_*` records filter cleanly away from the lead's.
1097
+
1098
+ - **API calls are retried with backoff, and the waiting is legible.** A transient
1099
+ provider failure — HTTP 429, 529, 5xx, 408, or a dropped connection — used to end
1100
+ the turn. One red notice, an idle prompt, and forty tool calls of work thrown
1101
+ away. It is now retried up to **10 times** with an increasing interval
1102
+ (1 s → 2 → 4 → 8 → 16 → 30 s, equal-jittered, 30 s per wait at most) under a
1103
+ 4-minute budget measured from the first failure.
1104
+
1105
+ What you see while it waits is **one line, rewritten in place** — never ten
1106
+ notices — carrying what failed, which attempt this is, and a countdown to the
1107
+ next one:
1108
+
1109
+ ```
1110
+ ↻ Provider overloaded · retry 3/10 in 7s Esc to cancel
1111
+ ↻ recovered after 3 retries · 12.4s
1112
+ ```
1113
+
1114
+ plus a `retry 3/10 7s` chip on the status bar (`[r3]` on a narrow terminal). The
1115
+ card settles into the transcript as history — `recovered`, `gave up`, or
1116
+ `interrupted` — and shows up in the exit replay, because a turn that spent three
1117
+ minutes retrying is exactly the kind of cost an exported transcript should
1118
+ account for.
1119
+
1120
+ **Esc ends the wait within a frame**, not at the end of the countdown, and it
1121
+ never produces a fabricated error: an aborted request is silent. That is the one
1122
+ detail everything else here depends on, because the provider layer marks an
1123
+ `AbortError` as retryable — so the signal is checked *before* the error, and a
1124
+ user pressing Esc can never be mistaken for a timeout worth retrying.
1125
+
1126
+ Never retried: `auth_error` (401/403), `invalid_request`, `context_overflow`.
1127
+ Ten retries of a bad API key is three minutes of looking broken.
1128
+
1129
+ `Retry-After` is honoured as a **floor**, never a replacement — a `Retry-After: 1`
1130
+ on the ninth retry does not undo eight retries of backoff — and a stated wait
1131
+ longer than a minute is surfaced immediately with the provider's own number
1132
+ rather than silently wedging the terminal.
1133
+
1134
+ A connection that dies **mid-answer** is also covered, and this is the case that
1135
+ needed more than a retry loop: the partial text is discarded, the affected tool
1136
+ cards are removed, and the answer restarts from the top. Nothing is duplicated,
1137
+ because the engine only writes history on a completed turn.
1138
+
1139
+ - **`/retry [show|on|off|max <n>]`, `--retry` / `--no-retry`, `--retry-max <n>`,
1140
+ `ARAGON_RETRY`, `ARAGON_RETRY_MAX`, and a `retry` config section** with nine
1141
+ keys (`aragon config set retry.*`). `/retry off` takes effect **in the running
1142
+ session** — subagents included, since they share the lead's provider registry —
1143
+ not only at the next launch. `retry.maxRetries: 0` is the kill switch and is a
1144
+ real value at every one of those entry points. `/settings` gains one read-only
1145
+ `API retries` row.
1146
+
1147
+ - **A subagent's retry is visible on the team card.** A child in backoff reports
1148
+ `retry 3/10` on its own row. Children inherit the retry policy for free, but
1149
+ their events never reach the lead's view, so without this a subagent spending
1150
+ three minutes waiting looked exactly like a hung dispatch.
1151
+
1152
+ - **Retry lines in `-p` mode go to stderr, never stdout.** `[retry 3/10]
1153
+ overloaded — waiting 7s` and `[retry] recovered after 3 retries` are on stderr,
1154
+ so `aragon -p … | jq` stays valid; a discarded partial answer is announced there
1155
+ too, because a piped consumer otherwise cannot tell a replay from a model that
1156
+ repeated itself. They are not suppressed by `--quiet`: a three-minute pause with
1157
+ no explanation is not a compact run, it is a hang.
1158
+
1159
+ - **`/perf`.** Reports what the renderer is actually doing: the frame interval
1160
+ and the last commit cost, how many entries exist / are retained / were dropped
1161
+ / are mounted, height-cache and render-cache occupancy, and the viewport
1162
+ geometry. `/perf reset` clears the caches and returns the governor to its
1163
+ fastest rung. Silent degradation is the one thing a claim of robustness cannot
1164
+ afford, and this is the place that names it.
1165
+
1166
+ - **Three configuration keys**, each with a flag and an environment override:
1167
+ `transcriptRetain` (`--transcript-retain`, `ARAGON_TRANSCRIPT_RETAIN`),
1168
+ `renderGovernor` (`--render-governor` / `--no-render-governor`,
1169
+ `ARAGON_RENDER_GOVERNOR`) and `maxRenderIntervalMs`
1170
+ (`--max-render-interval`, `ARAGON_MAX_RENDER_INTERVAL_MS`). No migration and no
1171
+ config version bump: a file written before they existed loads unchanged.
1172
+ `transcriptRetain` is raised to `transcriptWindow` when the two conflict —
1173
+ retaining less than you can scroll to would make part of the horizon
1174
+ unreachable — and a startup notice names both numbers, because overriding a
1175
+ value you typed and saying nothing is the one thing none of this may do.
1176
+
1177
+ - **Following the plan through, on a budget you can do arithmetic on.** A run
1178
+ that ended with steps outstanding used to print one sentence and stop. It now
1179
+ asks three questions the CLI already knew the answers to — did you abort it,
1180
+ did it error, did the list move — and does one of three things.
1181
+
1182
+ With the default `notify` the sentence is unchanged, except that a run **you**
1183
+ cancelled with `Esc` now says nothing at all: being told what you just
1184
+ interrupted is the CLI answering a question nobody asked.
1185
+
1186
+ With `/todo follow auto` it continues the plan itself, after announcing
1187
+ `Continuing with 4 remaining steps in 3s - Esc to stop.` Auto-continuation was
1188
+ refused last release as "an unbounded cost loop wearing a helpful hat", and
1189
+ that judgement stands — what changed is that the loop is now bounded first.
1190
+ A continuation that completes no step buys exactly one more attempt; a single
1191
+ plan is continued at most 25 times however productive it looks; and a re-plan
1192
+ forgives the first counter but never the second, so a model that reshapes its
1193
+ list every turn cannot lift the ceiling. A run that ended with an error never
1194
+ auto-continues in any mode. `Esc` cancels, and so does typing anything.
1195
+
1196
+ Whatever sends the continuation — the timer or `/todo continue` — now sends
1197
+ the numbered list of open steps rather than the words "continue with the
1198
+ remaining todo items", so a plan whose `todo_write` has scrolled out of the
1199
+ context window is still followed exactly. Neither path records that text in
1200
+ your prompt history any more; it is not something you typed.
1201
+
1202
+ Under `-p` there is no grace window, because there is nobody there to use it,
1203
+ which is precisely why the two counters rather than the human are the
1204
+ protection there. `[todo] continuing (3 steps left)` and
1205
+ `[todo] 3 steps unfinished` go to stderr, suppressed by `--quiet`, and an
1206
+ unfinished plan still never changes the exit code.
1207
+
1208
+ New surfaces: `/todo follow <notify|auto|off>`; `--todo-follow <mode>`;
1209
+ `ARAGON_TODO_FOLLOW`; and `todo.followThrough` in `config.json`. The default
1210
+ is `notify`, so a session that does not ask for any of this behaves as it did.
1211
+
1212
+ - **A plan strip for inline mode.** Inline mode has no fixed frame and so no
1213
+ rail, which left every pipe, every `CI=1`, every `TERM=dumb` terminal and
1214
+ every window under twelve rows able to see `todo 3/7` but not *which* step was
1215
+ running. There is now a one-row strip under the transcript —
1216
+ `todo 3/7 > Adding the rail to AppShell +2 done` — windowed on the
1217
+ same step the rail would have anchored on. It truncates rather than wrapping
1218
+ and is exactly one row at every width, so the composer does not move.
1219
+ `--no-todo-panel` hides it along with the rail.
1220
+
1221
+ ### Changed
1222
+
1223
+ - `npm run typecheck` now covers the test tree in both packages. `tsconfig.json`
1224
+ excludes `__tests__` so the build never emits fixtures, and vitest transpiles
1225
+ without typechecking — between the two, a widened required field could break
1226
+ ten test files while `npm run build` and `npm test` were both green. Twelve
1227
+ such errors had accumulated; all twelve were fixture drift and all twelve are
1228
+ repaired, with no suppressions and no production type relaxed to accommodate a
1229
+ fixture.
1230
+
1231
+ - **TODO planning, and a rail to watch it in.** For work with three or more
1232
+ distinct steps the agent now keeps a visible plan: it writes a checklist with
1233
+ a new `todo_write` tool, marks exactly one item in progress, and ticks it off
1234
+ before starting the next. In full-screen mode the list is rendered as a
1235
+ right-hand rail about a fifth of the terminal wide, windowed around the step
1236
+ being worked on rather than sliced from the top. Ask for something small and
1237
+ nothing appears — the prompt tells the model not to plan work it can finish in
1238
+ one or two steps, and a one-item list against an empty plan is refused
1239
+ outright, so a session that never plans has byte-identical layout to a build
1240
+ without this feature.
1241
+
1242
+ The list is a projection of what the model believes, and that single rule
1243
+ decides everything else: `/clear` keeps it (the conversation is still there),
1244
+ `/reset` drops it, `/save` writes it and `/resume` restores it — and resuming
1245
+ a session that carries no list CLEARS the current one rather than leaving a
1246
+ plan on screen whose conversation has just been replaced. A finished plan
1247
+ survives to the start of your next message so you get to see `7/7 done`; an
1248
+ unfinished one survives "continue" and "now do the rest", then expires after
1249
+ three unrelated turns rather than holding a fifth of the screen for the rest
1250
+ of the session. A run that ends with items left over produces a notice and
1251
+ `/todo continue`; nothing auto-continues on your behalf.
1252
+
1253
+ "One step at a time" is enforced by structure rather than asked for in a
1254
+ prompt: any payload with two in-progress items is repaired down to one, and a
1255
+ list with none promotes the first unfinished item. Whatever the model sends,
1256
+ the panel has exactly one current row.
1257
+
1258
+ New surfaces: the `todo_write` tool; `/todo [status|on|off|panel on|off|clear|
1259
+ continue]`; `--todo` / `--no-todo` and `--todo-panel` / `--no-todo-panel`;
1260
+ `ARAGON_TODO=0`; and `todo.enabled` / `todo.panel` in `config.json` (a third
1261
+ key, `todo.followThrough`, arrived with the follow-through entry above).
1262
+ `panel` is
1263
+ separate from `enabled` on purpose — a screen-reader user wants the planning
1264
+ discipline without the column, and the system prompt varies one sentence to
1265
+ match. Under `-p` the plan goes to stderr as `[todo] 3/7 <step>` lines,
1266
+ suppressed by `--quiet`. Below 80 columns, behind an overlay, in inline mode
1267
+ or on a short terminal the rail is not mounted and the counter appears in the
1268
+ status bar instead; the transcript keeps at least 62 columns at every width.
1269
+
1270
+ - **Output token limits that cannot themselves fail a run.** Every model and
1271
+ every provider now defaults to 64000 output tokens, and that number is
1272
+ configurable from the TUI, from a flag, from `ARAGON_MAX_TOKENS`, and by hand
1273
+ in `~/.aragon-agent/config.json`. Leave it alone and it stays 64000.
1274
+
1275
+ What is new is that the number is an *ambition*. `gpt-4o` caps at 16384 and
1276
+ `gemini-1.5-pro` at 8192; sending 64000 to either is an HTTP 400 that ends the
1277
+ turn with a raw provider string in the transcript. The cap is now clamped down
1278
+ to whatever the target model actually accepts, from a per-model table plus
1279
+ whatever the provider's own model list reports. For a model nothing knows — a
1280
+ proxy, a `--base-url` endpoint, something that shipped last week — the request
1281
+ goes out at 64000, and if the provider objects, `aragon` reads the real ceiling
1282
+ out of the error text, repairs the request, sends it exactly once more, and
1283
+ remembers the answer for the rest of the session. One warning line; the run
1284
+ continues.
1285
+
1286
+ Two combinations that were a guaranteed 400 on every request are fixed with
1287
+ it: `--thinking xhigh` asks for a 65536-token budget while Anthropic requires
1288
+ `max_tokens` to be strictly greater than it, and OpenAI's reasoning family
1289
+ (`o1`, `o3`, `gpt-5`) rejects the `max_tokens` parameter name outright in
1290
+ favour of `max_completion_tokens`.
1291
+
1292
+ New surfaces: `/max-tokens [<n>|auto|default]`, which with no argument reports
1293
+ the setting *and* the effective cap for the live model; an `Effective:` line
1294
+ under the settings screen's `Max tokens` field, so a value the model will not
1295
+ honour is visible before you save it; `--max-tokens auto`; and
1296
+ `aragon config set maxTokens <n|auto|default>`, which echoes the value that was
1297
+ actually stored rather than the one you typed.
1298
+
1299
+ - **Team subagents.** The agent can now hand independent parts of a job to up to
1300
+ five short-lived subagents that run in parallel, then read one combined report
1301
+ of what each of them found. It decides for itself whether to delegate, so a
1302
+ session that never calls the new `task` tool is byte-for-byte the session that
1303
+ existed before. On by default; `--no-team` or `team.enabled: false` turns it
1304
+ off, and `aragon config set team.maxSubagents <n>` sets the width (1-10; the
1305
+ 10 is a hard ceiling no config file can raise).
1306
+
1307
+ A subagent is a full agent with the same tools and working directory but no
1308
+ memory of your conversation, so its brief has to be self-contained. It cannot
1309
+ delegate further and it cannot ask you anything. Plan mode and a skill's
1310
+ `allowed-tools` ceiling both reach one level down, so delegating is never a
1311
+ way around either; `--confirm` queues subagent confirmations one at a time and
1312
+ labels each with the subagent that is asking.
1313
+
1314
+ Subagents can message each other with `team_send` / `team_wait`, delivered by
1315
+ attaching the message to the recipient's next tool result rather than
1316
+ interrupting it. The limits are deliberate — 6 messages each, one every 15
1317
+ seconds, 24 per dispatch — and every refusal is a plain result naming the
1318
+ limit rather than an error, because an error invites the retry the limits
1319
+ exist to prevent.
1320
+
1321
+ While a dispatch runs, a roster sits between the transcript and the composer
1322
+ and the status bar carries `agents 3/5`; both disappear when it finishes and
1323
+ the transcript keeps a card you can expand with `Ctrl+O`. `Esc` aborts every
1324
+ subagent and returns the partial report. Under `-p` the transitions go to
1325
+ stderr and the subagents' tokens are folded into the `[usage]` footer, so the
1326
+ cost readout cannot under-report what the team spent.
1327
+
1328
+ Full documentation, including the limits table and how team mode interacts
1329
+ with plan mode, skills and `--confirm`, is in the README.
1330
+
1331
+ - **The subagent roster now shows what each subagent is doing, and shows the
1332
+ ones that are working.** Where every row used to say `thinking` for minutes at
1333
+ a time, it now says `bash: npm test -w cli`, `read: src/api/routes.ts`,
1334
+ `waiting for a2`, or the tail of the sentence the subagent is currently
1335
+ writing. On a narrow terminal the same row falls back to a file name and a
1336
+ program name rather than wrapping, and the elapsed clock keeps its place at
1337
+ every width.
1338
+
1339
+ The five visible rows are now the five that matter: whatever is running comes
1340
+ first, then whatever is queued, then the most recent results. Above five
1341
+ subagents the old panel showed the five that had finished first and hid
1342
+ everything still working behind `+3 more`, which is the opposite of what the
1343
+ roster is for. `+3 more` now says how many of the hidden ones are still going.
1344
+
1345
+ - **A subagent no longer waits two minutes for a message nobody can send.**
1346
+ `team_wait` now checks whether anyone could actually answer before it blocks:
1347
+ if the teammate it named has already finished, does not exist, or is itself
1348
+ waiting in a way that cannot be released in time, it returns straight away and
1349
+ says which. Nothing is refused that could still have been answered — including
1350
+ by a third teammate further down the chain — and the subagent is told what to
1351
+ do instead rather than handed an error.
1352
+
1353
+ - **A subagent whose very first request dies on a rate limit is retried once.**
1354
+ Only a genuine cold start qualifies: no turn completed and no tool ran, so
1355
+ there is nothing to undo. It restarts after two seconds, the roster says
1356
+ `starting (retry)`, and the report notes `retried 1x`. Pressing `Esc`, a
1357
+ timeout, or any subagent that had already begun work is never retried.
1358
+
1359
+ ### Changed
1360
+
1361
+ - **`"maxTokens": null` in `config.json` now means AUTO** — use each model's own
1362
+ ceiling, never above 64000. It previously resolved to 64000 by accident (the
1363
+ layered resolver skipped `null`), and there was no way to express AUTO through
1364
+ any supported write path. If you have a `null` there today, the only difference
1365
+ is a downward clamp on models whose real ceiling is below 64000 — the direction
1366
+ that prevents failures rather than causing them. Absent still means 64000, and
1367
+ an explicit number still means that number.
1368
+
1369
+ - **`config.json` holds settings again.** The prompts you type are no longer
1370
+ stored in it. They move to `~/.aragon-agent/prompt-history.jsonl` — one JSON
1371
+ object per line, `0600` on POSIX — and the submit counter and the "notice
1372
+ already shown" flag move to `~/.aragon-agent/state.json`. `↑` and `↓` behave
1373
+ exactly as before.
1374
+
1375
+ Two things get better. Opening `config.json` to change your model no longer
1376
+ means scrolling past a transcript of your own typing, and copying it to
1377
+ another machine no longer carries your prompts along. And submitting a message
1378
+ no longer rewrites the file that holds your API keys: `config.json` is written
1379
+ when you change a setting, and at no other time.
1380
+
1381
+ **Your history and counters are migrated automatically, once, at the next
1382
+ launch.** Nothing is printed, because nothing changes for you. The dead
1383
+ `recentModels` key — which nothing has ever written — is dropped.
1384
+
1385
+ If you go back to 0.5.x after upgrading, that version does not know about the
1386
+ new file and `↑` will look empty. Nothing has been lost: the entries are still
1387
+ in `prompt-history.jsonl`, and upgrading again brings them back.
1388
+
1389
+ ### Added
1390
+
1391
+ - **`aragon history`** — `path`, `list` (`-n`, `--json`) and `clear --yes` for
1392
+ the prompt history, alongside the existing `aragon logs` commands. Entries are
1393
+ stored verbatim, so `clear` is how you erase them; `aragon config set
1394
+ historyEnabled false` stops new ones being recorded without deleting or hiding
1395
+ what is already there.
1396
+
1397
+ - **The mouse wheel scrolls what is under the pointer.** In full-screen mode the
1398
+ wheel now scrolls the transcript three rows per notch (a page with `Shift`),
1399
+ scrolls an open overlay when the pointer is over one, and steps prompt history
1400
+ one entry per notch when the pointer is over the input box — the same code
1401
+ path `↑` / `↓` use, so it inherits the rule that an in-progress draft is never
1402
+ overwritten. A slim rail on the viewport's right edge shows where you are in
1403
+ the conversation.
1404
+
1405
+ **This fixes a destructive bug.** Previously the wheel recalled prompt history
1406
+ no matter where the pointer was, because the alternate screen makes terminals
1407
+ translate each notch into arrow keys. Wheeling while composing a message
1408
+ silently replaced the draft with an old prompt, and nothing scrolled.
1409
+
1410
+ **Selecting text with the mouse now requires `Shift`+drag** in most terminals.
1411
+ That is the standard convention for "an application is tracking the mouse" and
1412
+ it applies to everyone, including people who never scroll with the wheel — so
1413
+ the first session says so once, in the transcript, and never again. Turn the
1414
+ whole feature off with `--no-mouse`, `ARAGON_MOUSE=0`, or
1415
+ `aragon config set mouse false`; the wheel then does nothing rather than
1416
+ reverting to the old behaviour. Inline mode (`--no-fullscreen`) is untouched:
1417
+ your terminal's own scrollback already does the right thing there.
1418
+
1419
+ Under `tmux` with `mouse on`, tmux keeps the wheel for itself and the app
1420
+ never sees it. `set -g mouse off` hands it back.
1421
+
1422
+ ### Changed
1423
+
1424
+ - **Your files moved to `~/.aragon-agent/`.** Config, sessions, installed skills
1425
+ and the usage counters now live in one directory in your home — on Windows
1426
+ `C:\Users\<you>\.aragon-agent\`, and the same path on macOS and Linux. They
1427
+ used to be split across `%APPDATA%\aragon-agent-nodejs\Config` and
1428
+ `%LOCALAPPDATA%\aragon-agent-nodejs\Data` (or the XDG equivalents), which are
1429
+ correct locations and terrible answers to "where do I change the model?".
1430
+
1431
+ **The move happens once, automatically, on first launch, and prints a line on
1432
+ stderr when it does.** Nothing is deleted: `config.json` is COPIED rather than
1433
+ moved, and the old directories are left where they are, so reinstalling 0.5.0
1434
+ remains lossless. `aragon config home` prints the new location and names the
1435
+ old ones. Once you are satisfied, you can delete them yourself.
1436
+
1437
+ `ARAGON_HOME` relocates the whole tree. It has to be a real environment
1438
+ variable — the path is resolved before any `.env` is read, so putting it in a
1439
+ `.env` will not work. `aragon config home` always prints what is actually in
1440
+ use.
1441
+
1442
+ ### Added
1443
+
1444
+ - **Logging.** Records go to `~/.aragon-agent/logs/aragon-<date>.log` as JSON
1445
+ Lines: startup and exit, config writes, turn boundaries with token counts,
1446
+ tool names with durations, skill loads, and every uncaught error. Files rotate
1447
+ by day and by size (`log.maxFileBytes`, default 5 MiB) and the oldest beyond
1448
+ `log.maxFiles` (default 10) are deleted.
1449
+
1450
+ **`info`, the default, records no conversation content**, so attaching a log
1451
+ to a bug report is safe. `--log-level debug` (or `--verbose`) adds prompts,
1452
+ replies and tool arguments truncated to `log.previewChars`; `trace` adds them
1453
+ in full. Those two write what you typed — check before sharing one.
1454
+
1455
+ API keys are removed at every level by two independent passes: fields whose
1456
+ name looks like a credential are blanked whatever they hold, and every string
1457
+ is scanned both for known key formats and for the literal keys this process is
1458
+ holding — which is what covers a custom endpoint whose key looks like nothing
1459
+ in particular. `log.redactSecrets false` turns both off and warns you on
1460
+ stdout when you set it.
1461
+
1462
+ Nothing is ever uploaded. There is no network path out of this subsystem.
1463
+
1464
+ New commands: `aragon logs path | list | tail [-n N] [--follow] [--level lv]
1465
+ [--json] | clear --yes | open`, and `/logs` inside the TUI. New flags:
1466
+ `--log-level`, `--verbose`, `--log-file` / `--no-log-file`, `--log-dir`. New
1467
+ environment variables: `ARAGON_LOG_LEVEL`, `ARAGON_LOG_FILE`, `ARAGON_LOG_DIR`
1468
+ — these three, unlike `ARAGON_HOME`, can come from a `.env`.
1469
+
1470
+ - **`aragon config get <key>` / `list [--json]` / `edit` / `home`.** `get` and
1471
+ `list` mask every secret, `--json` included. `edit` opens `config.json` in
1472
+ `$VISUAL` / `$EDITOR` (`notepad` on Windows), takes a `config.json.bak` first,
1473
+ and re-parses on exit — an invalid edit is reported immediately, and the
1474
+ backup is named in the message.
1475
+
1476
+ - **`/reload`** re-reads `config.json` into the running session, for when you
1477
+ have edited it in another window. Refused while a run is in progress: swapping
1478
+ the model mid-turn would let the second half of an answer come from different
1479
+ settings than the first, with nothing afterwards able to explain the result.
1480
+
1481
+ - **Log level in the settings screen**, alongside provider / model / thinking.
1482
+ The rest of the log settings — and `redactSecrets` above all — stay
1483
+ command-line-only, so the one switch that can put credentials on disk cannot
1484
+ be flipped with an arrow key.
1485
+
1486
+ ### Fixed
1487
+
1488
+ - **A malformed `config.json` no longer resets everything in silence.** A stray
1489
+ comma used to send the model, theme, timeouts, skills and (as far as you could
1490
+ tell) your API key back to defaults, with nothing anywhere explaining it. The
1491
+ fallback is unchanged — a bad config still never stops the CLI from starting —
1492
+ but it now says so, and records why.
1493
+
1494
+ - **Ctrl+C now flushes pending log records in every mode.** The signal handlers
1495
+ only existed in the full-screen branch, so `-p`, the inline renderer and every
1496
+ subcommand took Node's default termination, which does not run exit handlers.
1497
+
1498
+ ### Added
1499
+
1500
+ - **Plan mode.** `Shift+Tab` toggles between `BUILD` (everything as before) and
1501
+ `PLAN`, a read-only research-and-design posture. `/plan [on|off|status]` is a
1502
+ first-class equivalent for terminals that swallow `CSI Z`, and `--plan` /
1503
+ `--no-plan` / `ARAGON_PLAN=1` / `planModeDefault` cover the startup case.
1504
+
1505
+ In `PLAN`, `write_file`, `edit_file`, `bash`, `skill_install` and
1506
+ `skill_create` are refused **at the tool boundary**, so read-only is a
1507
+ property of the wiring rather than a promise in a prompt. `bash` is refused in
1508
+ full, `git status` included: a shell string cannot be classified reliably, and
1509
+ a gate that is right most of the time is worse than one that is always right,
1510
+ because you stop trusting the badge. The refusal names `read_file` / `glob` /
1511
+ `grep` as the alternatives.
1512
+
1513
+ Two tools exist only while a human is attached. `ask_user` renders a
1514
+ keyboard-driven wizard - 1-5 questions, 2-4 options each, exactly one marked
1515
+ `RECOMMENDED`, plus an `Other...` free-text option - where pressing `Enter`
1516
+ through the wizard accepts every recommendation. `submit_plan` renders the
1517
+ plan as a scrollable card: `a` approves, `r` sends written feedback (`<-`
1518
+ returns to the card), `Esc` dismisses. **Approving flips the session to
1519
+ `BUILD` immediately and the same run continues into implementation.**
1520
+
1521
+ Dismissing a plan asks for a better one rather than stopping - the agent is
1522
+ told to refine and resubmit - so the way out of a run is `Esc` twice: the
1523
+ first closes the card, the second aborts the run.
1524
+
1525
+ Toggling mid-run is asymmetric on purpose: `build -> plan` applies at once,
1526
+ `plan -> build` is deferred to the end of the run (the status bar shows
1527
+ `PLAN -> BUILD` meanwhile) so a run launched under a read-only guarantee
1528
+ cannot start writing files because of one stray keypress.
1529
+
1530
+ `aragon -p --plan "..."` registers no question or plan tool - there is nobody
1531
+ to ask - but the read-only gate still applies, so it means "tell me how you
1532
+ would do this, and do not touch my repository".
1533
+
1534
+ - Three flat config keys: `planModeDefault` (default `false`),
1535
+ `planModeMaxAskRounds` (default `4`, clamped `[1, 10]`) and
1536
+ `planModeHumanTimeoutMs` (default `1800000`, clamped `[60000, 7200000]`). All
1537
+ three are settable with `aragon config set`. Additive, as always: a config
1538
+ file written by an earlier version loads unchanged.
1539
+
1540
+ ### Fixed
1541
+
1542
+ - A `--confirm` prompt no longer races the idle watchdog. Taking longer than
1543
+ `idleTimeoutMs` over `Proceed? (y/N)` used to abort the run with no
1544
+ explanation; every human wait now suspends the watchdog and restarts it in a
1545
+ `finally`.
1546
+
1547
+ - Honor an explicit `NODE_TLS_REJECT_UNAUTHORIZED=0` setting in the CLI and the
1548
+ official npm release workflow while hiding only Node's standard insecure-TLS
1549
+ warning. Other process warnings remain visible.
1550
+
1551
+ ## 0.5.0
1552
+
1553
+ ### Breaking
1554
+
1555
+ - **The package is renamed `@argon-agent/cli` → `@aragon-agent/cli`.** The brand
1556
+ was always meant to be *Aragon*, matching AragonMesh; the missing `a` was a
1557
+ typo that reached the registry. Install with:
1558
+
1559
+ ```
1560
+ npm uninstall -g @argon-agent/cli
1561
+ npm install -g @aragon-agent/cli
1562
+ ```
1563
+
1564
+ `@argon-agent/cli` is deprecated and receives no further releases. **The
1565
+ executable is still `aragon`** — the command you type does not change.
1566
+
1567
+ - **Environment variables are `ARAGON_*`, not `ARGON_*`.** There is no
1568
+ compatibility fallback: `ARGON_MODEL`, `ARGON_PROVIDER`, `ARGON_BASE_URL`,
1569
+ `ARGON_THINKING`, `ARGON_MAX_TOKENS`, `ARGON_THEME`, `ARGON_FULLSCREEN`,
1570
+ `ARGON_SKILLS`, `ARGON_SKILLS_DISABLED`, `ARGON_SKILLS_PATH` and
1571
+ `ARGON_REDUCED_MOTION` are all ignored from this release on. Rename them in
1572
+ your shell profile and CI. Provider keys (`ANTHROPIC_API_KEY`,
1573
+ `OPENAI_API_KEY`, `GOOGLE_API_KEY`, `GEMINI_API_KEY`) are untouched.
1574
+
1575
+ - **The project-level skills directory is `.aragon/skills`, not
1576
+ `.argon/skills`.** This one lives in your repository, so rename it yourself:
1577
+
1578
+ ```
1579
+ git mv .argon .aragon
1580
+ ```
1581
+
1582
+ A config file that already persisted the old default keeps working — an
1583
+ explicitly saved `skills.projectDirs` still wins over the default — but the
1584
+ shipped default is now `['.aragon/skills', '.claude/skills']`. Update it with
1585
+ `aragon config set` if you want the new default.
1586
+
1587
+ ### Added
1588
+
1589
+ - **Automatic migration of your user-level state.** On first run, 0.5.0 moves
1590
+ the `env-paths` config and data directories from `argon-agent` to
1591
+ `aragon-agent` — your API key, sessions and installed skills come with it, and
1592
+ each installed skill's `.argon-skill.json` manifest is renamed to
1593
+ `.aragon-skill.json` so `skills update` and `skills uninstall` still recognise
1594
+ it. The migration prints one line to **stderr**, runs once, and is skipped
1595
+ entirely if the new directory already exists. If it fails for any reason the
1596
+ CLI still starts; the old directory is never deleted when a cross-volume copy
1597
+ was needed.
1598
+
1599
+ - The opening wordmark now reads `ARAGON` and is 52 columns wide (was 44).
1600
+ Terminals between 52 and 55 columns show the single-line banner rather than a
1601
+ clipped wordmark.
1602
+
1603
+ - **Skills.** A skill is a directory holding a `SKILL.md` (YAML frontmatter +
1604
+ Markdown body) plus optional `reference/`, `scripts/` and `assets/`. Skills
1605
+ reach the model through three levels of progressive disclosure: a name +
1606
+ one-line "when to use" catalog in the system prompt (≤ 6 000 bytes total),
1607
+ the full body only when the model calls the `skill` tool, and bundled files
1608
+ only when it reads them with `read_file` / `bash`. A skill therefore costs a
1609
+ line of context rather than its whole body. How many fit in Level 1 depends on
1610
+ description length and language — roughly 30 with terse English descriptions,
1611
+ roughly 10 with Chinese ones at the character cap; past that the catalog
1612
+ truncates and `skill_find` covers the remainder.
1613
+ - Four model-facing tools: `skill` (load), `skill_find` (search installed
1614
+ skills), `skill_install` (install from a local directory, git repo, or https
1615
+ `SKILL.md` / `.zip`) and `skill_create` (author a new one from a procedure the
1616
+ agent just worked out).
1617
+ - **`aragon skills update <name> | --all`**, with `--dry-run`, `--force` and
1618
+ `--check`. Re-fetches from the source recorded in the install manifest,
1619
+ preserving `installedAt` and recording `updatedAt` / `previousVersion`. Refuses
1620
+ before downloading anything when the installed copy has local edits, and
1621
+ re-validates the source against the *current* `skills.allowedHosts` rather than
1622
+ the one in force at install time. Not exposed to the model.
1623
+ - **Catalog ranking.** Level 1 entries are ordered by scope, then by how recently
1624
+ and often each skill was used, so truncation drops what you do not use rather
1625
+ than what sorts last alphabetically. With no usage data the order is unchanged.
1626
+ - **`skill_find`**, advertised in the prompt only when the catalog actually
1627
+ truncated. Searches installed skills by name, description and keyword; never
1628
+ reaches the network, never returns `activation: manual` skills, and tells the
1629
+ model to ask for a source rather than invent one when nothing matches.
1630
+ - **Cross-process install lock.** Install / create / remove / update take a
1631
+ per-directory advisory lock, closing a race in which two concurrent installs
1632
+ could interleave their atomic-replace steps and delete a skill with no error.
1633
+ Self-expires after 60 s; waits at most 5 s; only ever released by its owner.
1634
+ - **Load-time integrity.** Discovery re-checks `SKILL.md` against the sha256
1635
+ recorded at install, at no extra I/O. `skills.integrity` selects
1636
+ `off` / `warn` (default) / `strict`.
1637
+ - **Local usage counters** at `<data>/skill-usage.json` — skill name, count and
1638
+ timestamp only, never transmitted, disabled with `skills.usageTracking=false`.
1639
+ Automatically injected `activation: always` skills are not counted.
1640
+ - Config keys `skills.integrity` and `skills.usageTracking`; `aragon skills list
1641
+ --sort=recent` and `/skills list --sort=recent`.
1642
+ - Every usable skill also becomes a slash command: `/<skill-name> [args]`, with
1643
+ `$ARGUMENTS` / `$1..$9` substitution. On a name clash the built-in command
1644
+ always wins and the skill is reachable as `/skill:<name>`.
1645
+ - `/skills` management: `list`, `info`, `install`, `remove`, `enable`,
1646
+ `disable`, `reload`, `create`, `trust`, `untrust`.
1647
+ - `aragon skills …` non-interactive equivalents plus `path` and `doctor`.
1648
+ Exit codes follow `config set`: `0` ok, `1` run-time failure, `2` usage.
1649
+ - Four discovery scopes in ascending precedence: bundled (`<pkg>/skills`), user
1650
+ (`<data>/skills`), project (`<cwd>/.aragon/skills` and, read-only,
1651
+ `<cwd>/.claude/skills` for Claude Code interop), and `ARAGON_SKILLS_PATH`.
1652
+ - New flags `--no-skills`, `--skill <name>` (repeatable) and `--skills-yes`;
1653
+ env `ARAGON_SKILLS`, `ARAGON_SKILLS_PATH`, `ARAGON_SKILLS_DISABLED`; config keys
1654
+ `skills.enabled`, `skills.requireApproval`, `skills.catalogMaxBytes`,
1655
+ `skills.bodyMaxBytes`.
1656
+ - One bundled skill, `skill-creator`, documenting how to write a good one.
1657
+ - New runtime dependency: `fflate` (~30 KB, MIT, zero transitive deps) for zip
1658
+ extraction. `@aragon-agent/core` gains no dependency.
1659
+ - **Release tooling for the scope change.** `npm run verify:brand` scans every
1660
+ file that `npm pack` would put in the tarball — README and `dist/` included —
1661
+ and blocks the release on any surviving `argon` reference, with only the four
1662
+ documented exceptions (the two CHANGELOGs and the legacy-state migration
1663
+ module, which hold the old names by definition). `packages/cli` also gains a
1664
+ `prepublishOnly: npm run build`, so a publish that bypasses
1665
+ `publish-latest.ps1` can no longer ship a `dist/` that is out of step with the
1666
+ sources. `deprecate-legacy.ps1` retires `@argon-agent/*` on the registry, and
1667
+ refuses to do so until the replacements are actually published.
1668
+
1669
+ ### Changed
1670
+
1671
+ - The globally installed executable is now `aragon`. The previous `argon` and
1672
+ `argon-agent` aliases are no longer installed.
1673
+ - `config/store.ts` now deep-merges the `skills` section on both read and write,
1674
+ the same treatment `apiKeys` already received. Without it a partial patch such
1675
+ as the one `/skills disable` sends would replace the whole section and
1676
+ silently discard `trustedProjectDirs`, `allowedHosts` and `requireApproval`.
1677
+ - `slashSuggestions` accepts `-` and `:`, so kebab-case and `skill:`-namespaced
1678
+ commands autocomplete. Previously `/my-sk` produced no popup at all.
1679
+ - `AgentController` now has a single `agent.setSystemPrompt()` call site, so a
1680
+ `/cwd` change can no longer drop the skill catalog out of the prompt.
1681
+ - With skills off or none installed, the system prompt and the 7-tool array are
1682
+ byte-identical to the previous release.
1683
+ - Added a repository-level PowerShell release workflow that automatically
1684
+ updates CLI and Core versions, synchronizes their dependency and lockfile,
1685
+ verifies both tarballs, and publishes them in dependency order.
1686
+
1687
+ ### Security
1688
+
1689
+ - Installing a skill requires an explicit human approval that **probes for a
1690
+ human first and refuses when there is none**. Under `-p` there is no TUI and
1691
+ therefore no approver, so `skill_install` is refused with an actionable
1692
+ message rather than writing a third-party directory unattended. Use
1693
+ `--skills-yes` (or `skills.requireApproval=false`) to opt out deliberately.
1694
+ - Project skill directories require a one-time trust confirmation before they
1695
+ are loaded — cloning an unfamiliar repository does not grant it the ability
1696
+ to inject instructions into your session.
1697
+ - Git is invoked only via `execFile` with an argv array and `shell: false`, and
1698
+ owner / repo / ref / subdirectory fragments are whitelisted and refused if
1699
+ they begin with `-`. A leading dash matters even with a pure argv array:
1700
+ `--upload-pack=<program>` makes git execute that program.
1701
+ - Zip extraction is streamed and gated on **actually written** bytes, per-entry
1702
+ size, compression ratio and entry count, all of which can abort mid-archive.
1703
+ The size a zip *declares* is written by whoever built it and is never trusted.
1704
+ Path traversal, absolute entries, symlinks and Windows device names are
1705
+ refused, and a rejected archive is removed rather than left half-extracted.
1706
+ - Network fetches are `https:` only, restricted to `skills.allowedHosts`,
1707
+ re-checked on every redirect (max 3), size-capped, and refuse IP literals and
1708
+ loopback.
1709
+ - Nothing a skill ships is executed at install time, and the executable bit is
1710
+ not preserved. Scripts run only when the model invokes `bash` explicitly.
1711
+ There is no sandbox: approval blocks *silent* installation, it does not make
1712
+ a skill you approved safe.
1713
+
1714
+ ## 0.3.0
1715
+
1716
+ A full-screen TUI release. `@argon-agent/core` is untouched, no new runtime
1717
+ dependency is added, and the headless/print contract, exit codes, and
1718
+ slash-command semantics are unchanged. The 0.2.0 inline renderer remains
1719
+ available in full via `--no-fullscreen`.
1720
+
1721
+ ### Added
1722
+
1723
+ - **Full-screen mode (default).** `aragon` now takes over the terminal's
1724
+ alternate screen buffer — the same mechanism `vim` / `htop` / `lazygit` use.
1725
+ Your shell history is covered, not erased, and comes back untouched on exit.
1726
+ The frame is a fixed `rows - 1` tall, so **the composer and the status bar sit
1727
+ at the physical bottom of the screen from the very first frame**: empty
1728
+ session, long session, mid-scroll, or overlay open.
1729
+ - **Brand region.** A six-row gradient ASCII wordmark on a roomy empty session,
1730
+ degrading to a banner, then a single-line bar, then a bare wordmark as space
1731
+ runs out. Row 1 always begins with the brand glyph.
1732
+ - **Self-drawn scrolling.** `PgUp` / `PgDn` by the page, `Shift+↑` / `Shift+↓` by
1733
+ the line. The viewport auto-follows new output while pinned to the bottom;
1734
+ scrolling away shows `↑N` in the status bar plus a "N new lines" hint, and
1735
+ submitting a message always re-pins.
1736
+ - **Exit replay.** After leaving the alternate screen the session is replayed
1737
+ into the normal buffer as plain, colorless text, so the conversation does not
1738
+ evaporate with the screen. Turn it off with `--no-exit-transcript`.
1739
+ - **New flags** `--fullscreen` / `--no-fullscreen` / `--no-exit-transcript`, the
1740
+ env var `ARGON_FULLSCREEN=0|1`, and the config keys `fullscreen`,
1741
+ `exitTranscript`, and `transcriptWindow`.
1742
+ - **Automatic downgrade.** A non-TTY stdout, `TERM=dumb`, CI, and terminals under
1743
+ 12 rows / 40 columns fall back to the inline renderer. Only the non-TTY gate is
1744
+ un-overridable — `--fullscreen` beats the rest.
1745
+
1746
+ ### Changed
1747
+
1748
+ - The status bar lost its round border and is now exactly one row; it had been
1749
+ spending an eighth of a 24-row terminal framing a single line of text.
1750
+ - The toast strip holds a fixed row in full-screen mode, so the transcript no
1751
+ longer jumps as toasts appear and expire.
1752
+ - The composer is a rounded frame whose border color reports state (idle, has a
1753
+ draft, running, blurred by an overlay), with the completion popup above it.
1754
+ - `Ctrl+L` repaints the frame instead of writing a clear sequence. Ink dedupes
1755
+ identical output at two separate gates, so under a fixed frame the old
1756
+ approach erased the screen and then declined to redraw it.
1757
+ - `Shift+↑` / `Shift+↓` no longer recall prompt history — they scroll.
1758
+ - Full-screen mode routes `console.*` into the transcript as notices rather than
1759
+ letting Ink write them straight to stdout, which corrupts the frame's line
1760
+ accounting.
1761
+
1762
+ ### Known trade-offs
1763
+
1764
+ - The terminal's native scrollback and mouse wheel do not scroll the transcript
1765
+ in full-screen mode; use `PgUp` / `PgDn`, or run with `--no-fullscreen`.
1766
+ - Mouse tracking is deliberately left off: enabling it costs text selection and
1767
+ copy in most terminals.
1768
+ - Should a crash ever strand your terminal on the alternate screen, `reset`
1769
+ restores it. Four independent restore paths exist to prevent that: normal
1770
+ exit, `process.exit`, `SIGINT` / `SIGTERM` / `SIGHUP`, and Ink's own signal
1771
+ handling.
1772
+
1773
+ ## 0.2.0
1774
+
1775
+ A design-elevation & HCI-hardening release. No breaking changes: `@argon-agent/core`
1776
+ is untouched, no new runtime dependency is added, and the headless/print contract,
1777
+ exit codes, config keys, and slash-command semantics from 0.1.0 are unchanged.
1778
+
1779
+ ### Added
1780
+
1781
+ - **Real theming engine.** Distinct `dark` / `light` palettes with an `auto`
1782
+ resolution (`auto → dark`), color degradation across terminal depth
1783
+ (truecolor → 256 → 16 → monochrome), and an ASCII glyph fallback for terminals
1784
+ without Unicode. Honors `NO_COLOR`, `FORCE_COLOR`, `--no-color`, and
1785
+ `TERM=dumb`. Switch live with `/theme <auto|dark|light>` (persisted).
1786
+ - **Elegant chrome.** A gradient wordmark header that collapses to a slim sticky
1787
+ bar after the first turn, a first-run **Welcome / empty-state** card, and a
1788
+ status bar with a colored **context gauge** (threshold colors), a **tokens/sec**
1789
+ read-out while running, and a contextual hint.
1790
+ - **Legible tool output.** Colored unified diffs (green adds / red removes) and
1791
+ per-tool rich previews (`edit_file`/`write_file`/`read_file`/`bash`/`list_dir`/
1792
+ `glob`). Long previews collapse to 8 lines and expand with `Ctrl+O` or
1793
+ `/expand [n]`.
1794
+ - **Autocomplete.** A slash-command palette and `@file` path completion popup
1795
+ (`Tab`/`→` to complete, `Up`/`Down` to move, `Esc` to close).
1796
+ - **Full line editing.** Home/End, word jump/delete, kill-to-start/end, and
1797
+ multi-line vertical cursor navigation, with prompt-history recall at the edges.
1798
+ Unknown control/escape sequences are dropped instead of inserted.
1799
+ - **Reliability under load.** Ink `<Static>` finalization for settled entries and
1800
+ a streaming delta coalescer, so long/fast sessions stay flicker-free.
1801
+ - **Calm feedback.** Ephemeral, auto-dismissing **toasts** for transient acks;
1802
+ the transcript keeps only durable content (messages, tool cards, run errors).
1803
+ - `reducedMotion` config (also `ARGON_REDUCED_MOTION`; implied by `--no-color`)
1804
+ replaces spinners with a static glyph.
1805
+
1806
+ ### Changed
1807
+
1808
+ - History scrollback now uses the **native terminal scrollback** that `<Static>`
1809
+ prints into (this supersedes the never-implemented `PgUp`/`PgDn` promise).
1810
+
1811
+ ## 0.1.0
1812
+
1813
+ Initial release — a Claude-Code / Codex-style interactive terminal UI (TUI) on
1814
+ top of `@argon-agent/core`.
1815
+
1816
+ ### Added
1817
+
1818
+ - **Interactive TUI** (React + Ink): gradient header, streaming transcript with
1819
+ markdown + syntax highlighting, collapsible thinking blocks, live tool-call
1820
+ cards, a status bar (model / context % / tokens / cost / elapsed), and modal
1821
+ overlays (settings, model picker, help, confirm).
1822
+ - **Built-in toolset** wired into the core agent at full permission:
1823
+ `read_file`, `write_file`, `edit_file`, `list_dir`, `glob`, `grep`, `bash`.
1824
+ - **Layered configuration** (defaults → user file → env/`.env` → flags) with
1825
+ live in-TUI editing of provider / model / base URL / API keys / thinking level
1826
+ / max tokens. Secrets are masked and the config file is written `0600` on POSIX.
1827
+ - **One-shot / print mode** (`argon -p`) for scripting and piping, plus
1828
+ `argon config` / `argon config set` / `argon config path` / `argon models`.
1829
+ - **Session control**: abort (Esc), steer-while-running, follow-up queue,
1830
+ double-Ctrl-C exit, `/save` / `/resume` JSON sessions.
1831
+ - **Timeout invariant** (`idleTimeout ≥ toolTimeout`) so a long single tool run
1832
+ is never killed by the idle watchdog.
1833
+ - **Never-silent failures**: pre-flight API-key validation, error-StreamEvent
1834
+ rendering, and a guard that surfaces a swallowed agent error instead of a
1835
+ blank no-op (headless exits `1`/`2` accordingly).