Skip to content

Agent runtime

How the agent side actually runs: the protocol the desktop app speaks to it, the tools it has, how it delegates to sub-agents, and the patches carried on the vendored agent library.

One agent implementation serves both front ends. apps/agent-cli is a terminal TUI that doubles as a protocol server; the desktop app's agent pane is a client of that same protocol. This page is the implementation side. For connecting your own provider or tool servers, see Configuration, and for the sync and provider layer, Integrations.

The protocol surface

Running agent-cli with --acp makes it an Agent Client Protocol server over stdin and stdout: newline-delimited JSON-RPC 2.0, implementing a subset of the Gemini CLI's ACP v1 surface. Requests arrive on stdin; responses and streaming notifications leave on stdout.

MethodDoes
initializeAdvertises capabilities and the authentication methods the client may use.
session/newStarts a session with a working directory and, optionally, extra MCP servers. It also advertises the available providers and models so a client can switch models mid-session.
session/loadResumes an existing session, replaying the conversation as session/update notifications.
session/promptStreams session/update notifications for a turn and finishes with a stop reason.
session/set_config_optionChanges a session option, alongside session/set_mode and unstable_set_session_model.
session/cancelCancels the turn in progress.

The direction of travel is not one-way. The agent can send its own requests back to the client — fs/read_text_file and fs/write_text_file — and awaits the responses, correlating them by id. Those calls are gated on what the client says it supports at initialization.

A fallback switch is reported to the client rather than happening silently, so a model that quietly changed mid-session cannot be mistaken for the one you chose.

The connection

AcpConnection owns the wire. Its job is twofold: every write to stdout is serialized, so a response and a streaming notification produced by different tasks can never interleave into a corrupt line; and requests the agent has sent to the client are tracked by id so their answers can be matched up.

MethodDoes
send, send_lineSerialize a value, or a raw line, onto stdout.
response, errorA successful JSON-RPC response, or an error one.
notification, send_updateA JSON-RPC notification, and the session/update form of it.
send_available_commandsTells the client which slash commands exist.

Tools

Beyond the built-in tool set, the agent carries tools of its own. AskUserTool is the one worth knowing about, because it has two modes: in the TUI it puts the question to you and waits for the answer, and under ACP or a headless run it returns a structured result instead. That is what lets the same interview flow be driven from a terminal, from the desktop pane, or from a script without a second implementation.

Its input schema covers the question, an optional short header, suggested answers, a multi-select flag, and validation rules — the same shape the app's own question UI uses.

Sub-agents

Delegation is a tool: spawn_agents hands focused work to sub-agents that have their own system prompts and their own tools. The parent's system prompt lists the catalog, with a short note per sub-agent on when to reach for it, so spawning is a decision the model makes rather than something hardcoded around it.

FieldMeaning
id, display_nameHow the parent and the transcript refer to it.
spawner_promptWhat the parent model is told about the sub-agent, which is how it knows when to spawn it.
system_promptThe sub-agent’s own instructions.
toolsBuilds a fresh tool set for each spawned instance rather than sharing one.
max_turnsCaps how long a sub-agent may run.
include_message_historyWhether the sub-agent is seeded with the parent’s conversation.
strip_think_tagsWhether reasoning tags are stripped from its output before the parent sees it.

Sub-agent activity is broadcast on a channel rather than being flattened into the parent's output. The TUI subscribes and renders nested tool calls underneath the spawn_agents call that caused them, which is what makes delegation legible instead of a black box. Under ACP and headless runs there is no receiver, and those events are simply dropped.

Reaching the client's files

The file tools go through a trait rather than straight to disk, so a client can serve unsaved editor buffers and observe the edits the agent makes. In the TUI and in headless runs there is no client to ask, so the sink is absent and the tools touch the local filesystem directly. The capability is negotiated, not assumed.

Direct prompt mode

Not everything needs the agent loop. Direct prompt mode sends a single user message to one model and returns the raw streamed response, resolving the provider, model, and key through the same machinery as the rest of the CLI.

Its real purpose is testing: it captures exactly what a model streams, including the thinking deltas that the provider layer would otherwise drop, and saves them as fixtures organised by format family and model. Parsing can then be tested offline against real responses instead of hand-written approximations.

Patched cersei

The agent is built on the cersei agent library, and the repository carries patched copies of its agent and provider crates. The patches exist because the behaviour the app needs is in the library's internals rather than behind an interface.

The largest is auto-compaction: as a conversation approaches the model's context limit, older messages are summarized to make room while keeping the recent thread intact.

patched/cersei-agent/src/compact.rs
AUTOCOMPACT_TRIGGER_FRACTION = 0.90
KEEP_RECENT_MESSAGES        = 10
MAX_CONSECUTIVE_FAILURES    = 3

Compaction triggers at 90% of the window, always preserves the ten most recent messages, and disables itself after three consecutive failures rather than looping on a conversation it cannot shrink. A conversation's fullness is also surfaced to the UI as a three-state warning, so running out of context is something you can see coming.

Read the patches as part of the codebase
Anything in patched/ is code you maintain. A bug in agent behaviour may live there rather than in apps/agent-cli, and an upstream update has to be reconciled with the patches rather than merged over them.

The workflow engine explains the coding pipeline that drives these sessions, and Integrations covers the provider layer and the MCP servers you configure yourself.

Edit this page on GitHub