---
title: "Switch from Headroom to Caveman: step by step guide"
description: "Switching from Headroom to Caveman is mostly a launcher swap for coding agents and a one-line adapter swap for apps. The part that needs care is state: Headroom's retrieval handles point into Headroom"
canonical: https://caveman.ac/switch/headroom
last-updated: 2026-10-04
---

# Switch from Headroom to Caveman: step by step guide

Switching from Headroom to Caveman is mostly a launcher swap for coding agents and a one-line adapter swap for apps. The part that needs care is state: Headroom's retrieval handles point into Headroom's store, and Caveman cannot resolve them. Always start fresh sessions on Caveman and let running Headroom sessions finish first.

Read the [Headroom comparison](/compare/headroom) first if you are still deciding. Headroom is a strong tool, and for some setups it is the better one.

## Step 1: Write down what Headroom does today

Note which Headroom mode you run:

- `headroom wrap <agent>` around a coding agent
- `headroom proxy` with a client pointed at it
- a framework hook in your code, like the Vercel AI SDK middleware or the LiteLLM callback
- the MCP server

Record `headroom --version` and any settings you changed, such as `HEADROOM_CCR_TTL_SECONDS`. If you used Headroom's memory, `headroom learn` or output shaping, note those too. Caveman does not replace them, so decide if you still need them.

## Step 2: Free port 8787

Both tools default to `127.0.0.1:8787`. Stop Headroom's proxy for the agent you are moving, or move it to another port if other sessions still use it:

```bash
headroom proxy --port 8788
```

If you wrapped Claude Code durably, undo that first so plain `claude` stops routing through Headroom:

```bash
headroom unwrap claude
```

Leave Headroom's `ccr_store.db` alone until every old session is done.

## Step 3a: Move a coding agent

Install the Caveman CLI and its binaries. It needs Node.js 22.13 or newer and downloads about 205 MB of signed Go binaries into `~/.caveman/bin/`:

```bash
npm install -g @caveman-ai/cli
caveman setup --install
```

For a trial, use the ephemeral form. It runs one session through the local proxy and writes nothing to your config:

```bash
caveman wrap claude
```

When you are ready to keep it, `caveman claude` installs the integration so later `claude` sessions route through Caveman. Both forms run in compress mode and register `caveman_retrieve` through Caveman's MCP server. Codex, Gemini CLI, opencode, Aider and five more agents have profiles; the [wrap reference](https://docs.caveman.so/docs/proxy/wrap) shows how recovery installs on each.

Do not nest one wrapper inside the other. Two tools rewriting the same tool results and injecting two retrieval tools gives you a result you cannot read.

## Step 3b: Move an app on the Vercel AI SDK

Start the runtime, which is the same local proxy:

```bash
npm install @caveman-ai/middleware @caveman-ai/sdk ai
CAVEMAN_MODE=compress caveman start
```

Then replace Headroom's language model middleware with Caveman's adapter:

```diff
-const model = wrapLanguageModel({ model: baseModel, middleware: headroomMiddleware() });
-const result = streamText({ model, messages, tools });
+import { stepCountIs } from "ai";
+import { createMiddlewareRuntime } from "@caveman-ai/sdk/middleware";
+import { withCaveman } from "@caveman-ai/middleware/ai-sdk";
+
+const mode = process.env.CAVEMAN_CLIENT_MODE ?? "compress"; // "record" measures only, "off" disables
+const runtime = createMiddlewareRuntime({ endpoint: "http://127.0.0.1:8787", mode });
+const scope = { namespace: "support", session_id: conversationId, branch_id: "main", cache_epoch: "0" };
+if (mode !== "off") await runtime.ready(); // throws if the runtime is unreachable
+const result = streamText(withCaveman(
+  { model: baseModel, messages, tools, stopWhen: stepCountIs(8) }, { runtime, scope }));
```

`stopWhen` matters: without a multi-step limit the call ends after the first tool step, so the model never gets to run `caveman_retrieve` and read the result. `scope` names one conversation, and a handle only resolves under the scope that created it. Keep `session_id` stable across turns and never share it between users. Python apps follow the same shape with adapters for LangChain, LiteLLM, Agno, Strands, ASGI and more; see [Python middleware](https://docs.caveman.so/docs/sdk/middleware/python).

## Step 4: Check that it worked

Confirm the runtime is in the right mode:

```bash
curl -s http://127.0.0.1:8787/caveman/v1/middleware/capabilities | jq '{mode, persistent, recovery}'
```

Plain `caveman start` runs `record`, which measures and changes nothing. You want `compress`.

In an app, pass `onReport` to the runtime and watch the statuses. `applied` means a tool result was shortened, `reused` means a previous turn's choice was kept to protect the prompt cache, and `skipped` carries a reason such as `not_smaller` or `runtime_unavailable`.

Then test recovery for real. Give the agent a large tool result, like a long log or a big JSON export, and ask a follow-up that needs one detail the short view left out. You should see a `caveman_retrieve` call followed by the right answer. For coding agents, `caveman stats` summarises what the local layer did.

## Step 5: Compare on your own tasks

Run three arms on copies of the same tasks: direct, Headroom, Caveman. Use fresh sessions, the same model and the same instructions. Grade the final answers first and count provider input tokens second, including recovery calls and the follow-up requests they trigger. Note whether the Caveman output skill was on, since `caveman wrap` can include it. The [cost measurement guide](/guides/measure-agent-cost) has a reporting format.

Local token counts on both sides are estimates. The provider's usage report is the number that counts.

## Roll back

For a trial with `caveman wrap claude`, there is nothing to undo. Run `headroom wrap claude` again.

If you ran `caveman claude`, run `caveman disable claude` to restore each agent's config, then re-wrap with Headroom. In an app, go back to the old `streamText` call. `withCaveman` returns a new options object and mutates nothing, so deleting it restores the previous behaviour exactly. Setting `CAVEMAN_CLIENT_MODE=off` also stops compression without a code change.

Keep Caveman's runtime up until conversations that hold Caveman handles are finished. Handles from one tool never work in the other.

## Related

- [Caveman vs Headroom](/compare/headroom)
- [Coding agent setup guide](/guides/coding-agent-setup)
- [Caveman Middleware](/products/caveman-middleware)
- [Headroom CCR docs](https://docs.headroomlabs.ai/docs/ccr)
