Building a Safety Layer for AI Coding Agents: Inside The Companion’s WebSocket Bridge Architecture
Hook
Autonomous AI coding agents can delete files, execute shell commands, and modify your codebase—but they don’t wait for permission. The Companion intercepts every tool call before it runs, adding a human-in-the-loop approval system to CLI tools that were never designed for it.
Context
Claude Code and Codex represent a new generation of AI coding assistants that go beyond autocomplete. They’re autonomous agents that can read your codebase, plan multi-step changes, execute shell commands, and modify files across your project. The CLI tools are powerful, but they present three critical challenges: you lose all context if the process dies, managing multiple concurrent tasks requires juggling terminal windows, and most importantly, there’s no built-in way to review dangerous operations before they execute.
The Companion solves these problems by sitting between your browser and the CLI agent as a transparent proxy. Rather than forking the upstream tools or wrapping their APIs, it leverages their existing --sdk-url WebSocket interface—originally designed for editor integrations—to create a web UI with session persistence, parallel task management, and most critically, a permission gating system that lets you approve or deny each tool call. It’s a surgical intervention that adds safety rails without touching the underlying agent logic.
Technical Insight
The architecture is deceptively simple: a Bun-based Hono server maintains two WebSocket connections per session—one to the React frontend, one to the CLI agent—and forwards NDJSON events bidirectionally. When you launch a session from the browser, the Companion spawns the CLI process with --sdk-url ws://localhost:3456/ws/cli/:session, which causes the agent to connect back to the server instead of running in terminal mode. Every event the agent emits—chat messages, tool calls, streaming responses—flows through the proxy unchanged.
Here’s how you launch it:
# Install globally and run as a background service
bun install -g the-companion
the-companion install
the-companion start
# Or run in foreground for development
bunx the-companion --port 3456
The server auto-generates an authentication token on first run, stored at ~/.companion/auth.json. You can override this with the COMPANION_AUTH_TOKEN environment variable. The token is used to authenticate both browser WebSocket connections and CLI connections, preventing unauthorized access to your agent sessions.
The real engineering insight is in how it handles tool call approvals. When the agent emits a tool call event—say, a request to execute a shell command or modify a critical config file—the Companion intercepts it and pauses forwarding. The browser UI receives the event and displays a modal with the full tool payload, including the command, file paths, and any arguments. Only after you click “Approve” does the server forward the original event to the CLI. If you deny it, the server synthesizes a cancellation response and sends it back to the agent, which then continues with a different strategy.
This interception happens at the protocol level without any modifications to the CLI tools themselves. The agent sees a standard WebSocket connection and has no idea there’s a human in the loop. The Companion exploits the asynchronous nature of the NDJSON protocol—agents expect potential delays between tool call requests and responses.
Session persistence allows you to restore work after process or server restarts. When you refresh the browser or restart the server, the UI can replay the entire conversation history and tool timeline. The event stream is append-only and each event is self-contained, so the server doesn’t need to maintain complex in-memory state beyond the active WebSocket connections.
For developers who want to run this as a long-lived background service, the CLI includes install, start, stop, and uninstall commands that register the process with launchd on macOS or systemd on Linux. This is critical for a tool that manages long-running AI sessions—you don’t want your work disappearing because you closed a terminal tab.
The preview/prerelease system is particularly clever. Every push to main publishes both a Docker image tagged preview-main and an npm package under the next dist-tag. Preview builds use semver-patch bumps with a -preview.* suffix (e.g., 0.68.1-preview.abc1234 when stable is 0.68.0), which allows the in-app update checker to detect them as newer than the current stable release. Users can switch between stable and prerelease update channels in the settings UI, with changes taking effect on the next update check, giving early adopters access to bleeding-edge features while keeping the default experience conservative.
Gotcha
The Companion requires Bun, not Node.js. While Bun is increasingly popular and offers better performance for WebSocket workloads, it’s still an additional runtime dependency that some teams may not want to adopt.
The bigger limitation is that this is designed for single-user, local development workflows. Authentication is token-based, and there’s no concept of user accounts, permissions, or multi-tenancy. If you want to expose this to a team or run it on a remote server, you’d need to add a reverse proxy with proper authentication, TLS, and access controls. The README makes this clear—it’s a developer tool, not a production service. Additionally, the system is built for Claude Code with experimental support for Codex-backed flows. While the README describes it as supporting both, the primary focus is clearly Claude Code. The repository includes a WEBSOCKET_PROTOCOL_REVERSED.md document that details the protocol through reverse engineering, which is both impressive and a reminder that this is built on APIs that could change without warning.
Verdict
Use The Companion if you’re regularly working with Claude Code CLI and find yourself nervous about autonomous tool execution, frustrated by lost context when processes crash, or juggling multiple terminal windows for parallel tasks. The permission approval system alone justifies the setup cost—being able to review every shell command, file modification, or sensitive operation before it executes is invaluable when you’re letting an AI agent loose on a real codebase. The session recovery is a close second: long-running agent tasks can take significant time, and being able to survive server restarts or browser refreshes without losing work is a major productivity win. Skip it if you only occasionally use AI coding assistants for simple, low-risk tasks where you’re comfortable with full autonomy, if you’re philosophically opposed to adding another runtime dependency (Bun) to your toolchain, or if you need a multi-user system with proper authentication and access controls. This is a power tool for developers who trust AI agents to do real work but want a safety net—and that’s exactly what it delivers.