Skip to content

Commit f061c2b

Browse files
committed
docs: sync runner-selfhosting-cleanup design docs
Claude-Session: https://claude.ai/code/session_01XhENr63WL9npkKrJGnzDc1
1 parent 0f6f442 commit f061c2b

9 files changed

Lines changed: 70 additions & 22 deletions

File tree

docs/design/agent-workflows/projects/runner-selfhosting-cleanup/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ The normal deployment uses one runner service. That runner can support both loca
2727
- API and web get provider availability from the same environment value, set once per deployment by the hosting templates. A discovery endpoint is deferred (RSH-7).
2828
- Daytona configuration belongs under the runner namespace. Code-evaluator Daytona configuration is separate.
2929
- The runner never discovers an operator's home directory or automatically uploads Pi or Claude OAuth state.
30-
- Subscription authentication is an explicit local self-hosting setup: a read-only Compose volume mount taught in a tutorial. There is no bootstrap manifest in version 1 (RSH-4).
30+
- Subscription authentication is an explicit local self-hosting setup: a read-write Compose volume mount taught in a tutorial. The harness runs directly out of the mount so it can refresh its own OAuth token; there is no per-run copy and no bootstrap manifest in version 1 (RSH-4).
3131
- Runtime customization (extra binaries, certificates, dependencies) happens through operator-built images and the shipped Daytona snapshot scripts, not runner configuration.
3232
- Remote subscription authentication is unsupported until the relevant provider explicitly approves the integration and Agenta defines a safe product contract.
3333
- Pi installation is detected and repaired by the runtime. There is no deployment-wide "Pi is installed" boolean.
@@ -50,7 +50,7 @@ The normal deployment uses one runner service. That runner can support both loca
5050
- Runner provider selection and configuration.
5151
- Runner-specific Daytona names and validation.
5252
- Runner-to-Services routing and authentication.
53-
- Local subscription setup through explicit read-only mounts.
53+
- Local subscription setup through explicit read-write mounts.
5454
- Removal of automatic Daytona OAuth upload.
5555
- Removal of deployment-wide runtime facts and hidden policy switches.
5656
- A structured warning when a durable mount degrades.

docs/design/agent-workflows/projects/runner-selfhosting-cleanup/context.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ DAYTONA_JWT_TOKEN and DAYTONA_ORGANIZATION_ID.
5050

5151
Nothing was wrong with the user's Daytona account. The request reached a runner deployment that was not configured for Daytona. The setup made it easy to split capabilities accidentally.
5252

53-
The target local QA deployment is one trusted development runner with both providers enabled and explicit read-only local subscription mounts. This is a development convenience, not a production multi-tenant topology. A local harness shares the runner container and can inspect other same-user processes through `/proc`.
53+
The target local QA deployment is one trusted development runner with both providers enabled and explicit read-write local subscription mounts. This is a development convenience, not a production multi-tenant topology. A local harness shares the runner container and can inspect other same-user processes through `/proc`.
5454

5555
## Trust boundaries
5656

docs/design/agent-workflows/projects/runner-selfhosting-cleanup/documentation-plan.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ The opt-in path for a trusted personal deployment. Covers the three supported lo
9292
login, Claude Code OAuth, and the ChatGPT/Codex login.
9393

9494
1. Find the supported login state for the harness on the operator's machine.
95-
2. Add the read-only volume mount in the Compose file and point the harness config variable at it.
95+
2. Add the read-write volume mount in the Compose file and point the harness config variable at it.
9696
3. Run a self-managed agent and confirm it uses the mounted login.
9797
4. Remove the mount and confirm the run fails with the explicit missing-configuration error.
9898

docs/design/agent-workflows/projects/runner-selfhosting-cleanup/interface.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,20 +187,24 @@ The two problems this replaces the manifest for:
187187

188188
### Local subscription mounts
189189

190-
The operator mounts credential state read-only into the runner container and points the harness config variable at it. The Compose files ship commented examples:
190+
The operator mounts credential state read-write into the runner container and points the harness config variable at it. The Compose files ship commented examples:
191191

192192
~~~yaml
193193
runner:
194194
# Opt-in: use your own harness subscription for local runs.
195195
# volumes:
196-
# - ~/.pi:/agenta/harness/pi:ro
196+
# - ~/.pi:/agenta/harness/pi:rw
197197
# environment:
198198
# - PI_CODING_AGENT_DIR=/agenta/harness/pi
199199
~~~
200200

201201
Rules:
202202

203-
- Mounts are read-only. The runner copies the state into a per-run directory so harness writes never touch the operator's source credential.
203+
- Mounts are read-write, and the harness runs directly out of the mount. There is no per-run copy of the credential state.
204+
205+
A subscription login is an OAuth login: the harness refreshes its access token mid-run and writes the new one back to its own config directory. A read-only mount plus a per-run copy discarded that refresh, so as soon as the provider rotated the refresh token the next run failed and the operator had to log in again by hand. Letting the harness own its token lifecycle, exactly as it does on a normal local install, is the only shape that survives rotation.
206+
207+
The tradeoff: harness writes land in the operator's login directory (refreshed tokens, and any skills or system prompt a run installs), and concurrent local subscription runs share that directory the same way two local harness sessions do. This path is single-trusted-operator only, so both are acceptable.
204208
- A `runtime_provided` local run without the matching mount fails with an error naming the missing configuration.
205209
- Mounted subscription state never leaves the runner container. Daytona runs never receive it.
206210
- One personal subscription belongs to one operator. The docs state this is a single-tenant convenience.
@@ -250,7 +254,7 @@ The fail-loud contract (a required mount failure fails the run, no silent durabl
250254

251255
### Docker Compose
252256

253-
The runner service enumerates only runner variables. It has no shared `env_file`. The examples include commented, opt-in read-only volumes for subscription inputs (section 6).
257+
The runner service enumerates only runner variables. It has no shared `env_file`. The examples include commented, opt-in read-write volumes for subscription inputs (section 6).
254258

255259
One runner service can enable `local,daytona`; there is no second subscription runner in the default stack.
256260

docs/design/agent-workflows/projects/runner-selfhosting-cleanup/open-issues.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ No implementation or tutorial should precede that decision.
2626

2727
## RSH-4: Declarative bootstrap assets, hooks, and network plugins
2828

29-
Version 1 ships no bootstrap manifest at all: local subscription state arrives through an operator-owned read-only Compose mount, and runtime customization happens through images and snapshots. If operator demand shows a real need for declarative per-run file assets (typed manifest, validation, Daytona upload of non-auth files), design it then, together with hooks: repository checkout, VPN enrollment, certificate rotation, custom initialization.
29+
Version 1 ships no bootstrap manifest at all: local subscription state arrives through an operator-owned read-write Compose mount, and runtime customization happens through images and snapshots. If operator demand shows a real need for declarative per-run file assets (typed manifest, validation, Daytona upload of non-auth files), design it then, together with hooks: repository checkout, VPN enrollment, certificate rotation, custom initialization.
3030

3131
A future design must define:
3232

docs/design/agent-workflows/projects/runner-selfhosting-cleanup/plan.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Goal: restore a trustworthy 8280 test environment before larger refactors.
1212
- Remove the dead `AGENTA_AGENT_SANDBOX_DAYTONA_SNAPSHOT` line.
1313
- Point the 8280 deployment at one trusted development runner.
1414
- Give that runner the Daytona provisioning credential.
15-
- Keep local Pi and Claude login inputs read-only and explicit.
15+
- Keep local Pi and Claude login inputs read-write and explicit (the harness owns its token lifecycle).
1616
- Remove or stop the two ad hoc runner services after the unified runner passes the matrix.
1717
- Record the exact local setup without committing personal credentials.
1818

docs/design/agent-workflows/projects/runner-selfhosting-cleanup/qa.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,12 @@ Assert the presence of only configured runner values, runner token reference, AP
9191

9292
## 4. Subscription mount tests
9393

94-
- every runtime-provided run gets a unique per-run config copy;
95-
- Pi receives `PI_CODING_AGENT_DIR` pointing at the copy;
96-
- Claude receives `CLAUDE_CONFIG_DIR` pointing at the copy;
97-
- the operator source is mounted read-only and harness writes do not mutate it;
98-
- teardown removes the per-run copy;
99-
- concurrent runs cannot see each other's copies;
94+
- every runtime-provided run runs directly out of the operator's mount (no per-run config copy);
95+
- Pi receives `PI_CODING_AGENT_DIR` pointing at the mount;
96+
- Claude receives `CLAUDE_CONFIG_DIR` pointing at the mount;
97+
- the operator source is mounted read-write and a token the harness refreshes persists to it;
98+
- teardown does NOT delete the mount;
99+
- concurrent local subscription runs share the mount (accepted: single trusted operator);
100100
- subscription state never uploads to a Daytona sandbox;
101101
- content and credential paths do not appear in logs or traces.
102102

@@ -130,9 +130,9 @@ Before deleting the extra runners:
130130

131131
1. Record the currently selected `AGENTA_RUNNER_INTERNAL_URL`.
132132
2. Confirm which service contains the Daytona credential.
133-
3. Confirm which read-only subscription inputs exist.
133+
3. Confirm which read-write subscription inputs exist.
134134
4. Configure the normal runner with enabled providers `local,daytona`.
135-
5. Add local-only Pi and Claude read-only subscription mounts.
135+
5. Add local-only Pi and Claude read-write subscription mounts.
136136
6. Run the primary matrix.
137137
7. Confirm the Daytona sandbox count returns to zero.
138138
8. Stop the legacy subscription sidecars.

docs/design/agent-workflows/projects/runner-selfhosting-cleanup/research.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ That couples three unrelated decisions:
3434
2. the runner happens to have Pi state;
3535
3. the state should be copied to a third-party remote sandbox.
3636

37-
The target removes this inference. Local subscription use requires an explicit read-only mount. Daytona runtime-provided subscription authentication is unsupported in version 1.
37+
The target removes this inference. Local subscription use requires an explicit read-write mount. Daytona runtime-provided subscription authentication is unsupported in version 1.
3838

3939
### Runtime-fact and policy booleans
4040

docs/design/agent-workflows/projects/runner-selfhosting-cleanup/status.md

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Last updated: 2026-07-13
99
Owner review plus a second reviewing agent converged on a re-scope for the MVP release. All four owner comments were adopted:
1010

1111
- Cut the runner `GET /capabilities` endpoint. API and runner read the same enabled-provider value from one deployment entry (the API already had this pattern via `AGENTA_SANDBOX_LOCAL_ALLOWED`). Deferred as RSH-7.
12-
- Cut the declarative bootstrap manifest. Local subscriptions use an operator-owned read-only Compose mount; runtime customization uses custom images and the existing Daytona snapshot scripts. Deferred as RSH-4.
12+
- Cut the declarative bootstrap manifest. Local subscriptions use an operator-owned read-write Compose mount; runtime customization uses custom images and the existing Daytona snapshot scripts. Deferred as RSH-4.
1313
- Cut the fail-loud mount rework. Version 1 keeps best-effort behavior plus one structured degradation warning. Deferred as RSH-11.
1414
- Confirmed customization is owned by the operator through scripts and images, not runner environment machinery.
1515

@@ -46,10 +46,54 @@ The managed-deployment migration is assessed in a private working note outside t
4646

4747
- [ ] Phase 0: local QA and snapshot repair.
4848
- [ ] Phase 1: canonical names and typed runner configuration.
49-
- [ ] Phase 2: runner environment narrowing.
50-
- [ ] Phase 3: subscription cleanup.
49+
- [x] Phase 2: runner environment narrowing.
50+
- [x] Phase 3: subscription cleanup.
5151
- [ ] Phase 4: hosting layout and public documentation.
5252

53+
## Phases 2 + 3 landed (2026-07-14)
54+
55+
Shipped in `fix/runner-env-narrowing` (stacked on `refactor/runner-config-names`):
56+
57+
- Deleted `shouldUploadOwnLogin` + `uploadPiAuthToSandbox` and their tests. The runner no longer
58+
discovers its own Pi login and uploads it to a Daytona sandbox.
59+
- `buildRunPlan` rejects Daytona + `runtime_provided`, and rejects a local `runtime_provided` run
60+
whose subscription mount (`PI_CODING_AGENT_DIR` / `CLAUDE_CONFIG_DIR`) is unset, before any
61+
sandbox side effect.
62+
- Local `runtime_provided` Pi and Claude runs read and write the operator's read-write mounted
63+
login DIRECTLY: no per-run copy. The harness refreshes its own OAuth token and the new token
64+
persists to the mount, so a rotated refresh token no longer breaks the next run. Tradeoff:
65+
concurrent local subscription runs share the harness config dir (single-trusted-operator path).
66+
- Removed the static `AGENTA_API_KEY` exporter fallback in `tracing/otel.ts`; export auth rides
67+
the per-run caller credential.
68+
- One structured `mount degraded kind=<k> cause=<c>` warning at each durable-null site
69+
(session cwd, agent mount, harness transcript). Failure behavior unchanged (RSH-11 still open).
70+
- Helm: `AGENTA_RUNNER_TOKEN` wired via `agentRunner.auth.tokenSecretRef` in
71+
`runner-deployment.yaml` + `_helpers.tpl` (both ends), values.yaml/schema examples, and a
72+
rendered-chart secret-absence test (`hosting/kubernetes/helm/tests/`) wired into CI.
73+
- Compose: commented opt-in read-write subscription mount examples on the OSS + EE runner service.
74+
75+
No-ops on this base (deletions already satisfied, nothing to remove): `commonEnv` is absent from
76+
the runner deployment (the #5286 include that would add it is not an ancestor of this base),
77+
`AGENTA_RUNNER_INHERIT_ALL_PROVIDER_KEYS` has zero code occurrences, and
78+
`AGENTA_SESSION_HARNESS_MOUNTS` was already removed from `services/runner/src` in phase 1.
79+
80+
## Deferred to post-release: credentialMode strictness flip
81+
82+
The interface's required-`credentialMode` contract (interface.md section 5) is NOT free on this
83+
base, so the flip is deliberately deferred and this slice keeps the existing inference branch.
84+
85+
The caller audit (research.md / the env-narrowing spec section 9) found one structural path that
86+
omits the field: a **model-less agent template** in the SDK agent handler. When `_agent_model_ref`
87+
returns `None` (`sdks/python/agenta/sdk/agents/handler.py`, model-less template branch), no
88+
`resolved_connection` is threaded, so `wire_resolved_connection()` returns `{}` and the run request
89+
carries no `credentialMode` / `provider` / `deployment`. Every model-configured caller sends all
90+
three via `ResolvedConnection.to_wire()`.
91+
92+
Post-release work to unblock the flip: thread a sentinel `ResolvedConnection` (credential_mode
93+
`"none"`, or `"runtime_provided"` for a self-managed harness) when `model_ref is None` in
94+
`handler.py`, confirm across the matrix, then make `credentialMode` required in `buildRunPlan` and
95+
delete the inference branch. `AGENTA_RUNNER_INHERIT_ALL_PROVIDER_KEYS` is already deleted (no-op).
96+
5397
## Review guidance
5498

5599
The draft PR has inline decision threads on the most consequential choices. Resolve those before implementation. Small naming edits can land directly in this workspace; changes that alter credential movement, remote subscription support, or mount behavior should update the interface, plan, and QA documents together.

0 commit comments

Comments
 (0)