Skip to main content

Architecture

BOR is conceptually five layers, but the real code lives in three trees: server/ (the brain), shell/ (the classic browser display), and v2/host/ (the Electron Mac host). All three cooperate over one Node runtime.
┌──────────────────────────────────────────────────────────────┐
│  v2/host/  — Electron Mac host (the product)                   │
│    presence window · native app windows · macOS wallpaper      │
│    spawns or attaches to ↓                                     │
├──────────────────────────────────────────────────────────────┤
│  server/   — Node runtime ("the brain")                        │
│    HTTP server · LLM proxy · tool executor · state · memory    │
│    serves ↓                                                    │
├──────────────────────────────────────────────────────────────┤
│  shell/    — classic browser display (onboarding + dev)        │
│    served at http://localhost:7777                             │
└──────────────────────────────────────────────────────────────┘

server/ — the Node runtime (the brain)

A stdlib-only HTTP server. A single process serves the shell, proxies LLM calls, persists state, and executes tools. This is where everything important happens.
  • server/index.js — the HTTP server. Routes for /api/chat, surfaces, files, config, the MCP marketplace, the audit log, and more (see HTTP API). Every path that touches the filesystem is validated.
  • server/ai.js — the LLM harness. Builds the system prompt, runs the LLM stream, pipes parsed tool blocks through the executor, and emits SSE events to the client. The chat loop is multi-pass (see Chat loop).
  • server/providers/ — LLM provider adapters: anthropic.js, openai.js, gemini.js, openai-compatible.js, bor.js. Each exports a common interface. See Providers.
  • server/protocol/ — the XML tool protocol: a streaming parser, a tool registry (the single source of truth for the tool surface), an executor, and one handler module per tool family. See The protocol.
  • server/protocol/handlers/ — the implementations: widget.js (apps), shortcut.js, file.js, exec.js, theme.js, memory.js, computer.js, browser.js, tools.js (web/image), surface-data.js, svg.js, cron.js, notification.js, and more.
  • server/validator.js — static safety checks for AI-generated HTML and shell commands. A belt-and-suspenders layer alongside the iframe sandbox.
  • server/runtime/skills.js (loads skills), mcp.js (loads + dispatches MCP servers), browser.js (resolves Chromium), browser-session.js (the Playwright session for browser_action).
  • server/memory/sessions.js, profile.js, plus dream/consolidation. See Memory.
  • server/cron/ and server/notifications.js — scheduled tasks and the notification inbox.
  • server/tools/web-search.js, web-fetch.js, images.js.

shell/ — classic browser display

Vanilla HTML/CSS/JS served by the runtime — no build, no framework.
  • shell/app.js — the main client: onboarding, presence, chat input, the surface grid, system apps. Connects to /api/chat via Server-Sent Events.
  • shell/surface-bridge.js — the bootstrap injected into surface iframes; routes getState/setState/askAI/webSearch/webFetch/generateImage and friends through parent.postMessage to the server. See The bridge.
  • shell/themes/ — theme handbooks + CSS; shell/memoji.js — the DiceBear avatar wrapper.

v2/host/ — the Electron Mac host

This is the product surface. The classic shell is reduced to onboarding.
  • v2/host/main.cjs — the Electron main process. Spawns or attaches to the runtime, owns the onboarding + draggable presence windows, opens generated apps as native windows, applies macOS wallpaper, and runs a small local “host control” server so the runtime can call back into the host.
  • v2/host/presence.{html,js,css} — the always-on-top presence: collapsed orb, expanded prompt, thought bubble, and the live tool-call cards.
  • v2/host/surface-preload.cjs — lets a generated surface loaded as a top-level window keep using the same parent.postMessage bridge.
  • v2/host/preload.cjs — exposes window.borHost to the presence renderer.
  • v2/host/presences.cjs, native-apps.cjs, main-app.* — multi-presence registry, ~/Applications app wrappers, and the Main BOR app. See Multi-presence.

The request lifecycle

  1. You type into the presence → it POSTs to /api/chat (SSE).
  2. server/ai.js builds the system prompt and streams it to your provider.
  3. The streaming parser (server/protocol/parser.js) extracts tool blocks from the model’s reply as they arrive.
  4. The executor (server/protocol/executor.js) runs each tool’s handler.
  5. Each handler returns an event (streamed to the bubble as a live card) and an llmEcho (fed back to the model on the next pass).
  6. The loop repeats until the model emits no more tool calls.
See Chat loop for the details, and The protocol for the tool layer.

Two LLM harnesses

During an in-progress migration, two harnesses coexist:
  • Legacy (server/ai.js + server/protocol/ + server/providers/) — the XML-tool harness, currently the default.
  • New (server/llm/) — a native-tool-calling harness, gated by BOR_NEW_LLM=1.
Both read the same tool registry and the same handlers — the new path adapts them via a shim. Unless you opt in, you’re on the legacy path.