@aragon-agent/cli 0.5.2 → 0.5.4

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 (87) hide show
  1. package/CHANGELOG.md +127 -0
  2. package/README.md +193 -3
  3. package/dist/agent/controller.d.ts +51 -1
  4. package/dist/agent/controller.js +177 -2
  5. package/dist/agent/headless.d.ts +12 -0
  6. package/dist/agent/headless.js +41 -1
  7. package/dist/agent/reducer.d.ts +48 -0
  8. package/dist/agent/reducer.js +91 -2
  9. package/dist/agent/system-prompt.d.ts +17 -0
  10. package/dist/agent/system-prompt.js +4 -0
  11. package/dist/cli.js +98 -7
  12. package/dist/commands/builtins.d.ts +2 -2
  13. package/dist/commands/builtins.js +133 -3
  14. package/dist/config/app-paths.d.ts +17 -0
  15. package/dist/config/app-paths.js +21 -0
  16. package/dist/config/cli-commands.d.ts +26 -2
  17. package/dist/config/cli-commands.js +83 -6
  18. package/dist/config/env.d.ts +3 -2
  19. package/dist/config/env.js +44 -6
  20. package/dist/config/history-commands.d.ts +20 -0
  21. package/dist/config/history-commands.js +71 -0
  22. package/dist/config/load.d.ts +13 -0
  23. package/dist/config/load.js +107 -6
  24. package/dist/config/migrate-state-out-of-config.d.ts +32 -0
  25. package/dist/config/migrate-state-out-of-config.js +85 -0
  26. package/dist/config/prompt-history.d.ts +86 -0
  27. package/dist/config/prompt-history.js +332 -0
  28. package/dist/config/schema.d.ts +176 -18
  29. package/dist/config/schema.js +162 -8
  30. package/dist/config/store.js +40 -4
  31. package/dist/config/ui-state.d.ts +52 -0
  32. package/dist/config/ui-state.js +149 -0
  33. package/dist/logging/install.d.ts +85 -0
  34. package/dist/logging/install.js +94 -0
  35. package/dist/logging/logger.d.ts +1 -1
  36. package/dist/session/persist.d.ts +16 -0
  37. package/dist/session/persist.js +19 -1
  38. package/dist/team/activity.d.ts +67 -0
  39. package/dist/team/activity.js +130 -0
  40. package/dist/team/bus.d.ts +190 -0
  41. package/dist/team/bus.js +366 -0
  42. package/dist/team/comm-tools.d.ts +61 -0
  43. package/dist/team/comm-tools.js +221 -0
  44. package/dist/team/human-queue.d.ts +55 -0
  45. package/dist/team/human-queue.js +72 -0
  46. package/dist/team/limits.d.ts +123 -0
  47. package/dist/team/limits.js +128 -0
  48. package/dist/team/normalize.d.ts +39 -0
  49. package/dist/team/normalize.js +106 -0
  50. package/dist/team/panel-rows.d.ts +48 -0
  51. package/dist/team/panel-rows.js +75 -0
  52. package/dist/team/prompt.d.ts +49 -0
  53. package/dist/team/prompt.js +87 -0
  54. package/dist/team/report.d.ts +58 -0
  55. package/dist/team/report.js +205 -0
  56. package/dist/team/retry.d.ts +48 -0
  57. package/dist/team/retry.js +56 -0
  58. package/dist/team/runtime.d.ts +122 -0
  59. package/dist/team/runtime.js +406 -0
  60. package/dist/team/subagent.d.ts +90 -0
  61. package/dist/team/subagent.js +294 -0
  62. package/dist/team/task-tool.d.ts +47 -0
  63. package/dist/team/task-tool.js +118 -0
  64. package/dist/team/types.d.ts +172 -0
  65. package/dist/team/types.js +13 -0
  66. package/dist/tools/index.d.ts +48 -2
  67. package/dist/tools/index.js +26 -1
  68. package/dist/ui/App.d.ts +22 -1
  69. package/dist/ui/App.js +144 -18
  70. package/dist/ui/StatusBar.d.ts +21 -0
  71. package/dist/ui/StatusBar.js +5 -2
  72. package/dist/ui/TeamPanel.d.ts +57 -0
  73. package/dist/ui/TeamPanel.js +134 -0
  74. package/dist/ui/Transcript.js +10 -0
  75. package/dist/ui/entries/TeamCard.d.ts +31 -0
  76. package/dist/ui/entries/TeamCard.js +39 -0
  77. package/dist/ui/glyphs.d.ts +10 -0
  78. package/dist/ui/glyphs.js +6 -0
  79. package/dist/ui/layout/AppShell.d.ts +11 -1
  80. package/dist/ui/layout/AppShell.js +3 -3
  81. package/dist/ui/overlays/HelpOverlay.js +13 -0
  82. package/dist/ui/overlays/SettingsScreen.d.ts +12 -1
  83. package/dist/ui/overlays/SettingsScreen.js +38 -1
  84. package/dist/ui/transcript-text.js +20 -0
  85. package/dist/ui/use-startup-notices.d.ts +1 -1
  86. package/dist/ui/use-startup-notices.js +2 -1
  87. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -9,6 +9,133 @@ were written.
9
9
 
10
10
  ### Added
11
11
 
12
+ - **Output token limits that cannot themselves fail a run.** Every model and
13
+ every provider now defaults to 64000 output tokens, and that number is
14
+ configurable from the TUI, from a flag, from `ARAGON_MAX_TOKENS`, and by hand
15
+ in `~/.aragon-agent/config.json`. Leave it alone and it stays 64000.
16
+
17
+ What is new is that the number is an *ambition*. `gpt-4o` caps at 16384 and
18
+ `gemini-1.5-pro` at 8192; sending 64000 to either is an HTTP 400 that ends the
19
+ turn with a raw provider string in the transcript. The cap is now clamped down
20
+ to whatever the target model actually accepts, from a per-model table plus
21
+ whatever the provider's own model list reports. For a model nothing knows — a
22
+ proxy, a `--base-url` endpoint, something that shipped last week — the request
23
+ goes out at 64000, and if the provider objects, `aragon` reads the real ceiling
24
+ out of the error text, repairs the request, sends it exactly once more, and
25
+ remembers the answer for the rest of the session. One warning line; the run
26
+ continues.
27
+
28
+ Two combinations that were a guaranteed 400 on every request are fixed with
29
+ it: `--thinking xhigh` asks for a 65536-token budget while Anthropic requires
30
+ `max_tokens` to be strictly greater than it, and OpenAI's reasoning family
31
+ (`o1`, `o3`, `gpt-5`) rejects the `max_tokens` parameter name outright in
32
+ favour of `max_completion_tokens`.
33
+
34
+ New surfaces: `/max-tokens [<n>|auto|default]`, which with no argument reports
35
+ the setting *and* the effective cap for the live model; an `Effective:` line
36
+ under the settings screen's `Max tokens` field, so a value the model will not
37
+ honour is visible before you save it; `--max-tokens auto`; and
38
+ `aragon config set maxTokens <n|auto|default>`, which echoes the value that was
39
+ actually stored rather than the one you typed.
40
+
41
+ - **Team subagents.** The agent can now hand independent parts of a job to up to
42
+ five short-lived subagents that run in parallel, then read one combined report
43
+ of what each of them found. It decides for itself whether to delegate, so a
44
+ session that never calls the new `task` tool is byte-for-byte the session that
45
+ existed before. On by default; `--no-team` or `team.enabled: false` turns it
46
+ off, and `aragon config set team.maxSubagents <n>` sets the width (1-10; the
47
+ 10 is a hard ceiling no config file can raise).
48
+
49
+ A subagent is a full agent with the same tools and working directory but no
50
+ memory of your conversation, so its brief has to be self-contained. It cannot
51
+ delegate further and it cannot ask you anything. Plan mode and a skill's
52
+ `allowed-tools` ceiling both reach one level down, so delegating is never a
53
+ way around either; `--confirm` queues subagent confirmations one at a time and
54
+ labels each with the subagent that is asking.
55
+
56
+ Subagents can message each other with `team_send` / `team_wait`, delivered by
57
+ attaching the message to the recipient's next tool result rather than
58
+ interrupting it. The limits are deliberate — 6 messages each, one every 15
59
+ seconds, 24 per dispatch — and every refusal is a plain result naming the
60
+ limit rather than an error, because an error invites the retry the limits
61
+ exist to prevent.
62
+
63
+ While a dispatch runs, a roster sits between the transcript and the composer
64
+ and the status bar carries `agents 3/5`; both disappear when it finishes and
65
+ the transcript keeps a card you can expand with `Ctrl+O`. `Esc` aborts every
66
+ subagent and returns the partial report. Under `-p` the transitions go to
67
+ stderr and the subagents' tokens are folded into the `[usage]` footer, so the
68
+ cost readout cannot under-report what the team spent.
69
+
70
+ Full documentation, including the limits table and how team mode interacts
71
+ with plan mode, skills and `--confirm`, is in the README.
72
+
73
+ - **The subagent roster now shows what each subagent is doing, and shows the
74
+ ones that are working.** Where every row used to say `thinking` for minutes at
75
+ a time, it now says `bash: npm test -w cli`, `read: src/api/routes.ts`,
76
+ `waiting for a2`, or the tail of the sentence the subagent is currently
77
+ writing. On a narrow terminal the same row falls back to a file name and a
78
+ program name rather than wrapping, and the elapsed clock keeps its place at
79
+ every width.
80
+
81
+ The five visible rows are now the five that matter: whatever is running comes
82
+ first, then whatever is queued, then the most recent results. Above five
83
+ subagents the old panel showed the five that had finished first and hid
84
+ everything still working behind `+3 more`, which is the opposite of what the
85
+ roster is for. `+3 more` now says how many of the hidden ones are still going.
86
+
87
+ - **A subagent no longer waits two minutes for a message nobody can send.**
88
+ `team_wait` now checks whether anyone could actually answer before it blocks:
89
+ if the teammate it named has already finished, does not exist, or is itself
90
+ waiting in a way that cannot be released in time, it returns straight away and
91
+ says which. Nothing is refused that could still have been answered — including
92
+ by a third teammate further down the chain — and the subagent is told what to
93
+ do instead rather than handed an error.
94
+
95
+ - **A subagent whose very first request dies on a rate limit is retried once.**
96
+ Only a genuine cold start qualifies: no turn completed and no tool ran, so
97
+ there is nothing to undo. It restarts after two seconds, the roster says
98
+ `starting (retry)`, and the report notes `retried 1x`. Pressing `Esc`, a
99
+ timeout, or any subagent that had already begun work is never retried.
100
+
101
+ ### Changed
102
+
103
+ - **`"maxTokens": null` in `config.json` now means AUTO** — use each model's own
104
+ ceiling, never above 64000. It previously resolved to 64000 by accident (the
105
+ layered resolver skipped `null`), and there was no way to express AUTO through
106
+ any supported write path. If you have a `null` there today, the only difference
107
+ is a downward clamp on models whose real ceiling is below 64000 — the direction
108
+ that prevents failures rather than causing them. Absent still means 64000, and
109
+ an explicit number still means that number.
110
+
111
+ - **`config.json` holds settings again.** The prompts you type are no longer
112
+ stored in it. They move to `~/.aragon-agent/prompt-history.jsonl` — one JSON
113
+ object per line, `0600` on POSIX — and the submit counter and the "notice
114
+ already shown" flag move to `~/.aragon-agent/state.json`. `↑` and `↓` behave
115
+ exactly as before.
116
+
117
+ Two things get better. Opening `config.json` to change your model no longer
118
+ means scrolling past a transcript of your own typing, and copying it to
119
+ another machine no longer carries your prompts along. And submitting a message
120
+ no longer rewrites the file that holds your API keys: `config.json` is written
121
+ when you change a setting, and at no other time.
122
+
123
+ **Your history and counters are migrated automatically, once, at the next
124
+ launch.** Nothing is printed, because nothing changes for you. The dead
125
+ `recentModels` key — which nothing has ever written — is dropped.
126
+
127
+ If you go back to 0.5.x after upgrading, that version does not know about the
128
+ new file and `↑` will look empty. Nothing has been lost: the entries are still
129
+ in `prompt-history.jsonl`, and upgrading again brings them back.
130
+
131
+ ### Added
132
+
133
+ - **`aragon history`** — `path`, `list` (`-n`, `--json`) and `clear --yes` for
134
+ the prompt history, alongside the existing `aragon logs` commands. Entries are
135
+ stored verbatim, so `clear` is how you erase them; `aragon config set
136
+ historyEnabled false` stops new ones being recorded without deleting or hiding
137
+ what is already there.
138
+
12
139
  - **The mouse wheel scrolls what is under the pointer.** In full-screen mode the
13
140
  wheel now scrolls the transcript three rows per notch (a page with `Shift`),
14
141
  scrolls an open overlay when the pointer is over one, and steps prompt history
package/README.md CHANGED
@@ -60,7 +60,7 @@ aragon --help | -h Print help
60
60
  | `--base-url <url>` | Override the provider base URL (OpenAI-compatible endpoints) |
61
61
  | `--api-key <key>` | One-shot key override (not persisted) |
62
62
  | `--thinking <level>` | `off\|minimal\|low\|medium\|high\|xhigh` |
63
- | `--max-tokens <n>` | Output token cap |
63
+ | `--max-tokens <n\|auto>` | Output token cap: a number, or `auto` for the model's own ceiling (default `64000`) |
64
64
  | `--cwd <dir>` | Working directory for tools |
65
65
  | `--confirm` | Confirm each mutating tool call |
66
66
  | `--tool-timeout <ms>` | Per-tool executor ceiling (default 180000) |
@@ -72,6 +72,8 @@ aragon --help | -h Print help
72
72
  | `--no-fullscreen` | Force the inline renderer (the 0.2.0 behavior) |
73
73
  | `--no-exit-transcript` | Do not replay the session summary after exiting |
74
74
  | `--plan` / `--no-plan` | Start the session in PLAN mode (read-only research + review) or force BUILD |
75
+ | `--team` / `--no-team` | Enable or disable team subagents. `--no-team` does not register the `task` tool at all |
76
+ | `--team-max <n>` | Max subagents per dispatch for this run, clamped to `[1, 10]` |
75
77
  | `--no-skills` | Disable the skill system entirely (no catalog, no skill tools) |
76
78
  | `--skill <name>` | Force-load a skill's full body for this run (repeatable) |
77
79
  | `--skills-yes` | Approve skill installs for this run (CI / headless) |
@@ -89,6 +91,7 @@ Exit codes: `0` success · `1` agent/runtime error · `2` config/usage error ·
89
91
  | `/model` | Open the model picker |
90
92
  | `/settings` | Open the settings screen |
91
93
  | `/thinking <level>` | Set the thinking level |
94
+ | `/max-tokens [<n>\|auto\|default]` | Output token cap; with no argument, reports the setting **and** the effective cap for the live model |
92
95
  | `/tools` | List active tools |
93
96
  | `/clear` | Clear the visible transcript |
94
97
  | `/reset` | New conversation |
@@ -96,6 +99,7 @@ Exit codes: `0` success · `1` agent/runtime error · `2` config/usage error ·
96
99
  | `/save [file]` | Save the session to JSON |
97
100
  | `/resume [file]` | Load a saved session |
98
101
  | `/plan [on\|off\|status]` | Toggle plan mode - the keyboard-free equivalent of `Shift+Tab` |
102
+ | `/team [on\|off\|max <n>]` | Team subagents: status and the live roster, the on/off switch, the fan-out width |
99
103
  | `/theme <auto\|warm\|cool\|light>` | Switch the color theme live (persisted) |
100
104
  | `/expand [n]` | Expand / collapse the n-th-from-last (default last) tool card |
101
105
  | `/copy` | Copy the last answer to the clipboard |
@@ -308,6 +312,82 @@ When skills are enabled, four more are added — the two read tools `skill` and
308
312
  below). `--no-skills` removes them again. Updating a skill is deliberately not
309
313
  among them; that is a `aragon skills update` decision for you, not the model.
310
314
 
315
+ With team mode on — which is the default — one more is added: `task`, the
316
+ delegation tool (see below). `--no-team` removes it again.
317
+
318
+ ## Team subagents
319
+
320
+ The agent can hand parts of a job to short-lived **subagents** that run in
321
+ parallel, then read one combined report of what they each found. It decides for
322
+ itself whether to delegate; a session that never calls `task` is the session
323
+ that existed before this feature.
324
+
325
+ ```
326
+ > read the auth middleware, map the route table, and check the migration
327
+
328
+ ◆ team 2 running · 1 done · 84s ✉ 1
329
+ ⠋ a1 read the auth middleware tool: grep 22.1s
330
+ ⠙ a2 map the route table thinking 31.6s
331
+ ✔ a3 check the migration done 4 turns 18.2s
332
+ ```
333
+
334
+ **What a subagent is.** A full agent with its own message history, the same
335
+ tools and the same working directory — but no memory of your conversation, so
336
+ its brief has to be self-contained. It cannot delegate further (depth is capped
337
+ at one by construction) and it cannot ask you anything.
338
+
339
+ **Delegate wide, not deep.** Two to four subagents is the usual size. The
340
+ default cap is 5 per dispatch and 3 in flight at once; the hard maximum is 10
341
+ and no config file can raise it. `maxConcurrent` is separate from `maxSubagents`
342
+ on purpose: five simultaneous streams against one API key is a reliable way to
343
+ collect rate-limit errors, and each one would land in the report as a failed
344
+ subagent.
345
+
346
+ **The report.** One text result: a header with the ok/failed counts, aggregate
347
+ tokens and cost, then one section per subagent with its status, timing, the
348
+ files it wrote and its own final summary. A failed subagent never fails the
349
+ dispatch — partial results are the normal outcome of a fan-out. When two
350
+ subagents wrote the same file the header says so, phrased as a warning rather
351
+ than a fact: the file list is derived from `write_file` / `edit_file`, so a
352
+ write made through `bash` is invisible to it.
353
+
354
+ **Talking to each other.** Subagents get two extra tools, `team_send` and
355
+ `team_wait`. Messages are delivered by attaching them to the recipient's next
356
+ tool result, so nobody has to poll and nobody's work is interrupted. The limits
357
+ are the point rather than an afterthought: **6 messages per subagent, one every
358
+ 15 seconds, 24 per dispatch**, a broadcast costing two. Every refusal is a plain
359
+ result naming the limit, never an error — an error reads as a malfunction and
360
+ invites a retry, which is the behaviour the limits exist to prevent.
361
+
362
+ **What you see.** While a dispatch runs, the roster above sits between the
363
+ transcript and the composer and the status bar carries `agents 3/5` (`[3]` under
364
+ 100 columns). Both disappear when it finishes and the transcript keeps a card
365
+ with the per-agent results; `Ctrl+O` expands it to their summaries. Under `-p`
366
+ the same transitions go to stderr as `[team] a1 ok 22.1s 7 tools` lines, and the
367
+ children's tokens are folded into the `[usage]` footer.
368
+
369
+ **Interaction with the other subsystems.**
370
+
371
+ - **Plan mode reaches one level down.** In PLAN, every subagent is built with
372
+ the same read-only gate, so `write_file` / `edit_file` / `bash` are refused
373
+ inside them too. Parallel research is plan mode's best use, so `task` itself
374
+ is allowed. A single subagent can be pinned read-only with `readOnly: true`
375
+ even in a BUILD session — the field can only ever tighten.
376
+ - **A skill's `allowed-tools` ceiling reaches one level down too**, so
377
+ delegating is not a way around it. Subagents get `skill_find` but not `skill`:
378
+ loading a skill mutates a turn-scoped registry the lead owns, and three
379
+ subagents doing it at once would narrow what the lead may do next in a way
380
+ nothing would report. Always-on skills still reach them.
381
+ - **`--confirm`** queues subagent confirmations one at a time, labelled with the
382
+ subagent that is asking (`[a2] Write: src/routes.ts`).
383
+ - **Logs.** `dispatch_start` and `dispatch_end` are recorded at `info` with the
384
+ ok / failed / aborted counts and aggregate usage; phase transitions at
385
+ `debug`. A `team_send` subject is recorded, never its body; a subagent's brief
386
+ and summary only at `trace`.
387
+
388
+ **`Esc`** aborts the whole dispatch — every subagent within a couple of seconds
389
+ — and the report comes back marked `ABORTED` with whatever was finished.
390
+
311
391
  ## Skills
312
392
 
313
393
  A skill is a reusable expert procedure stored on disk: a directory containing a
@@ -595,27 +675,40 @@ env / `.env` → CLI flags**.
595
675
 
596
676
  - **Env / `.env`**: `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`,
597
677
  `GOOGLE_API_KEY` / `GEMINI_API_KEY`, plus `ARAGON_PROVIDER`, `ARAGON_MODEL`,
598
- `ARAGON_BASE_URL`, `ARAGON_THINKING`, `ARAGON_MAX_TOKENS`, `ARAGON_THEME`,
678
+ `ARAGON_BASE_URL`, `ARAGON_THINKING`,
679
+ `ARAGON_MAX_TOKENS` (a number, or `auto` / `0` for the per-model ceiling),
680
+ `ARAGON_THEME`,
599
681
  `ARAGON_FULLSCREEN`, `ARAGON_PLAN` (`1` starts in plan mode),
682
+ `ARAGON_TEAM` (`0` disables team subagents), `ARAGON_TEAM_MAX` (fan-out width),
600
683
  `ARAGON_SKILLS` (`0` disables), `ARAGON_SKILLS_PATH`,
601
684
  `ARAGON_SKILLS_DISABLED` (comma-separated names), `ARAGON_LOG_LEVEL`,
602
685
  `ARAGON_LOG_FILE` (`0` disables), `ARAGON_LOG_DIR`.
603
686
  `ARAGON_HOME` is the exception that **cannot** come from `.env`: it is read
604
687
  before any `.env` is loaded. See [Files & logs](#files--logs).
605
688
  - **User config file** (`aragon config path`): JSON, written `0600` on POSIX.
606
- Holds provider/model/keys and MRU lists. Keys are masked in the UI and never
689
+ Holds provider / model / keys and your preferences, and nothing else — the
690
+ prompts you type and the counters behind one-time notices live in their own
691
+ files (see [Files & logs](#files--logs)). Keys are masked in the UI and never
607
692
  logged. It lives in your home directory — see [Files & logs](#files--logs) —
608
693
  and editing it by hand is supported: `aragon config edit` opens it, and an
609
694
  invalid edit is reported rather than silently resetting every setting.
610
695
 
611
696
  | Config key | Default | Meaning |
612
697
  | --- | --- | --- |
698
+ | `maxTokens` | `64000` | Output token cap, clamped to `[256, 200000]`. `null` means **auto** — use each model's own ceiling, never above 64000. Absent means the default. See [Output token limits](#output-token-limits). |
613
699
  | `fullscreen` | `true` | Use the full-screen TUI (still subject to the automatic downgrades). Setting it to `false` opts out permanently; leaving it `true` is *not* a force — only `--fullscreen` / `ARAGON_FULLSCREEN=1` override the heuristics. |
614
700
  | `exitTranscript` | `true` | Replay a plain-text session summary after exiting (full-screen only). |
615
701
  | `transcriptWindow` | `300` | How many trailing entries the full-screen viewport renders, clamped to `[50, 2000]`. The full history stays in memory and in `/save`. |
616
702
  | `planModeDefault` | `false` | Start every session in plan mode. `--no-plan` still overrides it for a single run. |
617
703
  | `planModeMaxAskRounds` | `4` | `ask_user` rounds allowed per user message, clamped to `[1, 10]`. The counter resets on your next message; steering does **not** reset it. |
618
704
  | `planModeHumanTimeoutMs` | `1800000` | Ceiling on a single question / plan wait, clamped to `[60000, 7200000]`. Thirty minutes is far outside "went to get coffee", but a ceiling has to exist so an unattended terminal cannot wedge a CI job forever. |
705
+ | `historyEnabled` | `true` | Record submitted prompts to `prompt-history.jsonl` for `↑` recall. Setting it to `false` stops new writes; it does not delete what is already stored (that is `aragon history clear --yes`) and does not stop reading. See [Prompt history](#prompt-history). |
706
+ | `team.enabled` | `true` | Master switch for team subagents. `false` means the `task` tool is never registered — `/team on` in such a session saves the setting for next launch and says so, rather than advertising a tool that is not there. |
707
+ | `team.maxSubagents` | `5` | Subagents per dispatch, clamped to `[1, 10]`. The 10 is the hard ceiling and is enforced twice — on the config value and again on what the model asks for — so hand-editing this file cannot raise it. |
708
+ | `team.maxConcurrent` | `3` | Subagents in flight at once, clamped to `[1, 10]` and capped at `maxSubagents`. A separate knob because provider rate limits are a different constraint from context economics. |
709
+ | `team.subagentTimeoutMs` | `300000` | One subagent's wall clock before it is aborted, clamped to `[30000, 1800000]`. A wedged subagent dies on its own ceiling without taking the dispatch with it. |
710
+ | `team.dispatchTimeoutMs` | `900000` | The whole dispatch's wall clock, clamped to `[60000, 3600000]`. |
711
+ | `team.maxTurnsPerSubagent` | `24` | Runaway-loop cap, clamped to `[4, 100]`. A subagent stopped here is reported as `stopped: turn cap reached`, with whatever it had produced. |
619
712
  | `skills.enabled` | `true` | Master switch for the skill system. |
620
713
  | `skills.requireApproval` | `true` | Require a human to approve `skill_install` / `skill_create`. |
621
714
  | `skills.catalogMaxBytes` | `6000` | Level 1 catalog ceiling, in UTF-8 **bytes**, clamped to `[500, 40000]`. |
@@ -638,6 +731,65 @@ Byte, not character: `ToolExecutor` truncates at 100 000 **bytes**, so a
638
731
  character-based budget would be roughly triple its nominal size for CJK text
639
732
  and would get cut mid-tag.
640
733
 
734
+ ### Output token limits
735
+
736
+ Every model and every provider defaults to **64000** output tokens. You never
737
+ have to configure this, and if you never touch it the number stays 64000.
738
+
739
+ The number you set is an **ambition, not a promise**: it is clamped down to
740
+ whatever the target model actually accepts. `gpt-4o` caps at 16384 and
741
+ `gemini-1.5-pro` at 8192, and sending 64000 to either is an HTTP 400 that ends
742
+ the turn — so `aragon` sends what the model will take, silently. When the model
743
+ is one it has never seen (a proxy, an endpoint behind `--base-url`, a model that
744
+ shipped last week), it sends 64000, and if the provider objects it reads the real
745
+ ceiling out of the provider's own error, repairs the request, sends it again, and
746
+ remembers the answer for the rest of the session. You see one warning line and
747
+ the run continues.
748
+
749
+ Four ways to change it, highest priority first:
750
+
751
+ ```bash
752
+ aragon --max-tokens 32000 # this run only
753
+ aragon --max-tokens auto # this run only, per-model ceiling
754
+ ARAGON_MAX_TOKENS=32000 aragon # env layer, between the flag and the file
755
+ aragon config set maxTokens 32000 # persisted; prints "Set maxTokens = 32000"
756
+ aragon config set maxTokens auto # persisted as null
757
+ aragon config set maxTokens default # back to 64000
758
+ aragon config get maxTokens # "64000" | "auto"
759
+ ```
760
+
761
+ Inside the TUI, `/max-tokens` reports the current setting **and** the effective
762
+ cap for the live model, and `/max-tokens <n|auto|default>` changes it. The
763
+ settings screen (`/settings`) has the same field with an `Effective:` line under
764
+ it, so a value the model will not honour is visible before you save it.
765
+
766
+ And by hand, in `~/.aragon-agent/config.json` (`aragon config path` prints the
767
+ exact location; `aragon config edit` opens it, and `/reload` picks up an edit
768
+ made in another window):
769
+
770
+ ```jsonc
771
+ {
772
+ "version": 1,
773
+ "provider": "anthropic",
774
+ "model": "claude-sonnet-4-5-20250929",
775
+
776
+ // Output token cap.
777
+ // 64000 (or any 256..200000 integer) — an explicit cap, clamped down to
778
+ // the target model's real ceiling when that ceiling is lower.
779
+ // null — auto: use each model's own ceiling, never above 64000.
780
+ // absent — the product default, 64000.
781
+ "maxTokens": 64000
782
+ }
783
+ ```
784
+
785
+ Out-of-range numbers are clamped on the way in **and** on the way out, so a
786
+ hand-edited `900000` becomes `200000` on disk rather than reverting to the
787
+ default on every launch.
788
+
789
+ Extended thinking is reconciled with the cap automatically: `--thinking xhigh`
790
+ asks for a 65536-token budget, Anthropic requires `max_tokens` to be strictly
791
+ greater than it, and the two are resolved together rather than left to collide.
792
+
641
793
  These are additive: a config file written by an earlier version loads
642
794
  unchanged, with no migration and no version bump.
643
795
 
@@ -649,6 +801,8 @@ Everything AragonAgent keeps for you lives under one directory in your home:
649
801
  ~/.aragon-agent/ (Windows: C:\Users\<you>\.aragon-agent\)
650
802
  ├── config.json settings + API keys (0600 on POSIX)
651
803
  ├── config.json.bak written by `aragon config edit` before it opens
804
+ ├── prompt-history.jsonl prompts you submitted, for ↑ recall (0600 on POSIX)
805
+ ├── state.json UI bookkeeping: submit count, one-shot notices
652
806
  ├── logs/
653
807
  │ ├── aragon-2026-07-27.log today, JSON Lines
654
808
  │ └── aragon-2026-07-27.1.log rotated at log.maxFileBytes
@@ -657,6 +811,11 @@ Everything AragonAgent keeps for you lives under one directory in your home:
657
811
  └── skill-usage.json
658
812
  ```
659
813
 
814
+ `config.json` holds **settings only**. What you typed and how often you have
815
+ typed it live in the two files next to it, so that editing your config means
816
+ scrolling past your own settings and nothing else, and so that submitting a
817
+ prompt no longer rewrites the file that holds your API keys.
818
+
660
819
  `ARAGON_HOME` moves the whole tree. **It cannot come from a `.env` file** — the
661
820
  path is resolved when the process starts, long before a `.env` is read — so set
662
821
  it as a real environment variable. `aragon config home` always prints the
@@ -669,6 +828,33 @@ directories are **left in place** so that reinstalling an older build stays
669
828
  lossless; `aragon config home` names them, and you can delete them once you are
670
829
  satisfied.
671
830
 
831
+ ### Prompt history
832
+
833
+ Every prompt you submit is appended to `~/.aragon-agent/prompt-history.jsonl`,
834
+ one JSON object per line, so that `↑` recalls it — in this session and in every
835
+ later one. It is written `0600` on POSIX, it never leaves the machine, and it is
836
+ **stored verbatim**: a redacted history would recall the wrong text, which is
837
+ worse than not recalling at all.
838
+
839
+ The last 100 distinct prompts are what `↑` walks. The file is rewritten down to
840
+ that many entries once it passes 400 lines, and a single submission longer than
841
+ 16 KiB is not recorded at all rather than recorded truncated.
842
+
843
+ ```bash
844
+ aragon history path # where it is, plus a reminder of what is in it
845
+ aragon history list -n 50 # the 50 most recent, newest first
846
+ aragon history list --json # raw entries with timestamps
847
+ aragon history clear --yes # delete the file
848
+ ```
849
+
850
+ Set `historyEnabled` to `false` (`aragon config set historyEnabled false`) to
851
+ stop recording. Switching it off does **not** delete what is already stored —
852
+ `aragon history clear --yes` does that — and reading keeps working either way,
853
+ so you can look before you erase.
854
+
855
+ Upgrading from 0.5.x moves an existing `promptHistory` out of `config.json` into
856
+ this file once, automatically and silently.
857
+
672
858
  ### What gets logged
673
859
 
674
860
  Logs are local files. Nothing is uploaded, ever — there is no network path out
@@ -705,6 +891,10 @@ aragon logs tail --level warn # only warn and above
705
891
  aragon logs clear --yes # delete every log file
706
892
  aragon logs open # open the directory in your file manager
707
893
 
894
+ aragon history path # where prompt history is kept
895
+ aragon history list -n 50 # the 50 most recent prompts, newest first
896
+ aragon history clear --yes # delete the prompt history
897
+
708
898
  aragon config home # the user-state root (and whether ARAGON_HOME set it)
709
899
  aragon config get log.level # one value; secrets always masked
710
900
  aragon config list --json # everything; secrets always masked here too
@@ -9,8 +9,9 @@
9
9
  * from the event stream by the reducer (TUI) and the headless writer.
10
10
  */
11
11
  import { ModelRegistry, type AgentEvent, type AgentTool, type Message, type ModelInfo, type ProviderRegistry, type ThinkingLevel } from '@aragon-agent/core';
12
- import type { CliConfig, ThemeName } from '../config/schema.js';
12
+ import type { CliConfig, TeamConfig, ThemeName } from '../config/schema.js';
13
13
  import { type ConfirmRequest } from '../tools/index.js';
14
+ import type { TeamEvent, TeamSnapshot } from '../team/types.js';
14
15
  import { type HumanInputGate } from '../tools/human-input.js';
15
16
  import { SkillService, type ApprovalGate } from '../skills/service.js';
16
17
  import type { AgentMode } from './agent-mode.js';
@@ -80,6 +81,9 @@ export declare class AgentController {
80
81
  private askRounds;
81
82
  /** Static: whether this session could ever render a question overlay. */
82
83
  private readonly planInteractive;
84
+ private readonly teamRegistered;
85
+ private teamEnabled;
86
+ private readonly teamRuntime;
83
87
  constructor(config: CliConfig, deps?: ControllerDeps);
84
88
  private resolveKey;
85
89
  /**
@@ -177,8 +181,54 @@ export declare class AgentController {
177
181
  * path must not leave the watchdog disarmed for the rest of the run. Also used
178
182
  * by the `--confirm` gate, which had exactly this bug — a user who took four
179
183
  * minutes over `Proceed? (y/N)` had their run killed by the watchdog.
184
+ *
185
+ * RENAMED FROM `withHumanWait`, WITH THE OLD NAME KEPT AS AN ALIAS (D-12). The
186
+ * mechanism is not about humans any more — a `task` dispatch is a long wait
187
+ * with no human in it at all — but the plan tools and the `--confirm` gate read
188
+ * correctly with the old name at their call sites, and renaming those would be
189
+ * churn in files this change should barely touch.
190
+ *
191
+ * NOT RE-ENTRANT, and that matters here: `IdleWatchdog.pause()` sets a boolean
192
+ * rather than a counter, so a nested call's `finally` re-arms the watchdog
193
+ * while the outer wait is still going. That is why a child's `--confirm`
194
+ * dialog does NOT route through this (see the constructor's `humanQueue`).
180
195
  */
196
+ withPausedWatchdog<T>(fn: () => Promise<T>): Promise<T>;
197
+ /** @see withPausedWatchdog — the name the plan tools and `--confirm` use. */
181
198
  withHumanWait<T>(fn: () => Promise<T>): Promise<T>;
199
+ /** Whether `task` is in `this.tools`. Fixed at construction; see the fields. */
200
+ isTeamRegistered(): boolean;
201
+ /** Whether `task` will actually dispatch. Flipped live by `/team on|off`. */
202
+ isTeamEnabled(): boolean;
203
+ /**
204
+ * Flip the live switch and re-render the prompt.
205
+ *
206
+ * Turning it ON in a session that started with `--no-team` deliberately does
207
+ * NOT register the tool (D-17): the array is immutable, and advertising an
208
+ * unregistered tool is the dead end P0-2 is about. `/team` reports that
209
+ * honestly by checking `isTeamRegistered()` first.
210
+ */
211
+ setTeamEnabled(enabled: boolean): void;
212
+ getTeamConfig(): TeamConfig;
213
+ /**
214
+ * Adopt a new team config for this session and re-render the prompt (the block
215
+ * quotes the numbers). Clamped here as well as on the persist path, so a bad
216
+ * value can never reach the runtime.
217
+ */
218
+ setTeamConfig(patch: Partial<TeamConfig>): TeamConfig;
219
+ /** Refused mid-dispatch by `/team`; half a dispatch under two ceilings is not
220
+ * a result anything can afterwards explain (the reasoning `/reload` uses). */
221
+ isTeamBusy(): boolean;
222
+ getTeamSnapshot(): TeamSnapshot | null;
223
+ /**
224
+ * Subscribe to the CLI-local team event stream.
225
+ *
226
+ * Returns a no-op unsubscribe when team mode was off at construction, so every
227
+ * caller can subscribe unconditionally.
228
+ */
229
+ subscribeTeam(listener: (event: TeamEvent) => void): () => void;
230
+ /** Abort every child and clear timers. Idempotent; safe to call twice. */
231
+ dispose(): void;
182
232
  setModel(provider: string, model: string, baseUrl?: string): void;
183
233
  setThinkingLevel(level: ThinkingLevel): void;
184
234
  setMaxTokens(value: number | undefined): void;