Development record
abcd keeps a per-session ledger of every agent it launches
Summary
Delivers the record and the rollup of itd-2611031342011261: one entry per launch abcd starts, written under abcd's home before the harness starts and completed when it ends, and abcd agents, which lists and totals them. Planned by an agent under dcn-2611031615094092, since every open question of the draft has one answer on the record (decisions 14 to 21, dcn-2611041550129278). The first release ships the steps marked MUST; the steps marked AFTER stay on this spec, and the intent stays planned until they land (a close with --remainder carries them).
Approach. One function, runner.RecordLaunch, is the only way an entry is written. It writes the entry marked running, runs the launch it is handed, and completes the entry from what the launch returned; handed no launch, it writes the host's placeholder (decision 21). The dispatcher's runOn wraps every adapter run in it, and its two hand-offs to the host call it bare, so the build, the drain, the judge and the planning interviewer are all covered with no change to their launch code. A launcher outside the dispatcher (the unattended engine) calls the same function. The store is ~/.abcd.noindex/agents/, one file per launch holding one line of JSON, so concatenating the folder gives one line per launch and two launches never write one file. A file is replaced by a rename when its launch ends, and no reader writes.
Decisions this spec adds.
- An entry that cannot be written refuses the launch, naming the store: the mechanism's claim is that no launch escapes the record, and a key's cap will be summed from it. A completion that cannot be written leaves the answer standing and the entry reading as lost, which is the record's own visible sign.
- The ledger hangs off the runner configuration, which every dispatcher already holds and which
runner.Loadbuilds with the home it read, so no launcher can forget to name it. A configuration built with no home refuses the launch. - The billing route and the API time are read from the launch's transcript, not added to
AnswerorSides, becauseSidesis written into the run state and criterion 14 keeps that unchanged. The harness's process id reaches the entry through the context, so no adapter signature changes. - A launch that failed on the claude runner carries what its stream shows, as a killed one does: a failed launch spent too.
- The floor is 32 days, the longest calendar month plus one day (decision 14), so the shipped 30-day default reads as 32 until the person sets more; the setting is
ledger.retention_daysandledger.retention_count, in the machine configuration, and a repository's figure stands only where it is longer, for that repository's launches alone (dcn-2611042248450089).
How each criterion is met.
- Criterion 1 (entry at start and end), criterion 3 (the store), criterion 6 (killed and lost) and criterion 14 (run state unchanged): steps 1 and 2.
- Criterion 2 (the orchestrator): step 3.
- Criterion 5 (the billing route): step 2. The key route's field exists, and nothing sets it until the budget intent hands a key.
- Criterion 13 (retention): step 4.
- Criterion 4 (the lenient reader), criterion 10 (the verb), criterion 12 (two launches for one await) and criterion 8's default basis: step 5.
- Criterion 7 and criterion 9 (the status line), and criterion 8's alternative basis: step 6.
- Criterion 11 (a run's summary): step 7.
Out of scope. A session's by-hand launches (decision 19), the budget's own check against a cap (itd-2611011230226453, which sums from this ledger), and any new fetch of a key or an account's figures: a cost is what the harness reports, and no credential is read.
Footprint
- packages: internal/core/runner, internal/core/sessionname, internal/core/implement/loop, internal/core/interview, internal/surface/cli, internal/core/surface, commands, docs/reference/cli, .abcd/development/release, .abcd/development/release-gate, .abcd/development/brief/04-surfaces, .abcd/development/brief/05-internals, .abcd/rules.json
- tests: internal/core/runner (ledger_test.go, the dispatcher's launch tests), internal/core/sessionname (lookup_test.go), internal/surface/cli (agents_surface_test.go and the surface audits)
Steps
- MUST: the entry and the one function that writes it
- packages: internal/core/runner
- tests: an entry written before the launch runs and completed after, one file holding one line, the placeholder for a host-handed role, a launch refused when the entry cannot be written, a kept answer when the completion cannot
- needs: none
- landed: 7a02f0236
- MUST: every dispatched launch is recorded, with its process, route, model, tokens, cost and times
- packages: internal/core/runner, internal/core/implement/loop, internal/core/interview
- tests: the dispatcher over a fake harness for a finished, failed, killed and host-handed launch, the subscription, key and unknown routes, the run-state schema unchanged
- needs: 1
- landed: 7c21e2642
- MUST: an entry names the session that asked for it
- packages: internal/core/sessionname, internal/core/runner
- tests: the exported session id with its persona name, a host found above the process, and the run id when neither answers
- needs: 1
- landed: aa57aaffc
- MUST: retention never drops an entry inside the longest cap period
- packages: internal/core/runner
- tests: the oldest whole files pruned past days and past count, nothing pruned inside 32 days whatever is set, a setting below the floor read as the floor and named
- needs: 1
- landed: fb6305133
- MUST:
abcd agentslists and totals the launches- packages: internal/core/runner, internal/surface/cli, internal/core/surface, commands, docs/reference/cli, .abcd/development/release, .abcd/development/release-gate, .abcd/development/brief/04-surfaces, .abcd/rules.json
- tests: the verb bare, with --run, --session and --all, in text and --json; money summed for keys alone; an unreadable and a newer entry named; running against lost judged on the process; two launches for one await named
- needs: 1, 2
- landed: 981d898ae
- AFTER: the status line's row, its cached read and its explanation, with the token basis as a setting
- packages: internal/core/statusline, internal/surface/cli
- tests: the row from the ledger alone, within the status command's deadline, cached for the configured interval
- needs: 5
- AFTER: an unattended run's summary carries the ledger's totals
- packages: internal/core/implement/loop, internal/surface/cli
- tests: a drain's and a driven build's summary naming their totals and the verb
- needs: 5
Frontmatter
| id | spc-2611041701500441 |
|---|---|
| type | spec |
| lifecycle | closed |
.abcd/development/specs/closed/spc-2611041701500441-every-agent-abcd-launches-for-a-session.md
open on GitHub ↗ · commit history ↗
References1
- itd-2611031342011261abcd keeps a per-session ledger of every agent it launchesimplements
mentions6
- dcn-26110316150940922026-11-03 — The product thinker's rulings for an experiment testing a long autonomous run (given 2026-11-03): during the experiment a release is cut whenever every gate passes, and any refusal waits for the product thinker; each API key has a hard monthly cap and no separate daily limit; sessions use the person's subscriptions first and move to a key when a subscription window reaches 95%, returning once it resets; the run may use the API keys the person has named to it; agents may plan a draft whose open questions each have one defensible answer on the record, and hold every other draft for the person; and the run keeps the person informed through one private daily digest page (what merged, what stalled, spend per key, what waits for them).
- dcn-26110415501292782026-11-04 — The product thinker's rulings on the profiles draft itd-2611040344170206, at its planning interview. Every agent abcd starts unattended carries abcd's guard whichever way its work is paid for: a stage on the key route runs on a profile with hooks on, and the bare launch adr-2610222222326104 names for the key route gives way for stages. Each way of paying, a subscription or a named key, is one profile with its own login and its own bare settings; a worktree is where the files are, a profile is who pays and what an agent can reach, and abcd pairs one of each per agent. A subscription's profile needs one login by the person; a key's profile needs none. A session the person starts that runs work unattended off a profile is warned in a line that cannot be missed, never refused. Whether an agent on a profile may reach the machine's other sessions is a setting, off by default. A profile's name is a readable one, never a random string: abcd ships a neutral list, a themed one such as a television series' characters is the person's own in their machine configuration, and a name is fixed at creation and retired once used; this replaces the random names of the draft's fourth decision, and the registry records the name, the tool and the date. abcd ships a sensible default allow-list of tools and a repository configures it within one bound: a repository file may narrow the list, only the person's own machine configuration may widen it, and an agent can never widen it. The same stance settles every open question of that kind, those of the ledger draft itd-2611031342011261 among them: abcd ships a sensible default and the person configures it per repository. The draft's title and scope widen to every way of paying, keys included.
- dcn-26110422484500892026-11-04 — A repository's ledger.retention_days and ledger.retention_count may lengthen what this machine keeps and may not shorten it. Decision 14 of itd-2611031342011261 let a machine or repository figure override the shipped retention, but the store is machine-scoped and holds every repository's launches, so a figure in a repository's own config, which is whatever its last committer wrote, pruned other repositories' entries past the floor against the person's own machine figure. The machine layer sets the retention, a repository's figure stands only where it is longer, and one below is named and ignored; a figure past 36500 days or 1000000 entries is refused, so the date arithmetic cannot overflow and the store stays bounded. Each launch prunes the whole store by the figures it read, so a repository's longer figure binds that repository's launches alone, and another repository's launch still prunes by its own; only the machine's figure binds every launch. The floor of 32 days is unchanged. The cost is that a person who wants one repository's entries kept for less cannot say so from that repository; a per-repository pruner would have to open every old entry at every launch to read its repository, and nobody has asked for it.
- iss-2611060809036916`.abcd/development/brief/04-surfaces/41-agents.md:60-61` says the status line's row and an unattended run's summary are "the spec's remaining steps", and the only spec the chapter names (line 4) is spc-2611041701500441, which is in `.abcd/development/specs/closed/`. Those steps moved to the open remainder spc-2611050023402644, which the chapter does not name.
- itd-2611011230226453Agents abcd starts on your API key stay within the budget you set
- spc-2611050023402644The launch ledger reaches the status line and a run's own summary