# BooCode architecture

Last updated: 2026-05-25. **Navigation:** `AGENTS.md`. **Deep reference:** `CLAUDE.md`.

## System overview

```mermaid
flowchart TB
  subgraph client [Browser]
    SPA["apps/web React SPA"]
  end

  subgraph edge [Edge]
    Caddy --> Authelia
  end

  subgraph host ["Host 100.114.205.53"]
    subgraph docker [Docker boocode_net]
      BooChat["boocode container<br/>apps/server + built web<br/>:9500"]
      BooTerm["booterm container<br/>apps/booterm<br/>:9501"]
      PG[("boocode_db<br/>Postgres 16<br/>database: boochat<br/>host :5500")]
      CC["codecontext sidecar<br/>:8080 internal"]
    end
    BooCoder["boocoder.service<br/>apps/coder<br/>:9502"]
    Agents["Host CLI agents<br/>opencode goose claude qwen"]
    LLM["llama-swap<br/>100.101.41.16:8401"]
  end

  Authelia --> SPA
  SPA -->|"HTTP /api WS /api/ws"| BooChat
  SPA -->|"WS /ws/term"| BooTerm
  SPA -->|"HTTP /api/coder proxy<br/>WS direct"| BooCoder

  BooChat --> PG
  BooTerm --> PG
  BooCoder --> PG
  BooChat -->|"HTTP tools"| CC
  BooChat -->|"streamText"| LLM
  BooCoder -->|"native inference"| LLM
  BooCoder -->|"ACP or PTY spawn"| Agents
  Agents --> LLM
```

## Three surfaces, one database

| Surface | Code | Runtime | Primary role |
|---------|------|---------|--------------|
| BooChat | `apps/server` + `apps/web` | Docker | Read-only chat, file tools, MCP client, skills |
| BooTerm | `apps/booterm` + terminal panes in `apps/web` | Docker | tmux + xterm.js PTY panes |
| BooCoder | `apps/coder` + `CoderPane` in `apps/web` | Host systemd | Write tools, task queue, ACP/PTY agent dispatch |

All surfaces share Postgres (`boochat` DB). Cross-surface joins link chats, tasks, and sessions.

## BooChat request path

```mermaid
sequenceDiagram
  participant U as User
  participant W as apps/web
  participant S as apps/server
  participant DB as Postgres
  participant L as llama-swap

  U->>W: POST message
  W->>S: /api/sessions/:id/messages
  S->>DB: user + assistant streaming rows
  S->>S: inference.enqueue()
  loop outer step loop
    S->>L: streamText
    L-->>S: deltas / tool calls
    S->>W: WS frames via broker
    opt tool calls
      S->>S: executeToolPhase
      S->>DB: message_parts
    end
  end
  S->>DB: finalize message
  S->>W: session_updated user frame
```

Key modules: `services/inference/turn.ts` (outer loop), `stream-phase.ts` (AI SDK adapter), `tool-phase.ts`, `services/broker.ts`, `hooks/useSessionStream.ts`.

## BooCoder execution paths

```mermaid
flowchart LR
  Msg["User message<br/>CoderPane"] --> Route{"provider?"}
  Route -->|boocode| Inf["In-process inference<br/>pending_changes queue"]
  Route -->|external| Task["tasks row<br/>dispatcher poll"]
  Task --> ACP["ACP dispatch<br/>opencode goose"]
  Task --> PTY["PTY dispatch<br/>claude qwen"]
  ACP --> Host["spawn install_path<br/>on host"]
  PTY --> Host
  Inf --> Apply["apply_pending → disk"]
```

Since v2.1.0, BooCoder runs on the host (not Docker). Agent binaries spawn directly — no SSH tunnel.

See [coder-backends.md](./coder-backends.md) for the full dispatch-backend reference: routing predicates, the warm vs. one-shot lifecycle, agent-session resume, and the provider-discovery pipeline.

## Supporting services

| Service | Reachability | Purpose |
|---------|--------------|---------|
| codecontext | `http://codecontext:8080` from Docker network | Code graph / symbol analysis (Go sidecar) |
| llama-swap | `LLAMA_SWAP_URL` env | Local LLM inference + model props |
| SearXNG | `SEARXNG_URL` (Tailscale Fathom) | `web_search` / `web_fetch` when enabled |
| MCP servers | `/data/mcp.json` config | Optional tools (e.g. Context7), read-only in BooChat |

## Config and data files

| Path | Role |
|------|------|
| `data/AGENTS.md` | Global agent registry (bind-mounted `/data/AGENTS.md`) |
| `data/mcp.json` | MCP server config (opencode-compatible shape) |
| `data/skills/` | On-demand skill library |
| `BOOCHAT.md` / `BOOCODER.md` | Container guidance (mtime-cached into system prompt) |
| `apps/server/src/schema.sql` | Canonical DB schema |

## Deploy topology

- **BooChat + BooTerm + Postgres + codecontext:** `docker compose up --build -d` from `/opt/boocode`
- **BooCoder:** `pnpm -C packages/contracts build && pnpm -C apps/server build && pnpm -C apps/coder build && sudo systemctl restart boocoder`
- **Ports bind to Tailscale IP** `100.114.205.53`, not `0.0.0.0` — use that IP for host smoke curls
