Files
PaperClipAI/doc/architecture/runner-cursor-capabilities.md
T

14 KiB

Cursor ACP capability inventory

Evidence date: 2026-09-28. Candidate: 2026.09.26-dd393fe. This profile is not live-qualified. No billable prompt was sent ($0 of the assigned $25 budget); no explicit Cursor credential was available. Local authenticated execution, restrictive permission enforcement, dollar usage, and Daytona execution remain required qualification gates.

The reference is the runner's Codex app-server integration and its closed thread-item inventory in src/provider-events.ts. Cursor ACP and its private extension methods are the transport; the legacy Cursor adapter is unchanged.

Evidence and packaging

  • Cursor's ACP contract describes stdio JSON-RPC, sessions, permissions and five extensions. The pinned binary reveals additional capabilities and one material documentation discrepancy below.
  • packages/paperclip-runner/cursor-distributions.json pins vendor archive and complete extracted execution-closure SHA256 digests for macOS ARM64/x64 and Linux x64. All three archives were downloaded and independently inventoried (446 files on macOS, 454 on Linux). A real macOS ARM64 installation passed the materializer's full closure check.
  • The archive is a complete runtime: bundled node, index.js, dynamically loaded numbered JavaScript chunks, native addons, workers, and assets. Pinning only the launcher or one executable does not pin its execution dependencies. The materializer rejects links/special files and overwrites, and verifies every file against the pinned closure digest.
  • test/fixtures/cursor-acp/credential-free-probe.json records an actual macOS ARM64 initialization and nonbillable method probes. initialize reports ACP v1, session load/list, HTTP/SSE MCP, image prompts, and opt-in subagent events. Audio and embedded context are false. session/fork and session/resume return method-not-found. Creating/listing a session requires authentication.
  • Static evidence comes from 5672.index.js (ACP implementation), 8096.index.js (ACP SDK protocol schemas), 190.index.js (hook paths) and index.js (CLI/configuration), all bound by the archive and closure pins. SDK schema support alone is not counted as implemented harness capability.

Capability matrix against Codex app-server

“Implemented” below means a tested Cursor boundary implementation; the shared runtime must route its canonical events and durable requests. It is not a claim of authenticated end-to-end qualification.

Capability Cursor harness/ACP evidence Paperclip treatment Remaining gap or qualification
Streaming assistant/reasoning agent_message_chunk, agent_thought_chunk in live and replay presenters Existing ACP streaming path Authenticated event capture required
Tool lifecycle/input/output tool_call and tool_call_update, including raw input/output, locations and content Existing canonical tool lifecycle; Cursor extensions add semantic activity Standard content blocks/diffs must survive shared ACPX mapping; evaluate captured field coverage
Human questions cursor/ask_question, native single/multiple selections normalizeCursorQuestionRequest: all questions required; opaque UI IDs round-trip native IDs; forged/duplicate/missing selections rejected Active-turn adapter maps canonical answers, decline to skipped, and cancellation; durable delivery still requires end-to-end evidence
Proposed plans and decisions cursor/create_plan with full Markdown, overview, todos, named phases and project flag normalizeCursorPlanRequest: complete presentation; accept/reject/cancel; revision-derived question ID; rejection feedback Foundation question descriptions allow 100,000 chars; this boundary also enforces the 196 KiB UTF-8 durable payload cap. Oversize rejects; it is never truncated. No generated planUri, since no uploaded plan artifact is fabricated
Execution checklist Standard ACP plan and cursor/update_todos (merge) Per-turn reducer merges by native ID and emits complete snapshots with increasing revisions Native cancelled status is visible as “Cancelled” with canonical blocked status, since canonical plan schema has no cancelled enum
Child activity Optional subagent_spawned, subagent_state_update; metadata has tool-call/agent/model identity Stateful child normalizer emits canonical delegation and retains role/task across state deltas; active-turn adapter validates parent, known child spawn, and immutable tool/agent origin Requires client _meta.subagents: true. ACPX SDK 1.4.0 lacks these two update variants; a closed pre-parser intercept is required. Nested transcript routing and child authority need end-to-end evidence
Completed subagent tasks cursor/task: description, prompt, subtype, model, ID, duration Canonical delegation with role, model, task and duration in activity summary Dedicated numeric duration field absent from canonical delegation schema
Subagent questions Pinned ACP subagent handler explicitly rejects interactive questions No unsupported affordance advertised Confirmed harness omission; requires upstream support
Generated images cursor/generate_image: description, path and reference-image paths Canonical generated/viewed artifact events; description notice; realpath/regular-file containment checks; registered:false Paths are references, not automatic uploads. Revalidate before artifact ingestion. No image bytes invented
Files and diffs Tool content/location extraction, native edit output Existing workspace-diff machinery plus canonical tool events Need live fixture proving complete before/after content and path attribution; currently unverified
True active-turn steering No session/steer; handlePrompt cancels its existing pending prompt before starting another Advertise steering unsupported Concurrent prompt is interruption/replacement, not Codex-style in-place steering. Do not mislabel it
Queued follow-ups No harness queue method discovered Control-plane scheduling can send another prompt after settlement No native queue-management events; do not send concurrently to emulate queueing
Cancellation session/cancel calls the active prompt cancellation callback Existing interruption path Process/child cleanup and exact terminal settlement require live qualification
Turn settlement Prompt implementation drains background subagent completion and awaits child publishers Existing prompt result terminal boundary Background shell commands and child errors need live denial/settlement fixtures
Session continuity session/new, session/load; load replays historical messages, reasoning, tools, images and children Existing session load/recovery boundary with identity fencing Duplicate replay suppression and provider-death recovery need authenticated proof
Session discovery session/list implemented, cwd filter absolute; pagination cursor rejected Discovered and reported Currently unused: runner recovers only its exact recorded session; arbitrary history browsing needs company-scoped discovery API
Fork/resume methods session/fork and session/resume absent in agent implementation and return method-not-found Unsupported Session load is available; do not infer fork from SDK schema
Modes agent, plan, ask; session/set_mode and current_mode_update Existing review/mode activity plumbing can display changes Generic operator mode-selection surface not implemented in this provider slice
Model selection session/set_model, config option model, model-parameter options, config_option_update; cursor/list_available_models extension Exact requested model must be selected/verified by shared admission Available-model listing is authenticated; no model ID guessed or silently substituted. Parameterized model UI not added
Available commands available_commands_update, including skills/slash commands Existing ACP runtime event path Command-specific UI/discovery not implemented; preserve bounded metadata where shared mapping permits
Session metadata session_info_update title after automatic naming Capability documented Runner owns normalized session identity; provider title is currently not surfaced
Prompt media Image=true, audio=false, embeddedContext=false in observed initialize Image inputs may be admitted by advertised capability Product attachment-to-ACP conversion needs qualified test; audio/embedded context unsupported
MCP and semantic tools Session MCP injection supports stdio/HTTP/SSE; user/project config also loaded Runner-owned authenticated MCP bridge only; fail closed on ambient project MCP Exact tool discovery and company/token boundary remain live tests
Usage/cost No usage_update/token-usage emission found in pinned ACP implementation; prompt result contains stopReason Must report usage unavailable, never zero or estimates presented as actual Dollar accounting unavailable without another explicit measured source. Live spend needs a measurable bound before starting
Reviews, compaction, hooks, memory Native mode changes, hooks present internally; no dedicated ACP counterparts to Codex context/hook/memory lifecycle found No fabricated event families Distinguish confirmed absence of ACP event mapping from unverified native internals
Goal controls / lineage No ACP goal or fork lineage protocol found Unsupported No equivalent of Codex native goals/thread lineage

Wire and isolation findings

The documentation calls todo/task/image methods notifications. The pinned presenter actually calls connection.extMethod(...).catch(...): these messages can carry JSON-RPC IDs. They need immediate acknowledgement plus activity normalization. They must never become human input requests or block awaiting an unnecessary decision.

Question and plan requests lack a session ID. The shared hook must bind them to the retained connection, active execution/session/turn and originating request ID; reject stale/duplicate answers; cancel on turn termination; persist requests before exposing them; and acknowledge provider delivery before settlement. The provider module does not substitute a best-guess session.

Fixed launch arguments are --disable-project-configs --disable-auto-update acp, using the verified bundled Node and absolute verified index.js. Private HOME/XDG roots are required together with CURSOR_CONFIG_DIR, CURSOR_DATA_DIR, a private compile cache, AGENT_CLI_CREDENTIAL_STORE=memory, and NO_OPEN_BROWSER=1. Only explicitly bound CURSOR_API_KEY or CURSOR_AUTH_TOKEN may enter; never inherit shell credentials. Do not use --force, --trust, or --approve-mcps to paper over governance.

--disable-project-configs only suppresses .cursor/cli.json. It does not suppress project MCP, Cursor/Claude hooks, or installed plugins. assertCursorWorkspacePolicy refuses ambient project execution config from the workspace through its nearest Git root, including symlinks and unreadable configuration. Ordinary Claude settings with neither hooks nor plugins remain admissible. Enterprise system hooks are checked too. The host must protect these config paths during execution and repeat admission checks on recovery. Admission alone cannot prevent a concurrent file mutation. Team-provided remote hooks are another upstream boundary and remain unqualified under restrictive execution.

Artifact paths are never automatically read or uploaded. References require a present regular file under the physical workspace, reject traversal and symbolic links, and retain registered:false. Private/outside paths are omitted and produce a visible warning. This is metadata validation, not durable file ownership or a replacement for artifact registration checks.

Verification and open work

Passed in the provider worktree:

  • 13 Cursor Vitest cases: questions, multi-selection, native ID round-trip, invalid answers, exact plan revisions, outcomes, todo delta merging, delegation metadata, path containment/symlink refusal, child identity retention, private launch defaults and project config gates; active-turn canonical response mapping and immediate acknowledgements; stale/foreign/unknown child identity rejection.
  • 5 materializer Node tests: platform pins, entire-tree tampering, linked paths, archive tampering before extraction, and overwrite refusal.
  • Targeted strict TypeScript compilation for both provider modules and their imported contracts.
  • Credential-free wire initialization and auth/method probes, plus real macOS ARM64 materialization and archive/closure inventories for the other two platforms.

The generic native-distribution lease now snapshots the pinned closure, launches Cursor through its verified bundled Node with a closed-module guard, and uses the existing lifetime guardian. A real nonbillable Cursor initialization passed through that lease. Its six focused tests passed, including argument fencing, external module rejection, and native child ownership/exit proof. The existing snapshot suite passed; four legacy installation tests were blocked by the shared installed Claude SDK (0.3.280 versus the pinned 0.3.263), with the remaining legacy tests passing or platform-skipped.

Priority follow-ups before advertising support: (1) shared hook integration with durable response/recovery tests; (2) authenticated native lifetime and cleanup proof; (3) explicit credentials plus exact available model and measured dollar budget; (4) local and Daytona semantic tools, permissions, steering distinction, files/artifacts, questions/plans and settlement proof; (5) field-by-field captured trace audit to identify any additional unconsumed native fields.

Remaining rich capabilities intentionally unused: session discovery, generic mode/config-option UI, provider session titles, command/skill picker metadata, nested child transcripts beyond delegation summaries, native numeric task duration, and optional planUri. They are listed above with reasons; neither “unsupported” nor “complete” should be inferred for unverified live behaviors. The final combined report must update this inventory with integration evidence and include any further events observed during authenticated qualification.

Shared display-channel verification additionally covers exact rich-event schema validation, terminal/semantic/source injection rejection, active-turn fences, complete Unicode plan preservation through durable outbox persistence, secret redaction disclosure, and oversized UTF-8 rejection. The 4 KiB diagnostic preview cap remains active for diagnostics, never full approval documents.