@aragon-agent/cli 0.5.8 → 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 (156) hide show
  1. package/CHANGELOG.md +1157 -747
  2. package/README.md +1552 -1163
  3. package/dist/agent/coalesce.d.ts +13 -0
  4. package/dist/agent/coalesce.js +50 -11
  5. package/dist/agent/controller.d.ts +141 -2
  6. package/dist/agent/controller.js +396 -4
  7. package/dist/agent/headless.d.ts +8 -0
  8. package/dist/agent/headless.js +40 -0
  9. package/dist/agent/reducer.d.ts +245 -3
  10. package/dist/agent/reducer.js +490 -17
  11. package/dist/agent/retry-view.d.ts +68 -0
  12. package/dist/agent/retry-view.js +95 -0
  13. package/dist/agent/system-prompt.d.ts +11 -0
  14. package/dist/agent/system-prompt.js +2 -0
  15. package/dist/boot/guard.d.ts +135 -0
  16. package/dist/boot/guard.js +218 -0
  17. package/dist/boot/rollback.d.ts +86 -0
  18. package/dist/boot/rollback.js +185 -0
  19. package/dist/cli.js +368 -3
  20. package/dist/commands/builtins.d.ts +1 -1
  21. package/dist/commands/builtins.js +426 -2
  22. package/dist/commands/registry.d.ts +17 -0
  23. package/dist/config/app-paths.d.ts +31 -0
  24. package/dist/config/app-paths.js +37 -0
  25. package/dist/config/cli-commands.d.ts +79 -2
  26. package/dist/config/cli-commands.js +185 -3
  27. package/dist/config/env.d.ts +15 -3
  28. package/dist/config/env.js +143 -3
  29. package/dist/config/load.d.ts +66 -0
  30. package/dist/config/load.js +107 -1
  31. package/dist/config/schema.d.ts +268 -2
  32. package/dist/config/schema.js +288 -1
  33. package/dist/config/store.js +32 -1
  34. package/dist/fast/critique.d.ts +43 -0
  35. package/dist/fast/critique.js +62 -0
  36. package/dist/fast/digest.d.ts +42 -0
  37. package/dist/fast/digest.js +85 -0
  38. package/dist/fast/frames.d.ts +99 -0
  39. package/dist/fast/frames.js +180 -0
  40. package/dist/fast/limits.d.ts +98 -0
  41. package/dist/fast/limits.js +98 -0
  42. package/dist/fast/prompt.d.ts +72 -0
  43. package/dist/fast/prompt.js +94 -0
  44. package/dist/fast/resolve.d.ts +43 -0
  45. package/dist/fast/resolve.js +105 -0
  46. package/dist/fast/review-call.d.ts +99 -0
  47. package/dist/fast/review-call.js +130 -0
  48. package/dist/fast/reviewer.d.ts +248 -0
  49. package/dist/fast/reviewer.js +664 -0
  50. package/dist/fast/types.d.ts +128 -0
  51. package/dist/fast/types.js +14 -0
  52. package/dist/fast/wiring.d.ts +170 -0
  53. package/dist/fast/wiring.js +316 -0
  54. package/dist/launcher.d.ts +14 -0
  55. package/dist/launcher.js +43 -0
  56. package/dist/logging/install.d.ts +15 -1
  57. package/dist/logging/install.js +37 -4
  58. package/dist/logging/logger.d.ts +1 -1
  59. package/dist/session/persist.js +57 -1
  60. package/dist/team/normalize.d.ts +26 -1
  61. package/dist/team/normalize.js +23 -3
  62. package/dist/team/prompt.d.ts +11 -0
  63. package/dist/team/prompt.js +10 -0
  64. package/dist/team/report.d.ts +18 -0
  65. package/dist/team/report.js +27 -1
  66. package/dist/team/runtime.d.ts +13 -2
  67. package/dist/team/runtime.js +33 -6
  68. package/dist/team/subagent.d.ts +19 -1
  69. package/dist/team/subagent.js +72 -10
  70. package/dist/team/task-tool.d.ts +26 -0
  71. package/dist/team/task-tool.js +48 -4
  72. package/dist/team/types.d.ts +80 -1
  73. package/dist/tools/bash-tool.js +19 -3
  74. package/dist/tools/diff.d.ts +25 -5
  75. package/dist/tools/diff.js +72 -41
  76. package/dist/tools/file-change-store.d.ts +34 -0
  77. package/dist/tools/file-change-store.js +57 -0
  78. package/dist/tools/fs-tools.d.ts +26 -0
  79. package/dist/tools/fs-tools.js +62 -5
  80. package/dist/tools/index.d.ts +31 -0
  81. package/dist/tools/index.js +7 -1
  82. package/dist/tools/patch.d.ts +115 -0
  83. package/dist/tools/patch.js +453 -0
  84. package/dist/tools/terminal-output.d.ts +107 -0
  85. package/dist/tools/terminal-output.js +198 -0
  86. package/dist/tools/tool-output-store.d.ts +68 -0
  87. package/dist/tools/tool-output-store.js +102 -0
  88. package/dist/ui/ActivityLine.d.ts +48 -0
  89. package/dist/ui/ActivityLine.js +22 -0
  90. package/dist/ui/App.d.ts +11 -4
  91. package/dist/ui/App.js +359 -37
  92. package/dist/ui/BottomStatusRow.d.ts +65 -0
  93. package/dist/ui/BottomStatusRow.js +17 -0
  94. package/dist/ui/Composer.d.ts +1 -6
  95. package/dist/ui/Composer.js +2 -2
  96. package/dist/ui/PromptInput.d.ts +1 -15
  97. package/dist/ui/PromptInput.js +1 -38
  98. package/dist/ui/StatusBar.d.ts +37 -0
  99. package/dist/ui/StatusBar.js +5 -3
  100. package/dist/ui/TeamPanel.d.ts +5 -4
  101. package/dist/ui/TeamPanel.js +1 -1
  102. package/dist/ui/TodoPanel.d.ts +5 -4
  103. package/dist/ui/Transcript.d.ts +26 -3
  104. package/dist/ui/Transcript.js +76 -10
  105. package/dist/ui/UpdateLine.d.ts +44 -0
  106. package/dist/ui/UpdateLine.js +129 -0
  107. package/dist/ui/activity-phrases.d.ts +33 -0
  108. package/dist/ui/activity-phrases.js +50 -0
  109. package/dist/ui/entries/AssistantEntry.d.ts +20 -0
  110. package/dist/ui/entries/AssistantEntry.js +3 -2
  111. package/dist/ui/entries/DiffView.d.ts +67 -0
  112. package/dist/ui/entries/DiffView.js +103 -0
  113. package/dist/ui/entries/FastCard.d.ts +53 -0
  114. package/dist/ui/entries/FastCard.js +87 -0
  115. package/dist/ui/entries/RetryCard.d.ts +56 -0
  116. package/dist/ui/entries/RetryCard.js +60 -0
  117. package/dist/ui/entries/TeamCard.js +6 -1
  118. package/dist/ui/entries/ToolCard.d.ts +38 -1
  119. package/dist/ui/entries/ToolCard.js +68 -5
  120. package/dist/ui/glyphs.d.ts +9 -0
  121. package/dist/ui/glyphs.js +2 -0
  122. package/dist/ui/layout/AppShell.d.ts +13 -22
  123. package/dist/ui/layout/AppShell.js +3 -38
  124. package/dist/ui/layout/virtual-window.d.ts +1 -1
  125. package/dist/ui/layout/virtual-window.js +109 -5
  126. package/dist/ui/overlays/HelpOverlay.js +16 -2
  127. package/dist/ui/overlays/SettingsScreen.d.ts +82 -1
  128. package/dist/ui/overlays/SettingsScreen.js +147 -1
  129. package/dist/ui/transcript-text.js +27 -0
  130. package/dist/ui/use-wheel-routing.d.ts +16 -32
  131. package/dist/ui/use-wheel-routing.js +21 -38
  132. package/dist/update/classify-failure.d.ts +32 -0
  133. package/dist/update/classify-failure.js +60 -0
  134. package/dist/update/install-lock.d.ts +55 -0
  135. package/dist/update/install-lock.js +184 -0
  136. package/dist/update/install-source.d.ts +97 -0
  137. package/dist/update/install-source.js +218 -0
  138. package/dist/update/installer.d.ts +108 -0
  139. package/dist/update/installer.js +242 -0
  140. package/dist/update/limits.d.ts +111 -0
  141. package/dist/update/limits.js +111 -0
  142. package/dist/update/npm-view.d.ts +62 -0
  143. package/dist/update/npm-view.js +133 -0
  144. package/dist/update/registry.d.ts +52 -0
  145. package/dist/update/registry.js +161 -0
  146. package/dist/update/semver.d.ts +89 -0
  147. package/dist/update/semver.js +295 -0
  148. package/dist/update/service.d.ts +193 -0
  149. package/dist/update/service.js +636 -0
  150. package/dist/update/state.d.ts +103 -0
  151. package/dist/update/state.js +142 -0
  152. package/dist/update/types.d.ts +169 -0
  153. package/dist/update/types.js +68 -0
  154. package/package.json +3 -3
  155. package/dist/ui/layout/regions.d.ts +0 -55
  156. package/dist/ui/layout/regions.js +0 -52
package/CHANGELOG.md CHANGED
@@ -1,747 +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
- ### Changed
11
-
12
- - **A long session stays as fast as a short one.** The TUI used to get slower as
13
- a session grew and, past a threshold, stopped making progress at all. That was
14
- structural rather than incidental: Ink has no output caching, so every frame
15
- re-walked the entire mounted tree, re-measured every text node and
16
- re-serialised the frame. The per-frame cost was therefore proportional to every
17
- character the session had ever produced — and `transcriptWindow` bounded the
18
- entry *count*, which bounds nothing when one entry can be fifty thousand lines.
19
-
20
- Entries outside the visible band are no longer mounted. The viewport renders
21
- what you can see plus a couple either side and replaces the rest with two
22
- spacers of the right height, so the frame costs what the screen costs.
23
- Scrolling, the `↑N` readout and the wheel routing are untouched. Because the
24
- horizon is no longer a rendering budget, `transcriptWindow` rises from 300 to
25
- 1000 and its ceiling from 2000 to 20000; an existing setting is still valid
26
- and still clamps.
27
-
28
- Syntax highlighting and markdown parsing are memoised on their input, so a
29
- 200-line code block is tokenised once rather than thirty times a second for as
30
- long as it stays on screen. Only the *parsed* form is cached and never a themed
31
- one, so `/theme` still takes effect on the next frame.
32
-
33
- Under genuine load the streaming interval widens — 33 ms up to a 320 ms
34
- ceiling — so keystrokes and `Ctrl+C` do not queue behind renders. This is
35
- visible rather than silent: a muted **`eco`** chip appears in the status bar
36
- while it is in effect, because a user who cannot see why the stream got
37
- chunkier will conclude the model got slower. `--no-render-governor`,
38
- `renderGovernor: false` or `ARAGON_RENDER_GOVERNOR=0` turns it off;
39
- `--max-render-interval 33` flattens the ladder without disabling the mechanism.
40
-
41
- - **A live thinking block no longer grows without limit.** While an answer is
42
- streaming, visible thinking is clamped to its newest 24 rows behind a
43
- `... N earlier lines` marker, and the whole block renders again the moment the
44
- answer settles. Thinking is scratch reasoning you read from its newest end, and
45
- an unbounded one was the easiest way for a single live entry to fill the
46
- viewport on its own.
47
-
48
- ### Fixed
49
-
50
- - **Inline mode could hard-freeze the terminal, and now cannot.** Once a live
51
- entry grew taller than the terminal, Ink took a branch that writes
52
- `clearTerminal` plus the *entire accumulated session history* on every
53
- subsequent frame — bypassing both of its own dedupe gates, and growing without
54
- bound for the rest of the session. Any inline user (`--no-fullscreen`,
55
- `TERM=dumb`, CI, a terminal under 12 rows or 40 columns) whose model wrote a
56
- long answer could reach it. The live region is now clamped below that
57
- threshold, with a `... N earlier lines` marker naming what is deferred. Nothing
58
- is lost: the entry prints in full into the terminal's own scrollback the moment
59
- it settles.
60
-
61
- - **The view state no longer grows without a ceiling.** A single assistant answer
62
- is capped at 256 KiB in the view (thinking at 64 KiB, streamed tool arguments
63
- at 16 KiB) by eliding the MIDDLE, so both the opening and the live cursor
64
- survive; a marker states how many characters went. `transcriptRetain`
65
- (default 1000) caps the entries kept in memory, and what it removed is counted
66
- and reported both by `/perf` and at the top of the exit replay. A model that
67
- emits five megabytes no longer makes every later frame a five-megabyte scan.
68
-
69
- ### Added
70
-
71
- - **`/perf`.** Reports what the renderer is actually doing: the frame interval
72
- and the last commit cost, how many entries exist / are retained / were dropped
73
- / are mounted, height-cache and render-cache occupancy, and the viewport
74
- geometry. `/perf reset` clears the caches and returns the governor to its
75
- fastest rung. Silent degradation is the one thing a claim of robustness cannot
76
- afford, and this is the place that names it.
77
-
78
- - **Three configuration keys**, each with a flag and an environment override:
79
- `transcriptRetain` (`--transcript-retain`, `ARAGON_TRANSCRIPT_RETAIN`),
80
- `renderGovernor` (`--render-governor` / `--no-render-governor`,
81
- `ARAGON_RENDER_GOVERNOR`) and `maxRenderIntervalMs`
82
- (`--max-render-interval`, `ARAGON_MAX_RENDER_INTERVAL_MS`). No migration and no
83
- config version bump: a file written before they existed loads unchanged.
84
- `transcriptRetain` is raised to `transcriptWindow` when the two conflict —
85
- retaining less than you can scroll to would make part of the horizon
86
- unreachable — and a startup notice names both numbers, because overriding a
87
- value you typed and saying nothing is the one thing none of this may do.
88
-
89
- - **Following the plan through, on a budget you can do arithmetic on.** A run
90
- that ended with steps outstanding used to print one sentence and stop. It now
91
- asks three questions the CLI already knew the answers to — did you abort it,
92
- did it error, did the list move — and does one of three things.
93
-
94
- With the default `notify` the sentence is unchanged, except that a run **you**
95
- cancelled with `Esc` now says nothing at all: being told what you just
96
- interrupted is the CLI answering a question nobody asked.
97
-
98
- With `/todo follow auto` it continues the plan itself, after announcing
99
- `Continuing with 4 remaining steps in 3s - Esc to stop.` Auto-continuation was
100
- refused last release as "an unbounded cost loop wearing a helpful hat", and
101
- that judgement stands — what changed is that the loop is now bounded first.
102
- A continuation that completes no step buys exactly one more attempt; a single
103
- plan is continued at most 25 times however productive it looks; and a re-plan
104
- forgives the first counter but never the second, so a model that reshapes its
105
- list every turn cannot lift the ceiling. A run that ended with an error never
106
- auto-continues in any mode. `Esc` cancels, and so does typing anything.
107
-
108
- Whatever sends the continuation — the timer or `/todo continue` — now sends
109
- the numbered list of open steps rather than the words "continue with the
110
- remaining todo items", so a plan whose `todo_write` has scrolled out of the
111
- context window is still followed exactly. Neither path records that text in
112
- your prompt history any more; it is not something you typed.
113
-
114
- Under `-p` there is no grace window, because there is nobody there to use it,
115
- which is precisely why the two counters rather than the human are the
116
- protection there. `[todo] continuing (3 steps left)` and
117
- `[todo] 3 steps unfinished` go to stderr, suppressed by `--quiet`, and an
118
- unfinished plan still never changes the exit code.
119
-
120
- New surfaces: `/todo follow <notify|auto|off>`; `--todo-follow <mode>`;
121
- `ARAGON_TODO_FOLLOW`; and `todo.followThrough` in `config.json`. The default
122
- is `notify`, so a session that does not ask for any of this behaves as it did.
123
-
124
- - **A plan strip for inline mode.** Inline mode has no fixed frame and so no
125
- rail, which left every pipe, every `CI=1`, every `TERM=dumb` terminal and
126
- every window under twelve rows able to see `todo 3/7` but not *which* step was
127
- running. There is now a one-row strip under the transcript —
128
- `todo 3/7 > Adding the rail to AppShell +2 done` — windowed on the
129
- same step the rail would have anchored on. It truncates rather than wrapping
130
- and is exactly one row at every width, so the composer does not move.
131
- `--no-todo-panel` hides it along with the rail.
132
-
133
- ### Changed
134
-
135
- - `npm run typecheck` now covers the test tree in both packages. `tsconfig.json`
136
- excludes `__tests__` so the build never emits fixtures, and vitest transpiles
137
- without typechecking — between the two, a widened required field could break
138
- ten test files while `npm run build` and `npm test` were both green. Twelve
139
- such errors had accumulated; all twelve were fixture drift and all twelve are
140
- repaired, with no suppressions and no production type relaxed to accommodate a
141
- fixture.
142
-
143
- - **TODO planning, and a rail to watch it in.** For work with three or more
144
- distinct steps the agent now keeps a visible plan: it writes a checklist with
145
- a new `todo_write` tool, marks exactly one item in progress, and ticks it off
146
- before starting the next. In full-screen mode the list is rendered as a
147
- right-hand rail about a fifth of the terminal wide, windowed around the step
148
- being worked on rather than sliced from the top. Ask for something small and
149
- nothing appears — the prompt tells the model not to plan work it can finish in
150
- one or two steps, and a one-item list against an empty plan is refused
151
- outright, so a session that never plans has byte-identical layout to a build
152
- without this feature.
153
-
154
- The list is a projection of what the model believes, and that single rule
155
- decides everything else: `/clear` keeps it (the conversation is still there),
156
- `/reset` drops it, `/save` writes it and `/resume` restores it — and resuming
157
- a session that carries no list CLEARS the current one rather than leaving a
158
- plan on screen whose conversation has just been replaced. A finished plan
159
- survives to the start of your next message so you get to see `7/7 done`; an
160
- unfinished one survives "continue" and "now do the rest", then expires after
161
- three unrelated turns rather than holding a fifth of the screen for the rest
162
- of the session. A run that ends with items left over produces a notice and
163
- `/todo continue`; nothing auto-continues on your behalf.
164
-
165
- "One step at a time" is enforced by structure rather than asked for in a
166
- prompt: any payload with two in-progress items is repaired down to one, and a
167
- list with none promotes the first unfinished item. Whatever the model sends,
168
- the panel has exactly one current row.
169
-
170
- New surfaces: the `todo_write` tool; `/todo [status|on|off|panel on|off|clear|
171
- continue]`; `--todo` / `--no-todo` and `--todo-panel` / `--no-todo-panel`;
172
- `ARAGON_TODO=0`; and `todo.enabled` / `todo.panel` in `config.json` (a third
173
- key, `todo.followThrough`, arrived with the follow-through entry above).
174
- `panel` is
175
- separate from `enabled` on purpose — a screen-reader user wants the planning
176
- discipline without the column, and the system prompt varies one sentence to
177
- match. Under `-p` the plan goes to stderr as `[todo] 3/7 <step>` lines,
178
- suppressed by `--quiet`. Below 80 columns, behind an overlay, in inline mode
179
- or on a short terminal the rail is not mounted and the counter appears in the
180
- status bar instead; the transcript keeps at least 62 columns at every width.
181
-
182
- - **Output token limits that cannot themselves fail a run.** Every model and
183
- every provider now defaults to 64000 output tokens, and that number is
184
- configurable from the TUI, from a flag, from `ARAGON_MAX_TOKENS`, and by hand
185
- in `~/.aragon-agent/config.json`. Leave it alone and it stays 64000.
186
-
187
- What is new is that the number is an *ambition*. `gpt-4o` caps at 16384 and
188
- `gemini-1.5-pro` at 8192; sending 64000 to either is an HTTP 400 that ends the
189
- turn with a raw provider string in the transcript. The cap is now clamped down
190
- to whatever the target model actually accepts, from a per-model table plus
191
- whatever the provider's own model list reports. For a model nothing knows — a
192
- proxy, a `--base-url` endpoint, something that shipped last week — the request
193
- goes out at 64000, and if the provider objects, `aragon` reads the real ceiling
194
- out of the error text, repairs the request, sends it exactly once more, and
195
- remembers the answer for the rest of the session. One warning line; the run
196
- continues.
197
-
198
- Two combinations that were a guaranteed 400 on every request are fixed with
199
- it: `--thinking xhigh` asks for a 65536-token budget while Anthropic requires
200
- `max_tokens` to be strictly greater than it, and OpenAI's reasoning family
201
- (`o1`, `o3`, `gpt-5`) rejects the `max_tokens` parameter name outright in
202
- favour of `max_completion_tokens`.
203
-
204
- New surfaces: `/max-tokens [<n>|auto|default]`, which with no argument reports
205
- the setting *and* the effective cap for the live model; an `Effective:` line
206
- under the settings screen's `Max tokens` field, so a value the model will not
207
- honour is visible before you save it; `--max-tokens auto`; and
208
- `aragon config set maxTokens <n|auto|default>`, which echoes the value that was
209
- actually stored rather than the one you typed.
210
-
211
- - **Team subagents.** The agent can now hand independent parts of a job to up to
212
- five short-lived subagents that run in parallel, then read one combined report
213
- of what each of them found. It decides for itself whether to delegate, so a
214
- session that never calls the new `task` tool is byte-for-byte the session that
215
- existed before. On by default; `--no-team` or `team.enabled: false` turns it
216
- off, and `aragon config set team.maxSubagents <n>` sets the width (1-10; the
217
- 10 is a hard ceiling no config file can raise).
218
-
219
- A subagent is a full agent with the same tools and working directory but no
220
- memory of your conversation, so its brief has to be self-contained. It cannot
221
- delegate further and it cannot ask you anything. Plan mode and a skill's
222
- `allowed-tools` ceiling both reach one level down, so delegating is never a
223
- way around either; `--confirm` queues subagent confirmations one at a time and
224
- labels each with the subagent that is asking.
225
-
226
- Subagents can message each other with `team_send` / `team_wait`, delivered by
227
- attaching the message to the recipient's next tool result rather than
228
- interrupting it. The limits are deliberate — 6 messages each, one every 15
229
- seconds, 24 per dispatch — and every refusal is a plain result naming the
230
- limit rather than an error, because an error invites the retry the limits
231
- exist to prevent.
232
-
233
- While a dispatch runs, a roster sits between the transcript and the composer
234
- and the status bar carries `agents 3/5`; both disappear when it finishes and
235
- the transcript keeps a card you can expand with `Ctrl+O`. `Esc` aborts every
236
- subagent and returns the partial report. Under `-p` the transitions go to
237
- stderr and the subagents' tokens are folded into the `[usage]` footer, so the
238
- cost readout cannot under-report what the team spent.
239
-
240
- Full documentation, including the limits table and how team mode interacts
241
- with plan mode, skills and `--confirm`, is in the README.
242
-
243
- - **The subagent roster now shows what each subagent is doing, and shows the
244
- ones that are working.** Where every row used to say `thinking` for minutes at
245
- a time, it now says `bash: npm test -w cli`, `read: src/api/routes.ts`,
246
- `waiting for a2`, or the tail of the sentence the subagent is currently
247
- writing. On a narrow terminal the same row falls back to a file name and a
248
- program name rather than wrapping, and the elapsed clock keeps its place at
249
- every width.
250
-
251
- The five visible rows are now the five that matter: whatever is running comes
252
- first, then whatever is queued, then the most recent results. Above five
253
- subagents the old panel showed the five that had finished first and hid
254
- everything still working behind `+3 more`, which is the opposite of what the
255
- roster is for. `+3 more` now says how many of the hidden ones are still going.
256
-
257
- - **A subagent no longer waits two minutes for a message nobody can send.**
258
- `team_wait` now checks whether anyone could actually answer before it blocks:
259
- if the teammate it named has already finished, does not exist, or is itself
260
- waiting in a way that cannot be released in time, it returns straight away and
261
- says which. Nothing is refused that could still have been answered — including
262
- by a third teammate further down the chain — and the subagent is told what to
263
- do instead rather than handed an error.
264
-
265
- - **A subagent whose very first request dies on a rate limit is retried once.**
266
- Only a genuine cold start qualifies: no turn completed and no tool ran, so
267
- there is nothing to undo. It restarts after two seconds, the roster says
268
- `starting (retry)`, and the report notes `retried 1x`. Pressing `Esc`, a
269
- timeout, or any subagent that had already begun work is never retried.
270
-
271
- ### Changed
272
-
273
- - **`"maxTokens": null` in `config.json` now means AUTO** — use each model's own
274
- ceiling, never above 64000. It previously resolved to 64000 by accident (the
275
- layered resolver skipped `null`), and there was no way to express AUTO through
276
- any supported write path. If you have a `null` there today, the only difference
277
- is a downward clamp on models whose real ceiling is below 64000 — the direction
278
- that prevents failures rather than causing them. Absent still means 64000, and
279
- an explicit number still means that number.
280
-
281
- - **`config.json` holds settings again.** The prompts you type are no longer
282
- stored in it. They move to `~/.aragon-agent/prompt-history.jsonl` — one JSON
283
- object per line, `0600` on POSIX — and the submit counter and the "notice
284
- already shown" flag move to `~/.aragon-agent/state.json`. `↑` and `↓` behave
285
- exactly as before.
286
-
287
- Two things get better. Opening `config.json` to change your model no longer
288
- means scrolling past a transcript of your own typing, and copying it to
289
- another machine no longer carries your prompts along. And submitting a message
290
- no longer rewrites the file that holds your API keys: `config.json` is written
291
- when you change a setting, and at no other time.
292
-
293
- **Your history and counters are migrated automatically, once, at the next
294
- launch.** Nothing is printed, because nothing changes for you. The dead
295
- `recentModels` key — which nothing has ever written — is dropped.
296
-
297
- If you go back to 0.5.x after upgrading, that version does not know about the
298
- new file and `↑` will look empty. Nothing has been lost: the entries are still
299
- in `prompt-history.jsonl`, and upgrading again brings them back.
300
-
301
- ### Added
302
-
303
- - **`aragon history`** — `path`, `list` (`-n`, `--json`) and `clear --yes` for
304
- the prompt history, alongside the existing `aragon logs` commands. Entries are
305
- stored verbatim, so `clear` is how you erase them; `aragon config set
306
- historyEnabled false` stops new ones being recorded without deleting or hiding
307
- what is already there.
308
-
309
- - **The mouse wheel scrolls what is under the pointer.** In full-screen mode the
310
- wheel now scrolls the transcript three rows per notch (a page with `Shift`),
311
- scrolls an open overlay when the pointer is over one, and steps prompt history
312
- one entry per notch when the pointer is over the input box — the same code
313
- path `↑` / `↓` use, so it inherits the rule that an in-progress draft is never
314
- overwritten. A slim rail on the viewport's right edge shows where you are in
315
- the conversation.
316
-
317
- **This fixes a destructive bug.** Previously the wheel recalled prompt history
318
- no matter where the pointer was, because the alternate screen makes terminals
319
- translate each notch into arrow keys. Wheeling while composing a message
320
- silently replaced the draft with an old prompt, and nothing scrolled.
321
-
322
- **Selecting text with the mouse now requires `Shift`+drag** in most terminals.
323
- That is the standard convention for "an application is tracking the mouse" and
324
- it applies to everyone, including people who never scroll with the wheel — so
325
- the first session says so once, in the transcript, and never again. Turn the
326
- whole feature off with `--no-mouse`, `ARAGON_MOUSE=0`, or
327
- `aragon config set mouse false`; the wheel then does nothing rather than
328
- reverting to the old behaviour. Inline mode (`--no-fullscreen`) is untouched:
329
- your terminal's own scrollback already does the right thing there.
330
-
331
- Under `tmux` with `mouse on`, tmux keeps the wheel for itself and the app
332
- never sees it. `set -g mouse off` hands it back.
333
-
334
- ### Changed
335
-
336
- - **Your files moved to `~/.aragon-agent/`.** Config, sessions, installed skills
337
- and the usage counters now live in one directory in your home — on Windows
338
- `C:\Users\<you>\.aragon-agent\`, and the same path on macOS and Linux. They
339
- used to be split across `%APPDATA%\aragon-agent-nodejs\Config` and
340
- `%LOCALAPPDATA%\aragon-agent-nodejs\Data` (or the XDG equivalents), which are
341
- correct locations and terrible answers to "where do I change the model?".
342
-
343
- **The move happens once, automatically, on first launch, and prints a line on
344
- stderr when it does.** Nothing is deleted: `config.json` is COPIED rather than
345
- moved, and the old directories are left where they are, so reinstalling 0.5.0
346
- remains lossless. `aragon config home` prints the new location and names the
347
- old ones. Once you are satisfied, you can delete them yourself.
348
-
349
- `ARAGON_HOME` relocates the whole tree. It has to be a real environment
350
- variable — the path is resolved before any `.env` is read, so putting it in a
351
- `.env` will not work. `aragon config home` always prints what is actually in
352
- use.
353
-
354
- ### Added
355
-
356
- - **Logging.** Records go to `~/.aragon-agent/logs/aragon-<date>.log` as JSON
357
- Lines: startup and exit, config writes, turn boundaries with token counts,
358
- tool names with durations, skill loads, and every uncaught error. Files rotate
359
- by day and by size (`log.maxFileBytes`, default 5 MiB) and the oldest beyond
360
- `log.maxFiles` (default 10) are deleted.
361
-
362
- **`info`, the default, records no conversation content**, so attaching a log
363
- to a bug report is safe. `--log-level debug` (or `--verbose`) adds prompts,
364
- replies and tool arguments truncated to `log.previewChars`; `trace` adds them
365
- in full. Those two write what you typed — check before sharing one.
366
-
367
- API keys are removed at every level by two independent passes: fields whose
368
- name looks like a credential are blanked whatever they hold, and every string
369
- is scanned both for known key formats and for the literal keys this process is
370
- holding — which is what covers a custom endpoint whose key looks like nothing
371
- in particular. `log.redactSecrets false` turns both off and warns you on
372
- stdout when you set it.
373
-
374
- Nothing is ever uploaded. There is no network path out of this subsystem.
375
-
376
- New commands: `aragon logs path | list | tail [-n N] [--follow] [--level lv]
377
- [--json] | clear --yes | open`, and `/logs` inside the TUI. New flags:
378
- `--log-level`, `--verbose`, `--log-file` / `--no-log-file`, `--log-dir`. New
379
- environment variables: `ARAGON_LOG_LEVEL`, `ARAGON_LOG_FILE`, `ARAGON_LOG_DIR`
380
- — these three, unlike `ARAGON_HOME`, can come from a `.env`.
381
-
382
- - **`aragon config get <key>` / `list [--json]` / `edit` / `home`.** `get` and
383
- `list` mask every secret, `--json` included. `edit` opens `config.json` in
384
- `$VISUAL` / `$EDITOR` (`notepad` on Windows), takes a `config.json.bak` first,
385
- and re-parses on exit — an invalid edit is reported immediately, and the
386
- backup is named in the message.
387
-
388
- - **`/reload`** re-reads `config.json` into the running session, for when you
389
- have edited it in another window. Refused while a run is in progress: swapping
390
- the model mid-turn would let the second half of an answer come from different
391
- settings than the first, with nothing afterwards able to explain the result.
392
-
393
- - **Log level in the settings screen**, alongside provider / model / thinking.
394
- The rest of the log settings — and `redactSecrets` above all — stay
395
- command-line-only, so the one switch that can put credentials on disk cannot
396
- be flipped with an arrow key.
397
-
398
- ### Fixed
399
-
400
- - **A malformed `config.json` no longer resets everything in silence.** A stray
401
- comma used to send the model, theme, timeouts, skills and (as far as you could
402
- tell) your API key back to defaults, with nothing anywhere explaining it. The
403
- fallback is unchanged — a bad config still never stops the CLI from starting —
404
- but it now says so, and records why.
405
-
406
- - **Ctrl+C now flushes pending log records in every mode.** The signal handlers
407
- only existed in the full-screen branch, so `-p`, the inline renderer and every
408
- subcommand took Node's default termination, which does not run exit handlers.
409
-
410
- ### Added
411
-
412
- - **Plan mode.** `Shift+Tab` toggles between `BUILD` (everything as before) and
413
- `PLAN`, a read-only research-and-design posture. `/plan [on|off|status]` is a
414
- first-class equivalent for terminals that swallow `CSI Z`, and `--plan` /
415
- `--no-plan` / `ARAGON_PLAN=1` / `planModeDefault` cover the startup case.
416
-
417
- In `PLAN`, `write_file`, `edit_file`, `bash`, `skill_install` and
418
- `skill_create` are refused **at the tool boundary**, so read-only is a
419
- property of the wiring rather than a promise in a prompt. `bash` is refused in
420
- full, `git status` included: a shell string cannot be classified reliably, and
421
- a gate that is right most of the time is worse than one that is always right,
422
- because you stop trusting the badge. The refusal names `read_file` / `glob` /
423
- `grep` as the alternatives.
424
-
425
- Two tools exist only while a human is attached. `ask_user` renders a
426
- keyboard-driven wizard - 1-5 questions, 2-4 options each, exactly one marked
427
- `RECOMMENDED`, plus an `Other...` free-text option - where pressing `Enter`
428
- through the wizard accepts every recommendation. `submit_plan` renders the
429
- plan as a scrollable card: `a` approves, `r` sends written feedback (`<-`
430
- returns to the card), `Esc` dismisses. **Approving flips the session to
431
- `BUILD` immediately and the same run continues into implementation.**
432
-
433
- Dismissing a plan asks for a better one rather than stopping - the agent is
434
- told to refine and resubmit - so the way out of a run is `Esc` twice: the
435
- first closes the card, the second aborts the run.
436
-
437
- Toggling mid-run is asymmetric on purpose: `build -> plan` applies at once,
438
- `plan -> build` is deferred to the end of the run (the status bar shows
439
- `PLAN -> BUILD` meanwhile) so a run launched under a read-only guarantee
440
- cannot start writing files because of one stray keypress.
441
-
442
- `aragon -p --plan "..."` registers no question or plan tool - there is nobody
443
- to ask - but the read-only gate still applies, so it means "tell me how you
444
- would do this, and do not touch my repository".
445
-
446
- - Three flat config keys: `planModeDefault` (default `false`),
447
- `planModeMaxAskRounds` (default `4`, clamped `[1, 10]`) and
448
- `planModeHumanTimeoutMs` (default `1800000`, clamped `[60000, 7200000]`). All
449
- three are settable with `aragon config set`. Additive, as always: a config
450
- file written by an earlier version loads unchanged.
451
-
452
- ### Fixed
453
-
454
- - A `--confirm` prompt no longer races the idle watchdog. Taking longer than
455
- `idleTimeoutMs` over `Proceed? (y/N)` used to abort the run with no
456
- explanation; every human wait now suspends the watchdog and restarts it in a
457
- `finally`.
458
-
459
- - Honor an explicit `NODE_TLS_REJECT_UNAUTHORIZED=0` setting in the CLI and the
460
- official npm release workflow while hiding only Node's standard insecure-TLS
461
- warning. Other process warnings remain visible.
462
-
463
- ## 0.5.0
464
-
465
- ### Breaking
466
-
467
- - **The package is renamed `@argon-agent/cli` → `@aragon-agent/cli`.** The brand
468
- was always meant to be *Aragon*, matching AragonMesh; the missing `a` was a
469
- typo that reached the registry. Install with:
470
-
471
- ```
472
- npm uninstall -g @argon-agent/cli
473
- npm install -g @aragon-agent/cli
474
- ```
475
-
476
- `@argon-agent/cli` is deprecated and receives no further releases. **The
477
- executable is still `aragon`** — the command you type does not change.
478
-
479
- - **Environment variables are `ARAGON_*`, not `ARGON_*`.** There is no
480
- compatibility fallback: `ARGON_MODEL`, `ARGON_PROVIDER`, `ARGON_BASE_URL`,
481
- `ARGON_THINKING`, `ARGON_MAX_TOKENS`, `ARGON_THEME`, `ARGON_FULLSCREEN`,
482
- `ARGON_SKILLS`, `ARGON_SKILLS_DISABLED`, `ARGON_SKILLS_PATH` and
483
- `ARGON_REDUCED_MOTION` are all ignored from this release on. Rename them in
484
- your shell profile and CI. Provider keys (`ANTHROPIC_API_KEY`,
485
- `OPENAI_API_KEY`, `GOOGLE_API_KEY`, `GEMINI_API_KEY`) are untouched.
486
-
487
- - **The project-level skills directory is `.aragon/skills`, not
488
- `.argon/skills`.** This one lives in your repository, so rename it yourself:
489
-
490
- ```
491
- git mv .argon .aragon
492
- ```
493
-
494
- A config file that already persisted the old default keeps working — an
495
- explicitly saved `skills.projectDirs` still wins over the default — but the
496
- shipped default is now `['.aragon/skills', '.claude/skills']`. Update it with
497
- `aragon config set` if you want the new default.
498
-
499
- ### Added
500
-
501
- - **Automatic migration of your user-level state.** On first run, 0.5.0 moves
502
- the `env-paths` config and data directories from `argon-agent` to
503
- `aragon-agent` — your API key, sessions and installed skills come with it, and
504
- each installed skill's `.argon-skill.json` manifest is renamed to
505
- `.aragon-skill.json` so `skills update` and `skills uninstall` still recognise
506
- it. The migration prints one line to **stderr**, runs once, and is skipped
507
- entirely if the new directory already exists. If it fails for any reason the
508
- CLI still starts; the old directory is never deleted when a cross-volume copy
509
- was needed.
510
-
511
- - The opening wordmark now reads `ARAGON` and is 52 columns wide (was 44).
512
- Terminals between 52 and 55 columns show the single-line banner rather than a
513
- clipped wordmark.
514
-
515
- - **Skills.** A skill is a directory holding a `SKILL.md` (YAML frontmatter +
516
- Markdown body) plus optional `reference/`, `scripts/` and `assets/`. Skills
517
- reach the model through three levels of progressive disclosure: a name +
518
- one-line "when to use" catalog in the system prompt (≤ 6 000 bytes total),
519
- the full body only when the model calls the `skill` tool, and bundled files
520
- only when it reads them with `read_file` / `bash`. A skill therefore costs a
521
- line of context rather than its whole body. How many fit in Level 1 depends on
522
- description length and language — roughly 30 with terse English descriptions,
523
- roughly 10 with Chinese ones at the character cap; past that the catalog
524
- truncates and `skill_find` covers the remainder.
525
- - Four model-facing tools: `skill` (load), `skill_find` (search installed
526
- skills), `skill_install` (install from a local directory, git repo, or https
527
- `SKILL.md` / `.zip`) and `skill_create` (author a new one from a procedure the
528
- agent just worked out).
529
- - **`aragon skills update <name> | --all`**, with `--dry-run`, `--force` and
530
- `--check`. Re-fetches from the source recorded in the install manifest,
531
- preserving `installedAt` and recording `updatedAt` / `previousVersion`. Refuses
532
- before downloading anything when the installed copy has local edits, and
533
- re-validates the source against the *current* `skills.allowedHosts` rather than
534
- the one in force at install time. Not exposed to the model.
535
- - **Catalog ranking.** Level 1 entries are ordered by scope, then by how recently
536
- and often each skill was used, so truncation drops what you do not use rather
537
- than what sorts last alphabetically. With no usage data the order is unchanged.
538
- - **`skill_find`**, advertised in the prompt only when the catalog actually
539
- truncated. Searches installed skills by name, description and keyword; never
540
- reaches the network, never returns `activation: manual` skills, and tells the
541
- model to ask for a source rather than invent one when nothing matches.
542
- - **Cross-process install lock.** Install / create / remove / update take a
543
- per-directory advisory lock, closing a race in which two concurrent installs
544
- could interleave their atomic-replace steps and delete a skill with no error.
545
- Self-expires after 60 s; waits at most 5 s; only ever released by its owner.
546
- - **Load-time integrity.** Discovery re-checks `SKILL.md` against the sha256
547
- recorded at install, at no extra I/O. `skills.integrity` selects
548
- `off` / `warn` (default) / `strict`.
549
- - **Local usage counters** at `<data>/skill-usage.json` — skill name, count and
550
- timestamp only, never transmitted, disabled with `skills.usageTracking=false`.
551
- Automatically injected `activation: always` skills are not counted.
552
- - Config keys `skills.integrity` and `skills.usageTracking`; `aragon skills list
553
- --sort=recent` and `/skills list --sort=recent`.
554
- - Every usable skill also becomes a slash command: `/<skill-name> [args]`, with
555
- `$ARGUMENTS` / `$1..$9` substitution. On a name clash the built-in command
556
- always wins and the skill is reachable as `/skill:<name>`.
557
- - `/skills` management: `list`, `info`, `install`, `remove`, `enable`,
558
- `disable`, `reload`, `create`, `trust`, `untrust`.
559
- - `aragon skills …` non-interactive equivalents plus `path` and `doctor`.
560
- Exit codes follow `config set`: `0` ok, `1` run-time failure, `2` usage.
561
- - Four discovery scopes in ascending precedence: bundled (`<pkg>/skills`), user
562
- (`<data>/skills`), project (`<cwd>/.aragon/skills` and, read-only,
563
- `<cwd>/.claude/skills` for Claude Code interop), and `ARAGON_SKILLS_PATH`.
564
- - New flags `--no-skills`, `--skill <name>` (repeatable) and `--skills-yes`;
565
- env `ARAGON_SKILLS`, `ARAGON_SKILLS_PATH`, `ARAGON_SKILLS_DISABLED`; config keys
566
- `skills.enabled`, `skills.requireApproval`, `skills.catalogMaxBytes`,
567
- `skills.bodyMaxBytes`.
568
- - One bundled skill, `skill-creator`, documenting how to write a good one.
569
- - New runtime dependency: `fflate` (~30 KB, MIT, zero transitive deps) for zip
570
- extraction. `@aragon-agent/core` gains no dependency.
571
- - **Release tooling for the scope change.** `npm run verify:brand` scans every
572
- file that `npm pack` would put in the tarball — README and `dist/` included —
573
- and blocks the release on any surviving `argon` reference, with only the four
574
- documented exceptions (the two CHANGELOGs and the legacy-state migration
575
- module, which hold the old names by definition). `packages/cli` also gains a
576
- `prepublishOnly: npm run build`, so a publish that bypasses
577
- `publish-latest.ps1` can no longer ship a `dist/` that is out of step with the
578
- sources. `deprecate-legacy.ps1` retires `@argon-agent/*` on the registry, and
579
- refuses to do so until the replacements are actually published.
580
-
581
- ### Changed
582
-
583
- - The globally installed executable is now `aragon`. The previous `argon` and
584
- `argon-agent` aliases are no longer installed.
585
- - `config/store.ts` now deep-merges the `skills` section on both read and write,
586
- the same treatment `apiKeys` already received. Without it a partial patch such
587
- as the one `/skills disable` sends would replace the whole section and
588
- silently discard `trustedProjectDirs`, `allowedHosts` and `requireApproval`.
589
- - `slashSuggestions` accepts `-` and `:`, so kebab-case and `skill:`-namespaced
590
- commands autocomplete. Previously `/my-sk` produced no popup at all.
591
- - `AgentController` now has a single `agent.setSystemPrompt()` call site, so a
592
- `/cwd` change can no longer drop the skill catalog out of the prompt.
593
- - With skills off or none installed, the system prompt and the 7-tool array are
594
- byte-identical to the previous release.
595
- - Added a repository-level PowerShell release workflow that automatically
596
- updates CLI and Core versions, synchronizes their dependency and lockfile,
597
- verifies both tarballs, and publishes them in dependency order.
598
-
599
- ### Security
600
-
601
- - Installing a skill requires an explicit human approval that **probes for a
602
- human first and refuses when there is none**. Under `-p` there is no TUI and
603
- therefore no approver, so `skill_install` is refused with an actionable
604
- message rather than writing a third-party directory unattended. Use
605
- `--skills-yes` (or `skills.requireApproval=false`) to opt out deliberately.
606
- - Project skill directories require a one-time trust confirmation before they
607
- are loaded — cloning an unfamiliar repository does not grant it the ability
608
- to inject instructions into your session.
609
- - Git is invoked only via `execFile` with an argv array and `shell: false`, and
610
- owner / repo / ref / subdirectory fragments are whitelisted and refused if
611
- they begin with `-`. A leading dash matters even with a pure argv array:
612
- `--upload-pack=<program>` makes git execute that program.
613
- - Zip extraction is streamed and gated on **actually written** bytes, per-entry
614
- size, compression ratio and entry count, all of which can abort mid-archive.
615
- The size a zip *declares* is written by whoever built it and is never trusted.
616
- Path traversal, absolute entries, symlinks and Windows device names are
617
- refused, and a rejected archive is removed rather than left half-extracted.
618
- - Network fetches are `https:` only, restricted to `skills.allowedHosts`,
619
- re-checked on every redirect (max 3), size-capped, and refuse IP literals and
620
- loopback.
621
- - Nothing a skill ships is executed at install time, and the executable bit is
622
- not preserved. Scripts run only when the model invokes `bash` explicitly.
623
- There is no sandbox: approval blocks *silent* installation, it does not make
624
- a skill you approved safe.
625
-
626
- ## 0.3.0
627
-
628
- A full-screen TUI release. `@argon-agent/core` is untouched, no new runtime
629
- dependency is added, and the headless/print contract, exit codes, and
630
- slash-command semantics are unchanged. The 0.2.0 inline renderer remains
631
- available in full via `--no-fullscreen`.
632
-
633
- ### Added
634
-
635
- - **Full-screen mode (default).** `aragon` now takes over the terminal's
636
- alternate screen buffer — the same mechanism `vim` / `htop` / `lazygit` use.
637
- Your shell history is covered, not erased, and comes back untouched on exit.
638
- The frame is a fixed `rows - 1` tall, so **the composer and the status bar sit
639
- at the physical bottom of the screen from the very first frame**: empty
640
- session, long session, mid-scroll, or overlay open.
641
- - **Brand region.** A six-row gradient ASCII wordmark on a roomy empty session,
642
- degrading to a banner, then a single-line bar, then a bare wordmark as space
643
- runs out. Row 1 always begins with the brand glyph.
644
- - **Self-drawn scrolling.** `PgUp` / `PgDn` by the page, `Shift+↑` / `Shift+↓` by
645
- the line. The viewport auto-follows new output while pinned to the bottom;
646
- scrolling away shows `↑N` in the status bar plus a "N new lines" hint, and
647
- submitting a message always re-pins.
648
- - **Exit replay.** After leaving the alternate screen the session is replayed
649
- into the normal buffer as plain, colorless text, so the conversation does not
650
- evaporate with the screen. Turn it off with `--no-exit-transcript`.
651
- - **New flags** `--fullscreen` / `--no-fullscreen` / `--no-exit-transcript`, the
652
- env var `ARGON_FULLSCREEN=0|1`, and the config keys `fullscreen`,
653
- `exitTranscript`, and `transcriptWindow`.
654
- - **Automatic downgrade.** A non-TTY stdout, `TERM=dumb`, CI, and terminals under
655
- 12 rows / 40 columns fall back to the inline renderer. Only the non-TTY gate is
656
- un-overridable — `--fullscreen` beats the rest.
657
-
658
- ### Changed
659
-
660
- - The status bar lost its round border and is now exactly one row; it had been
661
- spending an eighth of a 24-row terminal framing a single line of text.
662
- - The toast strip holds a fixed row in full-screen mode, so the transcript no
663
- longer jumps as toasts appear and expire.
664
- - The composer is a rounded frame whose border color reports state (idle, has a
665
- draft, running, blurred by an overlay), with the completion popup above it.
666
- - `Ctrl+L` repaints the frame instead of writing a clear sequence. Ink dedupes
667
- identical output at two separate gates, so under a fixed frame the old
668
- approach erased the screen and then declined to redraw it.
669
- - `Shift+↑` / `Shift+↓` no longer recall prompt history — they scroll.
670
- - Full-screen mode routes `console.*` into the transcript as notices rather than
671
- letting Ink write them straight to stdout, which corrupts the frame's line
672
- accounting.
673
-
674
- ### Known trade-offs
675
-
676
- - The terminal's native scrollback and mouse wheel do not scroll the transcript
677
- in full-screen mode; use `PgUp` / `PgDn`, or run with `--no-fullscreen`.
678
- - Mouse tracking is deliberately left off: enabling it costs text selection and
679
- copy in most terminals.
680
- - Should a crash ever strand your terminal on the alternate screen, `reset`
681
- restores it. Four independent restore paths exist to prevent that: normal
682
- exit, `process.exit`, `SIGINT` / `SIGTERM` / `SIGHUP`, and Ink's own signal
683
- handling.
684
-
685
- ## 0.2.0
686
-
687
- A design-elevation & HCI-hardening release. No breaking changes: `@argon-agent/core`
688
- is untouched, no new runtime dependency is added, and the headless/print contract,
689
- exit codes, config keys, and slash-command semantics from 0.1.0 are unchanged.
690
-
691
- ### Added
692
-
693
- - **Real theming engine.** Distinct `dark` / `light` palettes with an `auto`
694
- resolution (`auto → dark`), color degradation across terminal depth
695
- (truecolor → 256 → 16 → monochrome), and an ASCII glyph fallback for terminals
696
- without Unicode. Honors `NO_COLOR`, `FORCE_COLOR`, `--no-color`, and
697
- `TERM=dumb`. Switch live with `/theme <auto|dark|light>` (persisted).
698
- - **Elegant chrome.** A gradient wordmark header that collapses to a slim sticky
699
- bar after the first turn, a first-run **Welcome / empty-state** card, and a
700
- status bar with a colored **context gauge** (threshold colors), a **tokens/sec**
701
- read-out while running, and a contextual hint.
702
- - **Legible tool output.** Colored unified diffs (green adds / red removes) and
703
- per-tool rich previews (`edit_file`/`write_file`/`read_file`/`bash`/`list_dir`/
704
- `glob`). Long previews collapse to 8 lines and expand with `Ctrl+O` or
705
- `/expand [n]`.
706
- - **Autocomplete.** A slash-command palette and `@file` path completion popup
707
- (`Tab`/`→` to complete, `Up`/`Down` to move, `Esc` to close).
708
- - **Full line editing.** Home/End, word jump/delete, kill-to-start/end, and
709
- multi-line vertical cursor navigation, with prompt-history recall at the edges.
710
- Unknown control/escape sequences are dropped instead of inserted.
711
- - **Reliability under load.** Ink `<Static>` finalization for settled entries and
712
- a streaming delta coalescer, so long/fast sessions stay flicker-free.
713
- - **Calm feedback.** Ephemeral, auto-dismissing **toasts** for transient acks;
714
- the transcript keeps only durable content (messages, tool cards, run errors).
715
- - `reducedMotion` config (also `ARGON_REDUCED_MOTION`; implied by `--no-color`)
716
- replaces spinners with a static glyph.
717
-
718
- ### Changed
719
-
720
- - History scrollback now uses the **native terminal scrollback** that `<Static>`
721
- prints into (this supersedes the never-implemented `PgUp`/`PgDn` promise).
722
-
723
- ## 0.1.0
724
-
725
- Initial release — a Claude-Code / Codex-style interactive terminal UI (TUI) on
726
- top of `@argon-agent/core`.
727
-
728
- ### Added
729
-
730
- - **Interactive TUI** (React + Ink): gradient header, streaming transcript with
731
- markdown + syntax highlighting, collapsible thinking blocks, live tool-call
732
- cards, a status bar (model / context % / tokens / cost / elapsed), and modal
733
- overlays (settings, model picker, help, confirm).
734
- - **Built-in toolset** wired into the core agent at full permission:
735
- `read_file`, `write_file`, `edit_file`, `list_dir`, `glob`, `grep`, `bash`.
736
- - **Layered configuration** (defaults → user file → env/`.env` → flags) with
737
- live in-TUI editing of provider / model / base URL / API keys / thinking level
738
- / max tokens. Secrets are masked and the config file is written `0600` on POSIX.
739
- - **One-shot / print mode** (`argon -p`) for scripting and piping, plus
740
- `argon config` / `argon config set` / `argon config path` / `argon models`.
741
- - **Session control**: abort (Esc), steer-while-running, follow-up queue,
742
- double-Ctrl-C exit, `/save` / `/resume` JSON sessions.
743
- - **Timeout invariant** (`idleTimeout ≥ toolTimeout`) so a long single tool run
744
- is never killed by the idle watchdog.
745
- - **Never-silent failures**: pre-flight API-key validation, error-StreamEvent
746
- rendering, and a guard that surfaces a swallowed agent error instead of a
747
- 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).