The failure this prevents is specific — a sub-agent burns the end of a limit window and the session the owner is actually sitting in dies mid-turn, because the credits went somewhere nobody was watching. So it is a condition on spawning rather than a refinement: an endpoint that can start unattended work without checking is wrong from its first call, and the symptom lands on someone else's conversation. Wired into POST /command-hq/commanders/new, which — this is the finding — already IS the spawn mechanism the sub-agents item was asking for. It starts a turn with ws: null, waits only for session:claude, and returns the transcript id, with command_hq_sessions naming, listing and costing it. So "commander or something lighter" answers itself: a commander costs nothing extra and a lighter thing would need its own registry to be visible at all. What is still missing is only the agent-callable surface. Refuses rather than queues or downgrades. Queueing means holding work against a window Officer does not control, and the reset it would wait for is a claim about a shared pool — every claude on the machine spends these, including terminals and pipelines. A refusal naming the window, the percentage and the reset is something a caller can act on now. The floor is 15% and the reasoning is in the file: the interactive failure is not "cannot start a chat", it is "a turn already in flight is cut off", and a turn costs a fraction of a window. Fails OPEN, deliberately. The numbers come from an external endpoint with a credential Officer does not own, so a blip or a signed-out CLI must not stop every spawn on the machine with an error about usage that has nothing to do with usage. The problem is reported so a caller can say "started, but unchecked". Seven tests on the pure rule — tightest window decides rather than the average, no limits allowed rather than blocked, exactly-at-the-ceiling refuses. Verified against the live account, where it correctly refuses right now at Session 90%. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
58 lines
3.3 KiB
Markdown
58 lines
3.3 KiB
Markdown
---
|
|
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: done
|
|
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.
|
|
|
|
|
|
---
|
|
|
|
**Built 2026-08-21.** `api/sub-agents/budget.ts`, wired into `POST /command-hq/commanders/new` — the one
|
|
door that starts unattended work.
|
|
|
|
The open questions, answered:
|
|
|
|
- **Refuse, not queue or downgrade.** Queueing means holding work against a window Officer does not
|
|
control, and the reset time it would wait for is a claim about a shared pool. Refusing with the window
|
|
name, the percentage and the reset is something the caller can act on immediately.
|
|
- **A fixed floor, 15%.** The interactive failure is not "cannot start a new chat", it is "a turn already
|
|
in flight is cut off" — and a turn costs a small fraction of a window, so the reserve only has to cover
|
|
what might be running. Adjustable per call; the default lives in one constant.
|
|
|
|
**It fails open**, deliberately: the numbers come from an external endpoint with a credential Officer does
|
|
not own, so a blip or a signed-out CLI must not stop every spawn on the machine with an error about usage
|
|
that has nothing to do with usage. The problem is reported rather than swallowed.
|
|
|
|
Seven tests on the pure rule — the tightest window decides rather than the average, no limits is allowed
|
|
rather than blocked, and the refusal names something actionable. Verified live: it refused at Session 90%.
|
|
|
|
**Still true and unsolved:** this cannot answer "how much has THIS user left". `claude-usage.ts` takes no
|
|
identity, structurally, so a per-account budget needs something that does not exist yet.
|