todo: turn timer in chat, and a sub-agent spawn endpoint bounded by usage limits
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,7 +16,7 @@ the owner's OS user and can never be granted. Indirection there really is accide
|
||||
|
||||
## Themes
|
||||
|
||||
**73 open, 18 closed**, across 25 themes.
|
||||
**76 open, 18 closed**, across 27 themes.
|
||||
|
||||
| Theme | Open | Closed |
|
||||
| ------------------------------------------------------------------------------------------ | ---- | ------ |
|
||||
@@ -24,6 +24,7 @@ the owner's OS user and can never be granted. Indirection there really is accide
|
||||
| [Speaking into a session from the backend](todo/agent-delivery/) | 2 | 0 |
|
||||
| [Backburner](todo/backburner/) | 2 | 0 |
|
||||
| [Background jobs](todo/background-jobs/) | 1 | 0 |
|
||||
| [Chat interface](todo/chat/) | 1 | 0 |
|
||||
| [Code editor](todo/code-editor/) | 1 | 0 |
|
||||
| [File watchers](todo/file-watchers/) | 1 | 0 |
|
||||
| [Files app — routing](todo/files-app/) | 3 | 0 |
|
||||
@@ -40,6 +41,7 @@ the owner's OS user and can never be granted. Indirection there really is accide
|
||||
| [Plugin system — gaps the email extraction found (2026-08-18)](todo/plugin-system/) | 3 | 0 |
|
||||
| [Prompt library](todo/prompt-library/) | 1 | 0 |
|
||||
| [Shell — spotlight and the dock](todo/shell/) | 2 | 0 |
|
||||
| [Sub-agents — agents spawning agents](todo/sub-agents/) | 2 | 0 |
|
||||
| [Sudo terminal modal](todo/sudo-terminal-modal/) | 1 | 0 |
|
||||
| [Tooling — the list about the list](todo/tooling/) | 1 | 0 |
|
||||
| [Transmission](todo/transmission/) | 6 | 0 |
|
||||
@@ -58,10 +60,10 @@ the owner's OS user and can never be granted. Indirection there really is accide
|
||||
- `2026-08-21` **No way to see which affordances are reaching your agents, or to turn one off** — [affordances/no-way-to-see-which-affordances-are-reaching](todo/affordances/no-way-to-see-which-affordances-are-reaching.md)
|
||||
- `2026-08-21` **Generalise it: deliver a turn to a named session, from anywhere in the backend** — [agent-delivery/generalise-it-deliver-a-turn-to-a-named](todo/agent-delivery/generalise-it-deliver-a-turn-to-a-named.md)
|
||||
- `2026-08-21` **The cost of resuming grows with the transcript** — [agent-delivery/the-cost-of-resuming-grows-with-the-transcript](todo/agent-delivery/the-cost-of-resuming-grows-with-the-transcript.md)
|
||||
- `2026-08-21` **Show how long a turn took, beside its cost and tokens** — [chat/show-how-long-a-turn-took-beside-its-cost](todo/chat/show-how-long-a-turn-took-beside-its-cost.md)
|
||||
- `2026-08-21` **Watch a directory, and attach actions to what lands in it** — [file-watchers/watch-a-directory-and-attach-actions-to-what](todo/file-watchers/watch-a-directory-and-attach-actions-to-what.md)
|
||||
- `2026-08-21` **A way to mark a commit "this one ships", so a release is not just `master`'s tip** — [fleet/a-way-to-mark-a-commit-this-one-ships-so-a](todo/fleet/a-way-to-mark-a-commit-this-one-ships-so-a.md)
|
||||
- `2026-08-21` **iPhone Action Button → run an Officer task from a locked phone** — [mobile-apps/iphone-action-button-run-an-officer-task-from](todo/mobile-apps/iphone-action-button-run-an-officer-task-from.md)
|
||||
- `2026-08-21` **The mobile recorder app, and the dispatcher agent behind it** — [mobile-apps/the-mobile-recorder-app-and-the-dispatcher](todo/mobile-apps/the-mobile-recorder-app-and-the-dispatcher.md)
|
||||
- `2026-08-21` **A plugin's settings routes are reachable by anyone the plugin is granted to** — [multi-user/a-plugin-s-settings-routes-are-reachable-by](todo/multi-user/a-plugin-s-settings-routes-are-reachable-by.md)
|
||||
- `2026-08-21` **A plugin cannot claim a WebSocket provider** — [plugin-infrastructure/a-plugin-cannot-claim-a-websocket-provider](todo/plugin-infrastructure/a-plugin-cannot-claim-a-websocket-provider.md)
|
||||
- `2026-08-21` **A store of ready-made prompts, versioned, categorized and tagged** — [prompt-library/a-store-of-ready-made-prompts-versioned](todo/prompt-library/a-store-of-ready-made-prompts-versioned.md)
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
theme: chat
|
||||
heading: "Chat interface"
|
||||
kind: theme
|
||||
---
|
||||
|
||||
The chat surface itself — what a turn shows about itself while and after it runs.
|
||||
@@ -0,0 +1,25 @@
|
||||
---
|
||||
id: chat/show-how-long-a-turn-took-beside-its-cost
|
||||
title: "Show how long a turn took, beside its cost and tokens"
|
||||
theme: chat
|
||||
status: open
|
||||
created: 2026-08-21
|
||||
date_source: stated
|
||||
order: 1
|
||||
---
|
||||
|
||||
**Show how long a turn took, beside its cost and tokens.** Wanted 2026-08-21. A timer running from the
|
||||
start of each turn, and the elapsed time kept on the settled row — in the same place that already
|
||||
renders cost and token count, not somewhere new.
|
||||
|
||||
That row is `MessageBubble.tsx:264`, and today it reads
|
||||
`Done · ${message.cost.totalUSD.toFixed(3)} · {inputTokens + outputTokens} tokens`. Duration is the
|
||||
third number that belongs there and is the only one missing.
|
||||
|
||||
Two things already exist and should be reused rather than rebuilt. `formatDuration` is in the same file
|
||||
(~line 395), and the compaction row beside it already does exactly this job — its header comment says
|
||||
the elapsed time is "honest for the window that watched it happen, and the settled row carries the
|
||||
duration", which is the behaviour wanted here. What is missing is the field: `MessageCost` in
|
||||
`Chat/types.ts:12` carries `totalUSD` and the token counters but no duration, while
|
||||
`compact:done` carries `durationMs`. So the harness result has to bring it along, or the client has to
|
||||
time the turn itself and keep it on the settled row.
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
theme: sub-agents
|
||||
heading: "Sub-agents — agents spawning agents"
|
||||
kind: theme
|
||||
---
|
||||
|
||||
An agent asking Officer to run another agent, through a door the owner defines rather than whatever the
|
||||
harness happens to offer. Related: `todo/agent-delivery/` is the other direction — the backend speaking
|
||||
into a session that already exists.
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
id: sub-agents/an-api-endpoint-for-spawning-an-agent-with-a
|
||||
title: "An API endpoint for spawning an agent with a prompt"
|
||||
theme: sub-agents
|
||||
status: open
|
||||
created: 2026-08-21
|
||||
date_source: stated
|
||||
order: 1
|
||||
---
|
||||
|
||||
**An API endpoint for spawning an agent with a prompt.** Wanted 2026-08-21. An agent calls it, names a
|
||||
prompt, and gets another agent running. A sub-agent system — but **defined by the owner**, which is the
|
||||
whole point of building one rather than leaning on the harness's own: the shapes, the limits and the
|
||||
vocabulary are Officer's, so every harness gets the same door and the definition does not change when a
|
||||
CLI does.
|
||||
|
||||
It has more of a starting point than it looks. `startClaudeTurn` already runs a turn with no browser
|
||||
attached (`nudger.ts:102`, `ws: null`), so the mechanism for "run an agent from the backend" is proven —
|
||||
what is missing is spawning a NEW one on request rather than feeding a known session, plus the surface
|
||||
an agent can actually call, which is MCP or an authenticated route.
|
||||
|
||||
Open: whether a spawned agent is a Command HQ commander (named, listed, costed — `command_hq_sessions`
|
||||
already does all three) or something lighter that disappears when it finishes; how its output returns to
|
||||
the caller, streamed or awaited; and what the caller may set — model, effort, cwd, permission mode — versus
|
||||
what Officer fixes.
|
||||
|
||||
**Bounded by the budget rule in `sub-agents/spawning-must-respect-the-account-s-own`, which is not
|
||||
optional.** An endpoint that spawns freely is exactly how a weekly limit gets spent by something nobody
|
||||
was watching.
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
id: sub-agents/spawning-must-respect-the-account-s-own
|
||||
title: "Spawning must respect the account's own session and weekly limits"
|
||||
theme: sub-agents
|
||||
status: open
|
||||
created: 2026-08-21
|
||||
date_source: stated
|
||||
order: 2
|
||||
---
|
||||
|
||||
**Spawning must respect the account's own session and weekly limits.** Wanted 2026-08-21, as a
|
||||
condition on the spawn endpoint rather than a later refinement. The failure it exists to prevent is
|
||||
specific: a sub-agent burns the last of a window, and the chat or session the owner is actually in dies
|
||||
mid-turn because the credits went somewhere nobody was watching.
|
||||
|
||||
**The numbers are already read.** `api/chat/claude-usage.ts` fetches the limit windows from Anthropic's
|
||||
OAuth usage endpoint using the token the CLI stored at login, and exposes them as `UsageLimit` — a label
|
||||
already fit to render (`Session`, `Weekly`, `Fable Weekly`) with its percentage. So the backend does not
|
||||
need new plumbing to know how much room is left; it needs to consult what it has before starting work.
|
||||
|
||||
Two facts from that file that shape this, both stated in its own header:
|
||||
|
||||
- **The windows belong to the ANTHROPIC ACCOUNT, not to Officer.** They are spent by every `claude` on
|
||||
the machine — this chat, a terminal, a task runner, a pipeline step. So a budget check has to reason
|
||||
about a shared pool it does not control, and a reservation Officer makes for itself is a guess.
|
||||
- **The module is owner-only and structurally so.** It takes no identity at all, deliberately, because
|
||||
`getOwnerHomeDir` ignores the email it is passed. Any budget rule that has to answer "how much has
|
||||
THIS user left" needs something that does not exist yet.
|
||||
|
||||
Open: what the endpoint does when the room is thin — refuse, queue until the window resets (the reset
|
||||
time is in the same payload), or downgrade the model; and whether the reserve is a fixed floor or a
|
||||
share the owner sets.
|
||||
Reference in New Issue
Block a user