Raw capture โ€” raw/bb-architecture-research-notes.md


url: https://gist.github.com/galligan/73beb12a47851dc0b3ce34aef4d8d529 date_fetched: 2026-08-07


Research notes from reading get-bb/bb (clone: research/repos/get-bb/bb in The Grid) and the locally installed bb 0.35.1 app.

bb does not call Anthropic/OpenAI HTTP APIs itself for coding threads. It shells out to existing agent harnesses (Codex CLI app-server, Claude Agent SDK โ†’ Claude Code CLI, Pi SDK, ACP agents like Cursor's agent acp) and normalizes their traffic into a shared bb thread-event model.

Two sanctioned adapter shapes:

Architecture path for a turn:

UI / CLI / HTTP API
  โ†’ bb Server (SQLite state, product policy)
  โ†’ Host daemon WebSocket RPC (thread.start / turn.submit)
  โ†’ AgentRuntime (process lifecycle, JSON-RPC framing)
  โ†’ ProviderAdapter (buildCommandPlan + translateEvent)
  โ†’ Provider process (codex app-server | bridge โ†’ SDK/ACP)
  โ†’ events stream back โ†’ daemon โ†’ server โ†’ clients
Piece Role
Server(apps/server) Source of truth. Threads, environments, providers policy. Sends host RPC commands over the daemon WebSocket.
Host daemon(apps/host-daemon) Provisions workspaces/worktrees, owns createAgentRuntime(), spawns provider processes, posts event batches.
Agent runtime(packages/agent-runtime) Multiplexes providers/threads; never interprets provider-specific wire content itself โ€” adapters own that.
Agent providers catalog(packages/agent-providers) Built-in provider IDs, capabilities, composer actions, reasoning ladders.
CLI / App First-class clients of the same server contract.

Environment variables injected into agent shells include BB_PROJECT_ID, BB_THREAD_ID, BB_ENVIRONMENT_ID, BB_CLI.

From a live bb provider list on this machine (and the repo catalog):

Provider ID Display Shape What actually runs
codex Codex Direct JSON-RPC codex app-server
claude-code Claude Code Bridge node bb-claude-code-bridge.mjsโ†’@anthropic-ai/claude-agent-sdkโ†’ hostclaudeCLI
pi Pi Bridge node bb-pi-bridge.mjsโ†’ Pi coding-agent SDK
acp-cursor Cursor Bridge + ACP child node bb-acp-bridge.mjsโ†’ spawnsagent acp
acp-opencode opencode Known ACP (if CLI on PATH) opencode acp
acp-omp omp Known ACP omp acp
acp-grok Grok Build Known ACP grok agent stdio
acp-hermes-agent Hermes Agent Known ACP hermes acp
acp-<slug> Custom Configured ACP ~/.bb/config.jsonโ†’customAcpAgents

Built-in ACP profile in agent-runtime today is Cursor (ACP_AGENT_PROFILES). Other known ACP agents are registered server-side in apps/server/src/services/system/known-acp-agents.ts and become available when their executable is detected on the host.

AgentRuntime keys provider processes via resolveProviderProcessKey:

Packaged bridge bundles live next to the host-daemon binary:

codex app-server

Adapter: packages/agent-runtime/src/codex/adapter.ts

bb command Codex method
initialize initialize(clientInfo name"bb",experimentalApi: true)
model/list model/list
skills skills/extraRoots/set
thread/start thread/start
thread/resume thread/resume
thread/fork thread/fork
turn/start turn/start(orthread/compact/startfor standalone compact)
turn/steer turn/steer
rename/archive thread/name/set,thread/archive, โ€ฆ

Thread start enables experimentalRawEvents: true so bb can translate richer item streams. Events are normalized in codex/event-translation.ts.

Via Codex config on start/resume/turn:

Auth: Codex's own credentials (CLI login / env). bb does not proxy OpenAI tokens for coding turns; it may reuse Codex credentials for helper inference routes separately.

node bb-claude-code-bridge.mjs

Bridge source: packages/agent-runtime/src/claude-code/bridge/

The bridge is a thin JSON-RPC shell. It does not translate to bb thread events; it forwards raw Claude Agent SDK messages as:

{ "method": "sdk/message", "params": { "threadId": "โ€ฆ", "message": /* SDKMessage */ } }The parent adapter (claude-code/adapter.ts) translates SDKMessage โ†’ ThreadEvent[].

SdkSession (bridge/sdk-session.ts) calls:

query({
  prompt: asyncIterableOfUserMessages,
  options: { cwd, systemPrompt, model, permissionMode, sandbox, hooks, mcpServers, โ€ฆ }
})

from @anthropic-ai/claude-agent-sdk.

User turns are pushed into that async iterable (pushInput), not sent as one-shot CLI argv prompts.

The SDK is pointed at the host Claude Code executable via:

(resolveClaudeCodeExecutable in session-options.ts)

So the request path is:

bb Server โ†’ daemon โ†’ AgentRuntime JSON-RPC
  โ†’ Claude bridge (thread/start, turn/start, โ€ฆ)
  โ†’ Claude Agent SDK query()
  โ†’ Claude Code CLI process (pathToClaudeCodeExecutable)
  โ†’ Anthropic (whatever the CLI/SDK uses for the selected model)

Interactive permissions/user questions are bridged back to bb as pending interactions, then answered via JSON-RPC responses into the SDK canUseTool / question handlers.

Same bridge pattern as Claude Code:

node bb-pi-bridge.mjs โ†’ @earendil-works/pi-coding-agent (and pi-ai)

Adapter owns event translation from Pi AgentSessionEvents. Process is provider-scoped like Claude. Capabilities are narrower (e.g. only full permission mode in the live provider list).

node bb-acp-bridge.mjs
  โ””โ”€ per thread: spawn(<agentCommand>) speaking Agent Client Protocol over NDJSON stdio

Bridge source: packages/agent-runtime/src/acp/bridge/

bb implements a minimal ACP client (no external ACP SDK). Frames are newline-delimited JSON-RPC. Schemas live in acp/wire.ts.

Built-in profile (acp/profiles.ts):

agentCommand: { command: "agent", args: ["acp"] }
modelCli: { listArgs: ["--list-models"], selectFlag: "--model", primaryModels: [โ€ฆ] }

Important comment in-repo: the Cursor editor binary (cursor) is not the ACP agent; the CLI agent binary is agent.

Model/reasoning for Cursor-style agents is often encoded in model id variants selected at launch (--model โ€ฆ), not only via ACP config options. Hermes uses ACP-native reasoning_effort config instead.

Adapter translates ACP updates into bb ThreadEvents (acp/adapter.ts).

Separate from provider-native files (CLAUDE.md, repo-root AGENTS.md for Codex):

Provider-native memory (Codex memories, Claude auto-memory) is controlled on Settings โ†’ Providers pages and applied at start/resume/fork โ€” not mid-turn.

Topic Path
Runtime public API / architecture packages/agent-runtime/README.md
Provider registry packages/agent-runtime/src/provider-registry.ts
Codex adapter packages/agent-runtime/src/codex/adapter.ts
Claude adapter + bridge packages/agent-runtime/src/claude-code/
ACP adapter + bridge packages/agent-runtime/src/acp/
Known ACP agents apps/server/src/services/system/known-acp-agents.ts
Daemon thread handlers apps/host-daemon/src/command-handlers/thread.ts
Runtime manager apps/host-daemon/src/runtime-manager.ts
System overview docs/system-overview.md
Config / custom ACP docs/configuration.md

Think of bb as an orchestrator + normalizer:

If you ask "how does bb send a request to Claude Code?", the accurate answer is: JSON-RPC into a Node bridge that drives the Claude Agent SDK's query() against the local claude binary โ€” not a direct Anthropic Messages API call from bb itself.

If you ask the same about Codex: JSON-RPC into a per-thread codex app-server process, using Codex's native

thread/* and turn/* methods.If you ask about Cursor: JSON-RPC into the ACP bridge, which spawns agent acp and calls ACP session/prompt.