Every company has the same conversation, every week, forever. “How many teams signed up?” “Is that bug already tracked?” “What shipped in the last release?” The answers exist. They’re just scattered across analytics, tickets, the database, billing, docs, and six git repos, and the person asking doesn’t have tabs open to all of them.
So we built Brain: an AI teammate that knows our product data, our users, our code, and our docs, and answers in seconds. Today it lives in our Slack, because that’s where we talk. But nothing about it is Slack-shaped. It’s a brain with a chat surface plugged in, built to live anywhere we do.
Our team stopped asking each other the same questions every week. Now they ask the company, and it answers.
This is the story of how we built it (with p0, obviously) and the tricks that made it work.
The trick: a coding agent, but headless
p0’s whole thesis is that the new generation of coding agents, Claude Code, Codex, and friends, are the best agent runtimes ever shipped, and the right app just drives them well. Brain is that thesis pointed at a server instead of a laptop. Today it runs on Claude Code; the design doesn’t care which agent binary sits underneath.
Brain is a small Node service on a Railway box. When a message arrives, it uses the Claude Agent SDK to spawn the Claude Code binary, the exact same binary you run in your terminal, as a one-shot headless process. Claude Code brings the hard parts for free: tool use, file access, session resume, MCP connections. We didn’t build an agent framework. We shipped an existing one in a Docker image.
The part people don’t believe: it runs on a normal Claude subscription. claude setup-token on a laptop produces an OAuth token; that token goes into the server’s environment; the headless binary authenticates as the same Max plan we already pay for. No per-token API metering for an internal tool that the whole team hammers all day.
Not one big agent, nine small ones
Our first instinct was One Big Agent That Does Everything. We killed that idea in the planning doc.
Instead, Brain is nine narrow presets behind a single runner: a generalist for questions, a bug triager, a report writer, a release-notes writer, an investor-update drafter, a meeting summarizer, a billing agent, an engineer, and one tiny internal parser. Each preset is just a bundle of working directory, system prompt, MCP servers, and tool allowlist. The runner is the only code path that executes any of them.
Why it matters: the triage agent physically cannot touch billing, because the billing connector isn’t mounted in its process. Safety by construction beats safety by prompt.
Each agent also gets its own persistent memory: a folder of markdown files on the volume it’s told to maintain. The meeting agent has learned who owns what. The release-notes agent remembers which commit range it covered last. It’s the least fancy memory system imaginable, and it works great.
The knowledge: mirrors, not integrations
Brain’s context comes from two dead-simple mirrors that sync every 15 minutes:
- Our cloud drive, mirrored to the volume with rclone. Meeting transcripts, plannings, docs, all greppable as plain files.
- Our git repos, mirrored to the volume as plain clones, hard-reset to origin on every sync. When someone reports a bug, the triage agent doesn’t guess. It greps the actual code and cites
file:line.
Live data comes over MCP: tickets, analytics, the production database, and billing, all mounted as remote servers. The agent queries the same sources we would, it’s just faster at it than we are.
The scary part: letting it write
Reading is easy to trust. Writing, like extending a customer’s trial or updating a row in production, is where everyone’s stomach tightens.
Our answer is a hard gate in the one place the agent can’t route around. The Agent SDK lets you intercept every tool call with a canUseTool callback. Anything on our dangerous list pauses the run and posts an Approve / Deny card in Slack. Only admins can press it. Ten minutes with no click means denied. Every request and verdict is written to an audit table.
One hard-won detail for anyone building this: that callback is never invoked if you run Claude Code in bypass-permissions mode. We run in default mode with a minimal allowlist instead, and we have a unit test whose only job is making sure nobody ever “simplifies” that line.
The engineer agent gets the same treatment structurally: it works in scratch clones, pushes branches, opens PRs, and has no path to main. And no agent ever sees a server secret, because the runner passes each subprocess a scrubbed environment allowlist. The chat token, the billing key, the API tokens: not in the room.
The fun parts
Building for chat instead of a UI made the details weirdly delightful:
- Brain posts a random “on it…” and streams its progress by editing that message, then delivers the answer as a new message, because edits don’t trigger notifications and answers should.
- Ask for a CSV, get a real file. Ask for a chart, and Brain writes a Vega-Lite spec that renders on our own server to a PNG. The data never leaves for some charting API. (Our first production chart rendered every label as □□□ because the container had no fonts installed. Very futuristic. We ship DejaVu now.)
- Brain schedules itself. “@brain schedule: every friday at 4pm, post the open bug count” gets parsed by a small model into a cron spec, an admin approves it with one click, and it survives redeploys in SQLite.
- When our CI finishes a p0 beta build, it pings Brain, which diffs the release and posts “v1.0.63-beta released” with the merged PRs: release notes nobody wrote.
Built with p0, in about a week
Here’s the meta part: Brain was built almost entirely in p0 sessions. Spec conversations, implementation, tests, deploy debugging, this blog post. An agent-built agent service. Around 120 unit tests, database migrations, and a boot dashboard that shows every credential and cron as ✓/○ so a broken config is visible in ten seconds of deploy logs.
Total infrastructure: one container, one volume, one SQLite file. Our “AI data center” has less ops surface than most side projects.
The vision: a data center you can talk to
The name isn’t a joke, or it’s at least a serious joke. Companies have data centers: machines that hold everything and answer queries. We wanted one made of understanding, a place where the company’s accumulated context lives, where anyone can query it in plain language, and where it can act, carefully, on our behalf.
We’re partway there. Brain answers, triages, reports, summarizes our daily calls, drafts our release emails, opens PRs, and asks permission before doing anything sharp. Next come watchers that notice things on their own (an error spike, a stuck ticket, a churn signal) and start the conversation themselves.
And new homes. Today Brain speaks Slack, but the chat layer is a thin shell around the brain itself. Point a different surface at it, email, a CLI, our own products, and it’s the same teammate everywhere. The data center doesn’t care where the terminal is.
The stack to copy is short: Claude Code headless on a small server, your subscription token, MCP for live data, mirrors for knowledge, one chat surface, and approval buttons where it counts. The rest is taste.
Ask your company something today. Ours answers.
— Andres