Caveman
CLI & SDKsWrapping agents

Wrapping agents

caveman wrap <agent> starts a coding agent with provider base URLs pointed at the local proxy. It changes the child process environment, not the agent binary or config files.

Fig. — the proxy request path
Agentbase-URL swapcaveman-proxy · 127.0.0.1:8787matchauthtransformbyte-safemeterProviderBYOK upstreambytes intactresponse~/.caveman/caveman.dbinferred spend · SQLite

Most coding agents already support a provider base URL override. wrap knows which setting each registered agent reads. It does not patch the agent, intercept its binary, or translate protocols.

Start, then wrap

You can start the proxy first, then wrap an agent in another shell:

terminal
caveman start
caveman wrap claude

caveman start launches the proxy on 127.0.0.1:8787. caveman wrap claude then starts Claude Code with the right environment. For Claude that includes ANTHROPIC_BASE_URL; for OpenAI-protocol agents it uses OPENAI_BASE_URL. The agent still speaks its native protocol.

The agent registry drives it

Which variables get set comes from the registry under public/agents: one profile per agent plus a draft-07 JSON Schema. There are five profiles today: aider, claude, codex, gemini, and opencode.

Each profile names the agent's binaries, its wire protocol, and how to inject the base URL. The injection method is one of two:

  • env — set literal environment variables, with values that may use templates like {{cave_base_url}}, {{cave_api_key}}, {{cave_proxy_url}}, and {{cave_org_id}}. A variable that renders empty is omitted, so an empty auth token is never set.
  • config-env-content — render a mode-selected inline JSON config and set it as a single env var. This is how opencode is wrapped (via OPENCODE_CONFIG_CONTENT) without ever touching the user's own config file.

The wire protocol is one of anthropic-messages, openai-chat, openai-responses, or gemini-generatecontent.

Adding an agent is a data change

A new coding agent is one JSON file in the registry — no CLI code changes. The compiler validates it fail-closed: an unknown wire_protocol or injection.method fails the build rather than guessing. See the agent registry docs.

Only native protocols

wrap only uses wire protocols the proxy speaks natively — anthropic-messages, openai-chat, openai-responses, and gemini-generatecontent. There is no protocol translation in the wrap path. An agent is wrappable when it speaks one of these and exposes a base-URL override; if it does, pointing it at the proxy is enough, and its requests reach the provider in the same shape they always had.

No code change, byte-safe in transit

Wrapping changes only the agent's base URL through its own configuration. The proxy is byte-safe: in record mode and on any transform error it forwards the original bytes unchanged, and every spend row it records is inferred, never verified.