Skip to Content
Krad ADE
Architecture

Chat pipeline

How krad-chat drives each harness without a terminal and turns its stream into the same chat events.

A chat drives its harness without a terminal and renders its stream natively. Each harness speaks its own protocol. krad-chat has one adapter per harness, and all adapters produce the same live events, so the rest of the app (the chat view, asks, diffs, skills, the agents bus) handles every harness the same way.

One adapter per harness

HarnessProcessProtocol
Claude Codeclaude -p --input-format stream-json --output-format stream-json --verbose, one live process per conversationstream-json over stdin and stdout, with the control protocol the Agent SDK speaks
Codexcodex app-serverJSON-RPC requests and notifications
opencodeopencode serve --stdio --port 0, a shared serverThe server's events
GatewayNone; the app's own engineAnthropic Messages, OpenAI Responses or Chat Completions over HTTP

The live events cover chat events (text, tool calls, diffs and states), asks, the model catalogue once the harness is ready, plan usage, notices, the result of a rewind, and a refused resume.

Claude Code

The chat starts one process per conversation and writes to its stdin. A message written while a turn is still running is not lost: it queues inside that process and Claude Code picks it up when it can.

  • Claude Code stores the conversation itself. The app passes --session-id the first time and --resume when it starts the process again later.
  • Tool approvals and the harness's questions come as the control protocol's can_use_tool requests, which the chat shows as asks.
  • The model switches with set_model, and a turn stops with interrupt.
  • Rewind restarts the process with --resume-session-at and --resume-drops-turn. Files are restored through Claude Code's file checkpointing, which the app turns on for its chats.
  • Terminal view switches in place, over the same conversation. A copy of the conversation can continue in a new tab with --resume <id> --fork-session.

Codex and opencode

Codex runs its app server. Rewind calls thread/revert, which keeps files, so only the conversation is rewound.

opencode runs as a shared server. Rewind stages and commits a revert, which also restores files. opencode Workers open as chats driven by that server, with no terminal; their brief is their first message.

For both, terminal view reopens the conversation in the other surface.

The Gateway engine

Gateway chats run on a loop inside krad-chat. The model's reply streams in, the engine runs the tools it asked for, returns their output to the model and goes round again. A message you send mid-loop is added at the next round, and old turns are summarised once the context is full. The protocol is picked per model from the owner the Gateway's /v1/models reports.

  • Tools follow Codex's: read, write, edit, find, grep and shell, plus web fetch and search, questions, plans, checklists, subagents and MCP tools.
  • The chat's permission mode decides each call. Commands known to only read run freely, risky commands always ask, and approval for an edit outside the group's folder is asked each time rather than remembered.
  • The engine's MCP client speaks initialize, tools/list and tools/call over stdio and streamable HTTP.
  • It runs synchronously on threads of its own and writes each chat's session to a JSONL file in the config folder.

History that survives restarts

Besides the harness's own record, the app saves the parsed events of every chat, keyed by its resume id, through krad-store. That is why a chat shows its past messages straight away on reopen, and still shows them if the harness can no longer continue the conversation. When a harness rejects the id, the chat starts a new conversation and says so.

Why no async runtime

krad-chat does not use an async runtime. The Gateway engine uses plain threads, ureq for HTTP and the ripgrep crates for search. The Codex JSON-RPC client and the MCP client are small hand-written ones built on threads and channels, rather than the official async SDKs.

Boundaries

  • Closing a chat or the app stops its process. There is no daemon.
  • A harness process that hangs is stopped the same way a hung terminal is.
  • Terminal view stays disabled until the harness has reported the conversation's resume id.

See Agents bus for how a lead's chat starts and follows Workers.

On this page