@aragon-agent/cli 0.5.9 → 0.5.10

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 (52) hide show
  1. package/CHANGELOG.md +1157 -1026
  2. package/README.md +123 -0
  3. package/dist/boot/guard.d.ts +135 -0
  4. package/dist/boot/guard.js +218 -0
  5. package/dist/boot/rollback.d.ts +86 -0
  6. package/dist/boot/rollback.js +185 -0
  7. package/dist/cli.js +283 -2
  8. package/dist/commands/builtins.js +118 -0
  9. package/dist/commands/registry.d.ts +17 -0
  10. package/dist/config/app-paths.d.ts +31 -0
  11. package/dist/config/app-paths.js +37 -0
  12. package/dist/config/cli-commands.d.ts +27 -1
  13. package/dist/config/cli-commands.js +51 -2
  14. package/dist/config/env.d.ts +10 -1
  15. package/dist/config/env.js +41 -1
  16. package/dist/config/load.d.ts +17 -0
  17. package/dist/config/load.js +25 -1
  18. package/dist/config/schema.d.ts +56 -0
  19. package/dist/config/schema.js +81 -0
  20. package/dist/config/store.js +13 -1
  21. package/dist/launcher.d.ts +14 -0
  22. package/dist/launcher.js +43 -0
  23. package/dist/logging/logger.d.ts +1 -1
  24. package/dist/ui/App.d.ts +11 -1
  25. package/dist/ui/App.js +88 -2
  26. package/dist/ui/BottomStatusRow.d.ts +25 -3
  27. package/dist/ui/BottomStatusRow.js +10 -7
  28. package/dist/ui/UpdateLine.d.ts +44 -0
  29. package/dist/ui/UpdateLine.js +129 -0
  30. package/dist/update/classify-failure.d.ts +32 -0
  31. package/dist/update/classify-failure.js +60 -0
  32. package/dist/update/install-lock.d.ts +55 -0
  33. package/dist/update/install-lock.js +184 -0
  34. package/dist/update/install-source.d.ts +97 -0
  35. package/dist/update/install-source.js +218 -0
  36. package/dist/update/installer.d.ts +108 -0
  37. package/dist/update/installer.js +242 -0
  38. package/dist/update/limits.d.ts +111 -0
  39. package/dist/update/limits.js +111 -0
  40. package/dist/update/npm-view.d.ts +62 -0
  41. package/dist/update/npm-view.js +133 -0
  42. package/dist/update/registry.d.ts +52 -0
  43. package/dist/update/registry.js +161 -0
  44. package/dist/update/semver.d.ts +89 -0
  45. package/dist/update/semver.js +295 -0
  46. package/dist/update/service.d.ts +193 -0
  47. package/dist/update/service.js +636 -0
  48. package/dist/update/state.d.ts +103 -0
  49. package/dist/update/state.js +142 -0
  50. package/dist/update/types.d.ts +169 -0
  51. package/dist/update/types.js +68 -0
  52. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -1,1026 +1,1157 @@
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 running command shows what it is doing.** `bash` is the only tool here that
13
- can run for minutes — `npm test`, a `git clone`, a training job — and while it
14
- ran, its card was one line of text that never changed. Nothing in that frame
15
- distinguished a test suite at 40% from a child process blocked forever on a
16
- password prompt this CLI will never show. Its card now carries the last eight
17
- lines of what the command is printing, plus one footer row that reads
18
- `(running)` or, once the child has been quiet for ten seconds,
19
- `no output for 45s` — with the seconds advancing.
20
-
21
- A `\r`-driven progress bar (npm, pip, curl, docker) is *one* line rewritten a
22
- thousand times, and it renders as **one row counting up in place** rather than
23
- a thousand rows of nearly the same string — including the ordinary case where
24
- the bar emits no newline at all for its entire run.
25
-
26
- Everything the tail shows is **stripped, not interpreted**: ANSI colour, cursor
27
- motion, `\r`, `\b`, tabs and every other control byte are removed at the
28
- boundary before a row is stored, so nothing can move a cursor inside a frame
29
- the renderer believes it owns. It is bounded twice by construction — eight rows
30
- per call, sixteen concurrent calls — so a command that writes 400 MB to stdout
31
- costs a fixed number of retained rows.
32
-
33
- It is a **display and nothing else**. The text the model receives is
34
- byte-for-byte what it was; `Ctrl+O` does nothing while a command runs, because
35
- expansion is a promise about stored content and there is no stored rest of a
36
- 400 MB stream; `/save` during a run writes no tail, since a resumed one would
37
- describe a process that died with the session; and at settle the card is
38
- replaced by the authoritative result exactly as before.
39
-
40
- New config key `liveToolOutput`, defaulting to **`true`** — unlike
41
- `showThinking` below, this adds information rather than hiding it.
42
- `aragon config set liveToolOutput false` (or `--no-live-tool-output`, or
43
- `ARAGON_LIVE_TOOL_OUTPUT=0`, or the **Live output** row in `/settings`) turns it
44
- off, and with it off no store is allocated and no recorder is attached: `bash`
45
- is byte-identical to the build before this entry.
46
-
47
- - **The working line stops guessing while a tool runs.** It reads
48
- `⠙ Running bash` instead of rotating thinking-words. `running` covers the whole
49
- turn, including the minutes the model is idle and a child process is doing the
50
- work, so "Pondering" during a build was not calm — it was wrong. One row, no
51
- digits, no clock: everything the row already promised still holds.
52
-
53
- ### Changed
54
-
55
- - **Reasoning blocks are now hidden by default.** `showThinking` is a new
56
- top-level config key and it defaults to `false`. If you have been reading
57
- thinking every day, this is the entry that concerns you: `Ctrl+T` still shows
58
- it for the session exactly as before, `aragon config set showThinking true`
59
- (or `--show-thinking`, or `ARAGON_SHOW_THINKING=1`) restores the old behaviour
60
- permanently, and `/settings` has a **Show thinking** row directly under
61
- **Thinking**.
62
-
63
- Nothing is hidden silently. A settled turn that thought leaves one muted row
64
- where the block used to be — `✱ thought for 12s · ctrl+t to show` — so the fact
65
- that reasoning happened, how long it took, and how to see it are all still on
66
- screen. In **inline** mode that row omits the key hint and the toast reads
67
- `Thinking shown for new output.`, because a settled entry there has already
68
- been printed into your terminal's scrollback and cannot be repainted; the
69
- toggle applies to the live entry and to everything drawn after it.
70
-
71
- `thinkingLevel` is untouched and means what it always did — the effort the
72
- provider is asked to spend. `showThinking` is only whether the terminal draws
73
- what came back. They are one word apart in the config file, which is why the
74
- flag is `--show-thinking` rather than the shorter name.
75
-
76
- ### Added
77
-
78
- - **A live working line while a run is in flight.** One row above the composer,
79
- carrying a spinner and a word that rotates every four seconds:
80
- `⠋ Percolating…`. Take reasoning off the screen and the gap between submitting
81
- and the first token is otherwise completely blank, which reads as dead rather
82
- than as busy — the two changes are one change.
83
-
84
- It carries no clock and no token count, deliberately: the status bar one row
85
- below already renders both, under the same running condition and driven by the
86
- same 200 ms ticker this row reuses. Under `reducedMotion` the spinner is a
87
- static glyph and the word is chosen once and holds, because rotating text is
88
- motion too. An idle frame is unchanged, and so is the viewport's row budget —
89
- the line shares the row the toast strip already owned rather than adding one.
90
-
91
- - **`write_file` and `edit_file` render a real diff.** Hunks with old/new line
92
- numbers, a `+N -M` summary, add/remove/context colouring, and `(truncated)` or
93
- a `binary` / `too-large` / `unreadable` note when the old side could not be
94
- read. Diffs collapse at 12 rows behind the existing `Ctrl+O` — no new
95
- keybinding. A resumed session written by an older build, or a card whose patch
96
- the bounded store already evicted, falls back to the previous text preview;
97
- nothing renders blank.
98
-
99
- `write_file` previously reported creating a 300-line file as
100
- `Wrote 8214 bytes to path`, and `edit_file`'s diff trimmed the common prefix
101
- and suffix and rendered *everything* in between as one removed block followed
102
- by one added block — for a `replace_all` touching line 40 and line 900, that
103
- was 860 removed rows followed by 860 nearly identical added ones.
104
-
105
- **The model's input got smaller, not larger.** The structured patch reaches the
106
- screen on a CLI-local channel rather than through the tool result, and the text
107
- the model reads gained a 4 000-character ceiling it did not have before (its
108
- only previous bound was the executor's 100 KB backstop). A single-region edit
109
- is byte-for-byte what it was plus one `@@` header; a multi-region edit is
110
- strictly smaller. `write_file`'s result text is unchanged.
111
-
112
- ### Changed
113
-
114
- - **A stream that stops mid-answer is now a loud failure instead of a silent
115
- truncated one.** All three provider adapters used to end their SSE loop by
116
- yielding "done" with whatever had arrived, so a connection closed cleanly
117
- half-way through an answer — a proxy idle cut, a load-balancer timeout, an
118
- HTTP/2 GOAWAY — was indistinguishable from a completed reply. You got a
119
- truncated answer and were told nothing.
120
-
121
- Each adapter now reports the truncation, which is what lets it be retried and
122
- recovered. An **abort** is explicitly excluded and still completes normally, and
123
- a model that legitimately says nothing and stops is still a success.
124
-
125
- This is deliberately **not** behind `--no-retry`: an adapter that reports a
126
- truncated stream honestly should do so whether or not retry is enabled. A switch
127
- that also disabled telling you the truth would be a mute button, not a kill
128
- switch.
129
-
130
- - **The mouse wheel now only ever scrolls.** A notch scrolls the transcript
131
- three rows (a page with `Shift`), or the open overlay when there is one, no
132
- matter where the pointer is sitting. Prompt history is recalled by `↑` / `↓`
133
- alone, exactly as in Claude Code and Codex.
134
-
135
- **This supersedes the 0.5.0 entry below**, which said the wheel "scrolls what
136
- is under the pointer" and stepped prompt history one entry per notch when the
137
- pointer was over the input box. That turned out to be wrong in use rather than
138
- in principle: the pointer is not an instrument you aim in a TUI — it rests
139
- wherever you last left it, which in a chat-shaped app is next to the thing you
140
- type into. So the ordinary "scroll back and see what just happened" gesture
141
- landed on the composer and replaced the draft with an old prompt, with no
142
- error, no undo and nothing visibly connecting the gesture to the outcome. The
143
- band that decided this was invisible too: its boundary was a measured row that
144
- moved as the toast row, the hint row and the completion popup came and went, so
145
- the same gesture could do two different things a second apart.
146
-
147
- Nothing else about the wheel changes — same three rows per notch, same
148
- `Shift`+wheel page, same `--no-mouse` / `ARAGON_MOUSE=0` / `mouse: false`
149
- escape hatches, same `Shift`+drag for selecting text.
150
-
151
- - **A long session stays as fast as a short one.** The TUI used to get slower as
152
- a session grew and, past a threshold, stopped making progress at all. That was
153
- structural rather than incidental: Ink has no output caching, so every frame
154
- re-walked the entire mounted tree, re-measured every text node and
155
- re-serialised the frame. The per-frame cost was therefore proportional to every
156
- character the session had ever produced — and `transcriptWindow` bounded the
157
- entry *count*, which bounds nothing when one entry can be fifty thousand lines.
158
-
159
- Entries outside the visible band are no longer mounted. The viewport renders
160
- what you can see plus a couple either side and replaces the rest with two
161
- spacers of the right height, so the frame costs what the screen costs.
162
- Scrolling, the `↑N` readout and the wheel routing are untouched. Because the
163
- horizon is no longer a rendering budget, `transcriptWindow` rises from 300 to
164
- 1000 and its ceiling from 2000 to 20000; an existing setting is still valid
165
- and still clamps.
166
-
167
- Syntax highlighting and markdown parsing are memoised on their input, so a
168
- 200-line code block is tokenised once rather than thirty times a second for as
169
- long as it stays on screen. Only the *parsed* form is cached and never a themed
170
- one, so `/theme` still takes effect on the next frame.
171
-
172
- Under genuine load the streaming interval widens — 33 ms up to a 320 ms
173
- ceiling — so keystrokes and `Ctrl+C` do not queue behind renders. This is
174
- visible rather than silent: a muted **`eco`** chip appears in the status bar
175
- while it is in effect, because a user who cannot see why the stream got
176
- chunkier will conclude the model got slower. `--no-render-governor`,
177
- `renderGovernor: false` or `ARAGON_RENDER_GOVERNOR=0` turns it off;
178
- `--max-render-interval 33` flattens the ladder without disabling the mechanism.
179
-
180
- - **A live thinking block no longer grows without limit.** While an answer is
181
- streaming, visible thinking is clamped to its newest 24 rows behind a
182
- `... N earlier lines` marker, and the whole block renders again the moment the
183
- answer settles. Thinking is scratch reasoning you read from its newest end, and
184
- an unbounded one was the easiest way for a single live entry to fill the
185
- viewport on its own.
186
-
187
- ### Fixed
188
-
189
- - **Inline mode could hard-freeze the terminal, and now cannot.** Once a live
190
- entry grew taller than the terminal, Ink took a branch that writes
191
- `clearTerminal` plus the *entire accumulated session history* on every
192
- subsequent frame — bypassing both of its own dedupe gates, and growing without
193
- bound for the rest of the session. Any inline user (`--no-fullscreen`,
194
- `TERM=dumb`, CI, a terminal under 12 rows or 40 columns) whose model wrote a
195
- long answer could reach it. The live region is now clamped below that
196
- threshold, with a `... N earlier lines` marker naming what is deferred. Nothing
197
- is lost: the entry prints in full into the terminal's own scrollback the moment
198
- it settles.
199
-
200
- - **The view state no longer grows without a ceiling.** A single assistant answer
201
- is capped at 256 KiB in the view (thinking at 64 KiB, streamed tool arguments
202
- at 16 KiB) by eliding the MIDDLE, so both the opening and the live cursor
203
- survive; a marker states how many characters went. `transcriptRetain`
204
- (default 1000) caps the entries kept in memory, and what it removed is counted
205
- and reported both by `/perf` and at the top of the exit replay. A model that
206
- emits five megabytes no longer makes every later frame a five-megabyte scan.
207
-
208
- ### Added
209
-
210
- - **A fast model tier: a second, cheaper model you can delegate to and be
211
- reviewed by.** Off by default — with `fast.enabled: false` the system prompt,
212
- the `task` schema, the transcript and the request payloads are byte-identical
213
- to a build without it — and it does two things once you turn it on.
214
-
215
- **Delegation.** `task` gains one optional field per subagent, `model: "fast"`.
216
- A child marked that way runs on the fast model and is otherwise identical:
217
- same tools, same working directory, same `--confirm` gate, same plan-mode
218
- gate, same skills ceiling. Delegating to a cheaper model is a *model* choice,
219
- never a permission boundary. It is where "not complicated, but very expensive
220
- in context" gets paid for — a child that reads nine files and reports four
221
- sentences moves the file bodies out of the lead's window and onto a model that
222
- costs a fraction as much per token.
223
-
224
- **Periodic review.** Every few turns a small digest of what the lead has been
225
- doing goes to the fast model with one question — is this still on track? — and
226
- a critique that is not "on track" is injected into the running loop as a
227
- `<fast_review>` block, so the lead sees a second opinion while it can still
228
- act on it:
229
-
230
- ```
231
- fast review #2 · claude-haiku-4-5 · turn 12 · 1.4s
232
- You have edited config/schema.ts three times without running the tests.
233
- ```
234
-
235
- The digest is built from a bounded ring of recent turns and **never** from the
236
- message history: sending a session's accumulated file bodies to the "cheap"
237
- model would make a review cost more than the turn it reviews, which is the
238
- inversion the whole feature exists to prevent.
239
-
240
- Spend is attributed **per tier** — a fast child's tokens are priced at the
241
- fast model's table, not the lead's, and the dispatch report states the two
242
- separately. A model the built-in price table has never seen is reported as
243
- `unknown` rather than as `$0.00`, because a feature that looks free while it
244
- is spending money is worse than one that admits it does not know.
245
-
246
- Turn it on with `/fast model <id>` then `/fast on`, with
247
- `aragon config set fast.enabled true`, with `--fast --fast-model <id>`, or with
248
- `ARAGON_FAST=1 ARAGON_FAST_MODEL=<id>`. `/fast status` is the guaranteed
249
- readout: the resolved model, the budget, and this session's reviews, delegated
250
- children, tokens and cost. Eleven `fast.*` config keys, four flags, four
251
- environment variables and five settings-screen rows; see the README.
252
-
253
- **The review has a session budget.** A session is not one run — it is one run
254
- per message you send — so a cadence bounds the pace and nothing bounds the
255
- total. `fast.reviewMaxPerSession` (default **40**, raisable live with
256
- `/fast budget <n>`) is the number of reviews a session may *start*; reaching it
257
- prints one `info` notice that names the remedy and says delegation is
258
- unaffected, and `/fast status` reads `12/40` from the first review rather than a
259
- bare count you can only size after the fact. It is denominated in **reviews,
260
- not currency**, because the fast tier is exactly where a model the price table
261
- has never seen lives — a dollar ceiling would silently never fire for the
262
- configuration that most needs one. Delegation is never budgeted: it is spend the
263
- lead chose in service of a message you sent, it is already bounded by `team.*`,
264
- and it exists to *reduce* total cost.
265
-
266
- **The review also fails fast, so it cannot compete with you.** It calls through
267
- its own provider registry with **one** retry rather than the ten
268
- `retry.maxRetries` defaults to for the lead, and it observes neither `retry.*`
269
- nor `/retry` — that policy says how hard to fight for *your* answer, and
270
- inheriting it for an unrequested background call is how an advisory ends up
271
- spending a rate-limited provider's quota on itself. Its own wall-clock bound
272
- is 20 s.
273
-
274
- Two failure modes are handled out loud rather than silently. If the tier stops
275
- resolving mid-session — you switch the main provider and `fast.provider` was
276
- inheriting it — `model:"fast"` is downgraded to the main model, **counted, and
277
- stated in the report**, because an agent that silently gets an expensive child
278
- has no way to learn its cost model is wrong. And three consecutive
279
- *misconfiguration* failures disable the reviewer for the session with exactly
280
- one warning, while a merely busy provider (rate-limited or overloaded) is
281
- treated as transient and never counts — that condition fixes itself, and a
282
- session-long silent shutdown over it would not. A review you *cancelled* is
283
- neither: Esc, a run that ends first, or quitting leaves a `cancelled` card and
284
- no strike against the tier.
285
-
286
- Reviews log under their own `fast` scope rather than under `agent`, so
287
- `fast_review_*` records filter cleanly away from the lead's.
288
-
289
- - **API calls are retried with backoff, and the waiting is legible.** A transient
290
- provider failure — HTTP 429, 529, 5xx, 408, or a dropped connection — used to end
291
- the turn. One red notice, an idle prompt, and forty tool calls of work thrown
292
- away. It is now retried up to **10 times** with an increasing interval
293
- (1 s → 2 → 4 → 8 → 16 → 30 s, equal-jittered, 30 s per wait at most) under a
294
- 4-minute budget measured from the first failure.
295
-
296
- What you see while it waits is **one line, rewritten in place** — never ten
297
- notices — carrying what failed, which attempt this is, and a countdown to the
298
- next one:
299
-
300
- ```
301
- ↻ Provider overloaded · retry 3/10 in 7s Esc to cancel
302
- ↻ recovered after 3 retries · 12.4s
303
- ```
304
-
305
- plus a `retry 3/10 7s` chip on the status bar (`[r3]` on a narrow terminal). The
306
- card settles into the transcript as history — `recovered`, `gave up`, or
307
- `interrupted` — and shows up in the exit replay, because a turn that spent three
308
- minutes retrying is exactly the kind of cost an exported transcript should
309
- account for.
310
-
311
- **Esc ends the wait within a frame**, not at the end of the countdown, and it
312
- never produces a fabricated error: an aborted request is silent. That is the one
313
- detail everything else here depends on, because the provider layer marks an
314
- `AbortError` as retryable — so the signal is checked *before* the error, and a
315
- user pressing Esc can never be mistaken for a timeout worth retrying.
316
-
317
- Never retried: `auth_error` (401/403), `invalid_request`, `context_overflow`.
318
- Ten retries of a bad API key is three minutes of looking broken.
319
-
320
- `Retry-After` is honoured as a **floor**, never a replacement — a `Retry-After: 1`
321
- on the ninth retry does not undo eight retries of backoff — and a stated wait
322
- longer than a minute is surfaced immediately with the provider's own number
323
- rather than silently wedging the terminal.
324
-
325
- A connection that dies **mid-answer** is also covered, and this is the case that
326
- needed more than a retry loop: the partial text is discarded, the affected tool
327
- cards are removed, and the answer restarts from the top. Nothing is duplicated,
328
- because the engine only writes history on a completed turn.
329
-
330
- - **`/retry [show|on|off|max <n>]`, `--retry` / `--no-retry`, `--retry-max <n>`,
331
- `ARAGON_RETRY`, `ARAGON_RETRY_MAX`, and a `retry` config section** with nine
332
- keys (`aragon config set retry.*`). `/retry off` takes effect **in the running
333
- session** — subagents included, since they share the lead's provider registry —
334
- not only at the next launch. `retry.maxRetries: 0` is the kill switch and is a
335
- real value at every one of those entry points. `/settings` gains one read-only
336
- `API retries` row.
337
-
338
- - **A subagent's retry is visible on the team card.** A child in backoff reports
339
- `retry 3/10` on its own row. Children inherit the retry policy for free, but
340
- their events never reach the lead's view, so without this a subagent spending
341
- three minutes waiting looked exactly like a hung dispatch.
342
-
343
- - **Retry lines in `-p` mode go to stderr, never stdout.** `[retry 3/10]
344
- overloaded — waiting 7s` and `[retry] recovered after 3 retries` are on stderr,
345
- so `aragon -p … | jq` stays valid; a discarded partial answer is announced there
346
- too, because a piped consumer otherwise cannot tell a replay from a model that
347
- repeated itself. They are not suppressed by `--quiet`: a three-minute pause with
348
- no explanation is not a compact run, it is a hang.
349
-
350
- - **`/perf`.** Reports what the renderer is actually doing: the frame interval
351
- and the last commit cost, how many entries exist / are retained / were dropped
352
- / are mounted, height-cache and render-cache occupancy, and the viewport
353
- geometry. `/perf reset` clears the caches and returns the governor to its
354
- fastest rung. Silent degradation is the one thing a claim of robustness cannot
355
- afford, and this is the place that names it.
356
-
357
- - **Three configuration keys**, each with a flag and an environment override:
358
- `transcriptRetain` (`--transcript-retain`, `ARAGON_TRANSCRIPT_RETAIN`),
359
- `renderGovernor` (`--render-governor` / `--no-render-governor`,
360
- `ARAGON_RENDER_GOVERNOR`) and `maxRenderIntervalMs`
361
- (`--max-render-interval`, `ARAGON_MAX_RENDER_INTERVAL_MS`). No migration and no
362
- config version bump: a file written before they existed loads unchanged.
363
- `transcriptRetain` is raised to `transcriptWindow` when the two conflict —
364
- retaining less than you can scroll to would make part of the horizon
365
- unreachable — and a startup notice names both numbers, because overriding a
366
- value you typed and saying nothing is the one thing none of this may do.
367
-
368
- - **Following the plan through, on a budget you can do arithmetic on.** A run
369
- that ended with steps outstanding used to print one sentence and stop. It now
370
- asks three questions the CLI already knew the answers to — did you abort it,
371
- did it error, did the list move — and does one of three things.
372
-
373
- With the default `notify` the sentence is unchanged, except that a run **you**
374
- cancelled with `Esc` now says nothing at all: being told what you just
375
- interrupted is the CLI answering a question nobody asked.
376
-
377
- With `/todo follow auto` it continues the plan itself, after announcing
378
- `Continuing with 4 remaining steps in 3s - Esc to stop.` Auto-continuation was
379
- refused last release as "an unbounded cost loop wearing a helpful hat", and
380
- that judgement stands — what changed is that the loop is now bounded first.
381
- A continuation that completes no step buys exactly one more attempt; a single
382
- plan is continued at most 25 times however productive it looks; and a re-plan
383
- forgives the first counter but never the second, so a model that reshapes its
384
- list every turn cannot lift the ceiling. A run that ended with an error never
385
- auto-continues in any mode. `Esc` cancels, and so does typing anything.
386
-
387
- Whatever sends the continuation — the timer or `/todo continue` — now sends
388
- the numbered list of open steps rather than the words "continue with the
389
- remaining todo items", so a plan whose `todo_write` has scrolled out of the
390
- context window is still followed exactly. Neither path records that text in
391
- your prompt history any more; it is not something you typed.
392
-
393
- Under `-p` there is no grace window, because there is nobody there to use it,
394
- which is precisely why the two counters rather than the human are the
395
- protection there. `[todo] continuing (3 steps left)` and
396
- `[todo] 3 steps unfinished` go to stderr, suppressed by `--quiet`, and an
397
- unfinished plan still never changes the exit code.
398
-
399
- New surfaces: `/todo follow <notify|auto|off>`; `--todo-follow <mode>`;
400
- `ARAGON_TODO_FOLLOW`; and `todo.followThrough` in `config.json`. The default
401
- is `notify`, so a session that does not ask for any of this behaves as it did.
402
-
403
- - **A plan strip for inline mode.** Inline mode has no fixed frame and so no
404
- rail, which left every pipe, every `CI=1`, every `TERM=dumb` terminal and
405
- every window under twelve rows able to see `todo 3/7` but not *which* step was
406
- running. There is now a one-row strip under the transcript —
407
- `todo 3/7 > Adding the rail to AppShell +2 done` — windowed on the
408
- same step the rail would have anchored on. It truncates rather than wrapping
409
- and is exactly one row at every width, so the composer does not move.
410
- `--no-todo-panel` hides it along with the rail.
411
-
412
- ### Changed
413
-
414
- - `npm run typecheck` now covers the test tree in both packages. `tsconfig.json`
415
- excludes `__tests__` so the build never emits fixtures, and vitest transpiles
416
- without typechecking — between the two, a widened required field could break
417
- ten test files while `npm run build` and `npm test` were both green. Twelve
418
- such errors had accumulated; all twelve were fixture drift and all twelve are
419
- repaired, with no suppressions and no production type relaxed to accommodate a
420
- fixture.
421
-
422
- - **TODO planning, and a rail to watch it in.** For work with three or more
423
- distinct steps the agent now keeps a visible plan: it writes a checklist with
424
- a new `todo_write` tool, marks exactly one item in progress, and ticks it off
425
- before starting the next. In full-screen mode the list is rendered as a
426
- right-hand rail about a fifth of the terminal wide, windowed around the step
427
- being worked on rather than sliced from the top. Ask for something small and
428
- nothing appears — the prompt tells the model not to plan work it can finish in
429
- one or two steps, and a one-item list against an empty plan is refused
430
- outright, so a session that never plans has byte-identical layout to a build
431
- without this feature.
432
-
433
- The list is a projection of what the model believes, and that single rule
434
- decides everything else: `/clear` keeps it (the conversation is still there),
435
- `/reset` drops it, `/save` writes it and `/resume` restores it — and resuming
436
- a session that carries no list CLEARS the current one rather than leaving a
437
- plan on screen whose conversation has just been replaced. A finished plan
438
- survives to the start of your next message so you get to see `7/7 done`; an
439
- unfinished one survives "continue" and "now do the rest", then expires after
440
- three unrelated turns rather than holding a fifth of the screen for the rest
441
- of the session. A run that ends with items left over produces a notice and
442
- `/todo continue`; nothing auto-continues on your behalf.
443
-
444
- "One step at a time" is enforced by structure rather than asked for in a
445
- prompt: any payload with two in-progress items is repaired down to one, and a
446
- list with none promotes the first unfinished item. Whatever the model sends,
447
- the panel has exactly one current row.
448
-
449
- New surfaces: the `todo_write` tool; `/todo [status|on|off|panel on|off|clear|
450
- continue]`; `--todo` / `--no-todo` and `--todo-panel` / `--no-todo-panel`;
451
- `ARAGON_TODO=0`; and `todo.enabled` / `todo.panel` in `config.json` (a third
452
- key, `todo.followThrough`, arrived with the follow-through entry above).
453
- `panel` is
454
- separate from `enabled` on purpose — a screen-reader user wants the planning
455
- discipline without the column, and the system prompt varies one sentence to
456
- match. Under `-p` the plan goes to stderr as `[todo] 3/7 <step>` lines,
457
- suppressed by `--quiet`. Below 80 columns, behind an overlay, in inline mode
458
- or on a short terminal the rail is not mounted and the counter appears in the
459
- status bar instead; the transcript keeps at least 62 columns at every width.
460
-
461
- - **Output token limits that cannot themselves fail a run.** Every model and
462
- every provider now defaults to 64000 output tokens, and that number is
463
- configurable from the TUI, from a flag, from `ARAGON_MAX_TOKENS`, and by hand
464
- in `~/.aragon-agent/config.json`. Leave it alone and it stays 64000.
465
-
466
- What is new is that the number is an *ambition*. `gpt-4o` caps at 16384 and
467
- `gemini-1.5-pro` at 8192; sending 64000 to either is an HTTP 400 that ends the
468
- turn with a raw provider string in the transcript. The cap is now clamped down
469
- to whatever the target model actually accepts, from a per-model table plus
470
- whatever the provider's own model list reports. For a model nothing knows — a
471
- proxy, a `--base-url` endpoint, something that shipped last week — the request
472
- goes out at 64000, and if the provider objects, `aragon` reads the real ceiling
473
- out of the error text, repairs the request, sends it exactly once more, and
474
- remembers the answer for the rest of the session. One warning line; the run
475
- continues.
476
-
477
- Two combinations that were a guaranteed 400 on every request are fixed with
478
- it: `--thinking xhigh` asks for a 65536-token budget while Anthropic requires
479
- `max_tokens` to be strictly greater than it, and OpenAI's reasoning family
480
- (`o1`, `o3`, `gpt-5`) rejects the `max_tokens` parameter name outright in
481
- favour of `max_completion_tokens`.
482
-
483
- New surfaces: `/max-tokens [<n>|auto|default]`, which with no argument reports
484
- the setting *and* the effective cap for the live model; an `Effective:` line
485
- under the settings screen's `Max tokens` field, so a value the model will not
486
- honour is visible before you save it; `--max-tokens auto`; and
487
- `aragon config set maxTokens <n|auto|default>`, which echoes the value that was
488
- actually stored rather than the one you typed.
489
-
490
- - **Team subagents.** The agent can now hand independent parts of a job to up to
491
- five short-lived subagents that run in parallel, then read one combined report
492
- of what each of them found. It decides for itself whether to delegate, so a
493
- session that never calls the new `task` tool is byte-for-byte the session that
494
- existed before. On by default; `--no-team` or `team.enabled: false` turns it
495
- off, and `aragon config set team.maxSubagents <n>` sets the width (1-10; the
496
- 10 is a hard ceiling no config file can raise).
497
-
498
- A subagent is a full agent with the same tools and working directory but no
499
- memory of your conversation, so its brief has to be self-contained. It cannot
500
- delegate further and it cannot ask you anything. Plan mode and a skill's
501
- `allowed-tools` ceiling both reach one level down, so delegating is never a
502
- way around either; `--confirm` queues subagent confirmations one at a time and
503
- labels each with the subagent that is asking.
504
-
505
- Subagents can message each other with `team_send` / `team_wait`, delivered by
506
- attaching the message to the recipient's next tool result rather than
507
- interrupting it. The limits are deliberate — 6 messages each, one every 15
508
- seconds, 24 per dispatch — and every refusal is a plain result naming the
509
- limit rather than an error, because an error invites the retry the limits
510
- exist to prevent.
511
-
512
- While a dispatch runs, a roster sits between the transcript and the composer
513
- and the status bar carries `agents 3/5`; both disappear when it finishes and
514
- the transcript keeps a card you can expand with `Ctrl+O`. `Esc` aborts every
515
- subagent and returns the partial report. Under `-p` the transitions go to
516
- stderr and the subagents' tokens are folded into the `[usage]` footer, so the
517
- cost readout cannot under-report what the team spent.
518
-
519
- Full documentation, including the limits table and how team mode interacts
520
- with plan mode, skills and `--confirm`, is in the README.
521
-
522
- - **The subagent roster now shows what each subagent is doing, and shows the
523
- ones that are working.** Where every row used to say `thinking` for minutes at
524
- a time, it now says `bash: npm test -w cli`, `read: src/api/routes.ts`,
525
- `waiting for a2`, or the tail of the sentence the subagent is currently
526
- writing. On a narrow terminal the same row falls back to a file name and a
527
- program name rather than wrapping, and the elapsed clock keeps its place at
528
- every width.
529
-
530
- The five visible rows are now the five that matter: whatever is running comes
531
- first, then whatever is queued, then the most recent results. Above five
532
- subagents the old panel showed the five that had finished first and hid
533
- everything still working behind `+3 more`, which is the opposite of what the
534
- roster is for. `+3 more` now says how many of the hidden ones are still going.
535
-
536
- - **A subagent no longer waits two minutes for a message nobody can send.**
537
- `team_wait` now checks whether anyone could actually answer before it blocks:
538
- if the teammate it named has already finished, does not exist, or is itself
539
- waiting in a way that cannot be released in time, it returns straight away and
540
- says which. Nothing is refused that could still have been answered — including
541
- by a third teammate further down the chain — and the subagent is told what to
542
- do instead rather than handed an error.
543
-
544
- - **A subagent whose very first request dies on a rate limit is retried once.**
545
- Only a genuine cold start qualifies: no turn completed and no tool ran, so
546
- there is nothing to undo. It restarts after two seconds, the roster says
547
- `starting (retry)`, and the report notes `retried 1x`. Pressing `Esc`, a
548
- timeout, or any subagent that had already begun work is never retried.
549
-
550
- ### Changed
551
-
552
- - **`"maxTokens": null` in `config.json` now means AUTO** — use each model's own
553
- ceiling, never above 64000. It previously resolved to 64000 by accident (the
554
- layered resolver skipped `null`), and there was no way to express AUTO through
555
- any supported write path. If you have a `null` there today, the only difference
556
- is a downward clamp on models whose real ceiling is below 64000 — the direction
557
- that prevents failures rather than causing them. Absent still means 64000, and
558
- an explicit number still means that number.
559
-
560
- - **`config.json` holds settings again.** The prompts you type are no longer
561
- stored in it. They move to `~/.aragon-agent/prompt-history.jsonl` — one JSON
562
- object per line, `0600` on POSIX — and the submit counter and the "notice
563
- already shown" flag move to `~/.aragon-agent/state.json`. `↑` and `↓` behave
564
- exactly as before.
565
-
566
- Two things get better. Opening `config.json` to change your model no longer
567
- means scrolling past a transcript of your own typing, and copying it to
568
- another machine no longer carries your prompts along. And submitting a message
569
- no longer rewrites the file that holds your API keys: `config.json` is written
570
- when you change a setting, and at no other time.
571
-
572
- **Your history and counters are migrated automatically, once, at the next
573
- launch.** Nothing is printed, because nothing changes for you. The dead
574
- `recentModels` key — which nothing has ever written — is dropped.
575
-
576
- If you go back to 0.5.x after upgrading, that version does not know about the
577
- new file and `↑` will look empty. Nothing has been lost: the entries are still
578
- in `prompt-history.jsonl`, and upgrading again brings them back.
579
-
580
- ### Added
581
-
582
- - **`aragon history`** — `path`, `list` (`-n`, `--json`) and `clear --yes` for
583
- the prompt history, alongside the existing `aragon logs` commands. Entries are
584
- stored verbatim, so `clear` is how you erase them; `aragon config set
585
- historyEnabled false` stops new ones being recorded without deleting or hiding
586
- what is already there.
587
-
588
- - **The mouse wheel scrolls what is under the pointer.** In full-screen mode the
589
- wheel now scrolls the transcript three rows per notch (a page with `Shift`),
590
- scrolls an open overlay when the pointer is over one, and steps prompt history
591
- one entry per notch when the pointer is over the input box — the same code
592
- path `↑` / `↓` use, so it inherits the rule that an in-progress draft is never
593
- overwritten. A slim rail on the viewport's right edge shows where you are in
594
- the conversation.
595
-
596
- **This fixes a destructive bug.** Previously the wheel recalled prompt history
597
- no matter where the pointer was, because the alternate screen makes terminals
598
- translate each notch into arrow keys. Wheeling while composing a message
599
- silently replaced the draft with an old prompt, and nothing scrolled.
600
-
601
- **Selecting text with the mouse now requires `Shift`+drag** in most terminals.
602
- That is the standard convention for "an application is tracking the mouse" and
603
- it applies to everyone, including people who never scroll with the wheel — so
604
- the first session says so once, in the transcript, and never again. Turn the
605
- whole feature off with `--no-mouse`, `ARAGON_MOUSE=0`, or
606
- `aragon config set mouse false`; the wheel then does nothing rather than
607
- reverting to the old behaviour. Inline mode (`--no-fullscreen`) is untouched:
608
- your terminal's own scrollback already does the right thing there.
609
-
610
- Under `tmux` with `mouse on`, tmux keeps the wheel for itself and the app
611
- never sees it. `set -g mouse off` hands it back.
612
-
613
- ### Changed
614
-
615
- - **Your files moved to `~/.aragon-agent/`.** Config, sessions, installed skills
616
- and the usage counters now live in one directory in your home — on Windows
617
- `C:\Users\<you>\.aragon-agent\`, and the same path on macOS and Linux. They
618
- used to be split across `%APPDATA%\aragon-agent-nodejs\Config` and
619
- `%LOCALAPPDATA%\aragon-agent-nodejs\Data` (or the XDG equivalents), which are
620
- correct locations and terrible answers to "where do I change the model?".
621
-
622
- **The move happens once, automatically, on first launch, and prints a line on
623
- stderr when it does.** Nothing is deleted: `config.json` is COPIED rather than
624
- moved, and the old directories are left where they are, so reinstalling 0.5.0
625
- remains lossless. `aragon config home` prints the new location and names the
626
- old ones. Once you are satisfied, you can delete them yourself.
627
-
628
- `ARAGON_HOME` relocates the whole tree. It has to be a real environment
629
- variable — the path is resolved before any `.env` is read, so putting it in a
630
- `.env` will not work. `aragon config home` always prints what is actually in
631
- use.
632
-
633
- ### Added
634
-
635
- - **Logging.** Records go to `~/.aragon-agent/logs/aragon-<date>.log` as JSON
636
- Lines: startup and exit, config writes, turn boundaries with token counts,
637
- tool names with durations, skill loads, and every uncaught error. Files rotate
638
- by day and by size (`log.maxFileBytes`, default 5 MiB) and the oldest beyond
639
- `log.maxFiles` (default 10) are deleted.
640
-
641
- **`info`, the default, records no conversation content**, so attaching a log
642
- to a bug report is safe. `--log-level debug` (or `--verbose`) adds prompts,
643
- replies and tool arguments truncated to `log.previewChars`; `trace` adds them
644
- in full. Those two write what you typed — check before sharing one.
645
-
646
- API keys are removed at every level by two independent passes: fields whose
647
- name looks like a credential are blanked whatever they hold, and every string
648
- is scanned both for known key formats and for the literal keys this process is
649
- holding — which is what covers a custom endpoint whose key looks like nothing
650
- in particular. `log.redactSecrets false` turns both off and warns you on
651
- stdout when you set it.
652
-
653
- Nothing is ever uploaded. There is no network path out of this subsystem.
654
-
655
- New commands: `aragon logs path | list | tail [-n N] [--follow] [--level lv]
656
- [--json] | clear --yes | open`, and `/logs` inside the TUI. New flags:
657
- `--log-level`, `--verbose`, `--log-file` / `--no-log-file`, `--log-dir`. New
658
- environment variables: `ARAGON_LOG_LEVEL`, `ARAGON_LOG_FILE`, `ARAGON_LOG_DIR`
659
- — these three, unlike `ARAGON_HOME`, can come from a `.env`.
660
-
661
- - **`aragon config get <key>` / `list [--json]` / `edit` / `home`.** `get` and
662
- `list` mask every secret, `--json` included. `edit` opens `config.json` in
663
- `$VISUAL` / `$EDITOR` (`notepad` on Windows), takes a `config.json.bak` first,
664
- and re-parses on exit — an invalid edit is reported immediately, and the
665
- backup is named in the message.
666
-
667
- - **`/reload`** re-reads `config.json` into the running session, for when you
668
- have edited it in another window. Refused while a run is in progress: swapping
669
- the model mid-turn would let the second half of an answer come from different
670
- settings than the first, with nothing afterwards able to explain the result.
671
-
672
- - **Log level in the settings screen**, alongside provider / model / thinking.
673
- The rest of the log settings — and `redactSecrets` above all — stay
674
- command-line-only, so the one switch that can put credentials on disk cannot
675
- be flipped with an arrow key.
676
-
677
- ### Fixed
678
-
679
- - **A malformed `config.json` no longer resets everything in silence.** A stray
680
- comma used to send the model, theme, timeouts, skills and (as far as you could
681
- tell) your API key back to defaults, with nothing anywhere explaining it. The
682
- fallback is unchanged — a bad config still never stops the CLI from starting —
683
- but it now says so, and records why.
684
-
685
- - **Ctrl+C now flushes pending log records in every mode.** The signal handlers
686
- only existed in the full-screen branch, so `-p`, the inline renderer and every
687
- subcommand took Node's default termination, which does not run exit handlers.
688
-
689
- ### Added
690
-
691
- - **Plan mode.** `Shift+Tab` toggles between `BUILD` (everything as before) and
692
- `PLAN`, a read-only research-and-design posture. `/plan [on|off|status]` is a
693
- first-class equivalent for terminals that swallow `CSI Z`, and `--plan` /
694
- `--no-plan` / `ARAGON_PLAN=1` / `planModeDefault` cover the startup case.
695
-
696
- In `PLAN`, `write_file`, `edit_file`, `bash`, `skill_install` and
697
- `skill_create` are refused **at the tool boundary**, so read-only is a
698
- property of the wiring rather than a promise in a prompt. `bash` is refused in
699
- full, `git status` included: a shell string cannot be classified reliably, and
700
- a gate that is right most of the time is worse than one that is always right,
701
- because you stop trusting the badge. The refusal names `read_file` / `glob` /
702
- `grep` as the alternatives.
703
-
704
- Two tools exist only while a human is attached. `ask_user` renders a
705
- keyboard-driven wizard - 1-5 questions, 2-4 options each, exactly one marked
706
- `RECOMMENDED`, plus an `Other...` free-text option - where pressing `Enter`
707
- through the wizard accepts every recommendation. `submit_plan` renders the
708
- plan as a scrollable card: `a` approves, `r` sends written feedback (`<-`
709
- returns to the card), `Esc` dismisses. **Approving flips the session to
710
- `BUILD` immediately and the same run continues into implementation.**
711
-
712
- Dismissing a plan asks for a better one rather than stopping - the agent is
713
- told to refine and resubmit - so the way out of a run is `Esc` twice: the
714
- first closes the card, the second aborts the run.
715
-
716
- Toggling mid-run is asymmetric on purpose: `build -> plan` applies at once,
717
- `plan -> build` is deferred to the end of the run (the status bar shows
718
- `PLAN -> BUILD` meanwhile) so a run launched under a read-only guarantee
719
- cannot start writing files because of one stray keypress.
720
-
721
- `aragon -p --plan "..."` registers no question or plan tool - there is nobody
722
- to ask - but the read-only gate still applies, so it means "tell me how you
723
- would do this, and do not touch my repository".
724
-
725
- - Three flat config keys: `planModeDefault` (default `false`),
726
- `planModeMaxAskRounds` (default `4`, clamped `[1, 10]`) and
727
- `planModeHumanTimeoutMs` (default `1800000`, clamped `[60000, 7200000]`). All
728
- three are settable with `aragon config set`. Additive, as always: a config
729
- file written by an earlier version loads unchanged.
730
-
731
- ### Fixed
732
-
733
- - A `--confirm` prompt no longer races the idle watchdog. Taking longer than
734
- `idleTimeoutMs` over `Proceed? (y/N)` used to abort the run with no
735
- explanation; every human wait now suspends the watchdog and restarts it in a
736
- `finally`.
737
-
738
- - Honor an explicit `NODE_TLS_REJECT_UNAUTHORIZED=0` setting in the CLI and the
739
- official npm release workflow while hiding only Node's standard insecure-TLS
740
- warning. Other process warnings remain visible.
741
-
742
- ## 0.5.0
743
-
744
- ### Breaking
745
-
746
- - **The package is renamed `@argon-agent/cli` → `@aragon-agent/cli`.** The brand
747
- was always meant to be *Aragon*, matching AragonMesh; the missing `a` was a
748
- typo that reached the registry. Install with:
749
-
750
- ```
751
- npm uninstall -g @argon-agent/cli
752
- npm install -g @aragon-agent/cli
753
- ```
754
-
755
- `@argon-agent/cli` is deprecated and receives no further releases. **The
756
- executable is still `aragon`** — the command you type does not change.
757
-
758
- - **Environment variables are `ARAGON_*`, not `ARGON_*`.** There is no
759
- compatibility fallback: `ARGON_MODEL`, `ARGON_PROVIDER`, `ARGON_BASE_URL`,
760
- `ARGON_THINKING`, `ARGON_MAX_TOKENS`, `ARGON_THEME`, `ARGON_FULLSCREEN`,
761
- `ARGON_SKILLS`, `ARGON_SKILLS_DISABLED`, `ARGON_SKILLS_PATH` and
762
- `ARGON_REDUCED_MOTION` are all ignored from this release on. Rename them in
763
- your shell profile and CI. Provider keys (`ANTHROPIC_API_KEY`,
764
- `OPENAI_API_KEY`, `GOOGLE_API_KEY`, `GEMINI_API_KEY`) are untouched.
765
-
766
- - **The project-level skills directory is `.aragon/skills`, not
767
- `.argon/skills`.** This one lives in your repository, so rename it yourself:
768
-
769
- ```
770
- git mv .argon .aragon
771
- ```
772
-
773
- A config file that already persisted the old default keeps working — an
774
- explicitly saved `skills.projectDirs` still wins over the default — but the
775
- shipped default is now `['.aragon/skills', '.claude/skills']`. Update it with
776
- `aragon config set` if you want the new default.
777
-
778
- ### Added
779
-
780
- - **Automatic migration of your user-level state.** On first run, 0.5.0 moves
781
- the `env-paths` config and data directories from `argon-agent` to
782
- `aragon-agent` — your API key, sessions and installed skills come with it, and
783
- each installed skill's `.argon-skill.json` manifest is renamed to
784
- `.aragon-skill.json` so `skills update` and `skills uninstall` still recognise
785
- it. The migration prints one line to **stderr**, runs once, and is skipped
786
- entirely if the new directory already exists. If it fails for any reason the
787
- CLI still starts; the old directory is never deleted when a cross-volume copy
788
- was needed.
789
-
790
- - The opening wordmark now reads `ARAGON` and is 52 columns wide (was 44).
791
- Terminals between 52 and 55 columns show the single-line banner rather than a
792
- clipped wordmark.
793
-
794
- - **Skills.** A skill is a directory holding a `SKILL.md` (YAML frontmatter +
795
- Markdown body) plus optional `reference/`, `scripts/` and `assets/`. Skills
796
- reach the model through three levels of progressive disclosure: a name +
797
- one-line "when to use" catalog in the system prompt (≤ 6 000 bytes total),
798
- the full body only when the model calls the `skill` tool, and bundled files
799
- only when it reads them with `read_file` / `bash`. A skill therefore costs a
800
- line of context rather than its whole body. How many fit in Level 1 depends on
801
- description length and language — roughly 30 with terse English descriptions,
802
- roughly 10 with Chinese ones at the character cap; past that the catalog
803
- truncates and `skill_find` covers the remainder.
804
- - Four model-facing tools: `skill` (load), `skill_find` (search installed
805
- skills), `skill_install` (install from a local directory, git repo, or https
806
- `SKILL.md` / `.zip`) and `skill_create` (author a new one from a procedure the
807
- agent just worked out).
808
- - **`aragon skills update <name> | --all`**, with `--dry-run`, `--force` and
809
- `--check`. Re-fetches from the source recorded in the install manifest,
810
- preserving `installedAt` and recording `updatedAt` / `previousVersion`. Refuses
811
- before downloading anything when the installed copy has local edits, and
812
- re-validates the source against the *current* `skills.allowedHosts` rather than
813
- the one in force at install time. Not exposed to the model.
814
- - **Catalog ranking.** Level 1 entries are ordered by scope, then by how recently
815
- and often each skill was used, so truncation drops what you do not use rather
816
- than what sorts last alphabetically. With no usage data the order is unchanged.
817
- - **`skill_find`**, advertised in the prompt only when the catalog actually
818
- truncated. Searches installed skills by name, description and keyword; never
819
- reaches the network, never returns `activation: manual` skills, and tells the
820
- model to ask for a source rather than invent one when nothing matches.
821
- - **Cross-process install lock.** Install / create / remove / update take a
822
- per-directory advisory lock, closing a race in which two concurrent installs
823
- could interleave their atomic-replace steps and delete a skill with no error.
824
- Self-expires after 60 s; waits at most 5 s; only ever released by its owner.
825
- - **Load-time integrity.** Discovery re-checks `SKILL.md` against the sha256
826
- recorded at install, at no extra I/O. `skills.integrity` selects
827
- `off` / `warn` (default) / `strict`.
828
- - **Local usage counters** at `<data>/skill-usage.json` — skill name, count and
829
- timestamp only, never transmitted, disabled with `skills.usageTracking=false`.
830
- Automatically injected `activation: always` skills are not counted.
831
- - Config keys `skills.integrity` and `skills.usageTracking`; `aragon skills list
832
- --sort=recent` and `/skills list --sort=recent`.
833
- - Every usable skill also becomes a slash command: `/<skill-name> [args]`, with
834
- `$ARGUMENTS` / `$1..$9` substitution. On a name clash the built-in command
835
- always wins and the skill is reachable as `/skill:<name>`.
836
- - `/skills` management: `list`, `info`, `install`, `remove`, `enable`,
837
- `disable`, `reload`, `create`, `trust`, `untrust`.
838
- - `aragon skills …` non-interactive equivalents plus `path` and `doctor`.
839
- Exit codes follow `config set`: `0` ok, `1` run-time failure, `2` usage.
840
- - Four discovery scopes in ascending precedence: bundled (`<pkg>/skills`), user
841
- (`<data>/skills`), project (`<cwd>/.aragon/skills` and, read-only,
842
- `<cwd>/.claude/skills` for Claude Code interop), and `ARAGON_SKILLS_PATH`.
843
- - New flags `--no-skills`, `--skill <name>` (repeatable) and `--skills-yes`;
844
- env `ARAGON_SKILLS`, `ARAGON_SKILLS_PATH`, `ARAGON_SKILLS_DISABLED`; config keys
845
- `skills.enabled`, `skills.requireApproval`, `skills.catalogMaxBytes`,
846
- `skills.bodyMaxBytes`.
847
- - One bundled skill, `skill-creator`, documenting how to write a good one.
848
- - New runtime dependency: `fflate` (~30 KB, MIT, zero transitive deps) for zip
849
- extraction. `@aragon-agent/core` gains no dependency.
850
- - **Release tooling for the scope change.** `npm run verify:brand` scans every
851
- file that `npm pack` would put in the tarball — README and `dist/` included —
852
- and blocks the release on any surviving `argon` reference, with only the four
853
- documented exceptions (the two CHANGELOGs and the legacy-state migration
854
- module, which hold the old names by definition). `packages/cli` also gains a
855
- `prepublishOnly: npm run build`, so a publish that bypasses
856
- `publish-latest.ps1` can no longer ship a `dist/` that is out of step with the
857
- sources. `deprecate-legacy.ps1` retires `@argon-agent/*` on the registry, and
858
- refuses to do so until the replacements are actually published.
859
-
860
- ### Changed
861
-
862
- - The globally installed executable is now `aragon`. The previous `argon` and
863
- `argon-agent` aliases are no longer installed.
864
- - `config/store.ts` now deep-merges the `skills` section on both read and write,
865
- the same treatment `apiKeys` already received. Without it a partial patch such
866
- as the one `/skills disable` sends would replace the whole section and
867
- silently discard `trustedProjectDirs`, `allowedHosts` and `requireApproval`.
868
- - `slashSuggestions` accepts `-` and `:`, so kebab-case and `skill:`-namespaced
869
- commands autocomplete. Previously `/my-sk` produced no popup at all.
870
- - `AgentController` now has a single `agent.setSystemPrompt()` call site, so a
871
- `/cwd` change can no longer drop the skill catalog out of the prompt.
872
- - With skills off or none installed, the system prompt and the 7-tool array are
873
- byte-identical to the previous release.
874
- - Added a repository-level PowerShell release workflow that automatically
875
- updates CLI and Core versions, synchronizes their dependency and lockfile,
876
- verifies both tarballs, and publishes them in dependency order.
877
-
878
- ### Security
879
-
880
- - Installing a skill requires an explicit human approval that **probes for a
881
- human first and refuses when there is none**. Under `-p` there is no TUI and
882
- therefore no approver, so `skill_install` is refused with an actionable
883
- message rather than writing a third-party directory unattended. Use
884
- `--skills-yes` (or `skills.requireApproval=false`) to opt out deliberately.
885
- - Project skill directories require a one-time trust confirmation before they
886
- are loaded — cloning an unfamiliar repository does not grant it the ability
887
- to inject instructions into your session.
888
- - Git is invoked only via `execFile` with an argv array and `shell: false`, and
889
- owner / repo / ref / subdirectory fragments are whitelisted and refused if
890
- they begin with `-`. A leading dash matters even with a pure argv array:
891
- `--upload-pack=<program>` makes git execute that program.
892
- - Zip extraction is streamed and gated on **actually written** bytes, per-entry
893
- size, compression ratio and entry count, all of which can abort mid-archive.
894
- The size a zip *declares* is written by whoever built it and is never trusted.
895
- Path traversal, absolute entries, symlinks and Windows device names are
896
- refused, and a rejected archive is removed rather than left half-extracted.
897
- - Network fetches are `https:` only, restricted to `skills.allowedHosts`,
898
- re-checked on every redirect (max 3), size-capped, and refuse IP literals and
899
- loopback.
900
- - Nothing a skill ships is executed at install time, and the executable bit is
901
- not preserved. Scripts run only when the model invokes `bash` explicitly.
902
- There is no sandbox: approval blocks *silent* installation, it does not make
903
- a skill you approved safe.
904
-
905
- ## 0.3.0
906
-
907
- A full-screen TUI release. `@argon-agent/core` is untouched, no new runtime
908
- dependency is added, and the headless/print contract, exit codes, and
909
- slash-command semantics are unchanged. The 0.2.0 inline renderer remains
910
- available in full via `--no-fullscreen`.
911
-
912
- ### Added
913
-
914
- - **Full-screen mode (default).** `aragon` now takes over the terminal's
915
- alternate screen buffer — the same mechanism `vim` / `htop` / `lazygit` use.
916
- Your shell history is covered, not erased, and comes back untouched on exit.
917
- The frame is a fixed `rows - 1` tall, so **the composer and the status bar sit
918
- at the physical bottom of the screen from the very first frame**: empty
919
- session, long session, mid-scroll, or overlay open.
920
- - **Brand region.** A six-row gradient ASCII wordmark on a roomy empty session,
921
- degrading to a banner, then a single-line bar, then a bare wordmark as space
922
- runs out. Row 1 always begins with the brand glyph.
923
- - **Self-drawn scrolling.** `PgUp` / `PgDn` by the page, `Shift+↑` / `Shift+↓` by
924
- the line. The viewport auto-follows new output while pinned to the bottom;
925
- scrolling away shows `↑N` in the status bar plus a "N new lines" hint, and
926
- submitting a message always re-pins.
927
- - **Exit replay.** After leaving the alternate screen the session is replayed
928
- into the normal buffer as plain, colorless text, so the conversation does not
929
- evaporate with the screen. Turn it off with `--no-exit-transcript`.
930
- - **New flags** `--fullscreen` / `--no-fullscreen` / `--no-exit-transcript`, the
931
- env var `ARGON_FULLSCREEN=0|1`, and the config keys `fullscreen`,
932
- `exitTranscript`, and `transcriptWindow`.
933
- - **Automatic downgrade.** A non-TTY stdout, `TERM=dumb`, CI, and terminals under
934
- 12 rows / 40 columns fall back to the inline renderer. Only the non-TTY gate is
935
- un-overridable — `--fullscreen` beats the rest.
936
-
937
- ### Changed
938
-
939
- - The status bar lost its round border and is now exactly one row; it had been
940
- spending an eighth of a 24-row terminal framing a single line of text.
941
- - The toast strip holds a fixed row in full-screen mode, so the transcript no
942
- longer jumps as toasts appear and expire.
943
- - The composer is a rounded frame whose border color reports state (idle, has a
944
- draft, running, blurred by an overlay), with the completion popup above it.
945
- - `Ctrl+L` repaints the frame instead of writing a clear sequence. Ink dedupes
946
- identical output at two separate gates, so under a fixed frame the old
947
- approach erased the screen and then declined to redraw it.
948
- - `Shift+↑` / `Shift+↓` no longer recall prompt history — they scroll.
949
- - Full-screen mode routes `console.*` into the transcript as notices rather than
950
- letting Ink write them straight to stdout, which corrupts the frame's line
951
- accounting.
952
-
953
- ### Known trade-offs
954
-
955
- - The terminal's native scrollback and mouse wheel do not scroll the transcript
956
- in full-screen mode; use `PgUp` / `PgDn`, or run with `--no-fullscreen`.
957
- - Mouse tracking is deliberately left off: enabling it costs text selection and
958
- copy in most terminals.
959
- - Should a crash ever strand your terminal on the alternate screen, `reset`
960
- restores it. Four independent restore paths exist to prevent that: normal
961
- exit, `process.exit`, `SIGINT` / `SIGTERM` / `SIGHUP`, and Ink's own signal
962
- handling.
963
-
964
- ## 0.2.0
965
-
966
- A design-elevation & HCI-hardening release. No breaking changes: `@argon-agent/core`
967
- is untouched, no new runtime dependency is added, and the headless/print contract,
968
- exit codes, config keys, and slash-command semantics from 0.1.0 are unchanged.
969
-
970
- ### Added
971
-
972
- - **Real theming engine.** Distinct `dark` / `light` palettes with an `auto`
973
- resolution (`auto → dark`), color degradation across terminal depth
974
- (truecolor → 256 → 16 → monochrome), and an ASCII glyph fallback for terminals
975
- without Unicode. Honors `NO_COLOR`, `FORCE_COLOR`, `--no-color`, and
976
- `TERM=dumb`. Switch live with `/theme <auto|dark|light>` (persisted).
977
- - **Elegant chrome.** A gradient wordmark header that collapses to a slim sticky
978
- bar after the first turn, a first-run **Welcome / empty-state** card, and a
979
- status bar with a colored **context gauge** (threshold colors), a **tokens/sec**
980
- read-out while running, and a contextual hint.
981
- - **Legible tool output.** Colored unified diffs (green adds / red removes) and
982
- per-tool rich previews (`edit_file`/`write_file`/`read_file`/`bash`/`list_dir`/
983
- `glob`). Long previews collapse to 8 lines and expand with `Ctrl+O` or
984
- `/expand [n]`.
985
- - **Autocomplete.** A slash-command palette and `@file` path completion popup
986
- (`Tab`/`→` to complete, `Up`/`Down` to move, `Esc` to close).
987
- - **Full line editing.** Home/End, word jump/delete, kill-to-start/end, and
988
- multi-line vertical cursor navigation, with prompt-history recall at the edges.
989
- Unknown control/escape sequences are dropped instead of inserted.
990
- - **Reliability under load.** Ink `<Static>` finalization for settled entries and
991
- a streaming delta coalescer, so long/fast sessions stay flicker-free.
992
- - **Calm feedback.** Ephemeral, auto-dismissing **toasts** for transient acks;
993
- the transcript keeps only durable content (messages, tool cards, run errors).
994
- - `reducedMotion` config (also `ARGON_REDUCED_MOTION`; implied by `--no-color`)
995
- replaces spinners with a static glyph.
996
-
997
- ### Changed
998
-
999
- - History scrollback now uses the **native terminal scrollback** that `<Static>`
1000
- prints into (this supersedes the never-implemented `PgUp`/`PgDn` promise).
1001
-
1002
- ## 0.1.0
1003
-
1004
- Initial release — a Claude-Code / Codex-style interactive terminal UI (TUI) on
1005
- top of `@argon-agent/core`.
1006
-
1007
- ### Added
1008
-
1009
- - **Interactive TUI** (React + Ink): gradient header, streaming transcript with
1010
- markdown + syntax highlighting, collapsible thinking blocks, live tool-call
1011
- cards, a status bar (model / context % / tokens / cost / elapsed), and modal
1012
- overlays (settings, model picker, help, confirm).
1013
- - **Built-in toolset** wired into the core agent at full permission:
1014
- `read_file`, `write_file`, `edit_file`, `list_dir`, `glob`, `grep`, `bash`.
1015
- - **Layered configuration** (defaults → user file → env/`.env` → flags) with
1016
- live in-TUI editing of provider / model / base URL / API keys / thinking level
1017
- / max tokens. Secrets are masked and the config file is written `0600` on POSIX.
1018
- - **One-shot / print mode** (`argon -p`) for scripting and piping, plus
1019
- `argon config` / `argon config set` / `argon config path` / `argon models`.
1020
- - **Session control**: abort (Esc), steer-while-running, follow-up queue,
1021
- double-Ctrl-C exit, `/save` / `/resume` JSON sessions.
1022
- - **Timeout invariant** (`idleTimeout ≥ toolTimeout`) so a long single tool run
1023
- is never killed by the idle watchdog.
1024
- - **Never-silent failures**: pre-flight API-key validation, error-StreamEvent
1025
- rendering, and a guard that surfaces a swallowed agent error instead of a
1026
- 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
+ - **An update that will not start is undone automatically.** The updater shipped
13
+ in this same release could install a version that fails to *import* — an
14
+ undeclared dependency, a Node API that moved, a syntax error past the transpile
15
+ target — and the only recovery was to know the package name and type
16
+ `npm i -g @aragon-agent/cli@<some older version>` from memory. None of those
17
+ failures reach any line inside `main()`, so no amount of care there helps.
18
+
19
+ The `aragon` command is now a small launcher that runs **before** the CLI. It
20
+ reads one ~300-byte file, and on every launch except the first one after an
21
+ auto-update that is all it does — no write at all. But if the version it is
22
+ about to start is one **this updater installed**, and that version has already
23
+ exited non-zero twice, it reinstalls the version that was running before the
24
+ update and marks the bad one so nothing puts it back:
25
+
26
+ ```
27
+ aragon 0.6.0 failed to start twice; rolling back to 0.5.9.
28
+ ```
29
+
30
+ It boots anyway. If the crash was transient, refusing to start would lock you
31
+ out of a working CLI on our guess; the reinstall is detached and finishes
32
+ either way. The next session says once what happened and then stops. A **newer**
33
+ release clears the mark and installs normally — you were never opted out of
34
+ updates, only out of the loop.
35
+
36
+ It never touches a version **you** installed yourself, and it does not try to
37
+ detect a release that starts and is merely wrong. `aragon update --rollback` is
38
+ the same mechanism run deliberately, for the case a human spots in one second
39
+ and a heuristic would get wrong on a bad day. Exit `4` means there was nothing
40
+ recorded to roll back to.
41
+
42
+ **`update.mode: off` disables this too.** The guard is armed only by an
43
+ auto-install, so a machine that never auto-installs never arms it — the kill
44
+ switch turns off the whole subsystem, recovery included.
45
+
46
+ - **A blocked install now says what is actually blocking it.** Every install
47
+ failure used to print the same line: `update failed · npm i -g
48
+ @aragon-agent/cli`. On Windows the commonest cause is that the shim which
49
+ launched us is held open by the shell running it, so that advice hits the same
50
+ handle and fails identically — the one visible failure was also a wrong
51
+ instruction. Failures are now classified, and three of them name the real
52
+ remedy and appear immediately rather than after three strikes, because each is
53
+ something you can fix and none of them fixes itself:
54
+
55
+ ```
56
+ ! update blocked · close other aragon windows, then: npm i -g @aragon-agent/cli
57
+ ! update failed · no disk space
58
+ ! update needs write access · npm i -g @aragon-agent/cli
59
+ ```
60
+
61
+ Network failures are deliberately **not** in that set: you cannot fix the
62
+ registry and the next check may well succeed, so they stay silent and back off.
63
+
64
+ - **Updates work behind a corporate proxy.** Node's `fetch` ignores `HTTP_PROXY`,
65
+ so on a proxied machine the check failed silently forever. When the direct
66
+ request fails, `aragon` now asks the npm you already have instead, which
67
+ honours `proxy`, `https-proxy` and your `.npmrc`. It runs *only* after a
68
+ request that has already failed, so on an ordinary machine it never runs.
69
+ `/update status` shows `probe: npm` when this is what answered. No credentials
70
+ are read or forwarded — we run the command you could have typed.
71
+
72
+ - `/update status` gained `rollback`, `lastgood` and `probe` lines, so what the
73
+ guard did and what `--rollback` would reinstall are answerable without reading
74
+ the log.
75
+
76
+ ### Changed
77
+
78
+ - **`aragon update` exit codes: a blocked install is now `2`, not `1`.** This is
79
+ the one change here a script can notice. `1` means "try again later" and `2`
80
+ means "this machine will never auto-update, run the command we printed" — and
81
+ for `EPERM` / `EBUSY` / `ENOSPC` the second is the accurate one: waiting does
82
+ not unblock a held file handle or an empty disk. A caller shaped like
83
+ `aragon update || sleep 300 && retry` changes behaviour. `0`, and `1` for an
84
+ ordinary failed check or install, are unchanged.
85
+
86
+ - `bin.aragon` now points at `dist/launcher.js` rather than `dist/cli.js`.
87
+ `dist/cli.js` is unchanged, keeps its shebang and stays executable, so
88
+ `npm start` and any script invoking it directly keep working — only the mapping
89
+ moved.
90
+
91
+ - **`aragon` keeps itself up to date.** Until now the installed copy was frozen
92
+ forever: nothing in the CLI ever looked at the registry, so someone who
93
+ installed 0.4.x eighteen releases ago was still running it and the only signal
94
+ that anything had moved was a README they were never going to re-read.
95
+
96
+ There is now a background updater. At most once every four hours, and at most
97
+ once per machine per interval, it asks npm what the `latest` dist-tag resolves
98
+ to; if that version is genuinely newer, stable, not deprecated and runnable on
99
+ this Node, it installs it silently into the same global installation you
100
+ already have and says so on **one line above the composer**:
101
+
102
+ ```
103
+ * 0.6.0 installed - restart aragon to apply
104
+ ```
105
+
106
+ **The running process is never mutated in any way it can observe.** The new
107
+ version lands on disk and takes effect on the *next* launch. A restart in the
108
+ middle of a turn would destroy a live run, a subagent dispatch and an open plan
109
+ review, so the line waits and the human decides when.
110
+
111
+ The notice does not get its own row — it shares the row the toast stack and the
112
+ working line already share, behind both of them. A toast is a response to
113
+ something you did and wins outright; the working line is transient and would be
114
+ lost if deferred; the update line is persistent and loses nothing by waiting.
115
+ The practical effect is that **someone who is actually working never sees the
116
+ updater until they stop.**
117
+
118
+ It only ever runs `npm i -g` for one kind of installation: a global one where
119
+ no project manifest claims to own the version. pnpm, yarn, bun and volta are
120
+ each detected and get the correct command for *that* manager printed instead
121
+ of a command run on their behalf; `npx`, a project's `node_modules` and a
122
+ clone of this repo produce no line at all, because none of them is out of date
123
+ in any sense the user can act on. A global directory that cannot be written is
124
+ detected before anything is spawned, and npm exiting `0` into a *different*
125
+ prefix — which happens on any machine with `prefix=` in `.npmrc` or two Node
126
+ installations — is caught by re-reading the version from the directory we
127
+ classified, rather than being believed.
128
+
129
+ Every failure is silent: it logs, backs off exponentially, and says nothing
130
+ until the third consecutive one, at which point it says something actionable.
131
+ Four config keys (`update.mode`, `update.checkIntervalMs`, `update.registry`,
132
+ `update.distTag`), the flags `--update` / `--no-update`, the environment
133
+ variables `ARAGON_UPDATE` and `ARAGON_UPDATE_REGISTRY`, the slash command
134
+ `/update [status|now|skip|off]`, and a foreground `aragon update
135
+ [--check] [--to <version>] [--json]` for headless users. `update.mode: off`
136
+ and `ARAGON_UPDATE=0` are kill switches, and with either set the CLI executes
137
+ zero lines of update code.
138
+
139
+ Auto-update widens the window in which a compromised release reaches users
140
+ without a human decision. The README says so plainly, along with what is and
141
+ is not mitigated. No credentials are ever attached to the check.
142
+
143
+ - **A running command shows what it is doing.** `bash` is the only tool here that
144
+ can run for minutes — `npm test`, a `git clone`, a training job — and while it
145
+ ran, its card was one line of text that never changed. Nothing in that frame
146
+ distinguished a test suite at 40% from a child process blocked forever on a
147
+ password prompt this CLI will never show. Its card now carries the last eight
148
+ lines of what the command is printing, plus one footer row that reads
149
+ `(running)` or, once the child has been quiet for ten seconds,
150
+ `no output for 45s` — with the seconds advancing.
151
+
152
+ A `\r`-driven progress bar (npm, pip, curl, docker) is *one* line rewritten a
153
+ thousand times, and it renders as **one row counting up in place** rather than
154
+ a thousand rows of nearly the same string — including the ordinary case where
155
+ the bar emits no newline at all for its entire run.
156
+
157
+ Everything the tail shows is **stripped, not interpreted**: ANSI colour, cursor
158
+ motion, `\r`, `\b`, tabs and every other control byte are removed at the
159
+ boundary before a row is stored, so nothing can move a cursor inside a frame
160
+ the renderer believes it owns. It is bounded twice by construction — eight rows
161
+ per call, sixteen concurrent calls — so a command that writes 400 MB to stdout
162
+ costs a fixed number of retained rows.
163
+
164
+ It is a **display and nothing else**. The text the model receives is
165
+ byte-for-byte what it was; `Ctrl+O` does nothing while a command runs, because
166
+ expansion is a promise about stored content and there is no stored rest of a
167
+ 400 MB stream; `/save` during a run writes no tail, since a resumed one would
168
+ describe a process that died with the session; and at settle the card is
169
+ replaced by the authoritative result exactly as before.
170
+
171
+ New config key `liveToolOutput`, defaulting to **`true`** — unlike
172
+ `showThinking` below, this adds information rather than hiding it.
173
+ `aragon config set liveToolOutput false` (or `--no-live-tool-output`, or
174
+ `ARAGON_LIVE_TOOL_OUTPUT=0`, or the **Live output** row in `/settings`) turns it
175
+ off, and with it off no store is allocated and no recorder is attached: `bash`
176
+ is byte-identical to the build before this entry.
177
+
178
+ - **The working line stops guessing while a tool runs.** It reads
179
+ `⠙ Running bash` instead of rotating thinking-words. `running` covers the whole
180
+ turn, including the minutes the model is idle and a child process is doing the
181
+ work, so "Pondering" during a build was not calm — it was wrong. One row, no
182
+ digits, no clock: everything the row already promised still holds.
183
+
184
+ ### Changed
185
+
186
+ - **Reasoning blocks are now hidden by default.** `showThinking` is a new
187
+ top-level config key and it defaults to `false`. If you have been reading
188
+ thinking every day, this is the entry that concerns you: `Ctrl+T` still shows
189
+ it for the session exactly as before, `aragon config set showThinking true`
190
+ (or `--show-thinking`, or `ARAGON_SHOW_THINKING=1`) restores the old behaviour
191
+ permanently, and `/settings` has a **Show thinking** row directly under
192
+ **Thinking**.
193
+
194
+ Nothing is hidden silently. A settled turn that thought leaves one muted row
195
+ where the block used to be — `✱ thought for 12s · ctrl+t to show` — so the fact
196
+ that reasoning happened, how long it took, and how to see it are all still on
197
+ screen. In **inline** mode that row omits the key hint and the toast reads
198
+ `Thinking shown for new output.`, because a settled entry there has already
199
+ been printed into your terminal's scrollback and cannot be repainted; the
200
+ toggle applies to the live entry and to everything drawn after it.
201
+
202
+ `thinkingLevel` is untouched and means what it always did — the effort the
203
+ provider is asked to spend. `showThinking` is only whether the terminal draws
204
+ what came back. They are one word apart in the config file, which is why the
205
+ flag is `--show-thinking` rather than the shorter name.
206
+
207
+ ### Added
208
+
209
+ - **A live working line while a run is in flight.** One row above the composer,
210
+ carrying a spinner and a word that rotates every four seconds:
211
+ `⠋ Percolating…`. Take reasoning off the screen and the gap between submitting
212
+ and the first token is otherwise completely blank, which reads as dead rather
213
+ than as busy — the two changes are one change.
214
+
215
+ It carries no clock and no token count, deliberately: the status bar one row
216
+ below already renders both, under the same running condition and driven by the
217
+ same 200 ms ticker this row reuses. Under `reducedMotion` the spinner is a
218
+ static glyph and the word is chosen once and holds, because rotating text is
219
+ motion too. An idle frame is unchanged, and so is the viewport's row budget —
220
+ the line shares the row the toast strip already owned rather than adding one.
221
+
222
+ - **`write_file` and `edit_file` render a real diff.** Hunks with old/new line
223
+ numbers, a `+N -M` summary, add/remove/context colouring, and `(truncated)` or
224
+ a `binary` / `too-large` / `unreadable` note when the old side could not be
225
+ read. Diffs collapse at 12 rows behind the existing `Ctrl+O` — no new
226
+ keybinding. A resumed session written by an older build, or a card whose patch
227
+ the bounded store already evicted, falls back to the previous text preview;
228
+ nothing renders blank.
229
+
230
+ `write_file` previously reported creating a 300-line file as
231
+ `Wrote 8214 bytes to path`, and `edit_file`'s diff trimmed the common prefix
232
+ and suffix and rendered *everything* in between as one removed block followed
233
+ by one added block — for a `replace_all` touching line 40 and line 900, that
234
+ was 860 removed rows followed by 860 nearly identical added ones.
235
+
236
+ **The model's input got smaller, not larger.** The structured patch reaches the
237
+ screen on a CLI-local channel rather than through the tool result, and the text
238
+ the model reads gained a 4 000-character ceiling it did not have before (its
239
+ only previous bound was the executor's 100 KB backstop). A single-region edit
240
+ is byte-for-byte what it was plus one `@@` header; a multi-region edit is
241
+ strictly smaller. `write_file`'s result text is unchanged.
242
+
243
+ ### Changed
244
+
245
+ - **A stream that stops mid-answer is now a loud failure instead of a silent
246
+ truncated one.** All three provider adapters used to end their SSE loop by
247
+ yielding "done" with whatever had arrived, so a connection closed cleanly
248
+ half-way through an answer — a proxy idle cut, a load-balancer timeout, an
249
+ HTTP/2 GOAWAY — was indistinguishable from a completed reply. You got a
250
+ truncated answer and were told nothing.
251
+
252
+ Each adapter now reports the truncation, which is what lets it be retried and
253
+ recovered. An **abort** is explicitly excluded and still completes normally, and
254
+ a model that legitimately says nothing and stops is still a success.
255
+
256
+ This is deliberately **not** behind `--no-retry`: an adapter that reports a
257
+ truncated stream honestly should do so whether or not retry is enabled. A switch
258
+ that also disabled telling you the truth would be a mute button, not a kill
259
+ switch.
260
+
261
+ - **The mouse wheel now only ever scrolls.** A notch scrolls the transcript
262
+ three rows (a page with `Shift`), or the open overlay when there is one, no
263
+ matter where the pointer is sitting. Prompt history is recalled by `↑` / `↓`
264
+ alone, exactly as in Claude Code and Codex.
265
+
266
+ **This supersedes the 0.5.0 entry below**, which said the wheel "scrolls what
267
+ is under the pointer" and stepped prompt history one entry per notch when the
268
+ pointer was over the input box. That turned out to be wrong in use rather than
269
+ in principle: the pointer is not an instrument you aim in a TUI — it rests
270
+ wherever you last left it, which in a chat-shaped app is next to the thing you
271
+ type into. So the ordinary "scroll back and see what just happened" gesture
272
+ landed on the composer and replaced the draft with an old prompt, with no
273
+ error, no undo and nothing visibly connecting the gesture to the outcome. The
274
+ band that decided this was invisible too: its boundary was a measured row that
275
+ moved as the toast row, the hint row and the completion popup came and went, so
276
+ the same gesture could do two different things a second apart.
277
+
278
+ Nothing else about the wheel changes — same three rows per notch, same
279
+ `Shift`+wheel page, same `--no-mouse` / `ARAGON_MOUSE=0` / `mouse: false`
280
+ escape hatches, same `Shift`+drag for selecting text.
281
+
282
+ - **A long session stays as fast as a short one.** The TUI used to get slower as
283
+ a session grew and, past a threshold, stopped making progress at all. That was
284
+ structural rather than incidental: Ink has no output caching, so every frame
285
+ re-walked the entire mounted tree, re-measured every text node and
286
+ re-serialised the frame. The per-frame cost was therefore proportional to every
287
+ character the session had ever produced — and `transcriptWindow` bounded the
288
+ entry *count*, which bounds nothing when one entry can be fifty thousand lines.
289
+
290
+ Entries outside the visible band are no longer mounted. The viewport renders
291
+ what you can see plus a couple either side and replaces the rest with two
292
+ spacers of the right height, so the frame costs what the screen costs.
293
+ Scrolling, the `↑N` readout and the wheel routing are untouched. Because the
294
+ horizon is no longer a rendering budget, `transcriptWindow` rises from 300 to
295
+ 1000 and its ceiling from 2000 to 20000; an existing setting is still valid
296
+ and still clamps.
297
+
298
+ Syntax highlighting and markdown parsing are memoised on their input, so a
299
+ 200-line code block is tokenised once rather than thirty times a second for as
300
+ long as it stays on screen. Only the *parsed* form is cached and never a themed
301
+ one, so `/theme` still takes effect on the next frame.
302
+
303
+ Under genuine load the streaming interval widens — 33 ms up to a 320 ms
304
+ ceiling — so keystrokes and `Ctrl+C` do not queue behind renders. This is
305
+ visible rather than silent: a muted **`eco`** chip appears in the status bar
306
+ while it is in effect, because a user who cannot see why the stream got
307
+ chunkier will conclude the model got slower. `--no-render-governor`,
308
+ `renderGovernor: false` or `ARAGON_RENDER_GOVERNOR=0` turns it off;
309
+ `--max-render-interval 33` flattens the ladder without disabling the mechanism.
310
+
311
+ - **A live thinking block no longer grows without limit.** While an answer is
312
+ streaming, visible thinking is clamped to its newest 24 rows behind a
313
+ `... N earlier lines` marker, and the whole block renders again the moment the
314
+ answer settles. Thinking is scratch reasoning you read from its newest end, and
315
+ an unbounded one was the easiest way for a single live entry to fill the
316
+ viewport on its own.
317
+
318
+ ### Fixed
319
+
320
+ - **Inline mode could hard-freeze the terminal, and now cannot.** Once a live
321
+ entry grew taller than the terminal, Ink took a branch that writes
322
+ `clearTerminal` plus the *entire accumulated session history* on every
323
+ subsequent frame — bypassing both of its own dedupe gates, and growing without
324
+ bound for the rest of the session. Any inline user (`--no-fullscreen`,
325
+ `TERM=dumb`, CI, a terminal under 12 rows or 40 columns) whose model wrote a
326
+ long answer could reach it. The live region is now clamped below that
327
+ threshold, with a `... N earlier lines` marker naming what is deferred. Nothing
328
+ is lost: the entry prints in full into the terminal's own scrollback the moment
329
+ it settles.
330
+
331
+ - **The view state no longer grows without a ceiling.** A single assistant answer
332
+ is capped at 256 KiB in the view (thinking at 64 KiB, streamed tool arguments
333
+ at 16 KiB) by eliding the MIDDLE, so both the opening and the live cursor
334
+ survive; a marker states how many characters went. `transcriptRetain`
335
+ (default 1000) caps the entries kept in memory, and what it removed is counted
336
+ and reported both by `/perf` and at the top of the exit replay. A model that
337
+ emits five megabytes no longer makes every later frame a five-megabyte scan.
338
+
339
+ ### Added
340
+
341
+ - **A fast model tier: a second, cheaper model you can delegate to and be
342
+ reviewed by.** Off by default — with `fast.enabled: false` the system prompt,
343
+ the `task` schema, the transcript and the request payloads are byte-identical
344
+ to a build without it — and it does two things once you turn it on.
345
+
346
+ **Delegation.** `task` gains one optional field per subagent, `model: "fast"`.
347
+ A child marked that way runs on the fast model and is otherwise identical:
348
+ same tools, same working directory, same `--confirm` gate, same plan-mode
349
+ gate, same skills ceiling. Delegating to a cheaper model is a *model* choice,
350
+ never a permission boundary. It is where "not complicated, but very expensive
351
+ in context" gets paid for — a child that reads nine files and reports four
352
+ sentences moves the file bodies out of the lead's window and onto a model that
353
+ costs a fraction as much per token.
354
+
355
+ **Periodic review.** Every few turns a small digest of what the lead has been
356
+ doing goes to the fast model with one question — is this still on track? — and
357
+ a critique that is not "on track" is injected into the running loop as a
358
+ `<fast_review>` block, so the lead sees a second opinion while it can still
359
+ act on it:
360
+
361
+ ```
362
+ fast review #2 · claude-haiku-4-5 · turn 12 · 1.4s
363
+ You have edited config/schema.ts three times without running the tests.
364
+ ```
365
+
366
+ The digest is built from a bounded ring of recent turns and **never** from the
367
+ message history: sending a session's accumulated file bodies to the "cheap"
368
+ model would make a review cost more than the turn it reviews, which is the
369
+ inversion the whole feature exists to prevent.
370
+
371
+ Spend is attributed **per tier** — a fast child's tokens are priced at the
372
+ fast model's table, not the lead's, and the dispatch report states the two
373
+ separately. A model the built-in price table has never seen is reported as
374
+ `unknown` rather than as `$0.00`, because a feature that looks free while it
375
+ is spending money is worse than one that admits it does not know.
376
+
377
+ Turn it on with `/fast model <id>` then `/fast on`, with
378
+ `aragon config set fast.enabled true`, with `--fast --fast-model <id>`, or with
379
+ `ARAGON_FAST=1 ARAGON_FAST_MODEL=<id>`. `/fast status` is the guaranteed
380
+ readout: the resolved model, the budget, and this session's reviews, delegated
381
+ children, tokens and cost. Eleven `fast.*` config keys, four flags, four
382
+ environment variables and five settings-screen rows; see the README.
383
+
384
+ **The review has a session budget.** A session is not one run — it is one run
385
+ per message you send — so a cadence bounds the pace and nothing bounds the
386
+ total. `fast.reviewMaxPerSession` (default **40**, raisable live with
387
+ `/fast budget <n>`) is the number of reviews a session may *start*; reaching it
388
+ prints one `info` notice that names the remedy and says delegation is
389
+ unaffected, and `/fast status` reads `12/40` from the first review rather than a
390
+ bare count you can only size after the fact. It is denominated in **reviews,
391
+ not currency**, because the fast tier is exactly where a model the price table
392
+ has never seen lives — a dollar ceiling would silently never fire for the
393
+ configuration that most needs one. Delegation is never budgeted: it is spend the
394
+ lead chose in service of a message you sent, it is already bounded by `team.*`,
395
+ and it exists to *reduce* total cost.
396
+
397
+ **The review also fails fast, so it cannot compete with you.** It calls through
398
+ its own provider registry with **one** retry rather than the ten
399
+ `retry.maxRetries` defaults to for the lead, and it observes neither `retry.*`
400
+ nor `/retry` — that policy says how hard to fight for *your* answer, and
401
+ inheriting it for an unrequested background call is how an advisory ends up
402
+ spending a rate-limited provider's quota on itself. Its own wall-clock bound
403
+ is 20 s.
404
+
405
+ Two failure modes are handled out loud rather than silently. If the tier stops
406
+ resolving mid-session — you switch the main provider and `fast.provider` was
407
+ inheriting it — `model:"fast"` is downgraded to the main model, **counted, and
408
+ stated in the report**, because an agent that silently gets an expensive child
409
+ has no way to learn its cost model is wrong. And three consecutive
410
+ *misconfiguration* failures disable the reviewer for the session with exactly
411
+ one warning, while a merely busy provider (rate-limited or overloaded) is
412
+ treated as transient and never counts — that condition fixes itself, and a
413
+ session-long silent shutdown over it would not. A review you *cancelled* is
414
+ neither: Esc, a run that ends first, or quitting leaves a `cancelled` card and
415
+ no strike against the tier.
416
+
417
+ Reviews log under their own `fast` scope rather than under `agent`, so
418
+ `fast_review_*` records filter cleanly away from the lead's.
419
+
420
+ - **API calls are retried with backoff, and the waiting is legible.** A transient
421
+ provider failure — HTTP 429, 529, 5xx, 408, or a dropped connection — used to end
422
+ the turn. One red notice, an idle prompt, and forty tool calls of work thrown
423
+ away. It is now retried up to **10 times** with an increasing interval
424
+ (1 s → 2 → 4 → 8 → 16 → 30 s, equal-jittered, 30 s per wait at most) under a
425
+ 4-minute budget measured from the first failure.
426
+
427
+ What you see while it waits is **one line, rewritten in place** — never ten
428
+ notices — carrying what failed, which attempt this is, and a countdown to the
429
+ next one:
430
+
431
+ ```
432
+ ↻ Provider overloaded · retry 3/10 in 7s Esc to cancel
433
+ ↻ recovered after 3 retries · 12.4s
434
+ ```
435
+
436
+ plus a `retry 3/10 7s` chip on the status bar (`[r3]` on a narrow terminal). The
437
+ card settles into the transcript as history — `recovered`, `gave up`, or
438
+ `interrupted` — and shows up in the exit replay, because a turn that spent three
439
+ minutes retrying is exactly the kind of cost an exported transcript should
440
+ account for.
441
+
442
+ **Esc ends the wait within a frame**, not at the end of the countdown, and it
443
+ never produces a fabricated error: an aborted request is silent. That is the one
444
+ detail everything else here depends on, because the provider layer marks an
445
+ `AbortError` as retryable — so the signal is checked *before* the error, and a
446
+ user pressing Esc can never be mistaken for a timeout worth retrying.
447
+
448
+ Never retried: `auth_error` (401/403), `invalid_request`, `context_overflow`.
449
+ Ten retries of a bad API key is three minutes of looking broken.
450
+
451
+ `Retry-After` is honoured as a **floor**, never a replacement — a `Retry-After: 1`
452
+ on the ninth retry does not undo eight retries of backoff — and a stated wait
453
+ longer than a minute is surfaced immediately with the provider's own number
454
+ rather than silently wedging the terminal.
455
+
456
+ A connection that dies **mid-answer** is also covered, and this is the case that
457
+ needed more than a retry loop: the partial text is discarded, the affected tool
458
+ cards are removed, and the answer restarts from the top. Nothing is duplicated,
459
+ because the engine only writes history on a completed turn.
460
+
461
+ - **`/retry [show|on|off|max <n>]`, `--retry` / `--no-retry`, `--retry-max <n>`,
462
+ `ARAGON_RETRY`, `ARAGON_RETRY_MAX`, and a `retry` config section** with nine
463
+ keys (`aragon config set retry.*`). `/retry off` takes effect **in the running
464
+ session** — subagents included, since they share the lead's provider registry —
465
+ not only at the next launch. `retry.maxRetries: 0` is the kill switch and is a
466
+ real value at every one of those entry points. `/settings` gains one read-only
467
+ `API retries` row.
468
+
469
+ - **A subagent's retry is visible on the team card.** A child in backoff reports
470
+ `retry 3/10` on its own row. Children inherit the retry policy for free, but
471
+ their events never reach the lead's view, so without this a subagent spending
472
+ three minutes waiting looked exactly like a hung dispatch.
473
+
474
+ - **Retry lines in `-p` mode go to stderr, never stdout.** `[retry 3/10]
475
+ overloaded — waiting 7s` and `[retry] recovered after 3 retries` are on stderr,
476
+ so `aragon -p … | jq` stays valid; a discarded partial answer is announced there
477
+ too, because a piped consumer otherwise cannot tell a replay from a model that
478
+ repeated itself. They are not suppressed by `--quiet`: a three-minute pause with
479
+ no explanation is not a compact run, it is a hang.
480
+
481
+ - **`/perf`.** Reports what the renderer is actually doing: the frame interval
482
+ and the last commit cost, how many entries exist / are retained / were dropped
483
+ / are mounted, height-cache and render-cache occupancy, and the viewport
484
+ geometry. `/perf reset` clears the caches and returns the governor to its
485
+ fastest rung. Silent degradation is the one thing a claim of robustness cannot
486
+ afford, and this is the place that names it.
487
+
488
+ - **Three configuration keys**, each with a flag and an environment override:
489
+ `transcriptRetain` (`--transcript-retain`, `ARAGON_TRANSCRIPT_RETAIN`),
490
+ `renderGovernor` (`--render-governor` / `--no-render-governor`,
491
+ `ARAGON_RENDER_GOVERNOR`) and `maxRenderIntervalMs`
492
+ (`--max-render-interval`, `ARAGON_MAX_RENDER_INTERVAL_MS`). No migration and no
493
+ config version bump: a file written before they existed loads unchanged.
494
+ `transcriptRetain` is raised to `transcriptWindow` when the two conflict —
495
+ retaining less than you can scroll to would make part of the horizon
496
+ unreachable — and a startup notice names both numbers, because overriding a
497
+ value you typed and saying nothing is the one thing none of this may do.
498
+
499
+ - **Following the plan through, on a budget you can do arithmetic on.** A run
500
+ that ended with steps outstanding used to print one sentence and stop. It now
501
+ asks three questions the CLI already knew the answers to — did you abort it,
502
+ did it error, did the list move — and does one of three things.
503
+
504
+ With the default `notify` the sentence is unchanged, except that a run **you**
505
+ cancelled with `Esc` now says nothing at all: being told what you just
506
+ interrupted is the CLI answering a question nobody asked.
507
+
508
+ With `/todo follow auto` it continues the plan itself, after announcing
509
+ `Continuing with 4 remaining steps in 3s - Esc to stop.` Auto-continuation was
510
+ refused last release as "an unbounded cost loop wearing a helpful hat", and
511
+ that judgement stands — what changed is that the loop is now bounded first.
512
+ A continuation that completes no step buys exactly one more attempt; a single
513
+ plan is continued at most 25 times however productive it looks; and a re-plan
514
+ forgives the first counter but never the second, so a model that reshapes its
515
+ list every turn cannot lift the ceiling. A run that ended with an error never
516
+ auto-continues in any mode. `Esc` cancels, and so does typing anything.
517
+
518
+ Whatever sends the continuation — the timer or `/todo continue` — now sends
519
+ the numbered list of open steps rather than the words "continue with the
520
+ remaining todo items", so a plan whose `todo_write` has scrolled out of the
521
+ context window is still followed exactly. Neither path records that text in
522
+ your prompt history any more; it is not something you typed.
523
+
524
+ Under `-p` there is no grace window, because there is nobody there to use it,
525
+ which is precisely why the two counters rather than the human are the
526
+ protection there. `[todo] continuing (3 steps left)` and
527
+ `[todo] 3 steps unfinished` go to stderr, suppressed by `--quiet`, and an
528
+ unfinished plan still never changes the exit code.
529
+
530
+ New surfaces: `/todo follow <notify|auto|off>`; `--todo-follow <mode>`;
531
+ `ARAGON_TODO_FOLLOW`; and `todo.followThrough` in `config.json`. The default
532
+ is `notify`, so a session that does not ask for any of this behaves as it did.
533
+
534
+ - **A plan strip for inline mode.** Inline mode has no fixed frame and so no
535
+ rail, which left every pipe, every `CI=1`, every `TERM=dumb` terminal and
536
+ every window under twelve rows able to see `todo 3/7` but not *which* step was
537
+ running. There is now a one-row strip under the transcript —
538
+ `todo 3/7 > Adding the rail to AppShell +2 done` — windowed on the
539
+ same step the rail would have anchored on. It truncates rather than wrapping
540
+ and is exactly one row at every width, so the composer does not move.
541
+ `--no-todo-panel` hides it along with the rail.
542
+
543
+ ### Changed
544
+
545
+ - `npm run typecheck` now covers the test tree in both packages. `tsconfig.json`
546
+ excludes `__tests__` so the build never emits fixtures, and vitest transpiles
547
+ without typechecking — between the two, a widened required field could break
548
+ ten test files while `npm run build` and `npm test` were both green. Twelve
549
+ such errors had accumulated; all twelve were fixture drift and all twelve are
550
+ repaired, with no suppressions and no production type relaxed to accommodate a
551
+ fixture.
552
+
553
+ - **TODO planning, and a rail to watch it in.** For work with three or more
554
+ distinct steps the agent now keeps a visible plan: it writes a checklist with
555
+ a new `todo_write` tool, marks exactly one item in progress, and ticks it off
556
+ before starting the next. In full-screen mode the list is rendered as a
557
+ right-hand rail about a fifth of the terminal wide, windowed around the step
558
+ being worked on rather than sliced from the top. Ask for something small and
559
+ nothing appears — the prompt tells the model not to plan work it can finish in
560
+ one or two steps, and a one-item list against an empty plan is refused
561
+ outright, so a session that never plans has byte-identical layout to a build
562
+ without this feature.
563
+
564
+ The list is a projection of what the model believes, and that single rule
565
+ decides everything else: `/clear` keeps it (the conversation is still there),
566
+ `/reset` drops it, `/save` writes it and `/resume` restores it — and resuming
567
+ a session that carries no list CLEARS the current one rather than leaving a
568
+ plan on screen whose conversation has just been replaced. A finished plan
569
+ survives to the start of your next message so you get to see `7/7 done`; an
570
+ unfinished one survives "continue" and "now do the rest", then expires after
571
+ three unrelated turns rather than holding a fifth of the screen for the rest
572
+ of the session. A run that ends with items left over produces a notice and
573
+ `/todo continue`; nothing auto-continues on your behalf.
574
+
575
+ "One step at a time" is enforced by structure rather than asked for in a
576
+ prompt: any payload with two in-progress items is repaired down to one, and a
577
+ list with none promotes the first unfinished item. Whatever the model sends,
578
+ the panel has exactly one current row.
579
+
580
+ New surfaces: the `todo_write` tool; `/todo [status|on|off|panel on|off|clear|
581
+ continue]`; `--todo` / `--no-todo` and `--todo-panel` / `--no-todo-panel`;
582
+ `ARAGON_TODO=0`; and `todo.enabled` / `todo.panel` in `config.json` (a third
583
+ key, `todo.followThrough`, arrived with the follow-through entry above).
584
+ `panel` is
585
+ separate from `enabled` on purpose — a screen-reader user wants the planning
586
+ discipline without the column, and the system prompt varies one sentence to
587
+ match. Under `-p` the plan goes to stderr as `[todo] 3/7 <step>` lines,
588
+ suppressed by `--quiet`. Below 80 columns, behind an overlay, in inline mode
589
+ or on a short terminal the rail is not mounted and the counter appears in the
590
+ status bar instead; the transcript keeps at least 62 columns at every width.
591
+
592
+ - **Output token limits that cannot themselves fail a run.** Every model and
593
+ every provider now defaults to 64000 output tokens, and that number is
594
+ configurable from the TUI, from a flag, from `ARAGON_MAX_TOKENS`, and by hand
595
+ in `~/.aragon-agent/config.json`. Leave it alone and it stays 64000.
596
+
597
+ What is new is that the number is an *ambition*. `gpt-4o` caps at 16384 and
598
+ `gemini-1.5-pro` at 8192; sending 64000 to either is an HTTP 400 that ends the
599
+ turn with a raw provider string in the transcript. The cap is now clamped down
600
+ to whatever the target model actually accepts, from a per-model table plus
601
+ whatever the provider's own model list reports. For a model nothing knows — a
602
+ proxy, a `--base-url` endpoint, something that shipped last week — the request
603
+ goes out at 64000, and if the provider objects, `aragon` reads the real ceiling
604
+ out of the error text, repairs the request, sends it exactly once more, and
605
+ remembers the answer for the rest of the session. One warning line; the run
606
+ continues.
607
+
608
+ Two combinations that were a guaranteed 400 on every request are fixed with
609
+ it: `--thinking xhigh` asks for a 65536-token budget while Anthropic requires
610
+ `max_tokens` to be strictly greater than it, and OpenAI's reasoning family
611
+ (`o1`, `o3`, `gpt-5`) rejects the `max_tokens` parameter name outright in
612
+ favour of `max_completion_tokens`.
613
+
614
+ New surfaces: `/max-tokens [<n>|auto|default]`, which with no argument reports
615
+ the setting *and* the effective cap for the live model; an `Effective:` line
616
+ under the settings screen's `Max tokens` field, so a value the model will not
617
+ honour is visible before you save it; `--max-tokens auto`; and
618
+ `aragon config set maxTokens <n|auto|default>`, which echoes the value that was
619
+ actually stored rather than the one you typed.
620
+
621
+ - **Team subagents.** The agent can now hand independent parts of a job to up to
622
+ five short-lived subagents that run in parallel, then read one combined report
623
+ of what each of them found. It decides for itself whether to delegate, so a
624
+ session that never calls the new `task` tool is byte-for-byte the session that
625
+ existed before. On by default; `--no-team` or `team.enabled: false` turns it
626
+ off, and `aragon config set team.maxSubagents <n>` sets the width (1-10; the
627
+ 10 is a hard ceiling no config file can raise).
628
+
629
+ A subagent is a full agent with the same tools and working directory but no
630
+ memory of your conversation, so its brief has to be self-contained. It cannot
631
+ delegate further and it cannot ask you anything. Plan mode and a skill's
632
+ `allowed-tools` ceiling both reach one level down, so delegating is never a
633
+ way around either; `--confirm` queues subagent confirmations one at a time and
634
+ labels each with the subagent that is asking.
635
+
636
+ Subagents can message each other with `team_send` / `team_wait`, delivered by
637
+ attaching the message to the recipient's next tool result rather than
638
+ interrupting it. The limits are deliberate — 6 messages each, one every 15
639
+ seconds, 24 per dispatch — and every refusal is a plain result naming the
640
+ limit rather than an error, because an error invites the retry the limits
641
+ exist to prevent.
642
+
643
+ While a dispatch runs, a roster sits between the transcript and the composer
644
+ and the status bar carries `agents 3/5`; both disappear when it finishes and
645
+ the transcript keeps a card you can expand with `Ctrl+O`. `Esc` aborts every
646
+ subagent and returns the partial report. Under `-p` the transitions go to
647
+ stderr and the subagents' tokens are folded into the `[usage]` footer, so the
648
+ cost readout cannot under-report what the team spent.
649
+
650
+ Full documentation, including the limits table and how team mode interacts
651
+ with plan mode, skills and `--confirm`, is in the README.
652
+
653
+ - **The subagent roster now shows what each subagent is doing, and shows the
654
+ ones that are working.** Where every row used to say `thinking` for minutes at
655
+ a time, it now says `bash: npm test -w cli`, `read: src/api/routes.ts`,
656
+ `waiting for a2`, or the tail of the sentence the subagent is currently
657
+ writing. On a narrow terminal the same row falls back to a file name and a
658
+ program name rather than wrapping, and the elapsed clock keeps its place at
659
+ every width.
660
+
661
+ The five visible rows are now the five that matter: whatever is running comes
662
+ first, then whatever is queued, then the most recent results. Above five
663
+ subagents the old panel showed the five that had finished first and hid
664
+ everything still working behind `+3 more`, which is the opposite of what the
665
+ roster is for. `+3 more` now says how many of the hidden ones are still going.
666
+
667
+ - **A subagent no longer waits two minutes for a message nobody can send.**
668
+ `team_wait` now checks whether anyone could actually answer before it blocks:
669
+ if the teammate it named has already finished, does not exist, or is itself
670
+ waiting in a way that cannot be released in time, it returns straight away and
671
+ says which. Nothing is refused that could still have been answered — including
672
+ by a third teammate further down the chain — and the subagent is told what to
673
+ do instead rather than handed an error.
674
+
675
+ - **A subagent whose very first request dies on a rate limit is retried once.**
676
+ Only a genuine cold start qualifies: no turn completed and no tool ran, so
677
+ there is nothing to undo. It restarts after two seconds, the roster says
678
+ `starting (retry)`, and the report notes `retried 1x`. Pressing `Esc`, a
679
+ timeout, or any subagent that had already begun work is never retried.
680
+
681
+ ### Changed
682
+
683
+ - **`"maxTokens": null` in `config.json` now means AUTO** — use each model's own
684
+ ceiling, never above 64000. It previously resolved to 64000 by accident (the
685
+ layered resolver skipped `null`), and there was no way to express AUTO through
686
+ any supported write path. If you have a `null` there today, the only difference
687
+ is a downward clamp on models whose real ceiling is below 64000 — the direction
688
+ that prevents failures rather than causing them. Absent still means 64000, and
689
+ an explicit number still means that number.
690
+
691
+ - **`config.json` holds settings again.** The prompts you type are no longer
692
+ stored in it. They move to `~/.aragon-agent/prompt-history.jsonl` — one JSON
693
+ object per line, `0600` on POSIX — and the submit counter and the "notice
694
+ already shown" flag move to `~/.aragon-agent/state.json`. `↑` and `↓` behave
695
+ exactly as before.
696
+
697
+ Two things get better. Opening `config.json` to change your model no longer
698
+ means scrolling past a transcript of your own typing, and copying it to
699
+ another machine no longer carries your prompts along. And submitting a message
700
+ no longer rewrites the file that holds your API keys: `config.json` is written
701
+ when you change a setting, and at no other time.
702
+
703
+ **Your history and counters are migrated automatically, once, at the next
704
+ launch.** Nothing is printed, because nothing changes for you. The dead
705
+ `recentModels` key — which nothing has ever written — is dropped.
706
+
707
+ If you go back to 0.5.x after upgrading, that version does not know about the
708
+ new file and `↑` will look empty. Nothing has been lost: the entries are still
709
+ in `prompt-history.jsonl`, and upgrading again brings them back.
710
+
711
+ ### Added
712
+
713
+ - **`aragon history`** — `path`, `list` (`-n`, `--json`) and `clear --yes` for
714
+ the prompt history, alongside the existing `aragon logs` commands. Entries are
715
+ stored verbatim, so `clear` is how you erase them; `aragon config set
716
+ historyEnabled false` stops new ones being recorded without deleting or hiding
717
+ what is already there.
718
+
719
+ - **The mouse wheel scrolls what is under the pointer.** In full-screen mode the
720
+ wheel now scrolls the transcript three rows per notch (a page with `Shift`),
721
+ scrolls an open overlay when the pointer is over one, and steps prompt history
722
+ one entry per notch when the pointer is over the input box — the same code
723
+ path `↑` / `↓` use, so it inherits the rule that an in-progress draft is never
724
+ overwritten. A slim rail on the viewport's right edge shows where you are in
725
+ the conversation.
726
+
727
+ **This fixes a destructive bug.** Previously the wheel recalled prompt history
728
+ no matter where the pointer was, because the alternate screen makes terminals
729
+ translate each notch into arrow keys. Wheeling while composing a message
730
+ silently replaced the draft with an old prompt, and nothing scrolled.
731
+
732
+ **Selecting text with the mouse now requires `Shift`+drag** in most terminals.
733
+ That is the standard convention for "an application is tracking the mouse" and
734
+ it applies to everyone, including people who never scroll with the wheel — so
735
+ the first session says so once, in the transcript, and never again. Turn the
736
+ whole feature off with `--no-mouse`, `ARAGON_MOUSE=0`, or
737
+ `aragon config set mouse false`; the wheel then does nothing rather than
738
+ reverting to the old behaviour. Inline mode (`--no-fullscreen`) is untouched:
739
+ your terminal's own scrollback already does the right thing there.
740
+
741
+ Under `tmux` with `mouse on`, tmux keeps the wheel for itself and the app
742
+ never sees it. `set -g mouse off` hands it back.
743
+
744
+ ### Changed
745
+
746
+ - **Your files moved to `~/.aragon-agent/`.** Config, sessions, installed skills
747
+ and the usage counters now live in one directory in your home — on Windows
748
+ `C:\Users\<you>\.aragon-agent\`, and the same path on macOS and Linux. They
749
+ used to be split across `%APPDATA%\aragon-agent-nodejs\Config` and
750
+ `%LOCALAPPDATA%\aragon-agent-nodejs\Data` (or the XDG equivalents), which are
751
+ correct locations and terrible answers to "where do I change the model?".
752
+
753
+ **The move happens once, automatically, on first launch, and prints a line on
754
+ stderr when it does.** Nothing is deleted: `config.json` is COPIED rather than
755
+ moved, and the old directories are left where they are, so reinstalling 0.5.0
756
+ remains lossless. `aragon config home` prints the new location and names the
757
+ old ones. Once you are satisfied, you can delete them yourself.
758
+
759
+ `ARAGON_HOME` relocates the whole tree. It has to be a real environment
760
+ variable — the path is resolved before any `.env` is read, so putting it in a
761
+ `.env` will not work. `aragon config home` always prints what is actually in
762
+ use.
763
+
764
+ ### Added
765
+
766
+ - **Logging.** Records go to `~/.aragon-agent/logs/aragon-<date>.log` as JSON
767
+ Lines: startup and exit, config writes, turn boundaries with token counts,
768
+ tool names with durations, skill loads, and every uncaught error. Files rotate
769
+ by day and by size (`log.maxFileBytes`, default 5 MiB) and the oldest beyond
770
+ `log.maxFiles` (default 10) are deleted.
771
+
772
+ **`info`, the default, records no conversation content**, so attaching a log
773
+ to a bug report is safe. `--log-level debug` (or `--verbose`) adds prompts,
774
+ replies and tool arguments truncated to `log.previewChars`; `trace` adds them
775
+ in full. Those two write what you typed — check before sharing one.
776
+
777
+ API keys are removed at every level by two independent passes: fields whose
778
+ name looks like a credential are blanked whatever they hold, and every string
779
+ is scanned both for known key formats and for the literal keys this process is
780
+ holding — which is what covers a custom endpoint whose key looks like nothing
781
+ in particular. `log.redactSecrets false` turns both off and warns you on
782
+ stdout when you set it.
783
+
784
+ Nothing is ever uploaded. There is no network path out of this subsystem.
785
+
786
+ New commands: `aragon logs path | list | tail [-n N] [--follow] [--level lv]
787
+ [--json] | clear --yes | open`, and `/logs` inside the TUI. New flags:
788
+ `--log-level`, `--verbose`, `--log-file` / `--no-log-file`, `--log-dir`. New
789
+ environment variables: `ARAGON_LOG_LEVEL`, `ARAGON_LOG_FILE`, `ARAGON_LOG_DIR`
790
+ — these three, unlike `ARAGON_HOME`, can come from a `.env`.
791
+
792
+ - **`aragon config get <key>` / `list [--json]` / `edit` / `home`.** `get` and
793
+ `list` mask every secret, `--json` included. `edit` opens `config.json` in
794
+ `$VISUAL` / `$EDITOR` (`notepad` on Windows), takes a `config.json.bak` first,
795
+ and re-parses on exit — an invalid edit is reported immediately, and the
796
+ backup is named in the message.
797
+
798
+ - **`/reload`** re-reads `config.json` into the running session, for when you
799
+ have edited it in another window. Refused while a run is in progress: swapping
800
+ the model mid-turn would let the second half of an answer come from different
801
+ settings than the first, with nothing afterwards able to explain the result.
802
+
803
+ - **Log level in the settings screen**, alongside provider / model / thinking.
804
+ The rest of the log settings — and `redactSecrets` above all — stay
805
+ command-line-only, so the one switch that can put credentials on disk cannot
806
+ be flipped with an arrow key.
807
+
808
+ ### Fixed
809
+
810
+ - **A malformed `config.json` no longer resets everything in silence.** A stray
811
+ comma used to send the model, theme, timeouts, skills and (as far as you could
812
+ tell) your API key back to defaults, with nothing anywhere explaining it. The
813
+ fallback is unchanged — a bad config still never stops the CLI from starting —
814
+ but it now says so, and records why.
815
+
816
+ - **Ctrl+C now flushes pending log records in every mode.** The signal handlers
817
+ only existed in the full-screen branch, so `-p`, the inline renderer and every
818
+ subcommand took Node's default termination, which does not run exit handlers.
819
+
820
+ ### Added
821
+
822
+ - **Plan mode.** `Shift+Tab` toggles between `BUILD` (everything as before) and
823
+ `PLAN`, a read-only research-and-design posture. `/plan [on|off|status]` is a
824
+ first-class equivalent for terminals that swallow `CSI Z`, and `--plan` /
825
+ `--no-plan` / `ARAGON_PLAN=1` / `planModeDefault` cover the startup case.
826
+
827
+ In `PLAN`, `write_file`, `edit_file`, `bash`, `skill_install` and
828
+ `skill_create` are refused **at the tool boundary**, so read-only is a
829
+ property of the wiring rather than a promise in a prompt. `bash` is refused in
830
+ full, `git status` included: a shell string cannot be classified reliably, and
831
+ a gate that is right most of the time is worse than one that is always right,
832
+ because you stop trusting the badge. The refusal names `read_file` / `glob` /
833
+ `grep` as the alternatives.
834
+
835
+ Two tools exist only while a human is attached. `ask_user` renders a
836
+ keyboard-driven wizard - 1-5 questions, 2-4 options each, exactly one marked
837
+ `RECOMMENDED`, plus an `Other...` free-text option - where pressing `Enter`
838
+ through the wizard accepts every recommendation. `submit_plan` renders the
839
+ plan as a scrollable card: `a` approves, `r` sends written feedback (`<-`
840
+ returns to the card), `Esc` dismisses. **Approving flips the session to
841
+ `BUILD` immediately and the same run continues into implementation.**
842
+
843
+ Dismissing a plan asks for a better one rather than stopping - the agent is
844
+ told to refine and resubmit - so the way out of a run is `Esc` twice: the
845
+ first closes the card, the second aborts the run.
846
+
847
+ Toggling mid-run is asymmetric on purpose: `build -> plan` applies at once,
848
+ `plan -> build` is deferred to the end of the run (the status bar shows
849
+ `PLAN -> BUILD` meanwhile) so a run launched under a read-only guarantee
850
+ cannot start writing files because of one stray keypress.
851
+
852
+ `aragon -p --plan "..."` registers no question or plan tool - there is nobody
853
+ to ask - but the read-only gate still applies, so it means "tell me how you
854
+ would do this, and do not touch my repository".
855
+
856
+ - Three flat config keys: `planModeDefault` (default `false`),
857
+ `planModeMaxAskRounds` (default `4`, clamped `[1, 10]`) and
858
+ `planModeHumanTimeoutMs` (default `1800000`, clamped `[60000, 7200000]`). All
859
+ three are settable with `aragon config set`. Additive, as always: a config
860
+ file written by an earlier version loads unchanged.
861
+
862
+ ### Fixed
863
+
864
+ - A `--confirm` prompt no longer races the idle watchdog. Taking longer than
865
+ `idleTimeoutMs` over `Proceed? (y/N)` used to abort the run with no
866
+ explanation; every human wait now suspends the watchdog and restarts it in a
867
+ `finally`.
868
+
869
+ - Honor an explicit `NODE_TLS_REJECT_UNAUTHORIZED=0` setting in the CLI and the
870
+ official npm release workflow while hiding only Node's standard insecure-TLS
871
+ warning. Other process warnings remain visible.
872
+
873
+ ## 0.5.0
874
+
875
+ ### Breaking
876
+
877
+ - **The package is renamed `@argon-agent/cli` → `@aragon-agent/cli`.** The brand
878
+ was always meant to be *Aragon*, matching AragonMesh; the missing `a` was a
879
+ typo that reached the registry. Install with:
880
+
881
+ ```
882
+ npm uninstall -g @argon-agent/cli
883
+ npm install -g @aragon-agent/cli
884
+ ```
885
+
886
+ `@argon-agent/cli` is deprecated and receives no further releases. **The
887
+ executable is still `aragon`** — the command you type does not change.
888
+
889
+ - **Environment variables are `ARAGON_*`, not `ARGON_*`.** There is no
890
+ compatibility fallback: `ARGON_MODEL`, `ARGON_PROVIDER`, `ARGON_BASE_URL`,
891
+ `ARGON_THINKING`, `ARGON_MAX_TOKENS`, `ARGON_THEME`, `ARGON_FULLSCREEN`,
892
+ `ARGON_SKILLS`, `ARGON_SKILLS_DISABLED`, `ARGON_SKILLS_PATH` and
893
+ `ARGON_REDUCED_MOTION` are all ignored from this release on. Rename them in
894
+ your shell profile and CI. Provider keys (`ANTHROPIC_API_KEY`,
895
+ `OPENAI_API_KEY`, `GOOGLE_API_KEY`, `GEMINI_API_KEY`) are untouched.
896
+
897
+ - **The project-level skills directory is `.aragon/skills`, not
898
+ `.argon/skills`.** This one lives in your repository, so rename it yourself:
899
+
900
+ ```
901
+ git mv .argon .aragon
902
+ ```
903
+
904
+ A config file that already persisted the old default keeps working — an
905
+ explicitly saved `skills.projectDirs` still wins over the default — but the
906
+ shipped default is now `['.aragon/skills', '.claude/skills']`. Update it with
907
+ `aragon config set` if you want the new default.
908
+
909
+ ### Added
910
+
911
+ - **Automatic migration of your user-level state.** On first run, 0.5.0 moves
912
+ the `env-paths` config and data directories from `argon-agent` to
913
+ `aragon-agent` — your API key, sessions and installed skills come with it, and
914
+ each installed skill's `.argon-skill.json` manifest is renamed to
915
+ `.aragon-skill.json` so `skills update` and `skills uninstall` still recognise
916
+ it. The migration prints one line to **stderr**, runs once, and is skipped
917
+ entirely if the new directory already exists. If it fails for any reason the
918
+ CLI still starts; the old directory is never deleted when a cross-volume copy
919
+ was needed.
920
+
921
+ - The opening wordmark now reads `ARAGON` and is 52 columns wide (was 44).
922
+ Terminals between 52 and 55 columns show the single-line banner rather than a
923
+ clipped wordmark.
924
+
925
+ - **Skills.** A skill is a directory holding a `SKILL.md` (YAML frontmatter +
926
+ Markdown body) plus optional `reference/`, `scripts/` and `assets/`. Skills
927
+ reach the model through three levels of progressive disclosure: a name +
928
+ one-line "when to use" catalog in the system prompt (≤ 6 000 bytes total),
929
+ the full body only when the model calls the `skill` tool, and bundled files
930
+ only when it reads them with `read_file` / `bash`. A skill therefore costs a
931
+ line of context rather than its whole body. How many fit in Level 1 depends on
932
+ description length and language — roughly 30 with terse English descriptions,
933
+ roughly 10 with Chinese ones at the character cap; past that the catalog
934
+ truncates and `skill_find` covers the remainder.
935
+ - Four model-facing tools: `skill` (load), `skill_find` (search installed
936
+ skills), `skill_install` (install from a local directory, git repo, or https
937
+ `SKILL.md` / `.zip`) and `skill_create` (author a new one from a procedure the
938
+ agent just worked out).
939
+ - **`aragon skills update <name> | --all`**, with `--dry-run`, `--force` and
940
+ `--check`. Re-fetches from the source recorded in the install manifest,
941
+ preserving `installedAt` and recording `updatedAt` / `previousVersion`. Refuses
942
+ before downloading anything when the installed copy has local edits, and
943
+ re-validates the source against the *current* `skills.allowedHosts` rather than
944
+ the one in force at install time. Not exposed to the model.
945
+ - **Catalog ranking.** Level 1 entries are ordered by scope, then by how recently
946
+ and often each skill was used, so truncation drops what you do not use rather
947
+ than what sorts last alphabetically. With no usage data the order is unchanged.
948
+ - **`skill_find`**, advertised in the prompt only when the catalog actually
949
+ truncated. Searches installed skills by name, description and keyword; never
950
+ reaches the network, never returns `activation: manual` skills, and tells the
951
+ model to ask for a source rather than invent one when nothing matches.
952
+ - **Cross-process install lock.** Install / create / remove / update take a
953
+ per-directory advisory lock, closing a race in which two concurrent installs
954
+ could interleave their atomic-replace steps and delete a skill with no error.
955
+ Self-expires after 60 s; waits at most 5 s; only ever released by its owner.
956
+ - **Load-time integrity.** Discovery re-checks `SKILL.md` against the sha256
957
+ recorded at install, at no extra I/O. `skills.integrity` selects
958
+ `off` / `warn` (default) / `strict`.
959
+ - **Local usage counters** at `<data>/skill-usage.json` — skill name, count and
960
+ timestamp only, never transmitted, disabled with `skills.usageTracking=false`.
961
+ Automatically injected `activation: always` skills are not counted.
962
+ - Config keys `skills.integrity` and `skills.usageTracking`; `aragon skills list
963
+ --sort=recent` and `/skills list --sort=recent`.
964
+ - Every usable skill also becomes a slash command: `/<skill-name> [args]`, with
965
+ `$ARGUMENTS` / `$1..$9` substitution. On a name clash the built-in command
966
+ always wins and the skill is reachable as `/skill:<name>`.
967
+ - `/skills` management: `list`, `info`, `install`, `remove`, `enable`,
968
+ `disable`, `reload`, `create`, `trust`, `untrust`.
969
+ - `aragon skills …` non-interactive equivalents plus `path` and `doctor`.
970
+ Exit codes follow `config set`: `0` ok, `1` run-time failure, `2` usage.
971
+ - Four discovery scopes in ascending precedence: bundled (`<pkg>/skills`), user
972
+ (`<data>/skills`), project (`<cwd>/.aragon/skills` and, read-only,
973
+ `<cwd>/.claude/skills` for Claude Code interop), and `ARAGON_SKILLS_PATH`.
974
+ - New flags `--no-skills`, `--skill <name>` (repeatable) and `--skills-yes`;
975
+ env `ARAGON_SKILLS`, `ARAGON_SKILLS_PATH`, `ARAGON_SKILLS_DISABLED`; config keys
976
+ `skills.enabled`, `skills.requireApproval`, `skills.catalogMaxBytes`,
977
+ `skills.bodyMaxBytes`.
978
+ - One bundled skill, `skill-creator`, documenting how to write a good one.
979
+ - New runtime dependency: `fflate` (~30 KB, MIT, zero transitive deps) for zip
980
+ extraction. `@aragon-agent/core` gains no dependency.
981
+ - **Release tooling for the scope change.** `npm run verify:brand` scans every
982
+ file that `npm pack` would put in the tarball — README and `dist/` included —
983
+ and blocks the release on any surviving `argon` reference, with only the four
984
+ documented exceptions (the two CHANGELOGs and the legacy-state migration
985
+ module, which hold the old names by definition). `packages/cli` also gains a
986
+ `prepublishOnly: npm run build`, so a publish that bypasses
987
+ `publish-latest.ps1` can no longer ship a `dist/` that is out of step with the
988
+ sources. `deprecate-legacy.ps1` retires `@argon-agent/*` on the registry, and
989
+ refuses to do so until the replacements are actually published.
990
+
991
+ ### Changed
992
+
993
+ - The globally installed executable is now `aragon`. The previous `argon` and
994
+ `argon-agent` aliases are no longer installed.
995
+ - `config/store.ts` now deep-merges the `skills` section on both read and write,
996
+ the same treatment `apiKeys` already received. Without it a partial patch such
997
+ as the one `/skills disable` sends would replace the whole section and
998
+ silently discard `trustedProjectDirs`, `allowedHosts` and `requireApproval`.
999
+ - `slashSuggestions` accepts `-` and `:`, so kebab-case and `skill:`-namespaced
1000
+ commands autocomplete. Previously `/my-sk` produced no popup at all.
1001
+ - `AgentController` now has a single `agent.setSystemPrompt()` call site, so a
1002
+ `/cwd` change can no longer drop the skill catalog out of the prompt.
1003
+ - With skills off or none installed, the system prompt and the 7-tool array are
1004
+ byte-identical to the previous release.
1005
+ - Added a repository-level PowerShell release workflow that automatically
1006
+ updates CLI and Core versions, synchronizes their dependency and lockfile,
1007
+ verifies both tarballs, and publishes them in dependency order.
1008
+
1009
+ ### Security
1010
+
1011
+ - Installing a skill requires an explicit human approval that **probes for a
1012
+ human first and refuses when there is none**. Under `-p` there is no TUI and
1013
+ therefore no approver, so `skill_install` is refused with an actionable
1014
+ message rather than writing a third-party directory unattended. Use
1015
+ `--skills-yes` (or `skills.requireApproval=false`) to opt out deliberately.
1016
+ - Project skill directories require a one-time trust confirmation before they
1017
+ are loaded — cloning an unfamiliar repository does not grant it the ability
1018
+ to inject instructions into your session.
1019
+ - Git is invoked only via `execFile` with an argv array and `shell: false`, and
1020
+ owner / repo / ref / subdirectory fragments are whitelisted and refused if
1021
+ they begin with `-`. A leading dash matters even with a pure argv array:
1022
+ `--upload-pack=<program>` makes git execute that program.
1023
+ - Zip extraction is streamed and gated on **actually written** bytes, per-entry
1024
+ size, compression ratio and entry count, all of which can abort mid-archive.
1025
+ The size a zip *declares* is written by whoever built it and is never trusted.
1026
+ Path traversal, absolute entries, symlinks and Windows device names are
1027
+ refused, and a rejected archive is removed rather than left half-extracted.
1028
+ - Network fetches are `https:` only, restricted to `skills.allowedHosts`,
1029
+ re-checked on every redirect (max 3), size-capped, and refuse IP literals and
1030
+ loopback.
1031
+ - Nothing a skill ships is executed at install time, and the executable bit is
1032
+ not preserved. Scripts run only when the model invokes `bash` explicitly.
1033
+ There is no sandbox: approval blocks *silent* installation, it does not make
1034
+ a skill you approved safe.
1035
+
1036
+ ## 0.3.0
1037
+
1038
+ A full-screen TUI release. `@argon-agent/core` is untouched, no new runtime
1039
+ dependency is added, and the headless/print contract, exit codes, and
1040
+ slash-command semantics are unchanged. The 0.2.0 inline renderer remains
1041
+ available in full via `--no-fullscreen`.
1042
+
1043
+ ### Added
1044
+
1045
+ - **Full-screen mode (default).** `aragon` now takes over the terminal's
1046
+ alternate screen buffer — the same mechanism `vim` / `htop` / `lazygit` use.
1047
+ Your shell history is covered, not erased, and comes back untouched on exit.
1048
+ The frame is a fixed `rows - 1` tall, so **the composer and the status bar sit
1049
+ at the physical bottom of the screen from the very first frame**: empty
1050
+ session, long session, mid-scroll, or overlay open.
1051
+ - **Brand region.** A six-row gradient ASCII wordmark on a roomy empty session,
1052
+ degrading to a banner, then a single-line bar, then a bare wordmark as space
1053
+ runs out. Row 1 always begins with the brand glyph.
1054
+ - **Self-drawn scrolling.** `PgUp` / `PgDn` by the page, `Shift+↑` / `Shift+↓` by
1055
+ the line. The viewport auto-follows new output while pinned to the bottom;
1056
+ scrolling away shows `↑N` in the status bar plus a "N new lines" hint, and
1057
+ submitting a message always re-pins.
1058
+ - **Exit replay.** After leaving the alternate screen the session is replayed
1059
+ into the normal buffer as plain, colorless text, so the conversation does not
1060
+ evaporate with the screen. Turn it off with `--no-exit-transcript`.
1061
+ - **New flags** `--fullscreen` / `--no-fullscreen` / `--no-exit-transcript`, the
1062
+ env var `ARGON_FULLSCREEN=0|1`, and the config keys `fullscreen`,
1063
+ `exitTranscript`, and `transcriptWindow`.
1064
+ - **Automatic downgrade.** A non-TTY stdout, `TERM=dumb`, CI, and terminals under
1065
+ 12 rows / 40 columns fall back to the inline renderer. Only the non-TTY gate is
1066
+ un-overridable — `--fullscreen` beats the rest.
1067
+
1068
+ ### Changed
1069
+
1070
+ - The status bar lost its round border and is now exactly one row; it had been
1071
+ spending an eighth of a 24-row terminal framing a single line of text.
1072
+ - The toast strip holds a fixed row in full-screen mode, so the transcript no
1073
+ longer jumps as toasts appear and expire.
1074
+ - The composer is a rounded frame whose border color reports state (idle, has a
1075
+ draft, running, blurred by an overlay), with the completion popup above it.
1076
+ - `Ctrl+L` repaints the frame instead of writing a clear sequence. Ink dedupes
1077
+ identical output at two separate gates, so under a fixed frame the old
1078
+ approach erased the screen and then declined to redraw it.
1079
+ - `Shift+↑` / `Shift+↓` no longer recall prompt history — they scroll.
1080
+ - Full-screen mode routes `console.*` into the transcript as notices rather than
1081
+ letting Ink write them straight to stdout, which corrupts the frame's line
1082
+ accounting.
1083
+
1084
+ ### Known trade-offs
1085
+
1086
+ - The terminal's native scrollback and mouse wheel do not scroll the transcript
1087
+ in full-screen mode; use `PgUp` / `PgDn`, or run with `--no-fullscreen`.
1088
+ - Mouse tracking is deliberately left off: enabling it costs text selection and
1089
+ copy in most terminals.
1090
+ - Should a crash ever strand your terminal on the alternate screen, `reset`
1091
+ restores it. Four independent restore paths exist to prevent that: normal
1092
+ exit, `process.exit`, `SIGINT` / `SIGTERM` / `SIGHUP`, and Ink's own signal
1093
+ handling.
1094
+
1095
+ ## 0.2.0
1096
+
1097
+ A design-elevation & HCI-hardening release. No breaking changes: `@argon-agent/core`
1098
+ is untouched, no new runtime dependency is added, and the headless/print contract,
1099
+ exit codes, config keys, and slash-command semantics from 0.1.0 are unchanged.
1100
+
1101
+ ### Added
1102
+
1103
+ - **Real theming engine.** Distinct `dark` / `light` palettes with an `auto`
1104
+ resolution (`auto → dark`), color degradation across terminal depth
1105
+ (truecolor → 256 → 16 → monochrome), and an ASCII glyph fallback for terminals
1106
+ without Unicode. Honors `NO_COLOR`, `FORCE_COLOR`, `--no-color`, and
1107
+ `TERM=dumb`. Switch live with `/theme <auto|dark|light>` (persisted).
1108
+ - **Elegant chrome.** A gradient wordmark header that collapses to a slim sticky
1109
+ bar after the first turn, a first-run **Welcome / empty-state** card, and a
1110
+ status bar with a colored **context gauge** (threshold colors), a **tokens/sec**
1111
+ read-out while running, and a contextual hint.
1112
+ - **Legible tool output.** Colored unified diffs (green adds / red removes) and
1113
+ per-tool rich previews (`edit_file`/`write_file`/`read_file`/`bash`/`list_dir`/
1114
+ `glob`). Long previews collapse to 8 lines and expand with `Ctrl+O` or
1115
+ `/expand [n]`.
1116
+ - **Autocomplete.** A slash-command palette and `@file` path completion popup
1117
+ (`Tab`/`→` to complete, `Up`/`Down` to move, `Esc` to close).
1118
+ - **Full line editing.** Home/End, word jump/delete, kill-to-start/end, and
1119
+ multi-line vertical cursor navigation, with prompt-history recall at the edges.
1120
+ Unknown control/escape sequences are dropped instead of inserted.
1121
+ - **Reliability under load.** Ink `<Static>` finalization for settled entries and
1122
+ a streaming delta coalescer, so long/fast sessions stay flicker-free.
1123
+ - **Calm feedback.** Ephemeral, auto-dismissing **toasts** for transient acks;
1124
+ the transcript keeps only durable content (messages, tool cards, run errors).
1125
+ - `reducedMotion` config (also `ARGON_REDUCED_MOTION`; implied by `--no-color`)
1126
+ replaces spinners with a static glyph.
1127
+
1128
+ ### Changed
1129
+
1130
+ - History scrollback now uses the **native terminal scrollback** that `<Static>`
1131
+ prints into (this supersedes the never-implemented `PgUp`/`PgDn` promise).
1132
+
1133
+ ## 0.1.0
1134
+
1135
+ Initial release — a Claude-Code / Codex-style interactive terminal UI (TUI) on
1136
+ top of `@argon-agent/core`.
1137
+
1138
+ ### Added
1139
+
1140
+ - **Interactive TUI** (React + Ink): gradient header, streaming transcript with
1141
+ markdown + syntax highlighting, collapsible thinking blocks, live tool-call
1142
+ cards, a status bar (model / context % / tokens / cost / elapsed), and modal
1143
+ overlays (settings, model picker, help, confirm).
1144
+ - **Built-in toolset** wired into the core agent at full permission:
1145
+ `read_file`, `write_file`, `edit_file`, `list_dir`, `glob`, `grep`, `bash`.
1146
+ - **Layered configuration** (defaults → user file → env/`.env` → flags) with
1147
+ live in-TUI editing of provider / model / base URL / API keys / thinking level
1148
+ / max tokens. Secrets are masked and the config file is written `0600` on POSIX.
1149
+ - **One-shot / print mode** (`argon -p`) for scripting and piping, plus
1150
+ `argon config` / `argon config set` / `argon config path` / `argon models`.
1151
+ - **Session control**: abort (Esc), steer-while-running, follow-up queue,
1152
+ double-Ctrl-C exit, `/save` / `/resume` JSON sessions.
1153
+ - **Timeout invariant** (`idleTimeout ≥ toolTimeout`) so a long single tool run
1154
+ is never killed by the idle watchdog.
1155
+ - **Never-silent failures**: pre-flight API-key validation, error-StreamEvent
1156
+ rendering, and a guard that surfaces a swallowed agent error instead of a
1157
+ blank no-op (headless exits `1`/`2` accordingly).