C3PO, part 2: a real agent and a chat interface
In part 1, Claude Code drove a simulated Unitree G1 through an MCP server, from my terminal. That proved the loop works, and it also made the limits obvious. The whole thing ran only on my machine, inside a tool built for editing code, so nobody else could talk to the robot.
This month was about making C3PO a system instead of a hack.
The agent moves to the backend
C3PO was already a monorepo with a SvelteKit frontend and an Elysia backend on Bun, but none of the robot work had touched either one yet. Now the backend runs its own agent. It’s a streaming loop on the Vercel AI SDK with Claude as the model and thinking enabled, capped at a dozen tool steps per turn.
Nothing about the robot changed. The skills live in a registry with JSON schemas. The backend converts them into tools for the model and sends every call over MCP to the same Python bridge from part 1, using streamable HTTP this time instead of stdio. The skill layer doesn’t depend on who’s driving, so moving the agent out of Claude Code didn’t change the skills, the bridge, or the protocol.
I’m glad I got two details in early. First, the backend returns tool failures to the model as errors instead of killing the stream, so the model can react and retry. Second, the system prompt has an honesty rule, because some skills only write a log line in the sim and don’t move anything: never claim the robot moved when it didn’t.
A chat interface
I like working in the terminal, but “type into a CLI on my laptop” is not how you talk to a robot. C3PO now has a proper console. Responses stream into a chat, and every skill call shows up as a small monospace pill marked pending, done, or failed. The chat has a stop button. Next to it, a live map polls the robot’s pose, heading, travel trail, battery, and latency every couple of seconds. A camera view streams over WebRTC from the sim’s head and wrist cameras. A big red PARAR button calls stop_everything directly.
The part I’m most excited about
So far everything has run in the simulator. That changes in a few weeks, when a real Unitree G1 arrives. The repo is already prepared for it. The real robot uses different DDS topics than the sim, so there’s a full protocol catalogue that maps every skill to the real firmware’s API, and a fault decoder for its error codes, including the emergency stop.
I’ll write part 3 next to a robot.
Code: github.com/mercho40/C3PO.