AILEENA MACHINA

Analysis · 2026.05.26

Centaur, and the market it's landing in

On May 21, 2026, Paradigm and Tempo open-sourced Centaur — a self-hosted runtime for "multiplayer, secure agents." It isn't another coding agent. It's the backend that lets a whole team share one.

Paradigm · Centaur · Agent Infra

▸ Narrated reading · 2026.05.26

Centaur, and the market it's landing in

Press play for a narrated reading — English-accent female where available.

0:00
0:00

What it actually is

Centaur is a self-hosted platform that gives a whole team one shared AI agent instead of N separate local setups. You talk to it from Slack or an API. Every conversation runs in its own isolated Kubernetes sandbox — a locked-down container K8s spins up just for that chat — with a real shell, a real workspace, git, Python, Node, Bun and the usual dev tooling. Add a tool once and every agent conversation can use it. Workflows can pause, resume, wait for events, spawn child agents, and survive a service restart. And credentials never make it into the sandbox in raw form.

The codebase is Apache 2.0 and built out of five components:

services/api          FastAPI control plane + Postgres
                      agent lifecycle, tool registry, durable workflows

services/slackbot     Slack event ingestion + threaded responses

services/sandbox      per-conversation K8s pod with shell + workspace

iron-proxy            credential gateway built on mitmproxy
                      sandbox sees placeholders; real keys injected at egress

plugins / workflows   Python tools + checkpointable workflow steps

The agent "brain" itself is bring-your-own: Amp, Codex, Claude Code, pi-mono, or any custom CLI harness drops straight into the sandbox. Centaur is the chassis, not the engine.

Why Paradigm built it themselves

Paradigm is a venture firm of roughly fifty people running a multi-billion crypto book, plus the Reth / Foundry stacks. They've been using Centaur internally since January 2026. The reason they built it comes down to three constraints that nothing off the shelf could satisfy:

  • Compliance + data boundary. A VC handling LP positions, portfolio diligence and unannounced deals can't pipe its repos, Slack DMs and secrets through someone else's SaaS cloud. By policy, Devin and the Cursor / Codex cloud agents are off the table.
  • Long-running work. Diligence memos, recruiting funnels, customer-support triage, CI investigations — none of these wrap up inside a 30-minute chat window. You need an agent that can sleep for hours, wake up when something happens, and not lose its place just because someone restarted a pod.
  • Shared institutional memory. Fifty people each running their own local Claude Code with their own tool wrappers is fifty disconnected knowledge bases. One shared agent with a single tool registry compounds over time; fifty separate ones never do.

The strategy here is the same one that produced Reth and Foundry: build the internal tool first, harden it on real work, then open-source it once it's a competitive moat for the entire portfolio and not just for the firm. Centaur is Paradigm's argument that the next layer of infrastructure portfolio companies need isn't a model or a sandbox — it's the multi-tenant runtime that turns either one into a coworker.

The PM bets, component by component

Each of the five components is a deliberate scope choice. The most useful way to read the repo is as a set of product decisions, not just a list of services.

Slack as the primary UI, not the IDE. Devin reaches for Slack too, but Cursor / Codex / Claude Code all reach for the editor. Choosing Slack is a statement that the target user is everyone in the company — analysts, recruiters, ops — not just engineers. That makes the product's reach much wider, and the bar on the UI much lower.

Durable workflows over chat turns. A FastAPI service backed by Postgres, with checkpointable workflow steps, says the unit of work is a job, not a turn. Jobs can sleep, wait, retry, and pick up again after a pod restart. That's what makes "run this overnight" or "watch this PR until CI is green" actually doable.

K8s sandboxes over a managed sandbox API. They could have just leaned on E2B or Daytona. They didn't — because the same compliance constraint that ruled out Devin rules out a third-party sandbox too. Running on the customer's own K8s keeps the entire data path inside the customer's boundary; the price is that the customer now has to operate K8s.

iron-proxy as the secrets boundary. The agent never sees raw long-lived keys. mitmproxy — a proxy that can intercept and rewrite traffic on the fly — sits between the sandbox and the public internet and slips the real credentials in only at the last second, on the outbound request, swapping placeholders for live keys. This is the one design choice that lets Paradigm hand the agent Stripe, 1Password, Slack admin and GitHub all at once and still sleep at night.

Bring-your-own harness + overlay images. Two extensibility pieces that look small but matter a lot. The first unhooks Centaur from any one model or CLI — Claude Code today, something else next quarter, no fork required. The second lets every adopter mount their own Docker image of tools, skills and workflows on top of upstream Centaur without ever touching the core. Together they keep Centaur from collapsing into "Paradigm's agent product" and let it grow into a real platform.

Bring your own harness — what you can actually plug in

This is the decision most people skim past, so it's worth slowing down on. A harness is the agent "brain" — the CLI program that actually talks to a model, reads your task, edits files, and runs commands. Centaur doesn't ship one. It ships the socket a harness plugs into and lets you bring whichever you like. The repo already speaks to four — Amp, OpenAI's Codex CLI, Claude Code, and pi-mono (Mario Zechner's open-source, model-agnostic "pi" agent) — but the list isn't the point. The contract is.

And the contract is refreshingly literal. Centaur's control plane speaks one wire format — Anthropic's message format, streamed as NDJSON (newline-delimited JSON, one object per line) over the harness's stdin and stdout. A small per-harness adapter in harness_session.py then translates that one standard format into whatever each CLI actually wants. Claude Code already speaks Anthropic format, so it's passed straight through. Amp only takes text on stdin, so image and document blocks get written to disk and swapped for @/path mentions. Codex and pi-mono take the text and hand it over as a command-line argument. Adding a fifth harness isn't a fork — it's one more translation entry in that file.

So "what are my options" really just means "which CLIs can run headless inside a box." Here's the field as it stands:

HARNESS        MODEL          OPEN?          HEADLESS ENTRY
──────────────────────────────────────────────────────────────────
Claude Code    Claude only    source-avail   claude -p  /  stdin
Codex CLI      OpenAI only    Apache-2.0     codex exec
Gemini CLI     Gemini only    Apache-2.0     --non-interactive
Amp            any (cloud)    contested      amp -x
pi (pi-mono)   any, BYO-key   yes            scriptable CLI
Aider          any            yes            --message  /  pipe
Goose          any (MCP)      yes            headless run
OpenHands      any            yes            --headless --json
SWE-agent      any            yes            scriptable runner
Cursor CLI     Cursor/any     proprietary    cursor-agent -p
Devin          Cognition      no (SaaS)      cloud — can't drop in

Three things decide whether a given harness is a good fit for a chassis like this. First, model-locked or model-agnostic? Claude Code, Codex CLI and Gemini CLI each ride a single vendor's model; pi, Aider, Goose, OpenHands and the others are bring-your-own-key and will run on whatever you point them at. For something whose entire pitch is "swap the brain without a fork," that axis matters most. Second, can it run headless? — non-interactively, driven by a pipe instead of a keyboard. A clean headless mode (the -p, exec, and --headless flags in that table) is the deciding feature, because Centaur drives the thing over stdin/stdout, not a terminal. Third, open or closed? — which decides whether you can ship it inside your own image at all.

Which is exactly why Devin doesn't belong on the list. It's a hosted cloud service, not a CLI you can drop in a box — the inference happens on Cognition's servers no matter what local bridge you wrap around it. That's the whole tell: a bring-your-own-harness runtime can adopt anything that runs as a process you control, and nothing that doesn't.

Memory: why it can babysit something for 48 hours

Ask an ordinary chat agent to "watch this PR and ping me when CI goes green" and it falls over within the hour. The reason is structural. A chat agent keeps everything it knows in its context window — the fixed-size scratchpad of tokens the model can see at once. Leave a task running for two days and that scratchpad fills with stale history, the bill climbs with every token re-read, and the moment the process restarts the memory is gone. A context window is short-term memory. It was never meant to hold 48 hours.

Centaur moves the memory out of the model entirely. The durable state of a job lives in Postgres, as a sequence of checkpointed workflow steps — the unit of work is a job, not a chat turn. A two-day monitor, then, is mostly a job that sleeps. It wakes on an event — a webhook, a timer, a fresh CI result — pulls just the slice of state it needs back out of Postgres, runs one short bounded turn through the harness, writes a new checkpoint, and goes back to sleep. The model's context window only ever holds that one short turn. It never carries the full 48 hours, so it never blows up.

That same checkpoint is what lets the job survive a restart. Because the last good step sits in Postgres rather than in a process's RAM, a sandbox that gets killed — a pod reschedule, a deploy, a 3 a.m. crash — comes back and resumes from where it stopped instead of starting over. "Run this overnight" only works if "overnight" is allowed to include a pod restart.

And because the state is a real database row instead of an opaque conversation, you get control over it: you can inspect a running job, pause and resume it, branch it, kill it, let it spawn child agents, and read back an audit trail of everything it did and which credentials it used. The length of an agent's memory stops being capped by the model's token limit and starts being capped by your disk. That's the whole difference between an assistant you chat with and a teammate you can hand a two-day job.

Multiplayer — how a whole team shares one agent

The other half of the pitch lives in that word "multiplayer." What Centaur is arguing against is a team each running their own agent on their own laptop — private setups whose memory and tooling never meet. Centaur is one shared agent the whole team talks to instead, and the sharing is what makes it more than a group chatbot.

Mechanically, a conversation lives in a Slack thread— Centaur keys it to the channel and thread it's happening in (slack:<channel>:<thread>). So collaboration is the default: anyone in that channel can jump into the same thread, and the agent holds one shared context for all of them instead of starting over per person. And it isn't anonymous — every message carries the sender's identity into the agent, so in a busy channel it can tell who asked for what and keep an attributable record of who did which.

The part that actually compounds is what's shared deployment-wide. The tool registry, the workflows, and the personas and skills mounted through the overlay are all org-level: someone adds a tool once, and from then on every conversation — everyone's — can reach it. That's the whole difference between capability that compounds and capability that stays trapped on one person's machine. Worth being precise, though: the conversations themselves still run in isolated sandboxes, and history is pulled back per thread. The durable record sits centrally in Postgres, but there's no single omniscient "search everything everyone ever said" memory — what's genuinely shared is the tooling and the workflows, not one giant collective transcript.

Which is the honest way to read "it knows each person's context and priorities." That isn't a dashboard or a dedicated feature — it's an emergent property of giving one shared agent a seat in the team's Slack and a key to the org's tools. The more of the team's real surfaces it can see — the channels where work gets discussed, the tools where work actually lives — the more it behaves like a coworker who already knows what everyone is working on. It picks up priorities the way a new teammate does: by being in the room, not by querying a priorities table.

One limit is worth naming, because it's the flip side of "secure." Centaur's boundaries are drawn around secrets and sandboxes, not around people. The iron-proxy keeps raw credentials out of every sandbox, and each conversation is walled off in its own pod — but there's no per-user access control deciding that your request can't touch a teammate's data. For a tight, high-trust team that's a deliberate simplification; for a bigger or less-trusted org, user-level permissions are the thing you'd have to build on top. "Secure" here means your keys never leak into the agent — not that teammates are walled off from each other.

How they're telling the story

The launch messaging is every bit as deliberate as the architecture. Four things about it are worth noticing.

The word "centaur." Not "agent," not "copilot." The centaur image — human and machine as one body — was Garry Kasparov's term for advanced chess, where a human and an engine play together. Paradigm is deliberately walking away from the "autonomous agent" story (Devin) and the "assistant" story (Copilot) and pitching a third one: a teammate. The name carries the positioning.

Co-released with Tempo. Paradigm is a VC; Tempo is a portfolio company that's been running Centaur in production. Shipping the launch jointly does two things — it shakes off the "internal toy" smell, and it quietly tells the other portfolio companies that the operating system for their AI work has already been picked for them.

Apache 2.0, not BSL. Foundry uses MIT/Apache; Reth uses MIT/Apache. Paradigm is being consistent. There's no "managed Centaur cloud" on the way — the license rules out the obvious SaaS play. The bet is that Centaur is worth more to Paradigm as portfolio leverage than as licensing revenue.

The use-case list is unusually wide. Investing, engineering, design, recruiting, events, customer support. That breadth is the marketing asset, because it's the part you can't fake. Six months of real internal use across a fifty-person firm produces a list of jobs-to-be-done that no vendor demo ever could.

The competitive grid

Centaur sits right where four neighbouring markets overlap. None of them has a direct equivalent yet — which is the most interesting thing about the launch.

                       Closed SaaS                     Open + self-hosted
─────────────────────────────────────────────────────────────────────────────
Full-stack             Devin (Cognition)               ★ Centaur
team agent             Cursor Background Agents
                       Codex Cloud
                       Tempo (now on Centaur)

Agent orchestration    LangGraph Cloud                 LangGraph OSS
                                                       kagent (CNCF Sandbox)

Sandbox infra          E2B, Daytona, Modal,            OpenSandbox (Alibaba)
                       Northflank, Blaxel, Sprites     AIO Sandbox (Agent-Infra)

Coding-only agent      Sweep, Tusk, GH Copilot         OpenDevin-style forks
                       Workspaces

vs. Devin. The closest functional cousin. Devin is closed SaaS, per-seat pricing, fully autonomous, single brand. Centaur is open, self-hosted, harness-agnostic, and a runtime rather than a product. For any team that can't ship its code or secrets off to a vendor cloud — finance, crypto, healthcare, anyone with a serious compliance posture — Centaur is the only thing in the column.

vs. E2B / Daytona / Modal / Blaxel. These sell sandbox APIs. Centaur swallows the sandbox layer whole (it runs its own on K8s) and adds the four things the sandbox vendors don't: Slack ingress, durable workflows, a credential gateway, an audit trail. If you're an agent builder renting E2B by the hour, carry on; if you're a company deploying one agent for fifty coworkers, you want Centaur.

vs. kagent / LangGraph Platform. Both are open-source, K8s-native control planes for agents. They sit lower in the stack than Centaur — orchestration primitives and observability aimed at platform-engineering teams. Centaur is a packaged product sitting on top: Slack bot included, secrets gateway included, sandbox image included. Time to your first working agent is hours, not weeks.

vs. Sweep / Tusk / Copilot Workspaces. Different scope entirely. These are PR-shaped: read an issue, hand back a PR. Centaur runs the whole company — the PR-bot pattern is just one of many workflows you could build on top of it.

Where this leaves the market

The spot Centaur stakes out is the top-right quadrant of that grid: open-source, self-hosted, full-stack team agent runtime. Twelve months ago that quadrant didn't exist as a category at all. Today it has one credible entrant, backed by a firm whose earlier infrastructure bets (Foundry, Reth, OpenClaw) turned into default tools for whole industries.

Three predictions fall straight out of the design choices above:

  • The sandbox-API vendors will commoditize faster. If the standard way to deploy becomes "an agent runtime on the customer's own K8s," then the standalone-sandbox layer is a feature, not a product. E2B and Daytona will either climb up into orchestration or get squeezed.
  • Devin gets a self-hosted SKU. The compliance gap is wide enough that Cognition can't ignore it forever — but moving from SaaS to self-hosted is a structural lift, not a flag you flip.
  • Over the next year, agent product PMs will spend most of their time on workflows, not on models. Centaur is a bet that the unsolved problem is durability, sharing, and credentials — not raw capability. And that bet lines up with what most users gripe about once the novelty wears off.

Centaur isn't the only thing that'll work. But it's the first credible answer to the question "what does an agent look like when it has to be a teammate to fifty people for a year?" — and it ships with six months of receipts from the firm that built it.

Update — June 2026, twenty-five days in

Some things only became visible after the repo was actually open and people started poking at it. Five updates to what I wrote on launch day.

It's not pure FastAPI — there's a Rust control plane too. The repo language breakdown sits at 43.6% Python, 26.7% Rust, 11.9% TypeScript, 11.5% Ruby. The Rust quarter is services/api-rs/ — a second control plane covering agents, tools, workflows, auth, and durable state, sitting alongside the Python one. The split looks like: Rust where the hot path matters (the spawn protocol, permission checks, the iron-proxy bridge), Python where the plugin ecosystem lives (tools, workflows, harness adapters). The Ruby chunk is the Slack bot; Slack's Ruby SDK is the most mature, and they took the obvious shortcut. The PL/pgSQL slice is Postgres stored procedures, which means Postgres isn't just the state store — it's a participant in the workflow checkpoint logic.

The Rust is also the Paradigm tell. Reth (Ethereum execution client), Foundry (Solidity toolchain), now api-rs in Centaur. Three for three on "the control plane is in Rust."

REST, not MCP — the unfashionable choice. In the second half of 2025 most agent frameworks defaulted to MCP (Model Context Protocol — Anthropic's tool-calling spec) as the universal tool interface. Centaur did not. From AGENTS.md in the repo: agents call tools via curl $CENTAUR_API_URL/tools/<tool>/<method> over the in-cluster Kubernetes service network. No stdio handshake, no protocol negotiation, no SDK pinning. Just curl.

MCP carries a coordination cost — every tool needs an MCP server implementation, every harness needs an MCP client, protocol upgrades ripple through both. REST means a new tool is one Python file in tools/ and the API picks it up and exposes a REST endpoint automatically via hot reload. The trade is portability (Centaur tools aren't drop-in MCP servers for other runtimes) for ergonomics inside the runtime. It's a deliberate counter-bet against the "MCP everywhere" narrative: the runtime should own the tool interface, not borrow a vendor protocol.

Warm pool — how the latency disappears in Slack. The piece my launch-day read missed entirely. services/sandbox/warm_pool.py maintains a pool of pre-spawned sandbox pods, and the three-step protocol is /agent/spawn /agent/message /agent/execute. Spawn pins one warm runtime to the Slack thread and returns a runtime_id plus an assignment_generation counter — the counter is what prevents a stale runtime from servicing a reconnected thread. Cold-start hits K8s pod creation latency (multi-second); warm-start hits effectively nothing. This is why mentioning the bot in Slack feels instant when it shouldn't be.

The security model is five layers, not one. I framed iron-proxy as "the credential boundary," which sells short what's actually there. The full stack a jailbroken harness has to break through:

  1. The harness's own guardrails.
  2. A default-deny Kubernetes NetworkPolicy on every sandbox pod — zero outbound traffic allowed unless the destination is iron-proxy.
  3. iron-proxy's host / path allowlist.
  4. centaur-perms — the Rust RBAC layer that maps Slack thread keys (canonical principal IDs) to role-based secret grants. Tool permissions are declared in pyproject.toml, the same file the tool's Python dependencies live in.
  5. 1Password. iron-proxy doesn't hold credentials — it fetches them from 1Password at request time. The credential vault is external.

That changes the threat model substantially. The agent isn't one mistake away from leaking keys; it's five mistakes away.

AGENTS.md is the handoff point. services/sandbox/SYSTEM_PROMPT.md gets baked into the sandbox image at ~/AGENTS.md at build time; on container start the entrypoint copies it into workspace/AGENTS.md, which becomes the system prompt every harness reads. The AGENTS.md filename is a quietly converged 2025-2026 convention — Claude Code, Codex CLI, Amp and Cursor all default to reading it from the working directory. Centaur weaponises the convention: the chassis controls the brain's identity by controlling the file the brain reads at boot.

Twenty-five days in: 767 stars / 135 forks / centaur-0.1.61. Sixty-one patch releases in twenty-five days is roughly 2.4 ships per day. Most VC-released OSS projects ship four or five patches in their first month. The cadence is the most honest signal that this is an actively-owned product, not a press-release dump.

RFC dive — the loop, the sandbox, the session

A day later, pulling on the services/api-rs/ directory produces a much sharper picture of what's in the Rust quarter. It isn't one file or one crate — it's sixteen Rust crates organised as a layered control plane. The list:

services/api-rs/crates/
├── absurd-sdk                  ?? — unexplained, likely a client SDK
├── centaur-api-server          public HTTP router
├── centaur-iron-control        control plane above iron-proxy
├── centaur-iron-proxy          egress proxy (the credential gateway)
├── centaur-perms               RBAC, Slack-thread-key → 1Password
├── centaur-sandbox-core        SandboxBackend / SandboxSpec / SandboxIo traits
├── centaur-sandbox-local       child-process backend (dev)
├── centaur-sandbox-agent-k8s   Agent Sandbox CRD backend (prod)
├── centaur-sandbox-manager     orchestration + reconciliation
├── centaur-sandbox-e2e         end-to-end tests
├── centaur-session-core        session model + state machine
├── centaur-session-runtime     execution runtime above the manager
├── centaur-session-sqlx        Postgres persistence
├── centaur-session-cli         operator CLI
├── centaur-telemetry           observability
└── centaur-workflows           workflow engine (cron, composition)

The naming alone reads as a multi-year codebase: the sandbox concern split across five crates, the session concern across four, a separate iron-control higher-level orchestrator above iron-proxy, the obligatory telemetry split. Two RFCs in services/api-rs/rfcs/ are the architectural doc.

RFC 0001 — the sandbox is an INTERNAL crate boundary. From 0001-sandbox-abstraction.md verbatim: "The sandbox layer should be an internal crate boundary. Higher-level concepts like thread keys, personas, harness choice, model selection, assignment generation, and durable execution rows belong in a later data model." The I/O contract is bytes only: "The sandbox abstraction moves bytes. It does not know whether those bytes are: NDJSON harness events, an interactive shell stream, a future binary protocol, or framed messages produced by another layer." The state machine is Created → Running ↔ Suspended → Stopped plus Gone for the K8s-evicted-the-pod case. Reconciliation compares desired against observed and corrects. Treating in-memory state as authoritative is explicitly forbidden.

RFC 0002 — the session is the durable thing; the sandbox is replaceable. This is the actual "loop." A session row carries thread_key (public ID + DB primary key), sandbox_id (mutable — if the pod dies, manager swaps a new one in), harness_type, harness_thread_id, and a status ∈ {active, executing, idle, failed, archived}. The INTERNAL session API is four endpoints — distinct from the public spawn / message / execute trio Slack-facing code calls:

  1. POST /api/session/{thread_key} — idempotent create / get.
  2. POST /api/session/{thread_key}/messages — append durable input.
  3. POST /api/session/{thread_key}/execute — run, serialised per conversation.
  4. GET /api/session/{thread_key}/events — SSE stream, replay or live tail from a stored offset.

Four tables back the model — sessions, session_messages, session_executions, session_events — all keyed by thread_key. The rule the RFC keeps repeating is short: "The session row is authoritative." In-memory state and live connections are caches. The implementation must recover from Postgres alone.

The design pays four user-visible dividends the launch-day article didn't connect:

  • The sandbox is interchangeable. Pod dies mid-conversation → manager spawns a new one, updates session_row.sandbox_id, harness picks up from the messages table. The Slack thread doesn't notice.
  • The control plane is restart-safe. The whole api-rs service can be re-deployed mid-execution; recovery is one Postgres scan away.
  • The SSE stream replays. Drop a connection, reconnect, ask for events since offset N, stitch back what you missed. This is what makes Slack threads survive bot restarts cleanly.
  • The protocol is harness-agnostic at the storage layer. Codex JSONL, Claude protocol, future formats — all opaque newline-delimited lines in session_messages. Adding a new harness is one SandboxBackend impl plus a parser for harness_thread_id semantics. The session plane doesn't change.

Three things I'm still chasing: the warm-pool depth + replenishment policy (the launch summary's warm_pool.py path doesn't exist at that literal path on main — my guess is it moved into centaur-sandbox-manager when the Rust port landed), whatever absurd-sdk actually is (probably a client SDK with attitude — the name suggests Paradigm fingerprints), and RFC 0003 (two files collide on that number — 0003-python-workflow-host.md and 0003-telemetry.md — either a numbering accident or a sign the two landed in parallel).

← Back to Archive
← Home