How it works

battlegent consists of a daemon that runs your agents, clients for viewing and controlling sessions, and a hub that connects them.

HTTPSQUICappendbrowserweb appiPhonenative apphubhub.battlegent.combattlegentdyour machinesession logSQLite, per sessionclaudestdiocodexstdio

The daemon

battlegentd runs on your machine: in the menu bar on macOS, in the notification area on Windows, as a user service on Linux, or in a container you build yourself. It drives the agent CLIs you already use. It starts claude and codex as child processes and speaks their own protocols over stdio: Claude Code’s stream-json and Codex’s app-server JSON-RPC. The daemon translates Codex notifications into the same event format used for Claude Code.

Your keys stay on that machine: its device key, and your login or token for the model provider. Model calls go straight from the machine to the provider, never through the hub.

The session does pass through the hub: your messages, and what the agent reads, writes and runs, code included. The hub keeps a copy of each session’s log so you can read it while the machine is off, and deletes it 90 days after the session last changed. What you send, such as messages and answers, is kept for 30 days after it is delivered.

The log

Everything that happens in a session is appended to its own SQLite log under a sequence number that only goes up: messages, tool calls and their results, approvals asked and answered, background tasks starting and finishing. Streaming deltas are sent to clients; completed events are stored in the log.

Nothing in it is ever rewritten. Rolling a session back is one more event, “the state as of seq N”, and the history before it stays readable. The log is also disposable: the agent CLIs keep transcripts of their own, and a session’s log can be rebuilt from Claude’s jsonl or Codex’s rollout file at any time.

Attaching

A client opens a session’s event stream and receives, in this order:

GET /api/v1/sessions/{id}/events

cursor
where this window opens, and where the log ends
approvals
prompts still waiting on an answer
log …
the backlog, one event per seq
snapshot
what is in flight and not logged yet
turn
whether a turn is running
log, delta
live, as it happens

Every event carries its seq as its id. A client that drops off reconnects with the last one it applied, as Last-Event-ID. The daemon resumes the stream after that sequence number.

Since every client builds its view from the same events in the same order, two screens on one session show the same thing, including one that joined halfway through a turn. Locally the stream is Server-Sent Events; through the hub, clients use WebTransport where they can and fall back to SSE.

Approvals

When an agent wants to run a tool that needs your permission, the daemon holds the request and offers it to every connected client: allow, deny, or allow from now on. The same goes for a plan the agent wants reviewed and a question it asks you. The answer is logged and the prompt is marked as answered on each client. A prompt raised by a subagent shows up on that subagent’s card instead of getting lost in its transcript.

The hub

Your phone is rarely on the same network as the machine running your agents. The hub bridges the two without either side opening a port.

The daemon dials out to the hub over QUIC, keeps that connection up, and answers the requests the hub sends back down it with the same API it serves locally. There is no inbound port to open and no VPN to join.

Commands sent while a device is offline wait in an outbox until it reconnects. An idempotency key prevents retried commands from running more than once.

Each device makes its own Ed25519 key when it is enrolled. The hub signs the public half and the device’s id is derived from it, so removing a device from your organization is all it takes to revoke it. You sign in with GitHub, or with an OpenID Connect provider your organization brings, and share devices with the people in it.

Anyone in the organization can start sessions on its devices, including sessions that skip permission prompts. Invite only people you would trust with a shell on those machines.