Repository navigation
Description
Problem
#3574 (per-run token file for agent runs; stop staging the box principal) was reverted in the v0.132.0 release PR (#3576) because nothing yet sends StartBoxRunRequest.run_token or reads CONTAINARIUM_JWT_TOKEN_FILE. The change also stops copying the box principal into the run user's home, so a run started without a token would have no platform credential. The release checklist's "paired changes" rule applies: the first half must not ship without the second.
Current state in v0.132.0 / v0.132.1: the run_token field (10) stays in the proto (the FILE-level breaking gate forbids deleting it), the daemon accepts and ignores it, and it does not advertise the box_run_token capability.
Task
Re-land #3574's behavior (by reverting the revert of the daemon code) only together with the senders and readers:
- every client that starts runs sends
run_tokenafter checking thebox_run_tokencapability, - every consumer reads
CONTAINARIUM_JWT_TOKEN_FILE, - an upgrade note names both, since an older client against a new daemon loses the staged credential.
Restore the field's doc comment at the same time.
Acceptance
- An end-to-end run with a token reaches the platform with the per-run credential and no staged principal.
- A run from a client that does not send a token is refused with a clear error, or documented as unsupported.
- Changelog has an "Upgrading" entry.
Blocked by: #3609, #3610
Sprint: #3603
Part of #3603
Estimate: build 1d · CI+review 1d · deploy+verify wait 1d → ships 2026-11-17 (P50) / 2026-11-19 (P80)
Waiting on: #3609, #3610 (dependencies); this is link 3 of 3: daemon re-land, pinning test, upgrade note
Verify on dev: start a run with a token and one without: the first reaches the platform with the per-run credential and no principal staged in the run user's home; the second is refused with a clear error; the box_run_token capability is advertised
Activity
hsinatfootprintai commentedon Nov 10, 2026
Decisions (Q3, Q4 on #3603, defaults accepted by @hsinatfootprintai, 2026-11-10): (Q3) a client that sends no
run_tokenis refused with a clear error. (Q4) scope is the senders and readers in this repo (CLIcode run, platform MCP, agent-runtime); external platforms get the upgrade note only. PR note: do not useCloses #3581until the daemon half and all in-repo senders and readers have landed; hold the daemon half withmerge-holduntil then.hsinatfootprintai commentedon Nov 10, 2026
Routed
model:fable(runtime:claude): critical path of #3603, cross-cutting (daemon, every in-repo sender and reader, capability, upgrade note), and the first attempt shipped half-done and was reverted. One tier above the rubric because a stall here stalls the sprint.hsinatfootprintai commentedon Nov 10, 2026
agent-6c9555e4-fable is starting processing it
Box: none
hsinatfootprintai commentedon Nov 10, 2026
agent-6c9555e4-fable: parking before any code. Q3/Q4 name the in-repo senders and readers as CLI
code run, platform MCP and agent-runtime. Reading the code, none of them is on theStartBoxRunpath, so building them as senders means inventing surface the issue does not specify.What the code says (origin/main at
9c8a2d34)internal/client/{grpc,http}.gohas noStartBoxRunmethod. Nothing ininternal/cmd,internal/mcporcmd/calls the RPC.code run(internal/cmd/code_run.go) and MCPcode_run(internal/mcp/code_tools.go) start a run through an agent-box SSH session (ProcessStart) as the box owner. They never build aStartBoxRunRequest, and an owner-identity run never used the staged copy.agent-runtimedoes not start box runs. It already passesCONTAINARIUM_JWT_TOKEN_FILEto the platform MCP from its seed, andcmd/mcp-serveralready reads that variable.So re-applying #3574 applies (I trial-applied it: conflicts only in
box_run_start.goagainst the #3582 supervised spawn, resolvable), but the "senders and readers" half has no existing home here. Questions, each with the default I would take:StartBoxRunplus a new daemon-API path oncontainarium code run(new flag), MCPcode_runwrapping the same function; or (b) accept that this repo has no sender, ship daemon + refusal + capability + upgrade note, and pair it with the external platform's sender undermerge-hold.StartBoxRun(which would make Q3's refusal moot).--run-token-fileflag; no minting in this PR, since the token's claims are specified outside this repo. MCPcode_rungets no token argument (a credential in tool arguments is worse than the problem).StartBoxRun, or only runs as the unprivileged run user (the only ones that lose a credential)? Command mode loads no agent credential today.FAILED_PRECONDITIONnamingrun_tokenandbox_run_token, before anything is rotated or spawned. Owner-identity runs are unchanged.mcp-serverand agent-runtime already useCONTAINARIUM_JWT_TOKEN_FILE. The staged MCP config still points at the removed principal path.Until these are answered the acceptance line "an end-to-end run with a token reaches the platform" cannot be met from this repo alone without guessing. No branch pushed, no PR.
agent-6c9555e4-fable parked: waiting on a decision
Box: none
hsinatfootprintai commentedon Nov 10, 2026
Decisions (Q5–Q8 on #3603, defaults accepted by @hsinatfootprintai, 2026-11-11): (Q5) build an in-repo sender: typed client
StartBoxRunplus an opt-in daemon-API path oncode run, MCP wraps it. (Q6) token is caller-supplied via--run-token-file; no minting; no token argument on MCP. (Q7) tokenless refusal applies only to runs as the unprivileged run user (engine and command mode),FAILED_PRECONDITIONbefore anything is rotated or spawned; owner-identity runs unchanged. (Q8) no in-repo reader change; add a pinning test and the upgrade note.Re-sized: Q5 takes this past size L, so per the sprint rules it is split into a chain instead of one issue: #3609 (typed client) → #3610 (CLI path + MCP) → this issue (link 3: re-apply the daemon half of #3574 on top of #3582's supervised spawn, pinning test, Upgrading entry). Link 3 must not merge before #3609 and #3610 are on main. Link 3 uses
Closes #3581; links 1–2 useRefs.hsinatfootprintai commentedon Nov 10, 2026
agent-8216b0de-fable is starting processing it
Box: none
Link 3 of the chain, after Q5–Q8: #3609 is PR #3611, #3610 is PR #3615 (stacked). This PR stacks on #3615 and carries
merge-hold.hsinatfootprintai commentedon Nov 10, 2026
agent-8216b0de-fable: PR #3616 opened at
40127009— CI pending (https://github.com/FootprintAI/Containarium/pull/3616/checks). It is stacked on #3615 (which is stacked on #3611) and carriesmerge-hold: it must not merge before #3611 and #3615 are onmain. Landing is /merge-steward's; a red run comes back to me as/engineer-implement fix 3616. This issue closes on merge, not now.Box: none
Steward note for the stack: retarget #3615 to
mainbefore thefeat/3609-client-startboxrunbranch is deleted, and #3616 beforefeat/3610-code-run-token-fileis; deleting a base branch closes the PR stacked on it.Verify on dev (fuller steps than the issue body; the same ones are in the PR). Needs a daemon at the deployed commit, an admin token, a box
<box>with a recorded tool-access level whose run user is signed in, a box<owner-box>with no recorded level, and a platform-minted per-run token in<token-file>(0600, one line).GET /v1/system/infoas admin listsbox_run_tokenininfo.capabilities.containarium code run <box> --command 'test -r "$CONTAINARIUM_JWT_TOKEN_FILE" && echo token-file-ok; test ! -e ~/.config/containarium/box-token && echo no-principal' --name verify-3581 --run-token-file <token-file> --server <host>printstoken-file-okandno-principaland exits 0./run/containarium/run-tokens/in the box has noverify-3581.token.POST /v1/containers/<box>/code-runswith{"command":"true","runName":"verify-3581-b"}and norunTokenis HTTP 400, gRPC code 9, namingrun_tokenandbox_run_token;containarium code runs <box>shows noverify-3581-b.<owner-box>starts and exits 0.Verification: #3603 (the row is already on the umbrella's queue).
One finding for whoever plans the next step, not a blocker here:
GetSystemInfois admin-only, so only an admin principal can readbox_run_token. The typed client andcode run --run-token-filefail closed when they cannot read it. A non-admin sender would need another way to read the capability.hsinatfootprintai commentedon Nov 10, 2026
Decision (Q9 on #3603, @hsinatfootprintai, 2026-11-11): the capability read stays admin-only (
GetSystemInfo) and the docs say so: sending a per-run token, including viacode run --run-token-file, needs an admin token. A non-admin owner is refused. No change to the gate. A non-admin read is a possible follow-up, not part of this sprint.hsinatfootprintai commentedon Nov 10, 2026
Update (2026-11-11): link 3's PR #3616 now says
Refs #3581 (part of #3603)instead ofCloses, so merging it does not close thisneeds-verificationissue before the batched pass. Close #3581 after its row on #3603 is ✅. Same change on #3612 (#3514) and #3614 (#3551).test(box-run): pin the token removal after a failed spawn and on the …
feat(box-run): re-land the per-run token file; refuse tokenless run-u…
test(box-run): pin the token removal after a failed spawn and on the …
test(box-run): workdir level tests send a run token
feat(box-run): re-land the per-run token file; refuse tokenless run-u…