Skip to content

Agent integrations

The harnesses Tapes captures, which lane each one uses, and how to point a generic provider client at the transparent proxy.

Tapes captures an agent in one of three ways. The client launches the agent under a just-in-time capture proxy that dies with the process. For an agent that launches itself, the client binds the address the agent was installed against and captures whatever runs in that window. For Cursor, the client records the structured output the agent’s own print mode emits.

Harness Lane Plugin needed first
claude tapesctl start claude none
codex tapesctl start codex none
pi tapesctl start pi tapesctl plugin install pi
cursor tapesctl start cursor none
codex-app tapesctl capture codex-app tapesctl plugin install codex-app

Capture commands address the private ingest API, :8082 by default — not the read API on :8081. A capture pointed at the read port reports success and stores nothing.

Start the server and its local dependencies before these examples:

Terminal window
tapes local up
tapes serve

Then install the client:

Terminal window
curl -sSfL https://download.tapes.dev/tapesctl/install | bash

The agent brings its own provider credentials. tapes auth stores credentials for the server-side features that call a provider themselves — span embedding and skill generation — and is not part of capturing an agent.

Terminal window
tapesctl start claude --ingest-url http://localhost:8082

tapesctl starts a loopback capture proxy, sets Claude Code’s ANTHROPIC_BASE_URL to it, launches claude, and ships the captured turns to the server. Pass Claude flags after --:

Terminal window
tapesctl start claude --ingest-url http://localhost:8082 -- --worktree

Claude sessions also produce transcripts on disk, which carry the subagent structure the wire traffic alone cannot show. start tails them live. For a session no capture was running for, sweep them afterwards:

Terminal window
tapesctl sync --ingest-url http://localhost:8082

sync sweeps the last seven days by default; --since-days 0 sweeps everything. Re-pushing is safe — the server deduplicates.

For a manually managed, fixed-port proxy instead of the just-in-time one:

Terminal window
tapes serve --provider anthropic --upstream https://api.anthropic.com
ANTHROPIC_BASE_URL=http://localhost:8080 claude

The Tapes extproc adapter captures Anthropic Messages, OpenAI Responses, and OpenAI Chat Completions (/v1/chat/completions). Chat Completions supports JSON and SSE responses, text/refusals, streamed function-call arguments (including parallel calls), tool-result history, completion usage and cached input tokens. It keeps the provider’s model ID after any gateway routing rewrite. Explicit Chat Completions tool exchanges are derived as conversation calls even when non-streaming, so tool results link back to their function calls.

Responses and Chat Completions use distinct shared reducers. The gateway adapter selects the reducer by provider and endpoint, so an OpenAI-compatible /v1/chat/completions turn is not sent through the Responses parser. When reducing stored raw-only turns or recovering a missing reduction, the captured request selects the format (input versus messages). Deploy the updated Tapes ingest/derive image before enabling raw-only capture with the updated extproc image; dual retains the adapter’s reduction as well as the original wire bytes.

A stream missing [DONE], a finish reason, or valid frames is retained as partial, not represented as a completed answer. Invalid function arguments remain attached to the tool call without a partially decoded object; valid argument numbers retain their JSON precision. Choice zero is the canonical answer; additional choices are preserved in response metadata rather than merged. If zero is absent, only the indexed alternatives are retained and the response is marked partial. Null optional fields are treated as absent. Audio and custom-tool streaming deltas are not yet normalized; they are marked partial and require the raw lane for full-fidelity replay. Request parameters are forwarded unchanged; this adds capture, not API translation or execution.

The wire contract follows the OpenAI Chat Completions reference.

The terminal CLI is launched like Claude:

Terminal window
tapesctl start codex --ingest-url http://localhost:8082

The ChatGPT desktop app launches itself, so it is captured through lifecycle hooks instead. Install the plugin once, then run a capture window and start a session in the app:

Terminal window
tapesctl plugin install codex-app
tapesctl capture codex-app --ingest-url http://localhost:8082

plugin install codex-app writes the handoff file and points the app’s Codex configuration at the capture address; capture reads that handoff and binds it. Running capture first fails and tells you to install. Unlike start, capture prints no turn counts when it stops — it reports the number of sessions it saw.

plugin uninstall codex-app removes the provider entry and the handoff, but the plugin stays registered with Codex; the command prints the codex plugin remove line that finishes the job.

pi is captured by an installed extension, so the install is a prerequisite rather than a convenience:

Terminal window
tapesctl plugin install pi
tapesctl start pi --ingest-url http://localhost:8082

start pi refuses to run when the extension is absent, before anything is bound or launched. pi redirects several providers to one endpoint, so it is the one harness that takes --schema:

Terminal window
tapesctl start pi --ingest-url http://localhost:8082 --schema openai

--schema on claude or codex is an error rather than a silent no-op: each speaks exactly one schema, taken from the harness.

Cursor’s CLI, the agent binary, has no provider base-URL setting, so it is captured from its stream-json output instead of through a proxy:

Terminal window
tapesctl start cursor --ingest-url http://localhost:8082 -- --trust "summarize this repo"

start cursor copies the stream to your terminal, saves it, and uploads it as a transcript when the run ends. It never adds --trust, so in an untrusted directory Cursor refuses and the run exits with Cursor’s status. If the upload fails, the file stays under ~/.tapes/transcripts/cursor. Sweep it later:

Terminal window
tapesctl sync cursor --ingest-url http://localhost:8082

Turn counts come from derived traces, which include prompts, assistant responses, and tool calls. Tool outputs are retained even when no assistant response follows them. Cursor capture does not report token usage. Use --since-days 0 to retry recordings older than seven days.

With default configuration, Tapes forwards Ollama-compatible traffic to http://localhost:11434:

Terminal window
tapes serve
curl http://localhost:8080/api/chat \
-H 'Content-Type: application/json' \
-d '{"model":"qwen3-coder:30b","messages":[{"role":"user","content":"hello"}],"stream":false}'

Pull a chat model separately; tapes local up pulls the embedding model, not every completion model:

Terminal window
ollama pull qwen3-coder:30b

For another Anthropic-, OpenAI-, or Ollama-compatible application, configure its base URL as http://localhost:8080 and run tapes serve with the matching --provider and --upstream. Preserve the path convention expected by the client and provider.

The read API health endpoint is separate from the proxy and from ingest:

Terminal window
curl http://localhost:8081/ping
tapes status
tapesctl sessions list --api-url http://localhost:8081

A captured session appears in that list. start prints the harness’s own session id on exit, which is a different id from the one tapesctl sessions get takes — find the session in the list rather than pasting the printed id.

Stop the foreground tapes serve process with Ctrl-C. tapes local down removes bootstrap containers but keeps PostgreSQL data unless --wipe is supplied.