Files
PaperClipAI/docs/adapters/overview.md
T
DottaandPaperclip 2991a59b17 fix(adapters): prevent engine fallback and preserve usable runtime defaults (#13105)
## Thinking Path

> - Paperclip manages agents that must write work and report task
outcomes through its API.
> - Local adapters select an execution engine and its permission
settings.
> - A higher ACP Node requirement can make an unchanged installation
lose access to its default engine.
> - The adapter then silently selects CLI, which can change permissions
and block API access.
> - This pull request keeps the engine choice fixed and reports missing
prerequisites before work starts.
> - It also gives explicit Codex CLI runs usable defaults and keeps
managed services on a supported Node runtime.

## Linked Issues or Issue Description

Refs #12215. Related changes: #11792 raised the Node requirement; #13094
addressed separate runner networking behavior. This change fixes the
engine-selection and managed-launcher paths.

**What happened?**

An unchanged agent could switch from ACP to CLI after an upgrade. Codex
CLI then used read-only permissions with networking disabled. The run
could finish without updating its task. Repeated recovery attempts used
the same unavailable setup. Managed updates also skipped the Node check
and did not refresh old launchers.

**Expected behavior**

An unavailable engine must fail with a clear setup error. It must not
silently select another engine. Explicit CLI runs must be able to write
workspace files and call the API unless the operator configures stricter
settings. Managed updates must validate Node and keep child tools on
that runtime.

**Steps to reproduce**

1. Run an ACP-default agent under Node 22 after the ACP minimum rises to
24.11.
2. Leave the engine unset and disable the approval/sandbox bypass.
3. Observe the old adapter select CLI and fail to write task disposition
through the API.
4. Start a managed service with an old launcher and a supervisor PATH
that selects a different Node for child tools.

## What Changed

- Remove automatic engine fallback for Codex, Claude, Gemini, and Kimi.
Check prerequisites for default and explicit ACP selections.
- Return a configuration error with proof that provider work did not
start. Stop automatic continuation retries for this error.
- Enable Codex ACP workspace networking at the actual turn boundary.
Upstream mode presets otherwise force it off even when config.toml
enables it. Preserve explicit network denial and read-only mode.
- Set workspace-write and network access defaults for explicit Codex CLI
runs. Preserve explicit sandbox modes, profiles, and network
restrictions.
- Pin the validated Node directory in managed launcher PATH. Refresh
legacy launchers during installs and npm/Git updates.
- Reject updates on unsupported Node. Keep update checks, dry runs, and
rollback available.
- Synchronize the qualified Codex ACP executable identity across server,
TypeScript runner, Rust runner, and provider-pack launch paths.
- Add regression tests and update engine and installation documentation.

## Verification

- [Full CI passed on the final
head](https://github.com/paperclipai/paperclip/actions/runs/34387099695):
typecheck, build/native runner verification, all general and serialized
test shards, all browser shards, release registry, canary dry run, and
policy checks.
- Greptile: 5/5 on `2c1d6e2815830a5cd39e36c8a082cc0c4441b6c0`, with no
unresolved review findings. Security gates are green.
- Full workspace typecheck and build also passed locally. The final
deployed Linux build passed.
- Full Codex, Claude, Gemini, and Kimi source test suites: 804 passed, 2
skipped. Installer, updater, and launcher tests: 47 passed. Installed
ACP turn-boundary tests: 3 passed. ACP packaging tests: 14 passed.
Focused recovery classification tests also passed.
- Real Linux Codex CLI runs, both fresh and resumed, wrote a workspace
file and reached the control-plane health API with the new defaults.
- Explicit read-only and network-disabled control probes retained those
restrictions.
- A real ACP run on the final deployed Linux build wrote a file and
reached the control-plane API with HTTP 200, without engine fallback.
The same probe failed DNS before the turn-policy patch.
- Executable-identity and installed-policy contracts: 12 passed.
Affected native server tests: 197 passed. Runner factory tests: 21
passed. Rust qualification and native provider integration tests: 11
passed.
- Deployed the production changes to a Linux service on Node 24.20 after
a verified database backup. Health, bootstrap readiness, static UI,
executable/cwd identity, and guarded restart checks passed. The restart
lost no runs.
- Corrected stale Kimi skill-default and Gemini remote-archive fixtures;
both suites pass.

## Risks

- Default or legacy auto engine settings now fail when ACP is
unavailable. Operators who intend to use CLI must select it explicitly.
- Codex CLI now permits workspace writes and networking by default, and
ACP workspace-write turns permit networking by default. Explicit
operator sandbox settings remain authoritative.
- Old managed launchers keep their pinned Node until they are
reinstalled under a supported runtime. An old updater cannot repair
itself; the documentation gives the current installer command.
- Custom service wrappers and global/source installations must configure
their runtime PATH. No database migration is required.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, repository inspection,
shell execution, and test tools. The exact serving model identifier and
context-window size are not exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-09 13:27:24 -05:00

8.9 KiB

title, summary
title summary
Adapters Overview What adapters are and how they connect agents to Paperclip

Adapters are the bridge between Paperclip's orchestration layer and agent runtimes. Each adapter knows how to invoke a specific type of AI agent and capture its results.

How Adapters Work

When a heartbeat fires, Paperclip:

  1. Looks up the agent's adapterType and adapterConfig
  2. Calls the adapter's execute() function with the execution context
  3. The adapter spawns or calls the agent runtime
  4. The adapter captures stdout, parses usage/cost data, and returns a structured result

Built-in Adapters

Adapter Type Key Description
Claude Code claude_local Runs Claude Code CLI locally, with a native ACP engine when available
Codex codex_local Runs OpenAI Codex CLI locally, with a native ACP engine when available
Gemini CLI gemini_local Runs Gemini CLI locally (experimental — adapter package exists, not yet in stable type enum)
Kimi Code CLI kimi_local Runs Kimi Code CLI locally through ACP, with explicitly selectable headless -p mode
OpenCode opencode_local Runs OpenCode CLI locally (multi-provider provider/model)
Cursor cursor Runs Cursor in background mode
Pi pi_local Runs an embedded Pi agent locally
Hermes hermes_local Runs the local Hermes CLI through @paperclipai/hermes-paperclip-adapter
Hermes Gateway hermes_gateway Calls an already-running Hermes API server through @paperclipai/hermes-paperclip-adapter/gateway
OpenClaw Gateway openclaw_gateway Connects to an OpenClaw gateway endpoint
Process process Executes arbitrary shell commands
HTTP http Sends webhooks to external agents

Credential ownership for sandbox targets

Local CLI adapters can run on the Paperclip host, SSH targets, or managed sandbox targets. The adapter decides which credential home is authoritative before the CLI starts:

Adapter Credential topology Which credential file wins on managed sandbox targets
codex_local Host-owns-auth for Paperclip-managed CODEX_HOME A host-owned auth.json is symlinked into the managed CODEX_HOME and uploaded to the sandbox. If a per-agent OPENAI_API_KEY is configured, Paperclip writes an API-key auth.json instead and that file wins. A login baked into the sandbox image is shadowed because Codex runs with Paperclip's uploaded CODEX_HOME.
claude_local Snapshot-owns-auth for managed remote Claude config A configured ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN (agent or environment env) wins over any stored login. Otherwise Paperclip uploads only sanitized settings and skill/runtime assets, and when the remote managed config has no Claude credential files it copies .credentials.json or credentials.json from the sandbox image's own $HOME/.claude, so the image's login wins.

Worked examples:

  • Codex sandbox with host ChatGPT login: the host ~/.codex/auth.json is symlinked into the managed home, then uploaded as the sandbox CODEX_HOME. Codex reads that uploaded file and does not use any auth.json already present inside the sandbox image.
  • Claude sandbox with image login: Paperclip materializes a remote CLAUDE_CONFIG_DIR, then fills missing .credentials.json / credentials.json from the sandbox image's own $HOME/.claude. The snapshot's Claude login is the credential source for the run.

Hermes local vs gateway

Use hermes_local when Paperclip should start the local hermes CLI on the same host for each heartbeat. Use hermes_gateway when Hermes is already running as an HTTP/SSE API server and Paperclip should call that server instead of spawning a process. Both type keys are stable built-ins.

The unified Hermes package owns both built-in adapters. The older @paperclipai/adapter-hermes-gateway package remains only as a deprecated compatibility shim that re-exports the gateway entrypoints for one release. New plugin overrides should target @paperclipai/hermes-paperclip-adapter and set the desired type key (hermes_local or hermes_gateway).

External (plugin) adapters

These adapters ship as standalone npm packages and are installed via the plugin system:

Adapter Package Type Key Description
Droid @henkey/droid-paperclip-adapter droid_local Runs Factory Droid locally

External Adapters

You can build and distribute adapters as standalone packages — no changes to Paperclip's source code required. External adapters are loaded at startup via the plugin system.

# Install from npm via API
curl -X POST http://localhost:3102/api/adapters \
  -d '{"packageName": "my-paperclip-adapter"}'

# Or link from a local directory
curl -X POST http://localhost:3102/api/adapters \
  -d '{"localPath": "/home/user/my-adapter"}'

See External Adapters for the full guide.

Adapter Architecture

Each adapter is a package with modules consumed by three registries:

my-adapter/
  src/
    index.ts            # Shared metadata (type, label, models)
    server/
      execute.ts        # Core execution logic
      parse.ts          # Output parsing
      test.ts           # Environment diagnostics
    ui-parser.ts        # Self-contained UI transcript parser (for external adapters)
    cli/
      format-event.ts   # Terminal output for `paperclipai run --watch`
Registry What it does Source
Server Executes agents, captures results createServerAdapter() from package root
UI Renders run transcripts, provides config forms ui-parser.js (dynamic) or static import (built-in)
CLI Formats terminal output for live watching Static import

Choosing an Adapter

  • Need a coding agent? Use claude_local, codex_local, opencode_local, hermes_local, or install droid_local as an external plugin
  • Need the richest live run feedback? Use claude_local, codex_local, or gemini_local with adapterConfig.engine set to acp when the execution environment satisfies the ACP prerequisites — see Feedback granularity
  • Need Hermes on another host or already running as a service? Use hermes_gateway
  • Need to run a script or command? Use process
  • Need to call a custom external service? Use http
  • Need something custom? Create your own adapter or build an external adapter plugin

Feedback Granularity

Adapter choice determines how much structured, live detail a run's transcript can show while the agent is still working. Every adapter's stdout is streamed to the run log and rendered live in the UI — including runs on sandbox execution targets, whose logs are tailed and delivered incrementally — but the granularity of what you see depends on the event stream the adapter emits.

Rough tiers, richest first:

  1. Native ACP engine (claude_local, codex_local, or gemini_local with engine: "acp") — full structured event stream. ACP emits a JSONL event per meaningful runtime moment: acpx.session (agent, mode, session identity), acpx.status (progress text plus context-window usage), acpx.text_delta (assistant/thinking token deltas), acpx.tool_call (tool title, call id, and status updates as the call progresses), acpx.result (stop reason summary), and acpx.error (code, message, retryability). The transcript renders these as live-updating message, thinking, tool, and status blocks, and repeated acpx.tool_call status updates fold into a single tool card instead of stacking duplicates.
  2. CLI wrappers (claude_local, codex_local, cursor, opencode_local, …). These parse each CLI's own streaming JSON output. You get assistant text, tool calls/results, and a final usage/cost summary, but granularity is limited to what the CLI prints — some emit tool progress, others only call/finish pairs.
  3. Generic adapters (process, http). Plain stdout/stderr lines with no structured transcript — you see raw output only.

Recommendation: use the native ACP engine on claude_local, codex_local, or gemini_local when the selected execution environment supports it. Rich ACP status events (including context usage) and incremental tool-call updates give the closest thing to watching the agent work locally.

UI Parser Contract

External adapters can ship a self-contained UI parser that tells the Paperclip web UI how to render their stdout. Without it, the UI uses a generic shell parser. See the UI Parser Contract for details.