|
| 1 | +# Cowork on E2B: canonical architecture and delivery plan |
| 2 | + |
| 3 | +**Status:** implementation contract (2026-08-01) |
| 4 | +**Branch:** `codex/onevibe-computer` |
| 5 | +**Owner:** ONEComputer Control + Cowork runtime |
| 6 | + |
| 7 | +This is the single source of truth for the lightweight Cowork runtime. It |
| 8 | +supersedes any earlier plan that describes Cowork as a Kasm workspace or that |
| 9 | +requires KasmVNC parity inside an ephemeral chat sandbox. |
| 10 | + |
| 11 | +## Product boundary |
| 12 | + |
| 13 | +ONEComputer has two deliberately different experiences: |
| 14 | + |
| 15 | +| Experience | User mental model | Runtime | State lifetime | Visual surface | |
| 16 | +| --- | --- | --- | --- | --- | |
| 17 | +| **Computer** | “I am using my governed computer.” | Kasm/KasmVNC (or a later durable provider) | Persistent workspace and home volume | Full desktop, human takeover, clipboard, office apps | |
| 18 | +| **Cowork / ONEVibe** | “An agent is doing this task for me.” | E2B Firecracker microVM per conversation/task | Disposable task session; fixed TTL; destroy by default | Application-scoped evidence (browser/document PNGs), not a desktop login | |
| 19 | + |
| 20 | +Cowork is not a lightweight alias for Computer. It does not create, open, or |
| 21 | +list a Kasm workspace; it does not mount a durable home volume; and it does not |
| 22 | +expose port 6901. If a user needs a persistent desktop, human takeover, |
| 23 | +clipboard, or long-running office state, Control must route them to Computer. |
| 24 | + |
| 25 | +The current `/v1/onevibe/tasks` implementation still uses an internal |
| 26 | +workspace-shaped handle for compatibility with existing task/event tables. That |
| 27 | +handle is transitional and is never a durable workspace or a user-selectable |
| 28 | +Computer resource. New APIs and code must use a first-class Cowork session |
| 29 | +identifier and must not add dependencies on the workspace lifecycle. |
| 30 | + |
| 31 | +## Canonical Cowork session model |
| 32 | + |
| 33 | +The target Control model is an owned `cowork_session` with: |
| 34 | + |
| 35 | +- `sessionId`, tenant, subject, task, agent, policy hash, provider profile; |
| 36 | +- an immutable image/template digest and provider sandbox id; |
| 37 | +- a short creation-anchored deadline, turn budget, byte budget, and state; |
| 38 | +- durable redacted activity, ACP transcript references, VCR frame references, |
| 39 | + artifact ownership, and cleanup evidence; |
| 40 | +- no durable user home, no provider credential, and no hidden reasoning. |
| 41 | + |
| 42 | +The session is the authorization and retention boundary. The E2B sandbox is an |
| 43 | +implementation detail behind an `EphemeralExecutionAdapter`; it is never |
| 44 | +returned as a launch URL or treated as a workspace by the UI. |
| 45 | + |
| 46 | +### Target endpoints |
| 47 | + |
| 48 | +The compatibility endpoints remain read-only/deprecation paths while the |
| 49 | +following session-scoped endpoints are introduced: |
| 50 | + |
| 51 | +```text |
| 52 | +POST /v1/cowork/sessions |
| 53 | +GET /v1/cowork/sessions/:sessionId |
| 54 | +POST /v1/cowork/sessions/:sessionId/turns |
| 55 | +GET /v1/cowork/sessions/:sessionId/events?after=N |
| 56 | +GET /v1/cowork/sessions/:sessionId/events/stream?after=N |
| 57 | +POST /v1/cowork/sessions/:sessionId/frames |
| 58 | +GET /v1/cowork/sessions/:sessionId/vcr |
| 59 | +GET /v1/cowork/sessions/:sessionId/artifacts/:artifactId |
| 60 | +DELETE /v1/cowork/sessions/:sessionId |
| 61 | +``` |
| 62 | + |
| 63 | +Every route checks tenant, subject, session, task, policy, and expiry. Expired |
| 64 | +sessions are immutable for audit reads and reject all new turns, captures, |
| 65 | +approvals, and artifact mutations. |
| 66 | + |
| 67 | +## E2B Cowork runtime profile |
| 68 | + |
| 69 | +The first managed profile is `cowork-e2b-ephemeral-v1`: |
| 70 | + |
| 71 | +- pinned `linux/amd64` E2B template built from a minimal single-stage image; |
| 72 | +- Node 22, the official ACP SDK, pinned `codex-acp`, pinned OpenCode, and the |
| 73 | + `/usr/local/libexec/onecomputer-acp-chat.mjs` bridge; |
| 74 | +- Playwright and a pinned Chromium/Firefox runtime for browser tasks; |
| 75 | +- optional document tooling only when the image explicitly declares it; |
| 76 | +- a task-confined filesystem under `/workspace/task`, with no host mounts; |
| 77 | +- provider-native network allowlist plus the signed external egress proxy; |
| 78 | +- no Kasm daemon, VNC server, desktop login, nested KVM, or durable volume. |
| 79 | + |
| 80 | +The image is promoted by digest, carries SBOM/provenance, and never contains |
| 81 | +model-provider keys, enterprise OAuth tokens, E2B credentials, or registry |
| 82 | +passwords. E2B template build credentials are short-lived and supplied only to |
| 83 | +the build command. |
| 84 | + |
| 85 | +### Application-scoped VCR |
| 86 | + |
| 87 | +Cowork VCR means “what the agent did in the application,” not “a streamed |
| 88 | +desktop.” The capture contract is explicit: |
| 89 | + |
| 90 | +- browser: Playwright captures the actual page/context inside E2B; |
| 91 | +- document: a document-aware capture helper is used only if the profile has |
| 92 | + that application installed; |
| 93 | +- desktop: unsupported by the Cowork profile and fails closed with a typed |
| 94 | + capability error; Computer is the correct route. |
| 95 | + |
| 96 | +Each PNG is size-bounded, signature-checked, hash-linked to an activity |
| 97 | +sequence, and stored through Control. A screenshot produced by the browser UI, |
| 98 | +a fixture, or a host process is not evidence. |
| 99 | + |
| 100 | +## ACP and model boundary |
| 101 | + |
| 102 | +Codex and OpenCode run inside E2B as real ACP stdio servers. Control starts the |
| 103 | +allow-listed binary, negotiates the ACP protocol version/capabilities, and |
| 104 | +maps updates to the canonical event stream. Model traffic goes only through |
| 105 | +the governed LiteLLM route using a short-lived broker grant. The E2B guest never |
| 106 | +receives an OpenAI, Anthropic, Kimi, or LiteLLM administrator key. |
| 107 | + |
| 108 | +ACP is not the sandbox, approval, VCR, or model protocol. ACP permission |
| 109 | +requests are converted to an exact Control operation and otherwise cancelled; |
| 110 | +the UI cannot approve an action by itself. Product-facing SSE is Control’s |
| 111 | +ordered replay stream, not a direct unauthenticated ACP socket. |
| 112 | + |
| 113 | +## Lifecycle and failure semantics |
| 114 | + |
| 115 | +1. Authenticate and resolve the signed effective policy. |
| 116 | +2. Create an idempotent Cowork session and reserve its budget. |
| 117 | +3. Create the E2B microVM from the pinned profile and inject scoped grants. |
| 118 | +4. Start Codex or OpenCode ACP in the confined task directory. |
| 119 | +5. Stream redacted canonical events; capture application frames at governed |
| 120 | + action boundaries; persist artifacts before returning them to the UI. |
| 121 | +6. Pause only as an E2B cost optimization if the session deadline remains |
| 122 | + authoritative; never extend the deadline because a sandbox resumed. |
| 123 | +7. Destroy the sandbox, revoke grants, and purge task state at completion, |
| 124 | + cancellation, expiry, budget exhaustion, policy revocation, or provider |
| 125 | + failure. Preserve only the minimum redacted audit evidence. |
| 126 | + |
| 127 | +Provider, process, SSE, browser, and storage disconnects produce explicit |
| 128 | +failed/expired states. There is no synthetic assistant response, fake VCR |
| 129 | +frame, or “ready” state when a real ACP/model call did not happen. |
| 130 | + |
| 131 | +## Migration sequence |
| 132 | + |
| 133 | +### Phase 0 — contract and documentation (current) |
| 134 | + |
| 135 | +- Adopt this document as the canonical plan. |
| 136 | +- Keep Kasm Computer behavior unchanged. |
| 137 | +- Add `cowork-e2b-ephemeral-v1` capability metadata and an adapter seam that |
| 138 | + cannot call `open()` or `purgeWorkspace()`. |
| 139 | +- Mark the workspace-shaped task handle as compatibility-only. |
| 140 | + |
| 141 | +**Exit:** architecture tests prove Cowork cannot be exposed through the durable |
| 142 | +workspace list or a Kasm launch route. |
| 143 | + |
| 144 | +### Phase 1 — local image and ACP qualification |
| 145 | + |
| 146 | +- Build the minimal Cowork image locally or on a large-disk builder. |
| 147 | +- Run real Codex and OpenCode ACP against the local LiteLLM route where the |
| 148 | + binaries are available; assert initialize, streaming, cancellation, |
| 149 | + permission cancellation, malformed input, and path confinement. |
| 150 | +- Run Playwright in the image and retrieve a real PNG before any UI test. |
| 151 | + |
| 152 | +**Exit:** API qualification is green with no fixture response involved. |
| 153 | + |
| 154 | +### Phase 2 — E2B template and API-first live gate |
| 155 | + |
| 156 | +- Publish the image by digest and create a named E2B template. |
| 157 | +- Configure provider-reachable Control, LiteLLM, and egress HTTPS routes. |
| 158 | +- Prove create/resume/turn/stream/capture/artifact/cleanup with real E2B |
| 159 | + resources, including owner isolation, budget limits, and zero secret leakage. |
| 160 | +- Record sandbox/template ids, image digest, event hashes, PNG hashes, and |
| 161 | + final kill/purge evidence without recording credentials. |
| 162 | + |
| 163 | +**Exit:** the real API gate passes for Codex and OpenCode before browser work. |
| 164 | + |
| 165 | +### Phase 3 — browser UX and Manus-like VCR |
| 166 | + |
| 167 | +- Exercise the Cowork page against the same live API session. |
| 168 | +- Render left-side streaming activity and right-side application VCR with |
| 169 | + previous/next, scrub, jump-to-live, reconnect, and truthful degraded states. |
| 170 | +- Generate and download a real PPTX from a Cowork session; validate the Office |
| 171 | + package and its evidence links. |
| 172 | + |
| 173 | +**Exit:** browser E2E is a projection of a previously qualified API run. |
| 174 | + |
| 175 | +### Phase 4 — Computer handoff and optional providers |
| 176 | + |
| 177 | +- Add an explicit “open in Computer” handoff that creates/uses a durable Kasm |
| 178 | + workspace only when the user asks for desktop state or takeover. |
| 179 | +- Qualify Modal/gVisor or another provider against the same ephemeral contract; |
| 180 | + do not claim Kasm desktop parity for a provider that lacks it. |
| 181 | + |
| 182 | +## Non-negotiable QA gates |
| 183 | + |
| 184 | +- `npm test`, strict TypeScript build, and Playwright regression suite; |
| 185 | +- API E2E: real ACP initialize, ordered stream, terminal event, cancellation, |
| 186 | + budget/backpressure, owner isolation, PNG signature/hash, PPTX validation, |
| 187 | + and provider cleanup; |
| 188 | +- negative tests: no workspace listing, no Kasm open route, no desktop capture, |
| 189 | + expired-session mutation, invalid policy/grant, route rejection, secret |
| 190 | + leakage, and fabricated/fixture response rejection; |
| 191 | +- browser E2E only after API evidence exists; browser failures cannot be hidden |
| 192 | + by fixtures or simulated state. |
| 193 | + |
| 194 | +## Done means |
| 195 | + |
| 196 | +ONEComputer reaches Manus-like Cowork parity when a user can submit a task, |
| 197 | +watch a real Codex/OpenCode ACP stream, see truthful browser/document evidence, |
| 198 | +scrub and replay it, receive a real artifact, resume within the fixed session |
| 199 | +deadline, and observe deterministic cleanup—without ever creating or depending |
| 200 | +on a full Kasm workspace. |
0 commit comments