Development
How BOR is built, the conventions to follow, and where things live. If you’re extending BOR, start here.Setup
electron, @modelcontextprotocol/sdk, and @playwright/mcp.
The three trees
server/— the Node runtime (the brain). HTTP server, LLM harness, providers, the tool protocol, handlers, memory, cron.shell/— the classic browser display (onboarding + dev), vanilla HTML/CSS/JS.v2/host/— the Electron Mac host (the product): presence window, native app windows, wallpaper.
Key files
| File | What it is |
|---|---|
server/index.js | HTTP server + routes. Keep the path-validation guards. |
server/ai.js | The LLM harness — system prompt, chat loop, streaming. |
server/protocol/registry.js | The single source of truth for the tool surface. |
server/protocol/parser.js | The streaming XML/CDATA parser. |
server/protocol/executor.js | Runs handlers, formats tool results. |
server/protocol/handlers/* | One module per tool family. |
server/providers/* | Provider adapters. |
server/validator.js | Safety checks for AI HTML + shell commands. |
v2/host/main.cjs | Electron main process. |
v2/host/presence.{html,js,css} | The presence UI. |
Conventions
These are enforced across the codebase:- Strict B&W default aesthetic. No emojis, gradients, or color in core UI. Apple-grade. Named themes are the deliberate exceptions. Run the design process before any UI redesign.
- LLM model ids go stale. Before editing
server/providers/*.js, fetch the provider’s live model docs — hardcoded ids rot in months. - Avatar = DiceBear
avataaarsonly. Extendshell/memoji.js; never re-add hand-rolled canvas drawing. - Provider parity. All providers are first-class; never “optimize for one, adapt the rest.”
- The default file root for AI-created files (no path given) is
.bor/, not the project tree. - Surfaces are sandboxed iframes. All I/O goes through
parent.postMessage→ the bridge, validated server-side. - Audit everything that mutates state. Call
ctx.audit({ kind, … })from handlers.
The two LLM harnesses
During a migration, two harnesses coexist. The legacy XML-tool harness (server/ai.js + server/protocol/) is the default; the native-tool-calling harness (server/llm/) is gated behind BOR_NEW_LLM=1. Both read the same registry and handlers. When you add a tool, both pick it up automatically (the new path shims the legacy handler).
Extending BOR
Code style
Match the surrounding code — its comment density, naming, and idioms. Reference code asfile_path:line. The runtime is dependency-light by design; prefer the standard library.