Condensate is a runtime and a durable layer for coding agents. You run it on your own machines. It runs several vendors' agents under one record and one set of rules.
- Many engines. The real Claude Code and Codex, with their own tools, sub-agents and plugins, run beside two engines built into Condensate: its own agent loop, and pi, a thinner loop over a provider's API that the app lists as API.
- Durable. Every message, tool result and approval is written down before any agent acts on it.
- Provable. On Condensate's own loop, each request to the model is rebuilt from the record, and its fingerprint is saved before it is sent, so a replay can be checked byte for byte.
- One policy. A single policy service checks tool calls from every engine.
- Pooled. Your Claude and Codex plans are shared across agents, and the same pool is served as an OpenAI-compatible endpoint.
- Self-hosted. It runs on a machine you keep on. Your code and logins stay there.
Each section below says what is built, what runs only in tests, and what is designed but not built yet.
The layers
Condensate is easiest to understand as five layers, each resting on the one below.
| Layer | What it holds | What it brings |
|---|---|---|
| The record | Every thread, written before anything acts on it | What durable agent frameworks offer |
| The runtime | The engines, and the logins kept away from them | What the native CLIs offer, under one policy |
| The workflow | Separate copies of the repository, diffs, stacked pull requests, reviews, a view of every agent | What agent UI wrappers offer |
| Always on | Threads that keep running on your machine, several people guiding one thread, GitHub-triggered review and fixes | What hosted agents offer, self-hosted |
| The ways in | The web app, the phone app, a completions endpoint, one MCP address, an SDK | Your own programs on the same accounts and rules |
Four things here would require a competitor to change how its product is built: the provable request, the sub-agent that starts with a warm cache, one policy across engines, and subscriptions behind a completions endpoint. The workflow and always-on layers are features others also have, and the gaps are listed below.
The record
The runtime writes each message, tool result, approval and reply to the thread's store, and only then hands it to the engine. Every engine shares this record, and every app reads it, so the web app, the phone and the review server show the same thread.
Condensate's own loop keeps a second, lower record of its own. Each entry is chained to the one before it by a hash and written to disk before the loop continues. If the machine dies mid-write, the half-written last entry is trimmed when the record reopens. If anyone edits an entry, the chain breaks and the record is refused. Entries name the account that was used and never contain a login.
Provable requests
- 1YouStored
Add a retry to the upload client, and prove it with a test.
- 2AgentReply
Reading the client first.
- 3ToolTool call
Read src/upload.ts
- 4ResultResult
214 lines
- 5ToolTool call
Edit src/upload.ts: retry three times, with backoff
- 6ResultResult
One block replaced
- 7ToolTool call
Bash: bun test tests/upload.test.ts
- 8ResultResult
3 pass, 0 fail
- 9AgentReply ends
Added a retry with backoff, and a test that fails without it. Two commits on the branch.
- !Condensate, at bootLost
The process running this reply died before it could land. Nothing is retrying it. Press Resume, or send a new message, to run it again.
On Condensate's own loop, every request to the model is built the same way:
- The loop builds the exact request it will send from the record.
- It computes a fingerprint (a hash) of that request.
- It writes the fingerprint to the record.
- Then it sends the request.
Opening the same record later, in a new process, rebuilds the same request byte for byte. A replay rebuilds every request and compares fingerprints, and a resume refuses to continue if anything has drifted. The version of the code that builds requests is saved in the record too, so an upgrade can't quietly change the bytes.
That matters for the model provider's prompt cache, which is keyed on those exact bytes: a correct resume can read the cache it left behind, and a live test confirms it does. The cache still expires and belongs to one account and model, so identical bytes are needed for a cache hit but don't guarantee one.
UI wrappers never see these bytes, because the vendor's CLI builds them. Claude Code and Codex keep them in an internal format that changes between versions, and don't fingerprint them. Pi Durable designs its transcript to keep the cache valid, and has no proof that it did.
Moving a thread
A turn is one message to an agent and its full reply, tool calls included.
| Situation | State |
|---|---|
| The same process, across turns | Built |
| A new process on the same machine | Built |
| A new process, with the fingerprint check on resume | Runs in tests |
| A new machine, with the cache still warm | Designed, not built |
| A different account | Refused on purpose, because a cache belongs to one account |
Claude Code's --teleport and the Codex app's handoff already move a session between machines today, without a proof.
Sub-agents that start warm
When Condensate's own loop hands part of a task to a sub-agent, the sub-agent's record starts as an exact copy of its parent's, up to the hand-off. Because the request is rebuilt from the record, the sub-agent's first request starts with the same bytes the parent already sent, so it reads the parent's cache. If the model, account, provider, request-builder version or tools differ, the hand-off is refused instead of quietly starting cold. A live test confirms the sub-agent's first call reads from the cache.
Claude Code's sub-agents start from an empty context, and its --fork-session copies a session without checking the cache. Sub-agents on Claude Code and Codex don't have this property inside Condensate either; it belongs to Condensate's own loop.
After a crash
When Condensate's own loop reopens after a crash, it looks at each tool call that was in flight. Calls that only read run again. Calls that change something are recorded as "effect unknown", and the agent decides what to do. Once a tool has started, the runtime never retries the turn on its own. Undoing a step adds a new entry that marks it undone; nothing is erased.
Pi Durable and Claude Code handle interrupted calls in a similar way, so this is parity. Pi Durable goes further: after a crash it resumes on its own. Condensate marks the interrupted turn as lost, and a person presses Resume.
The engines
claudeA Claude model id picks it unless you name another engine.codexChosen only when you name it.condensateThe default for every model that is not a Claude model. The fourth engine, pi, shown as API in the app, runs beside it inside Condensate.Claude Code runs through Anthropic's Agent SDK, Codex runs as its own app server, and pi and Condensate's own loop run inside the runtime. Claude Code and Codex bring their tools, sub-agents, sandbox and plugins with them. Condensate changes three things:
- it replaces their context trimming with its own;
- it doesn't load your personal Claude Code settings;
- it switches off Claude Code's own permission prompts and checks every tool call itself instead.
Condensate's own loop is newer and does less. It has 7 tools, MCP servers, approvals, messages sent mid-turn, and interrupts, skills, the warm sub-agent hand-off and crash repair. It doesn't yet have context trimming, plan mode, questions back to you, thinking control, switching models mid-thread, or a sandbox for shell commands. An existing Claude Code session can be imported.
One policy layer
The same four events reach one policy service from every engine: before a tool runs, after it runs, when you send a prompt, and when the agent stops. The service can let a call through, block it with a reason, or add a note to the agent's next turn. You choose how far it may go, from only recording to interrupting the agent, and a control group with no notes measures whether the notes help.
Each native CLI's hooks cover only that CLI, and UI wrappers start the CLIs without seeing their tool calls.
Logins
Agents hold placeholder keys and reach the model providers through a proxy that adds the real login on the way out. The runtime refuses to start without the proxy, and refuses to start any agent that carries a real login. In the Docker install, agents run with no network of their own. One process refreshes each login, exactly once, under a lock, so two agents never race to refresh the same token.
Claude Code on the web does the same thing for its own agent in Anthropic's cloud. In the other self-hosted tools that run several engines, agents run as your own user.
Accounts and the completions endpoint
- Model login
proxy-…a placeholder- GitHub token
proxy-gh-tokena placeholder- Notion key
proxy-notiona placeholder- Outbound proxy
- Set, so every call passes the credential proxy
- 1One refresh, inside Condensate
Agents never refresh anything. They keep their placeholders.
- 2Two locks first
One in the process and one file lock on the Mac, so a refresh token is spent once and never by two refreshes at the same time.
- 3Saved only if nothing moved
The new token is stored only if the one it spent is still the stored one. Otherwise it goes to a recovery copy, so a crash mid-refresh does not log you out.
Claude, Codex, OpenCode and Cerebras subscription accounts sit behind one OpenAI-compatible completions endpoint. A project lists the accounts it may spend. The runtime picks an account by weighing the usage it has left against the time until it resets.
- A task starts
The first account with usage left pays for the first message.
- The first account runs out
It reached its limit before any tool ran, so the message runs again on the next account. Nothing happened twice.
- The second runs out, mid-work
A tool had already run, so that message is not repeated. The agent carries on from its next message, on the third account.
A tool had already run, so that message is not repeated. The third account is not on this workspace's list, so there is no next account.
- Every account is out
The task stops and says so, naming each account, why it is out, and the earliest reset.
The task stops rather than borrow an account from outside the workspace. The refusal names the accounts the workspace may use.
If an account runs out, the request moves to the next one, but only before the first word of the answer has come back. Each call writes a usage record that holds no prompt or answer text. Switching models on a Claude Code agent is checked against a limit on what re-filling the cache would cost.
The endpoint has limits today:
- it answers only on the machine itself, with no key of its own;
- it takes text only, and can't force a tool call;
- it doesn't yet check the project's list of allowed models.
bb pools subscriptions only for its own CLI, and LiteLLM speaks the OpenAI format over API keys rather than subscriptions.
The workflow
- Review: the builder commits A
A build agent makes the change and commits it. The reviewer has not seen it yet.
- Review: the reviewer reads A
A second agent reads the diff and writes its findings into the same thread.
- Review: request changes, pinned to A
The result belongs to commit A and to nothing else.
- Review: the builder fixes, commits B
A new commit means the result for A says nothing about B. It is stale.
- Review: a new round, approve pinned to B
The reviewer reads B and approves. Rounds are capped, so this cannot go on forever.
- Push: the builder's reply ends with commits
Condensate counts the commits GitHub does not have and asks the review server to push them. It never runs
git pushitself. - Push: four questions first
- Whose branch is this?
- Which repository, and is it in this workspace?
- Does the commit build on what GitHub has?
- What would it merge, and may it?
- Push: pushed
The commits go up, and a pull request opens if the branch had none. Some pull requests also need a person's approval before they merge.
- Push: or refused
Two commits on fix/example are not on GitHub, and the push was refused: the branch belongs to someone else. Do not push by hand. Fix the cause.
Nothing reached GitHub. The commits stay in the agent's worktree.
Each agent gets its own copy of the repository from a pool kept ready in advance, and a copy is archived as a patch before it's ever deleted. Changes show as a diff you can comment on line by line. Stacked pull requests work with Graphite or jj. A merge needs an approval for the exact latest commit. A review puts two vendors' agents on one change, with one fixing and one checking, and can merge on approval. A check spots two agents doing the same work. A project's lead agent keeps watching work after any terminal closes. Several clients can follow and guide one thread, any thread can be forked from any point, and archiving never deletes. By default two build agents run at once.
Where Condensate is behind
- No hosted option. Amp, Conductor Cloud, Claude Code and Codex in the cloud, Cursor and Devin run with no machine for you to look after. Condensate needs your own machine, always on.
- No pausing. Amp can pause a running agent and resume it later with its files and services intact.
- No move between machines yet. It's designed and not built. Claude Code and Codex already move sessions between machines.
- No automatic resume. After a crash, a person presses Resume. Pi Durable resumes on its own.
- No exactly-once send. A message sent twice arrives twice. T3 Code and Pi Durable de-duplicate.
- No terminal you type into, no desktop app, no app-store phone app. The Condensate app runs in the browser and installs on a phone as a web app.
- No schedules beyond a daily brief, and no Slack. Conductor, Amp, bb and Claude Code have schedules, and several have Slack.
- Fewer engines. bb runs about 13 CLIs, T3 Code 6, Condensate 4.
- No live presence. Amp and Conductor show who else is in a thread.
- Condensate's own loop is shallower than Claude Code, which has about 35 hook events to the loop's 4.
- Review tools. Devin's review spots moved code and has a rules editor.
- Operations at scale. Temporal and Cloudflare are far ahead on scaling out and observability.
How it compares
| Kind of tool | How much Condensate matches | How |
|---|---|---|
| UI wrappers (T3 Code, Conductor) | Most features | Builds its own copies, diffs, stacks, a view of all running agents, and forks, and goes further on review and the merge check. Missing a terminal, desktop and phone apps, and more than 2 builds at once |
| Hosted agents (Amp, bb, cloud agents) | Part | Threads that keep going, several people guiding, GitHub loops, self-hosted. Missing a cloud, pausing, schedules, Slack and presence |
| Native CLIs (Claude Code, Codex) | Inherits, with changes | Runs the real CLIs, replaces context trimming, skips personal settings, checks every tool call. Its own loop covers part of what they do |
| Durable frameworks (Pi Durable) | Level on crash repair, ahead on the cache, behind on resume | The hash chain, provable requests, warm sub-agents and a record with no logins in it are ahead. Automatic resume and exactly-once are behind |