# Paperclip Runner compatibility and rollout - Status: Proposed - Date: 2026-08-24 - Parent decision: [Paperclip Runner architecture](paperclip-runner.md) ## Purpose This document defines compatibility rules for introducing the experimental Paperclip Runner. These rules are acceptance criteria for each implementation change. They are not a migration plan for existing adapters. ## Compatibility invariants 1. Existing adapter selection is authoritative. A direct adapter stays direct. 2. A non-runner run must not start runnerd or open PRP. 3. A non-runner run must not create native result, finalization, status-decision, or runner-transport records. 4. A non-runner run must not invoke native status arbitration. 5. Direct adapters keep their current transcript, interaction, cancellation, result, and finalization behavior. 6. Runner-only UI controls depend on persisted runtime facts and are absent from direct runs. 7. The rollout flag controls fresh runner selection and fresh runner starts. 8. A flag change does not rewrite an agent profile or a persisted run choice. 9. Persisted native data remains readable after the flag is disabled. 10. Recovery may finish an already persisted native run while fresh native starts remain blocked. ## Runtime selection The server resolves and persists the runtime once, before provider launch. | Persisted runtime | Adapter | Flag | Result | | --- | --- | --- | --- | | none | Any direct adapter | off or on | Use the existing direct path. | | none | `paperclip_runner` with any qualified provider | off | Reject the fresh start with a stable rollout-disabled error. | | none | `paperclip_runner` with a qualified provider | on | Use PRP v1 and the provider's persisted runnerd backend. | | none | `paperclip_runner` with an incomplete or unqualified profile | on | Reject the profile before runnerd starts. | | direct | Any | changed later | Keep the persisted direct path. | | native | Any | changed later | Keep the persisted native path for read, cancel, recovery, and finalization. | The server must not fall back from a selected `paperclip_runner` start to `codex_local`. A configuration or rollout error must be visible. Silent fallback would hide the runtime that executed the task. ## Direct adapter boundary This rule applies to every built-in and plugin direct adapter. It includes: - `codex_local`; - `claude_local`; - `opencode_local`; - other local CLI or session adapters; - process and HTTP adapters; - gateway adapters; and - external adapter plugins. Adding Paperclip Runner must not add runner imports or runner branches inside a direct adapter implementation. The heartbeat coordinator may select the explicit runner adapter at one narrow seam. All other adapters continue through their existing code. For a flag-off `codex_local` heartbeat, compatibility proof must show: - one direct invocation; - the same normalized result and finalization bytes as the approved baseline; - zero runner processes; - zero PRP connections; and - zero native rows. ## Configuration behavior When the rollout flag is off: - creation UI does not offer `paperclip_runner`; - edit UI does not offer switching to `paperclip_runner`; - server creation and import reject a new `paperclip_runner` selection; - the server rejects a fresh start for an existing runner-configured agent; - read and export preserve an existing runner configuration; - unrelated edits to an existing runner-configured agent do not erase its configuration; and - switching that agent to a direct adapter remains allowed. When the rollout flag is on: - creation, import, and edit accept `paperclip_runner` only with a qualified Codex, OpenCode, Claude Managed, AWS AgentCore, or Claude/Codex ACPX profile; - switching from a direct adapter affects only future unresolved runs; and - switching away from the runner affects only future unresolved runs. Server validation is the authority in both states. Import files and API clients cannot bypass the flag or provider allowlist. ## Persisted native runs The following data remains readable independent of the current flag: - the persisted runtime selection and reason; - run, runner, session, turn, and provider identity; - ordered runner and provider events; - accepted result and evidence assessment; - finalization coordinator and status decision; - usage, cost, cancellation, and terminal details; and - durable interactions and final task-thread reply. If the flag is disabled during an in-flight native run, the server may reconnect, cancel, reconcile, and finalize that same run. It must not use that recovery as authority to start a new native run. Recovery must remain idempotent. Repeating it cannot add a second final reply, interaction, wake, status decision, or application effect. ## Task-page compatibility The task page uses one provider-neutral thread projection. Runtime facts may add runner event groups, semantic receipts, usage, and structured questions. They must not replace classic direct-adapter content. Direct-adapter coverage must include: - an active run; - a settled run; - an empty transcript; - a pending interaction; - a resolved interaction; and - the classic interface state. The existing composer remains usable for direct adapters. A direct run does not show reconnect, runner cancel, semantic receipt, or other runner-only controls. Final replies continue to use the existing issue-comment behavior. ## Structured input compatibility New structured questions use `paperclip.question_set.v1` and the matching response contract. Provider-specific question objects remain inside their drivers. Legacy unstructured interaction records remain readable and resolvable. A structured form fails closed when its required schema, question mode, question ID, option ID, or response value is invalid. The implementation must not silently convert malformed structured input to a legacy text prompt. ## Protocol version compatibility PRP wire versions, fixture versions, event schema versions, and typed schema discriminators are independently versioned. - Peers negotiate the highest common PRP version. - No common required version fails closed before command or provider execution. - An unknown required fixture or event schema version fails closed. - An unknown required typed discriminator fails closed. - Additive optional properties remain compatible only when an old v1 consumer can ignore them without changing behavior. - Unknown object properties must survive validation when the owning schema permits additive fields. Breaking meaning requires a new required version. A provider error is not a protocol negotiation result. ## Semantic action compatibility Catalog generation and production authorization are separate steps. - A catalog entry does not authorize production use. - An operation without a production binding is undiscoverable. - An operation denied to the run is undiscoverable unless the protocol explicitly defines a safe denied receipt for that discovery mode. - A duplicate call with the same idempotency key and canonical input returns the original safe receipt. - Reusing the key with different input returns a conflict and performs no second effect. - Receipts redact credentials, private provider payloads, and hidden identity. ## Required compatibility matrix Each runner-related pull request updates only rows that it can execute. The complete first-wave matrix must cover: | Area | Required cases | | --- | --- | | Runtime selection | Every built-in direct adapter, explicit runner selection, unsupported provider, flag on, and flag off. | | Direct regression | Flag-off `codex_local` invocation count, byte-stable result/finalization, and zero native rows. | | Configuration | Enabled and disabled create, import, edit, read, export, and adapter switch. | | Recovery | Persisted native run after flag disable, reconnect, duplicate event, duplicate command, cancellation, and server restart. | | Protocol security | Cross-company binding, ticket replay, ticket expiry, malformed frame, unsupported version, and revoked lease. | | Semantic actions | Discovery denial, unbound action, duplicate call, conflicting retry, redaction, and governed action. | | Task page | Active, settled, empty transcript, interaction, and classic direct-adapter states. | | Structured input | Valid response, malformed response, stale response, duplicate response, provider loss, and cancellation. | ## Pull request acceptance Every implementation pull request must: - build and work against its declared base; - keep its changed-file count below 100; - update manifests and exports only for implemented surfaces; - run the smallest relevant tests before the repository handoff gate; - run typecheck, tests, and build for handoff; - run protocol parity, Cargo, clean-consumer, migration, token, and browser gates when those areas change; - contain no unexplained failed, cancelled, or path-skipped verification; and - resolve actionable review and security findings before it is ready. Generated files land with their source and a drift check. `pnpm-lock.yaml` is owned by CI and is not part of these pull requests.