Host-controlled persistence
Apps choose the persistence adapter and keep invocation ownership, status reads, quota, and product-level authorization in their own backend.
Architecture
The worker never needs inbound network access. It connects to the host, claims eligible work, runs Codex locally, and submits the result.
Sequence
The host app keeps product identity and persistence. The local worker keeps local runtime access and claims only queued work for its owner.
sequenceDiagram
autonumber
actor User as "User"
participant UI as "Host App UI"
participant Host as "Host App Routes"
participant SDK as "@codexdock/sdk"
participant Store as "Persistence Adapter"
participant Worker as "Local codexdock CLI"
participant Codex as "Local Codex Runtime"
User->>UI: Start AI generation
UI->>Host: POST app generation route
Host->>Host: Resolve owner from cookie/session
Host->>SDK: invoke({ type, prompt, parameters }, owner)
SDK->>Store: createInvocation(status: pending, owner)
Store-->>SDK: invocation record
SDK-->>Host: invocationId + statusUrl
Host-->>UI: pending handle
Worker->>Host: POST /worker/connect
Host->>SDK: authenticate worker token
SDK->>Store: upsertWorker(owner, capabilities)
Store-->>SDK: worker record
SDK-->>Worker: polling policy
loop Short polling with backoff
Worker->>Host: POST /worker/next
Host->>SDK: authenticate worker token
SDK->>Store: claimNextInvocation(owner, capabilities)
Store-->>SDK: pending invocation or null
SDK-->>Worker: invocation or 204
end
Worker->>Codex: Run prompt in local workdir
Codex-->>Worker: generated result
Worker->>Host: POST /worker/result
Host->>SDK: validate worker claim + result schema
SDK->>Store: completeInvocation(result)
UI->>Host: GET statusUrl
Host-->>UI: completed resultOwner scope
The example uses an anonymous browser UUID cookie. A product app can swap that resolver for login, account, workspace, or system-job ownership. Worker tokens map back to the same owner.
sequenceDiagram autonumber participant Browser as "Browser" participant Host as "Host App" participant Pairing as "Pairing Store" participant SDK as "@codexdock/sdk" participant Store as "Persistence Adapter" participant Worker as "Owner-Scoped CLI" Browser->>Host: Open playground Host->>Browser: Set anon owner cookie Browser->>Host: POST create pairing code Host->>Pairing: Store code hash for anon owner Host-->>Browser: Show codexdock connect --code Worker->>Host: POST /pairing/exchange with code Host->>Pairing: Atomically consume valid code Pairing-->>Host: owner scope Host->>Pairing: Store worker token hash Host-->>Worker: worker token Browser->>Host: Create generation Host->>SDK: invoke(input, owner: anon uuid) SDK->>Store: createInvocation(owner: anon uuid) Worker->>Host: POST /worker/next with token Host->>SDK: authenticate token SDK->>SDK: token resolves to anon owner SDK->>Store: claim pending where owner matches Store-->>SDK: matching invocation only SDK-->>Worker: work item Worker->>Host: POST /worker/result Host->>SDK: authenticate token SDK->>SDK: require same owner, same workerId, status running SDK->>Store: complete invocation
Boundaries
Apps choose the persistence adapter and keep invocation ownership, status reads, quota, and product-level authorization in their own backend.
Local machines poll the host for work, so no inbound tunnel or public local port is required for a user's Codex runtime.