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.
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 forbrowser_action).server/memory/—sessions.js,profile.js, plus dream/consolidation. See Memory.server/cron/andserver/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/chatvia Server-Sent Events.shell/surface-bridge.js— the bootstrap injected into surface iframes; routesgetState/setState/askAI/webSearch/webFetch/generateImageand friends throughparent.postMessageto 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 sameparent.postMessagebridge.v2/host/preload.cjs— exposeswindow.borHostto the presence renderer.v2/host/presences.cjs,native-apps.cjs,main-app.*— multi-presence registry,~/Applicationsapp wrappers, and the Main BOR app. See Multi-presence.
The request lifecycle
- You type into the presence → it
POSTs to/api/chat(SSE). server/ai.jsbuilds the system prompt and streams it to your provider.- The streaming parser (
server/protocol/parser.js) extracts tool blocks from the model’s reply as they arrive. - The executor (
server/protocol/executor.js) runs each tool’s handler. - 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).
- The loop repeats until the model emits no more tool calls.
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 byBOR_NEW_LLM=1.