Getting started
Biorouter is a desktop research environment that connects local, institution-hosted, and commercial AI models in one interface. It runs on your machine, stores its data as plain files on disk, and talks only to the provider you choose. Setup is a few minutes: download, put the bundled command-line tool on your PATH if you want it, connect a provider, and start a session. This guide covers biorouter 1.88.3 on macOS, Windows, and Linux.
Download and install
Get the build for your platform from the Download page or from GitHub Releases. Install the newest release for the latest fixes.
- macOS: open the
.dmgand drag Biorouter to/Applications. A.zipis also published for the in-app auto-updater. - Windows: unzip
Biorouter-win32-x64-*.zipand runBiorouter.exe. - Linux desktop: install
biorouter_*_amd64.deb(Debian/Ubuntu) orBioRouter-*-1.x86_64.rpm(Fedora/RHEL). - Linux headless (servers, HPC nodes, containers): install the CLI-only package
biorouter-cli_*_amd64.deborbiorouter-cli-*-1.x86_64.rpm. It ships just thebiorouterCLI and thebiorouterddaemon, with no desktop app.
npx.
Put the bundled CLI on your PATH
On macOS and Windows the biorouter command-line tool ships inside the desktop app, so there is no separate CLI download. It shares the same config, sessions, and settings as the app.
- From the app: accept the Install Biorouter CLI prompt on launch. One click symlinks the bundled binary onto your PATH.
- From a terminal: run
biorouter setup-path. If the target directory is not on your PATH, it prints the exact line to add.
On Linux, install the standalone biorouter-cli package instead of running setup-path. After a desktop upgrade on macOS or Windows, re-run biorouter setup-path so your PATH points at the new binary.
Connect your first provider
Biorouter needs a provider to function and prompts you to pick one on first launch. Choose whichever fits your trust boundary:
- UCSF researchers: choose Versa API Azure (UCSF ChatGPT, via Azure OpenAI) or Versa API Bedrock (UCSF-hosted Anthropic, via Amazon Bedrock). Your data stays inside UCSF's tenant.
- Everyone else: paste an API key for Anthropic, OpenAI, Google Gemini, or another commercial provider.
- Zero setup, fully local: pick Llama Server, Biorouter's bundled llama.cpp runtime. No key and no separate install; weights download once from Hugging Face and nothing else leaves your machine.
From a terminal you can do the same with biorouter configure and selecting Configure Providers.
Start your first session
Type a message in the desktop chat, or open a terminal session:
biorouter session # interactive terminal chat
biorouter run -t "Summarize ./notes.md in 5 bullets" # one-shot, headless
Send a short test prompt to confirm the setup works. If Biorouter replies, you are ready.
Where your data lives
Biorouter keeps everything under your user config directory as plain files you can inspect, back up, and version. The desktop app and the CLI share this directory.
| Path | Holds |
|---|---|
~/.config/biorouter/config.yaml | Providers, models, extensions, and settings |
~/.config/biorouter/sessions/ | Conversation history in a SQLite database |
~/.config/biorouter/workflows/ and skills/ | Installed workflows and skills |
~/.config/biorouter/logs/ | Log files (check these first when something fails) |
Secrets never touch config.yaml
API keys and credentials are written to your operating system's credential store (macOS Keychain, Windows Credential Manager, Linux Secret Service), not to any config file. See Vaulting and security below for how that works.
On Windows the config directory is %APPDATA%\biorouter\config\. The Electron app state lives separately at ~/Library/Application Support/Biorouter/ on macOS.
Using the desktop app
The Biorouter desktop app (v1.88.3) is where most people do their day-to-day work: you type a research question, watch the agent plan and call tools, and read the files, figures, and apps it produces, all in one window. This guide walks through every surface of the app: the sidebar and titlebar, the chat composer and its toolbar, the browser-style tabs and side-by-side split panes, the in-app terminal, and the Home, History, and Settings pages. It assumes you have the app installed and a model provider connected. If you do not, start with Biorouter in 5 minutes.
The window at a glance
Every Biorouter window has three regions. Across the top is a thin titlebar with the traffic-light window controls, a couple of quick actions, and the active session's name. Down the left is the sidebar, a fixed column of navigation and a list of recent chats. Everything else is the main area, which shows whichever section you have open (a chat, the Home page, History, Settings, and so on).
When you are in a chat, the main area is itself split top-to-bottom: the scrolling transcript fills the space, and a floating composer (the box you type into) sits at the bottom. The composer is the only element in the app that carries a soft shadow; everything else is flat, separated by hairlines.
The sidebar
The sidebar is your map of the app. From top to bottom it holds a New Session action, the navigation list, a Recents list, and Settings pinned to the footer.
Navigation order
| Item | What it opens |
|---|---|
| New Session | Starts a fresh, empty chat. This is the top action in the rail. |
| Home | The landing page: greeting prompt, usage analytics, the activity heatmap, and recent chats. |
| Chat | The current conversation (or a new one), with its tabs and any split panes. |
| History | Every past session, grouped by day, with full-text search. |
| Workflows | Saved, reusable session templates you can run again or share. |
| Scheduler | Cron-style scheduled tasks that run workflows automatically. |
| Extensions | MCP extensions (pluggable tool servers). Toggle them on and off here. |
| Skills | Reusable instruction sets that guide how the agent behaves. |
| Knowledge | Personal, agent-maintained knowledge bases backed by markdown folders and git history. |
| Apps | Interactive apps the agent has built, plus their export controls. |
| Settings | Providers and models, permission modes, themes, and the CLI install. Pinned to the footer. |
Each row is 32px tall with a line-drawn icon and a label. The active row is tinted and carries a 2px coral bar on its leading edge, the one place the accent colour appears in the sidebar.
The Recents list
Below the navigation, the Recents list shows chats you have touched lately, grouped by day (Today, then dated headings). Each row is the session's title as plain text; a small indicator appears next to a chat that is currently running. Click a row to reopen that session as a tab in the chat area. A count badge shows how many chats you have used in the past seven days, and View all chat history at the foot of the list jumps to the full History page. If the rail gets crowded, Recents has a disclosure control so you can fold it away.
Collapsing the sidebar
The sidebar is 240px wide when expanded and collapses to a 60px icon rail. Use the toggle in the titlebar to switch between them. Below about 1120px of window width the app collapses the sidebar for you and shows it as an overlay when you need it, so the chat keeps its full measure on a narrow screen.
Titlebar controls
The titlebar carries the standard window controls plus two quick actions: a + that starts a new session, and a split/panel control for opening a new window. When the sidebar is collapsed or overlaid on macOS, the app reserves space after the traffic lights so the session name never sits under them. The session name in the titlebar is editable: renaming a chat here updates it everywhere the name appears (its tab, the Recents list, and History).
Chat and the composer
A chat is one continuous conversation. You type a request, the agent forms a plan and works through it (calling tools, writing files, drawing figures), and you read the results in the transcript. Your own turns are tinted so the eye can find them when scrolling; the agent's prose runs full width, unboxed, like a document.
Starting a session
Click New Session in the sidebar (or the + in the titlebar, or press Cmd+T). The composer opens centered and empty. Type your question or task in plain language and press Enter (or click Send). There is no special syntax: describe the task the way you would to a research assistant.
The composer toolbar
Under the text box is a row of controls. Each one is a chip you click to open a picker or to change a setting for this chat. From left to right:
| # | Control | What it does |
|---|---|---|
| 1 | Working directory (folder icon + path) | The folder the agent reads and writes in. Click to switch it. Relative paths the agent uses resolve against this directory. |
| 2 | Attach files (paperclip + count) | Attach files or images to the next message. The count shows how many are staged; remove one with its close control. |
| 3 | Extensions (puzzle + count) | Which MCP extensions (tool servers) are active for this session. Open the picker to enable or disable them per chat. |
| 4 | Skills (layers + count) | Which skills (instruction sets) are in play. Open to add or drop skills for this chat. |
| 5 | Knowledge (book + KB count) | Which knowledge bases the agent can see and write to in this chat. Open to change the visible set. |
| 6 | Cost (dollar + running total) | The estimated spend for this session so far, updated as turns complete. |
| 7 | Model (brain + model name) | The model driving this chat. Click to switch model or provider mid-conversation. |
| 8 | Mode (label) | The permission mode: how much the agent may do on its own (autonomous, approve each action, or chat only). Click to change it. |
The toolbar folds when the chat is narrow
Inside a split pane, or in a small window, the composer keeps only the working-directory, attach, extensions, and skills chips visible and folds the rest (cost, model, mode) behind a chevron. Click the chevron to reach them. Nothing is removed, it is just tucked away so the row fits.
Sending, stopping, and streaming
Press Enter or click Send to submit. Send is disabled while the box is empty. While the agent works, the button becomes a Stop control; click it to cancel the current turn. As the agent replies, text streams in with a blinking caret at the end, which disappears when the turn finishes. You can submit a message even while extensions are still loading in the background: your message lands in the transcript, the chat shows it streaming, and Stop works throughout.
Tool-call lines
When the agent uses a tool, it shows up as a single line in the transcript, not a boxed card: a status icon, the tool name, a short summary of its arguments, and a duration. A spinner means the call is running, a check means it succeeded, and a warning triangle with a faint red wash means it failed. Click any tool-call line to expand it and read the full arguments and results as code blocks; click again to collapse. This keeps a long chain of tool calls readable while the details stay one click away.
Editing, branching, copying, and retrying
Hover a message to reveal its actions. On your turns you get copy and edit; on the agent's turns you get copy, retry, and branch.
- Copy puts the message text on the clipboard.
- Edit lets you rewrite one of your earlier prompts and re-run the conversation from that point.
- Retry re-runs the agent's last turn, useful if a response was cut off or you want another attempt.
- Branch (Diverge) forks the conversation into a new session from the chosen point, so you can explore an alternative without losing the original. The branch opens as its own tab.
You can walk back through the messages with Cmd+Up and Cmd+Down to select an earlier one to edit, which is what the composer's placeholder hint refers to.
Switch the model mid-chat
Click the model chip in the composer toolbar (the brain icon with the current model name, for example gpt-5.6). Pick a different model, or a different provider, from the list. The next turn uses the new model; the transcript so far is unchanged.
Branch a conversation
Hover the agent turn you want to branch from and click Branch. Biorouter forks a new session that copies the conversation up to that point and opens it as a new tab. Continue in the branch; the original chat stays exactly as it was.
Tabs
The chat area works like a browser: every conversation is a tab in a strip along the top of the chat. Each tab is an independent session with its own transcript, model, working directory, and knowledge-base selection. A tab that is actively running shows a small activity dot.
Opening tabs
- The + at the right end of the tab strip opens a fresh blank chat in that group.
Cmd+Topens a new tab (a new chat) from anywhere in the chat area.- Clicking a row in History or Recents opens that session as a tab. Opening the same session twice reuses its existing tab rather than duplicating it, and the tab arrives already carrying the session's real name.
Renaming, closing, and reordering
Rename a chat from its titlebar name; the new name mirrors into the tab, Recents, and History. Close a tab with its × or with Cmd+W. Cycle between tabs with Ctrl+Tab (next) and Ctrl+Shift+Tab (previous), wrapping around at the ends. Biorouter uses Ctrl+Tab rather than Cmd+Tab because the operating system reserves Cmd+Tab for switching applications; this is the same choice Safari and Chrome make on macOS.
Reorder tabs by dragging
Press and hold a tab, then drag it left or right along the strip. A ghost of the tab follows your cursor and the other tabs shift to make room. Release it where you want it. Reordering never changes which session a tab holds; it only changes the order they sit in.
Split panes
You can split the chat area into side-by-side (or stacked) panes and run a different conversation in each. This lets you watch several agents work at once: one querying a clinical database, another running a SPOKE graph query, a third scanning literature, all visible together. Each pane is its own group with its own tab strip, transcript, model, and composer.
Making a split
Split a chat into two panes
Grab a tab and drag it toward an edge of the chat area. As you move, drop zones light up: dragging to the left or right edge creates a vertical (side-by-side) split, and dragging to the top or bottom edge creates a horizontal (stacked) split. The zone tints live as your cursor crosses it, so you can see where the tab will land before you release. Drop the tab and the chat area splits, with that tab's session now living in its own pane.
Dropping a tab onto the center of another pane instead moves it into that pane's tab strip rather than creating a new split. You can keep splitting up to 6 panes in one window. Each new pane runs a full, independent session.
Resizing panes
Between any two panes is a draggable splitter. Hover it, then drag to give one pane more room and the other less. The split reflows as you drag. If you shrink the window far enough that the panes would become unusable slivers, Biorouter merges the split back to a single group so the chat stays readable; a split you deliberately created at a narrow width is left alone.
Each pane is genuinely separate
A pane carries its own model, working directory, permission mode, knowledge bases, and enabled extensions. Two panes can run different models against different folders at the same time. The transcripts do not share context; they are separate sessions that happen to be on screen together.
The in-app terminal
Every chat tab can open its own terminal, docked beneath the transcript, so you can run shell commands right next to the conversation (inspect a file the agent wrote, run a script, check git status) without leaving the app.
Open a terminal for the current chat
Use the terminal control in the chat to toggle the terminal dock open. It appears below the transcript for the tab you are in. The shell starts in that session's working directory, the same folder shown in the composer's working-directory chip, captured at the moment the terminal opens.
Terminals are per tab. Each chat tab has its own terminal with its own open/hidden state and its own panes; switching tabs switches which terminal you see. A background tab's shell keeps running (hidden) until you close the tab. Inside the dock, a + after the last terminal tab opens an additional terminal pane. When focus is in the terminal, Cmd+T opens a new terminal pane (rather than a new chat tab), so the shortcut follows wherever your attention is.
Home
Home is the app's landing page and a summary of your usage. Top to bottom it holds a greeting, your activity analytics, and your recent chats, with the composer at the bottom so you can start typing immediately.
The greeting and prompt
A short kicker ("UCSF Biorouter") sits over a single greeting line, and the composer is right there: Home doubles as a launch pad for a new session. Type into it and you are in a chat.
Usage analytics and the heatmap
Home shows cached statistics about how much you have used the app: total sessions and total tokens, with 30-day and 7-day figures. Below them is a GitHub-style usage heatmap: roughly five months of daily activity, one cell per day, shaded by how much work that day held (sessions started and tokens processed). A header shows your current streak of consecutive active days and your longest streak.
Hover or keyboard-focus any cell to see that day's detail: sessions started, tokens processed, messages, and the top model used. Shading is relative to your own recent window, so ordinary days stay distinguishable from heavy ones rather than all collapsing to the faintest colour.
How the numbers are counted
Tokens are attributed to the day a session started (older sessions that predate per-day accounting are anchored to their start day), which the heatmap tooltip notes. The counts include your own and scheduled sessions; sub-agent, hidden, and terminal sessions are excluded so the tiles match the list beneath them.
Recent chats
Under the heatmap is a short list of recent sessions, each with a token count and a relative time. Click one to reopen it as a tab, or use See all to jump to the full History page.
History
History is the searchable record of every conversation you have had. Sessions are grouped by day (Today, then dated headings), and each row shows the session title, its time, its working folder, and its message and token counts.
Searching and reopening
Reopen a past session
Press Cmd+F to search across your past conversations by their content, or scroll the day-grouped list. Click a session to open it as a named tab in the chat area, right where you left off. Opening a session that is already open just switches to its existing tab.
Importing and exporting sessions
Use Import Session on the History page to bring in a session file (for example one a colleague exported). Individual sessions can be exported for sharing or backup. Under the hood, your history lives in a local SQLite database at ~/.config/biorouter/sessions/, so search and recall read straight from your own machine.
The other sidebar sections
The remaining sidebar routes each manage one kind of thing. They share the same page shape: a title, a short description, an action or two in the top-right, and a list below.
- Workflows turn a successful session into a reusable template. Each workflow row has actions to run it, open a terminal for it, edit it, share it, schedule it, and delete it. Create Workflow and Import Workflow sit at the top.
- Scheduler lists scheduled tasks that run workflows on a cron schedule, showing each one's timing and last run, with edit, pause, and delete controls. Some schedules are built in.
- Extensions lists your MCP extensions, grouped by built-in and installed, each with an on/off switch. Add Extension, Browse Extensions (the marketplace), and Add Custom Extension are at the top. Turn off extensions you are not using: fewer active tools improves the agent's tool selection and saves context.
- Skills lists reusable instruction sets, grouped into families, with tags. Add Skill, Browse Skills, and Add Custom Skill are at the top.
- Knowledge is where you build and view personal knowledge bases. You ingest sources (drop files, paste text, or add a URL) into a KB, and the agent digests them into a markdown tree with a git history. The page shows a KB selector, an ingest panel, and a graph of the pages and their links, with export (
.brkb), a change log, and an open-folder control. - Apps lists interactive apps the agent has built for you and is the only place to delete one (deleting removes its files from disk, so the in-chat card never offers a delete).
Settings
Settings is the app's configuration hub. The areas you will use most:
Providers and models
Provider Configuration is where you connect LLM providers and pick models. Providers are grouped as Local (Llama Server, Ollama), Institutional (UCSF Versa via Azure and Bedrock), and Commercial (Anthropic, OpenAI, Google Gemini, OpenRouter, and more), with Local listed first. A configured provider shows a check. API keys are encrypted and stored in your operating system's credential store, not in a plaintext file. You can also switch model per chat from the composer's model chip; the setting here is the default.
Permission modes
Permission modes decide how much the agent may do without asking. You can give it full autonomy, require your approval before it takes actions, or keep it to chat only (no actions at all). The composer's mode chip changes this per chat; choose the level that matches how much supervision you want. Sensitive files can be fenced off entirely with a .biorouterignore file listing paths the agent must not read or change.
Themes
Biorouter ships three theme families, each available in light and dark:
| Family | Character |
|---|---|
| Parchment (default) | Warm paper and terracotta. The base look. |
| Alma Mater | UCSF brand: navy ground with a teal accent. |
| Roche Limit | JupyterLab-inspired white, grey, and orange. |
Change the theme
Pick a theme family in Settings, and choose Light, Dark, or System for the mode. System follows your operating system's light/dark setting and is the default, so the app matches the rest of your desktop. The light/dark choice and the family are independent, so any family works in either mode.
Capabilities
Capabilities are the categories of action the agent can take (reading and writing files, running shell commands, querying data, driving an app's own interface). Which capabilities are available in a chat depends on the extensions you have enabled and the permission mode you have set. Apps the agent builds have their own capability switches, so, for example, a text-only app can be built with file and shell access turned off.
Install the command-line tool
The desktop app bundles the biorouter command-line tool. To put it on your PATH, run biorouter setup-path in a terminal (macOS and Windows). If your terminal's biorouter is older than the app, the in-app Biorouter CLI Update card re-installs and links the matching version; the app's own bundled daemon always matches the app.
The CLI and the desktop app share the same account and configuration, so a session you start in one shows up in the other. The CLI is documented separately in the command-line reference.
The menu bar and tray
The application menu bar mirrors the sidebar with keyboard shortcuts and adds a few things the sidebar does not: New Window, Open Directory, theme switching (Light, Dark, System), provider configuration, and links to the documentation and bug reports. On macOS, left-clicking the tray icon brings the window to the front; right-clicking it opens a short menu (Home, New Chat, Settings, Extensions, Skills, Check for Updates, Quit).
Menu-bar navigation shortcuts (such as the number keys for the main sections) can vary between app versions as sections are added. The browser-style keys below (new tab, new window, close, cycle) are stable across the app.
Keyboard shortcuts
Shortcuts use Cmd on macOS and Ctrl on Windows and Linux, except where noted.
| Action | Shortcut |
|---|---|
| New tab (new chat), or new terminal pane when the terminal is focused | Cmd+T |
| New window | Cmd+N |
| Close the current tab | Cmd+W |
| Close the window | Shift+Cmd+W |
| Next tab / previous tab (wraps) | Ctrl+Tab / Ctrl+Shift+Tab |
| Search the current list (History, Workflows, Extensions, Skills) | Cmd+F |
| Navigate to an earlier / later message to edit | Cmd+Up / Cmd+Down |
| Open Settings | Cmd+, |
| Open a directory as the working folder | Cmd+O |
| Focus the Biorouter window | Option+Cmd+G |
| Quick Launcher (start a session from anywhere) | Cmd+Option+Shift+G (macOS), Ctrl+Alt+Shift+G (Windows/Linux) |
| Quit | Cmd+Q |
Where to go next
- Biorouter in 5 minutes walks through your first task end to end.
- Usage tips collects short habits for prompting, cost control, and session hygiene.
- Choosing a model provider covers each provider's credentials and default model.
- The command-line reference documents the
biorouterCLI, which shares your account and sessions with the app.
Command line
The biorouter command-line interface is the terminal side of BioRouter. It runs the same agent that powers the desktop app: you can hold an interactive chat, run a one-shot task in a script, manage sessions and providers, install extensions and skills, maintain knowledge bases, schedule recurring workflows, and start local web or server interfaces. This page documents every subcommand, every flag, the interactive session (the REPL), the terminal integration, and the biorouterd daemon that the GUI talks to. It targets BioRouter 1.88.3 (Node 24+, Rust 1.92).
Top-level usage and global structure
The CLI is a single binary named biorouter with one subcommand per task. Run it with no subcommand to drop straight into an interactive session (BioRouter runs first-time configuration instead if no config file exists yet).
biorouter [SUBCOMMAND] [FLAGS] [ARGS]
biorouter # start (or first-time-configure then start) an interactive session
biorouter --help # print the top-level help and the full subcommand list
biorouter --version # print the installed version (1.88.3)
biorouter <subcommand> --help # per-subcommand help, flags, and defaults
| Flag | Purpose |
|---|---|
-h, --help | Show help for the CLI or any subcommand. Every subcommand accepts --help. |
-V, --version | Print the version and exit. The CLI (biorouter), the daemon (biorouterd), and the core library are compiled from one workspace version, so they never disagree. |
Command aliases
Several subcommands have short aliases: session = s, project = p, projects = ps, knowledge = kb, extension = ext, schedule = sched, and setup-path = install-cli.
Exit codes
The CLI returns 0 on success. A turn that ran but did not complete its work reports its own exit code so a caller can tell a rejected provider key apart from a normal disagreement: for example 75 when the provider rejected the credentials. Any other error returns 1.
Flag naming conventions
Flag names are consistent across subcommands so they are predictable:
--session-idfor session identifiers (for example20251108_1);--idis an accepted alias.-n, --namefor human-readable names.--pathfor file paths (legacy session support).-o, --outputfor output file paths.-rmeans--resumefor sessions and--regexfor filters, depending on the command.-v, --verbosefor detailed output,-l, --limitfor result counts,-f, --formatfor output format,-w, --working_dirfor directory filters.
Session and chat
session
Start or resume an interactive chat session. This is the CLI's main interface: a persistent conversation with the agent, tool calls, and slash commands. Alias: s.
biorouter session [--resume] [--history] [-n NAME | --session-id ID | --path PATH] [FLAGS]
| Flag | Type | Default | Description |
|---|---|---|---|
-n, --name <NAME> | string | none | Name for the session. With --resume, resumes the session with this name if it exists; otherwise a new named session is created (with a warning) rather than erroring. |
--session-id <ID> | string | none | Address a session by its ID (for example 20250921_143022). Only valid together with --resume. Alias: --id. |
--path <PATH> | path | none | Legacy: derive the session ID from a file path (the file stem). For older file-based session storage. |
-r, --resume | flag | off | Resume a previous session. With no identifier, resumes the most recently used session. |
--history | flag | off | Render the previous messages when resuming. Requires --resume. |
--debug | flag | off | Debug output: full tool responses with no truncation and full file paths. |
--max-tool-repetitions <N> | integer | unset | Cap how many times the same tool can be called consecutively with identical parameters. Guards against infinite loops. |
--max-turns <N> | integer | 1000 | Cap the number of turns the agent takes without asking for user input. |
--with-extension <COMMAND> | string (repeatable) | none | Add a stdio extension from a full command, optionally with env vars. Format: ENV1=val1 command args.... |
--with-streamable-http-extension <URL> | string (repeatable) | none | Add a remote extension over Streamable HTTP. |
--with-builtin <NAME> | comma list | none | Enable one or more built-in extensions by name, for example developer,computercontroller. |
# Start a named session
biorouter session -n gwas-analysis
# Resume the last session, showing prior messages
biorouter session --resume --history
# Resume a specific session by ID
biorouter session --resume --session-id 20251108_2
# Start with the developer builtin and a memory MCP extension
biorouter session --with-builtin developer \
--with-extension "npx -y @modelcontextprotocol/server-memory"
session subcommands
The session command also groups management subcommands. Each targets a session by --session-id, -n/--name, or legacy --path; if you supply none, most prompt you to pick one interactively.
session list
List saved sessions.
biorouter session list [-f text|json] [--ascending] [-w PATH] [-l N]
| Flag | Type | Default | Description |
|---|---|---|---|
-f, --format <FMT> | text or json | text | Output format. |
--ascending | flag | off (newest first) | Sort oldest first. |
-w, --working_dir <PATH> | path | none | Filter by working directory. Short alias -p. |
-l, --limit <N> | integer | none | Limit the number of results. |
session remove
Remove one or more saved sessions. Runs interactively if no identifier or regex is given.
biorouter session remove [--session-id ID | -n NAME | -r REGEX]
| Flag | Type | Description |
|---|---|---|
--session-id <ID> | string | Remove a specific session by ID. |
-n, --name <NAME> | string | Remove a specific session by name. |
-r, --regex <PATTERN> | regex | Remove every session matching the pattern. |
session export
Export a session for backup, sharing, or documentation.
biorouter session export [IDENTIFIER] [-o FILE] [--format markdown|json|yaml]
| Flag | Type | Default | Description |
|---|---|---|---|
-o, --output <FILE> | path | stdout | Write the export to a file instead of stdout. |
--format <FMT> | markdown, json, yaml | markdown | markdown is a readable transcript; json and yaml are complete backups that preserve history, metadata, and settings. |
# Full JSON backup of a named session
biorouter session export -n gwas-analysis --format json -o backup.json
# Readable markdown transcript to stdout
biorouter session export --session-id 20251108_4
session diagnostics
Generate a troubleshooting bundle (a ZIP) for a session.
biorouter session diagnostics [IDENTIFIER] [-o FILE]
| Flag | Type | Default | Description |
|---|---|---|---|
-o, --output <FILE> | path | diagnostics_<session_id>.zip | Where to write the bundle. |
The bundle includes system information (version, OS, architecture, timestamp), the session's full message history, your configuration files, and recent logs.
session rename
Rename a saved session.
biorouter session rename [IDENTIFIER] --new-name "NAME"
| Flag | Type | Description |
|---|---|---|
--new-name <NAME> | string (required) | The new session name. |
session diverge
Branch a stored conversation into a brand-new session, keeping the full history. The original is left untouched. The new session ID is printed to stdout; resume it with biorouter session --resume --session-id <ID>.
biorouter session diverge [IDENTIFIER] [--branch-name "NAME"]
| Flag | Type | Description |
|---|---|---|
--branch-name <NAME> | string | Optional name for the branched session. |
sessions.db) under BioRouter's data directory, not as individual files. Older .jsonl sessions are imported automatically; the legacy files stay on disk but are no longer managed.run
Execute a task non-interactively from an instruction file, a text string, stdin, or a workflow. This is the command for scripting and automation. By default it processes the input and exits; add -s/--interactive to continue in a chat afterward.
biorouter run (-i FILE | -t "TEXT" | --workflow NAME_OR_PATH) [FLAGS]
| Flag | Type | Default | Description |
|---|---|---|---|
-i, --instructions <FILE> | path | none | Read the prompt from an instruction file. Use - for stdin. Mutually exclusive with -t and --workflow. |
-t, --text <TEXT> | string | none | Provide the prompt directly on the command line. |
--workflow <NAME_OR_PATH> | string | none | Load a workflow by name (from local dirs or a configured GitHub repo) or full path. |
--system <TEXT> | string | none | Additional system prompt to customize agent behavior. Not valid with --workflow. |
--params <KEY=VALUE> | repeatable | none | Parameters passed to the workflow. Repeat for multiple values. |
--sub-workflow <WORKFLOW> | repeatable | none | Include sub-workflows (names or local paths) alongside the main workflow. |
--explain | flag | off | Print the workflow's title, description, and parameters, then exit without running. |
--render-workflow | flag | off | Print the rendered workflow YAML instead of running it. |
-s, --interactive | flag | off | Continue in an interactive session after the initial input is processed. |
-n, --name <NAME> | string | none | Name for this run's session. |
-r, --resume | flag | off | Resume from a previous run. |
--path <PATH> | path | none | Legacy file-based session path. |
--no-session | flag | off | Run without creating or storing a session file. Conflicts with --resume, --name, --path. |
--debug | flag | off | Full tool responses and paths, no truncation. |
--max-tool-repetitions <N> | integer | unset | Consecutive identical tool-call limit. |
--max-turns <N> | integer | 1000 | Turn limit without user input. |
-q, --quiet | flag | off | Quiet mode. Suppress non-response output; print only the model response to stdout. |
--output-format <FMT> | text, json, stream-json | text | Structured output for automation: json for a single result after completion, stream-json for events as they occur. |
--provider <PROVIDER> | string | config | Override the provider for this run (overrides BIOROUTER_PROVIDER). |
--model <MODEL> | string | config | Override the model for this run (overrides BIOROUTER_MODEL). |
--with-extension, --with-streamable-http-extension, --with-builtin | see session | none | Same extension flags as session. |
# One-shot prompt, machine-readable JSON, no stored session
biorouter run --no-session -t "summarize this VCF header" --output-format json
# Pipe a prompt in via stdin
cat plan.md | biorouter run -i -
# Run a parameterized workflow, then stay interactive
biorouter run --workflow daily-report.yaml --params region=us-west-2 --interactive
# Inspect a workflow without running it
biorouter run --workflow daily-report.yaml --explain
The interactive session (REPL)
An interactive session is BioRouter's terminal REPL. Start it with biorouter, biorouter session, or biorouter run --interactive. Unlike a one-shot run, an interactive session keeps a live prompt (Biorouter ❯) where you type messages, watch tool calls stream, and issue slash commands between turns. A one-shot run processes a single input and exits, which is what you want in scripts and CI; the interactive session is for iterative work.
Slash commands
Type these at the prompt. Press / then Tab to cycle through them; Tab also completes /skill: and /ext: references.
| Command | Effect |
|---|---|
/help, /? | Show the in-session help with every slash command. |
/clear | Clear the current chat history. |
/compact | Compact and summarize the conversation to reclaim context while keeping key information. (Replaces the deprecated /summarize.) |
/diverge [name] | Branch this conversation into a new session, keeping the full history. |
/rename <name> | Rename the current session. |
/goal <condition> | Keep working until the condition is met. /goal clear stops it. |
/loop <interval> <prompt> | Run a prompt on an interval, for example /loop 5m .... /loop stop <id> stops it. |
/schedule <spec> <prompt> | Schedule a recurring prompt using 5m, @daily, or a quoted cron expression. |
/mode <name> | Set the permission mode: auto, approve, chat, or smart_approve. |
/plan [message] | Enter plan mode: build a plan from the current conversation and offer to act on it. |
/endplan | Exit plan mode and return to normal mode. |
/workflow [file.yaml] | Save the current conversation as a workflow. Defaults to ./workflow.yaml; a supplied path must end in .yaml. |
/extension <cmd> | Add a stdio extension during the session. Format: ENV1=val1 command args.... |
/builtin <names> | Add built-in extensions by name (comma-separated). |
/t | Toggle the markdown theme through light, dark, ansi. |
/t <name> | Set the theme directly to light, dark, or ansi. |
/r | Toggle full, untruncated tool output. |
/exit, /quit | Exit the session. |
Keyboard shortcuts
| Key | Action |
|---|---|
Ctrl+C | Interrupt the current request. The conversation resets to before the interrupted turn. |
Ctrl+J | Insert a newline without submitting. |
Up / Down | Navigate command history. |
Ctrl+R | Reverse-search command history. Type a term, press Ctrl+R to cycle backward and Ctrl+S to cycle forward, then Enter to run or Esc to cancel. |
Tab | Complete slash commands, file paths, and /skill: / /ext: references. |
Themes
The /t command controls syntax highlighting for markdown in CLI responses (headers, code blocks, emphasis). It affects fonts and colors only, not the terminal chrome. There are three themes: light and dark use subtle colors, and ansi is the most visually distinct. The default is dark. The choice is saved to the configuration file as BIOROUTER_CLI_THEME and persists between sessions; the BIOROUTER_CLI_THEME environment variable overrides the saved value for one session. The CLI theme is independent of the desktop app theme.
Workflows and scheduling
workflow
Validate workflow files, install them into your library, generate shareable links, list what is available, and open workflows in BioRouter Desktop.
biorouter workflow <install|validate|deeplink|open|list> [ARGS]
| Subcommand | Synopsis | Description |
|---|---|---|
install | workflow install <PATH> | Install a workflow .json or .yaml file into the workflow library. |
validate | workflow validate <NAME_OR_PATH> | Validate a workflow file by name or path. |
deeplink | workflow deeplink <NAME> [-p KEY=VALUE]... | Generate a shareable deeplink. -p/--param pre-fills a parameter (repeatable). |
open | workflow open <NAME> [-p KEY=VALUE]... | Open the workflow in BioRouter Desktop. -p/--param pre-fills a parameter (repeatable). |
list | workflow list [--format text|json] [-v] | List workflows from local directories and configured GitHub repos. --format defaults to text; -v/--verbose adds titles and full paths. |
biorouter workflow validate daily-report.yaml
biorouter workflow deeplink daily-report.yaml -p region=us-west-2
biorouter workflow list --verbose
schedule
Run workflows automatically on a cron schedule. Adding a job copies the current workflow into a scheduled_workflows directory in BioRouter's data dir, so later edits to the source file do not change the scheduled copy. Alias: sched.
biorouter schedule <add|list|remove|sessions|run-now|cron-help> [FLAGS]
| Subcommand | Synopsis | Description |
|---|---|---|
add | schedule add --schedule-id ID --cron "EXPR" --workflow-source PATH | Create a scheduled job. --workflow-source is a path to a YAML file (or a base64-encoded workflow). --id aliases --schedule-id. |
list | schedule list | List all scheduled jobs. |
remove | schedule remove --schedule-id ID | Delete a scheduled job. |
sessions | schedule sessions --schedule-id ID [-l N] | List sessions a schedule created. -l/--limit caps the count. |
run-now | schedule run-now --schedule-id ID | Run a scheduled workflow immediately. |
cron-help | schedule cron-help | Print a cron expression guide with common examples. |
Cron expressions may be 5-field (minute hour day month weekday), 6-field (with a leading seconds field), or shorthands like @hourly, @daily, @weekly, @monthly.
# Run every day at 9:00 AM (6-field form with seconds)
biorouter schedule add --schedule-id daily-report \
--cron "0 0 9 * * *" --workflow-source ./workflows/daily-report.yaml
biorouter schedule sessions --schedule-id daily-report -l 10
biorouter schedule run-now --schedule-id daily-report
biorouter schedule remove --schedule-id daily-report
services-status and services-stop subcommands are deprecated no-ops. The scheduler no longer runs an external service, so there is nothing to start or stop.Extensions, skills, knowledge, and apps
extension
Install and manage MCP extensions distributed as .brxt bundles. Alias: ext.
biorouter extension <install|list|remove> [FLAGS]
| Subcommand | Synopsis and flags | Description |
|---|---|---|
install | extension install <PATH> [--env KEY=VALUE]... [--secret KEY=VALUE]... [--no-enable] | Install from a .brxt bundle: extract, run uv sync, and register. --env sets a plain env var; --secret stores a value in the keyring; both repeatable. --no-enable installs without enabling. |
list | extension list [--format text|json] | List configured extensions. |
remove | extension remove <NAME> [--purge] | Remove a configured extension. --purge also deletes the installed files on disk. |
skill
Install and manage skills distributed as .zip archives.
biorouter skill <install|list|remove> [FLAGS]
| Subcommand | Synopsis | Description |
|---|---|---|
install | skill install <PATH> [--force] | Install a skill (or bundle) from a .zip. --force overwrites an existing install. |
list | skill list | List installed skills, including each slug. |
remove | skill remove <SLUG> | Remove an installed skill by its slug. |
knowledge
Manage personal, agent-maintained knowledge bases (markdown trees backed by git history). Alias: kb. Most subcommands default to the active knowledge base when --kb is omitted.
biorouter knowledge <list|active|create|ingest|ingest-conversation|lint|hide|unhide|query> [FLAGS]
| Subcommand | Synopsis and key flags | Description |
|---|---|---|
list | knowledge list [--format text|json] | List knowledge bases; the active one is marked. |
active | knowledge active [--set ID] [--clear] | Show the active KB, or set it with --set, or clear it with --clear. |
create | knowledge create <ID> [--name NAME] [--color #HEX] | Create a KB with a kebab-case id, an optional display name, and an accent color. |
ingest | knowledge ingest [--kb ID] [--url URL | --file PATH | --text TEXT] [--focus HINTS] [--provider P] [--model M] | Ingest a URL, file, or text into a KB. --focus passes optional focus hints; --provider/--model override the model used for digestion. |
ingest-conversation | knowledge ingest-conversation [--kb ID] [--session SESSION_ID]... [--new-kb NAME] [--focus HINTS] [--provider P] [--model M] | Digest chat session history into a KB. --session is repeatable and defaults to the most recent session; --new-kb creates a new KB with that display name and ingests into it. |
lint | knowledge lint [--kb ID] [--fix] [--provider P] [--model M] | Check a KB for orphans, contradictions, and stale sources. --fix lets the sub-agent repair findings. |
hide | knowledge hide <ID> | Hide a KB from the agent; it stays on disk. |
unhide | knowledge unhide <ID> | Make a hidden KB visible to the agent again. |
query | knowledge query "QUESTION" [--kb ID] [--save] [--provider P] [--model M] | Ask a question against a KB. --save persists the answer as a knowledge page. |
biorouter knowledge create ms-genetics --name "MS genetics" --color "#cf6d47"
biorouter knowledge active --set ms-genetics
biorouter knowledge ingest --url https://example.org/paper --focus "risk loci"
biorouter knowledge query "which HLA alleles raise MS risk?" --save
apps
List, open, and serve BioRouter apps (the front-ends built by Agent Drafter). open and serve reuse a biorouterd already listening on the configured port (BIOROUTER_PORT, default 3000) or start one for you, then open http://127.0.0.1:<port>/apps/<id>/. Apps render in a real browser, not in the terminal.
biorouter apps <list|open|serve> [ARGS]
| Subcommand | Synopsis | Description |
|---|---|---|
list | apps list [--json] | List installed apps. --json emits machine-readable JSON instead of a table. |
open | apps open <ID> | Open an app in your default browser. |
serve | apps serve <ID> | Serve an app in the foreground until Ctrl+C. |
mcp
Run one of the MCP servers bundled with BioRouter over stdio. MCP (Model Context Protocol) is the standard BioRouter extensions speak. This command is normally launched by a host, not typed by hand.
biorouter mcp <server>
Accepted server names: autovisualiser, computercontroller, developer, memory, tutorial.
Providers and models
models
Inspect and update provider and model configuration, and manage downloaded local models.
biorouter models <current|providers|list|set|local> [FLAGS]
| Subcommand | Synopsis | Description |
|---|---|---|
current | models current [--format text|json] | Show the configured provider and model. |
providers | models providers [--format text|json] | List available providers. |
list | models list <PROVIDER> [--format text|json] | List known models for a provider (for example openai, anthropic, ollama, databricks). |
set | models set --provider P --model M | Set the default provider and model. |
local | models local <list|pull|rm> | Manage on-disk local models (Llama Server). See below. |
models local subcommand | Synopsis | Description |
|---|---|---|
list (alias ls) | models local list [--format text|json] | List the local model catalog and what is already downloaded. |
pull | models local pull <MODEL> | Download (pre-cache) a model without starting a chat. Accepts a catalog name (for example qwen3.5-4b) or a raw owner/repo:QUANT Hugging Face spec. |
rm (alias delete) | models local rm <MODEL> | Delete a downloaded model to reclaim disk space. |
biorouter models current
biorouter models list ollama --format json
biorouter models set --provider openai --model gpt-5.5
biorouter models local pull qwen3.5-4b
configure
Interactively configure BioRouter: providers, API keys, extensions, and permission settings. With no configuration file present, running biorouter with no subcommand launches first-time setup, which is the same flow.
biorouter configure
Diagnostics and information
info
Print BioRouter's version and key paths: the config directory, config.yaml, the sessions SQLite database, and the logs directory. Each path is annotated when missing (and whether it can be created).
biorouter info [-v]
| Flag | Description |
|---|---|
-v, --verbose | Also print the resolved configuration (the config.yaml values) as YAML. |
doctor
Check system prerequisites and the CLI install. It reports installed dependencies (git, uv, node, and others) with versions, whether biorouter is on your PATH, the local-model (Llama Server) sidecar status and model cache location, the shell-sandbox enforcement tier, and (unless skipped) whether a newer release is available.
biorouter doctor [--format text|json] [--no-update]
| Flag | Type | Default | Description |
|---|---|---|---|
--format <FMT> | text or json | text | Human-readable report or machine-readable JSON. |
--no-update | flag | off | Skip the networked self-update check (faster, offline-friendly). |
setup-path
Install the biorouter command onto your PATH by symlinking the running executable into a standard bin directory, so you can call it from any terminal. If the target directory is not on your PATH, it prints the exact export PATH=... line to add. Alias: install-cli.
biorouter setup-path
usage
Report token and cost usage per day or per model, with a month-to-date summary against your configured monthly budget.
biorouter usage [--from YYYY-MM-DD] [--to YYYY-MM-DD] [--by-model] [--json]
| Flag | Type | Default | Description |
|---|---|---|---|
--from <YYYY-MM-DD> | date | 30 days ago | Start of the range (local time). |
--to <YYYY-MM-DD> | date | today | End of the range (local, inclusive). |
--by-model | flag | off (by day) | Group usage by model instead of by day. |
--json | flag | off | Emit machine-readable JSON instead of a table. |
biorouter usage --from 2026-07-01 --to 2026-07-20 --by-model
biorouter usage --json
Project management
project
Resume work on your most recently accessed project directory, or start a new session in the current directory when there is no history. Alias: p.
biorouter project
projects
Choose from your recent project directories interactively. Alias: ps.
biorouter projects
Terminal integration
Terminal integration ties a persistent BioRouter session to each terminal window and lets you ask questions from your shell prompt with recent command history as context. Set it up once, then use the @biorouter and @g aliases.
term
biorouter term <init|run|info> [ARGS]
| Subcommand | Synopsis | Description |
|---|---|---|
init | term init <bash|zsh|fish|powershell> [-n NAME] [--default] | Print the shell initialization script. It exports BIOROUTER_SESSION_ID, defines the @biorouter and @g aliases, and installs a preexec hook that logs your commands into the session. -n/--name names the terminal session; --default makes BioRouter the handler for unknown commands (zsh and bash only). |
run | term run <prompt words...> | Send a prompt to this terminal's session, with the recent shell history included as context. Words do not need quoting. |
info | term info | Print compact session info (a context-usage meter and the model name) for shell-prompt integration, for example ●○○○○ sonnet. |
Add the init line to your shell profile
For zsh: echo 'eval "$(biorouter term init zsh)"' >> ~/.zshrc. Add --default if you want anything that is not a valid command sent to BioRouter.
Reload the shell
source ~/.zshrc (or open a new terminal). Each terminal now keeps its own session that resumes automatically.
Ask from the prompt
Use the aliases created by the init script.
@biorouter and @g
These aliases both call biorouter term run, so your recent commands are in context.
@biorouter create a python script to process these files
@biorouter create a PR description summarizing these changes
@g how do I fix these permission denied errors?
biorouter term log subcommand. The shell hook calls it to record each command into the terminal session; you do not run it directly.Server and headless
web
Start BioRouter Web: a lightweight, browser-based chat interface launched from the CLI that mirrors the desktop chat experience. It is useful when you want a GUI without installing the desktop app, or need access from another device.
biorouter web [-p PORT] [--host HOST] [--open] [--auth-token TOKEN] [--no-auth]
| Flag | Type | Default | Description |
|---|---|---|---|
-p, --port <PORT> | integer | 3000 | Port to run the web server on. |
--host <HOST> | string | 127.0.0.1 | Address to bind. Use a LAN address to reach it from other devices. |
--open | flag | off | Open the browser automatically when the server starts. |
--auth-token <TOKEN> | string | none | Require this token (as a password or bearer token) to access the interface. |
--no-auth | flag | off | Allow running without auth even when bound to a network address. Unsafe; use only on trusted networks. |
# Local web UI, open the browser
biorouter web --open
# Reachable on the LAN, password-protected
biorouter web --host 192.168.1.7 --port 8080 --auth-token "$TOKEN"
Stop the server with Ctrl+C. Extension management, some file operations, and configuration changes still go through the CLI or a restart.
The biorouterd daemon
biorouterd is the REST plus WebSocket agent server. The desktop GUI spawns it on an ephemeral local port and talks to it over HTTP and WebSocket using a type-safe client generated from the OpenAPI spec. You rarely start it yourself, but you can run it headlessly to back a self-hosted GUI, an exported app, or automation.
# Run the agent server (foreground, graceful shutdown on SIGINT/SIGTERM)
biorouterd agent
| Variable | Default | Description |
|---|---|---|
BIOROUTER_PORT | 3000 | Port the daemon binds. This is the flat form (the Settings struct is flat); it is not BIOROUTER_SERVER__PORT. |
BIOROUTER_HOST | 127.0.0.1 | Address the daemon binds. |
BIOROUTER_SERVER__SECRET_KEY | random per run | Auth key required on requests. If unset, the daemon generates a random key for the process and logs a warning. The nested key uses the __ separator. In debug-server mode this is test. |
On start the daemon publishes its base URL as BIOROUTER_APP_BASE_URL so in-process tools can emit absolute http://host:port/apps/<id>/ links. CORS is restricted to local origins. The daemon also exposes the same bundled MCP servers via biorouterd mcp <server>.
acp
Run BioRouter as an Agent Client Protocol (ACP) agent server so ACP-compatible clients (for example Zed) can drive it. It speaks over stdio by default, or over a WebSocket with --ws. Clients normally launch and manage this process; you rarely run it by hand.
biorouter acp [--with-builtin NAMES] [--ws [ADDR]]
| Flag | Type | Default | Description |
|---|---|---|---|
--with-builtin <NAMES> | comma list | none | Enable built-in extensions by name. |
--ws [ADDR] | optional string | 127.0.0.1:11577 when the flag is given without a value | Serve ACP over a WebSocket at ADDR instead of stdio. Used for agent-enabled artifacts. |
bench
Evaluate a system configuration across a range of practical tasks. Intended for benchmarking and model evaluation.
biorouter bench <init-config|run|selectors|eval-model|exec-eval|generate-leaderboard> [FLAGS]
| Subcommand | Synopsis | Description |
|---|---|---|
init-config | bench init-config -n <FILE> | Write a starter config file. |
run | bench run -c <FILE> | Run all benchmarks from a config. |
selectors | bench selectors [-c FILE] | List all available selectors. |
eval-model | bench eval-model -c <CONFIG> | Run an evaluation of a single model. |
exec-eval | bench exec-eval -c <CONFIG> | Run a single eval. |
generate-leaderboard | bench generate-leaderboard -b <DIR> | Generate a leaderboard CSV from a benchmark results directory. |
completion
Generate a shell completion script.
biorouter completion <bash|zsh|fish|powershell|elvish> [--bin-name biorouter]
| Flag | Default | Description |
|---|---|---|
--bin-name <NAME> | biorouter | Custom binary name to embed in the completion script. |
# zsh: source the completion for the current shell
source <(biorouter completion zsh)
Running headless in a server or CI
biorouter run is the entry point for non-interactive use. Combine a few flags for clean, scriptable behavior:
- Provide the prompt with
-t "...", an instruction file (-i file), stdin (-i -), or a workflow (--workflow name.yaml --params k=v). - Add
--no-sessionso nothing is persisted, or-n nameto keep a named session for later resumption. - Use
--output-format jsonfor a single result after completion, orstream-jsonto consume events as they occur; add-q/--quietto print only the model response. - Pin the model with
--providerand--modelrather than relying on ambient config. - Bound the run with
--max-turnsand--max-tool-repetitionsso an automated job cannot loop indefinitely.
# Non-interactive, isolated data dir, JSON out, bounded turns
BIOROUTER_PATH_ROOT="$(mktemp -d)" \
biorouter run --no-session \
--provider anthropic --model claude-sonnet-4-6 \
--output-format json --max-turns 10 \
-t "validate config.yaml and report problems"
Headless Linux servers
On a headless Linux host with no desktop keyring, BioRouter automatically falls back to a plaintext secrets.yaml for credentials; you can force this anywhere by setting BIOROUTER_DISABLE_KEYRING. Set BIOROUTER_PATH_ROOT to isolate config, data, and state per environment (handy for CI). The bundled local-model server (Llama Server) needs glibc 2.35 or newer plus libssl3 and libgomp1, so Debian 12 / Ubuntu 22.04 or newer.
Environment variables the CLI honors
Environment variables override the config file for a single invocation. This is the CLI-relevant subset; the full reference lives on the environment variables page.
| Variable | Purpose | Default |
|---|---|---|
BIOROUTER_PROVIDER | LLM provider to use. | must be configured |
BIOROUTER_MODEL | Model to use from the provider. | must be configured |
BIOROUTER_MODE | Permission mode for tool execution: auto, approve, chat, smart_approve. | auto |
BIOROUTER_MAX_TURNS | Turn limit without user input (the env form of --max-turns). | 1000 |
BIOROUTER_CONTEXT_STRATEGY | How to handle a full context window: summarize, truncate, clear, prompt. | prompt interactive, summarize headless |
BIOROUTER_AUTO_COMPACT_THRESHOLD | Fraction of the context window at which the session auto-compacts (0.0 disables). | 0.8 |
BIOROUTER_CLI_THEME | CLI markdown theme: light, dark, ansi. | dark |
BIOROUTER_CLI_SHOW_COST | Show per-response cost estimates in CLI output. | off |
BIOROUTER_DEBUG | Show full tool parameters without truncation (the env form of --debug). | off |
BIOROUTER_DISABLE_KEYRING | Store secrets in plaintext secrets.yaml instead of the OS keyring (set to any value). | unset (keyring on) |
BIOROUTER_WORKFLOW_PATH | Extra directories to search for workflows (path-separated). | none |
BIOROUTER_WORKFLOW_GITHUB_REPO | GitHub owner/repo to resolve workflow names from. | none |
BIOROUTER_PATH_ROOT | Override the root for all config, data, and state (isolate environments). | platform default |
BIOROUTER_SESSION_ID | Set by term init to bind a terminal to one session; read by term run/log/info. | unset |
BIOROUTER_TERMINAL | Set to 1 automatically while BioRouter runs a shell command, so your shell profile can adjust behavior. | unset |
ALPHA_FEATURES | Enable experimental alpha features. | off |
For the daemon-specific variables (BIOROUTER_PORT, BIOROUTER_HOST, BIOROUTER_SERVER__SECRET_KEY), see the daemon section above.
Providers and models
BioRouter connects local, institution-hosted, and commercial models through one interface, so you can match each task to the right trust boundary and switch whenever you want. Providers are grouped into three tiers. Local ranks first everywhere (onboarding, the Settings grid, and biorouter configure) because nothing leaves your machine.
The in-app model picker is the source of truth
Model lineups change constantly, so BioRouter does not ship a fixed per-model list. It reads each provider's live catalog and shows it in Settings → Models (and via biorouter models list <provider>). Trust the picker for the exact models available to you today.
Local: zero setup
Keeping data on your own machine is the strongest privacy guarantee, and BioRouter makes it the easy path. Two providers run locally.
- Llama Server (
llamacpp) is the bundled, zero-setup option and the first card a new user sees. The desktop app ships a pinned llama.cppllama-serverbinary and manages it as a sidecar process, so you can run capable local models without installing anything else. Pick it, choose a model, and BioRouter downloads the GGUF weights from Hugging Face on first use and starts the server for you. No API key; nothing leaves the device after the one-time download. - Ollama (
ollama) connects to an Ollama install you already run. Pull any model and select it; everything stays on your machine.
Institutional: UCSF-hosted
UCSF-managed endpoints keep prompts and completions inside UCSF's own cloud tenant, which is what makes them appropriate for institution-approved, sensitive work.
- Versa API Azure (
versa_azure) serves the UCSF ChatGPT models (OpenAI models inside UCSF's Azure tenant). - Versa API Bedrock (
versa_bedrock) serves the UCSF-hosted Anthropic models through Amazon Bedrock.
Commercial cloud
Direct API access to hosted providers. Paste an API key (or complete the provider's sign-in flow) and BioRouter reads that provider's live model catalog. The shipping commercial providers are:
| Provider | Notes |
|---|---|
| Anthropic | Direct access to Claude models. |
| OpenAI | Direct access to GPT and o-series models. |
| Google Gemini | Direct access to Gemini models. |
| GCP Vertex AI | Google and Anthropic models through Google Cloud (service-account or application-default credentials). |
| Azure OpenAI | OpenAI models on Azure; works with the Azure credential chain and single sign-on. |
| Amazon Bedrock | Anthropic and other models on AWS (AWS credential chain, including SSO profiles). |
| Databricks | Claude, Llama, and DBRX models through Databricks (supports OAuth). |
| Snowflake Cortex | Claude and other models through Snowflake Cortex. |
| OpenRouter | A single API that fans out to many upstream providers. |
| LiteLLM | A proxy or gateway that unifies many backends behind an OpenAI-compatible interface. |
| Venice AI | A privacy-focused inference provider (Llama and Mistral families). |
| GitHub Copilot | GPT, Claude, Gemini, and Grok models through Copilot (device-code OAuth, no API key). |
| X.AI (Grok) | Direct access to Grok models from xAI. |
| z.ai (GLM) | The GLM model family on an OpenAI-compatible surface. |
| Xiaomi MiMo | Xiaomi's MiMo models, with regional endpoints. |
| Tetrate Agent Router | A routing service across upstream models (the quickstart path). |
| AWS SageMaker TGI | Models you deploy on SageMaker endpoints using Text Generation Inference. |
| Custom (OpenAI-compatible) | Any OpenAI-compatible endpoint, added through the "Add Custom Provider" card (display name, base URL, key variable, models, streaming). |
Adding a provider
Providers are managed in Settings → Models. Each card shows its status (configured or not), a Configure button to enter an API key or credentials, and a Launch button to switch to that provider and choose a model. Paste your key, pick a model from the live catalog, and you are ready. Keys are written to your operating system's credential store, not to any config file. From the terminal, run biorouter configure and select "Configure Providers".
Switching per session or per workflow
Your default provider and model apply until you change them, but you can override the choice without touching that default:
- Per session. Start a session with
biorouter session --provider <name> --model <id>, or switch in the desktop app from the model selector. - Per workflow. A workflow can set
settings.biorouter_providerandsettings.biorouter_modelso it always runs on a specific model, whatever your default is. - Lead and worker routing. A lead model can orchestrate a task and delegate sub-tasks to worker models, which may be on different providers.
Extensions and skills
BioRouter connects to databases, APIs, file systems, and services through pluggable parts instead of built-in special cases. Extensions add tools the agent can call over the Model Context Protocol (MCP); skills teach the agent repeatable methods for using those tools; and the BAAM marketplace one-click-installs both. Add a capability once and it works in every session. This section covers biorouter 1.88.3.
What an MCP extension is
An extension is an MCP server that BioRouter connects to. Because MCP is an open standard, any server anyone writes can become a BioRouter extension. An MCP server can expose three kinds of thing:
- Tools the agent can call (run a query, edit a file, fetch a URL).
- Resources the agent can read (files, records, data sources the server makes available).
- Prompts the server offers as ready-made starting points.
BioRouter scans every extension for known malware before it starts. Enable or disable any extension from Settings → Extensions in the desktop app, or with biorouter configure in the terminal.
Built-in extensions
These ship inside BioRouter, so nothing needs to be installed. The default-on set is the working toolkit most sessions use; the opt-in set is there when a task calls for it.
| Extension | Default | What it does | Key tools |
|---|---|---|---|
| Developer | On | The core agent toolkit: file operations, shell commands, code search and text editing. Its shell and text_editor tools run with your user privileges, so it carries the most security guidance of any extension. | shell, text_editor, analyze, screen_capture, image_processor |
| Extension Manager | On | Lets the agent discover, enable, and disable other extensions mid-session, keeping the active tool count small. It runs a malware check before it enables an extension that launches a package runner. | search_available_extensions, manage_extensions, list_resources, read_resource |
| Skills | On | Discovers skills on disk at startup and loads the relevant ones into the agent's context (see Skills below). | Loads SKILL.md instruction sets from the skill directories |
| Todo | On | Breaks multi-step work into a tracked checklist and reports progress as the agent goes, so you can see where it is rather than waiting for one opaque answer. | todo_write, todo_add, todo_update, plan_write |
| Knowledge | On | Ingest, query, and lint your personal, LLM-maintained knowledge bases from inside any chat. Bases are markdown pages backed by git history. | ingest, query, lint, plus page, search, and graph reads |
| Memory | Off | Teaches the agent durable facts and preferences (commands, lab conventions, configurations) that ride along in every prompt, in a project-local or user-global scope. | remember_memory, retrieve_memories, remove_memory_category, remove_specific_memory |
| Auto Visualiser | Off | Turns structured data into self-contained interactive HTML figures rendered inline in chat. It registers 34 tools (charts, scientific plots, diagrams, maps, and a composite report) and picks the right one automatically. | render_dashboard and 33 other render_* / show_chart tools |
| Computer Controller | Off | Automates your real desktop: launches apps, clicks and types, changes system settings, scrapes the web, and reads or writes Office documents. The highest-blast-radius built-in, because it acts on your actual machine. | computer_control, automation_script, web_scrape, xlsx_tool, docx_tool, pdf_tool, cache |
| Tutorial | Off | Loads interactive, step-by-step walkthroughs of BioRouter features and guides you a step at a time. Seven tutorials ship, from getting started to building an MCP extension. | load_tutorial |
| Chat Recall | Off | Searches your past session history by keyword or session ID so the agent can pull earlier context into the current conversation. Search runs entirely against local session history; nothing is sent to a remote service. | chatrecall (search mode or load mode) |
| Code Execution | On | Backs Code Mode: instead of calling tools one at a time, the model writes one short JavaScript program that batches many tool calls into a single execution, using the context window more efficiently. | execute_code, search_modules, read_module |
| Agent Drafter | On | Builds BioRouter apps: TypeScript front-ends wired to a live per-app agent, and exports them as standalone, directly runnable projects (see below). | create_app, configure_app, build_app, export_app, plus the ui_* tools |
shell, text_editor) and Computer Controller (computer_control) can run any command and change your machine. In the default Autonomous mode BioRouter does this without asking. Switch to Smart Approval or Manual Approval, set per-tool permissions, and use a .biorouterignore file to constrain them for sensitive work.
Adding an extension
Any MCP-compatible server can be added as an extension. There are two routes, both of which write to the same configuration.
From the BAAM marketplace
BAAM is BioRouter's agent, extension, and skill marketplace, served from the public site and browsable at the BAAM page. Its catalog is a machine-readable registry the app reads to list and install items. For a curated extension this is the shortest path: download the .brxt bundle and drag it into Extensions → Add Extension. BioRouter installs the environment, configures the tool, and adds it to your session, with no terminal needed.
Adding a custom extension
For anything not in the catalog, open Settings → Extensions → Add custom extension and pick the transport. A local command server (stdio) is the common case; a remote server uses streamable_http.
Command / stdio server
BioRouter launches a local process (typically a uvx or npx MCP server) and talks to it over standard I/O. You provide: the type (stdio), an id and display name, the command, its arguments, any environment variables (such as an API token), and an optional timeout.
extensions:
github:
name: GitHub
cmd: npx
args: ["-y", "@modelcontextprotocol/server-github"]
type: stdio
enabled: true
timeout: 300
envs:
GITHUB_PERSONAL_ACCESS_TOKEN: "<your_token>"
Remote / streamable_http server
For a server that already runs somewhere and is reached over a URL, you provide the type (streamable_http), an id and name, the URL, and an optional timeout. No local process is launched.
extensions:
my-remote-agent:
name: My Remote Agent
url: https://my-mcp-server.example.com/mcp
type: streamable_http
enabled: true
timeout: 300
The same entries can be declared directly under extensions: in ~/.config/biorouter/config.yaml, or added for a single session from the CLI:
biorouter session --with-extension "TOKEN=<t> npx -y @modelcontextprotocol/server-github" biorouter session --with-streamable-http-extension "https://my-mcp-server.example.com/mcp"
Enabling and disabling mid-session
You can turn extensions on and off during a running session without restarting. Toggle any extension by hand from Settings → Extensions, or let the agent manage them: the Extension Manager recognizes when a task needs a specific extension, enables it, and suggests disabling unused ones when the tool count starts eating your context window. An extension the agent enables this way is active for that session only; to persist it, enable it through Settings or the config file.
Extension agents in the marketplace
BAAM features a set of extension agents that connect BioRouter to specialized data and services. Each installs as a .brxt bundle. Several are UCSF connectors that need institutional credentials.
| Agent | What it connects | Credentials |
|---|---|---|
| SPOKEAgent | Cypher queries on the SPOKE biomedical knowledge graph (diseases, genes, proteins, drugs, pathways). | SPOKEAGENT_PASSCODE from the UCSF wiki credentials page. |
| UCSFOMOPAgent | Natural-language SQL over the UCSF OMOP de-identified clinical database (read-only). | UCSF credentials. |
| CDWAgent | Multimodal access to the UCSF Clinical Data Warehouse: cohorts, labs, imaging, notes and NLP (read-only). | UCSF network credentials (CAMPUS\username). |
| PlaywrightAgent | Browser automation: navigate pages, extract content, and fill forms. No vision model needed. | None. Requires Node.js. |
| CodeGraphAgent | A pre-indexed code knowledge graph across 23 languages ("who calls X?", "what breaks if I change Z?"). | None. |
| BiorOffice | Create, read, and edit Word, Excel, and PowerPoint files from chat. | None. No Microsoft Office install needed. |
Skills
A skill is a reusable instruction set: a folder containing a SKILL.md file with YAML frontmatter (name, description) followed by freeform instructions that teach the agent to do one thing the same way every time. Unlike extensions, which add tools, skills add procedural knowledge: checklists, deployment procedures, analysis conventions, and API guides. A skill folder may also carry helper scripts and templates the agent reads while it runs.
Skills work two ways:
- Auto-applied. At session start BioRouter discovers every available skill and loads a relevant one when your request clearly matches its purpose, without you naming it.
- User-invocable. Name a skill to run it deliberately, for example
/code-review, or in plain language ("use the code-review skill on this PR"). Ask "what skills are available?" to see the loaded list.
A skill's identity comes from the name in its frontmatter, not from its directory name, so a folder named run-gwas/ that declares name: gwas-pipeline is known to BioRouter as gwas-pipeline. When two skills share a name, the more specific location wins.
Installing and combining skills
Install a skill by dragging its .zip onto Skills → Add Skill in the app, with biorouter skill install ./bundle.zip, or in one click from BAAM. Around 85 skills are published through the marketplace, grouped into core, developer, and biomedical categories (single-cell, variant calling, differential expression, pathway analysis, clinical biostatistics, and more). BioRouter-specific global skills live under ~/.config/biorouter/skills/; project-level skills live under ./.biorouter/skills/, and portable locations shared with other AI agents (~/.config/agents/skills/, .agents/skills/) are also read. Skill folders are plain text, so a lab can share them to standardize analysis style without sharing any data. Because skills are just instructions, the agent can apply several at once in a single task, for example a scripting skill together with a visualization skill.
Apps and Agent Drafter
The Agent Drafter built-in extension builds BioRouter apps: each a TypeScript front-end (an index.html plus src/main.ts) wired to its own per-app BioRouter agent over a WebSocket. The distinguishing point is that the agent drives the interface rather than only answering inside it. It renders panels, charts, and graphs into the page, highlights regions, switches themes, and asks the user questions, all through typed ui_* tools whose command frames the app's runtime applies to the DOM. Because ui_ask blocks the tool call until the browser replies, the agent can branch on the user's answer within a single turn. Reach for an app when a workflow needs a richer surface than a transcript: a cohort reviewer, a calculator, a knowledge-map explorer, a data dashboard, or a lab-specific tool.
The Apps SDK v2
Every app imports a small client runtime and talks to its agent over one WebSocket. The SDK provides:
| Piece | What it provides |
|---|---|
br.* client runtime | Prompt, stream, cancel, subscribe to lifecycle events, and read context usage. br.model lists providers and live-switches the session model; br.kb reads and ingests into granted knowledge bases; br.state exposes the shared document; br.agent(name) reaches a worker profile. |
| Component catalog | Agent-driven UI primitives (panels, charts, graphs, tables, highlights, notifications) that the SDK applies to the page. Authors expose render targets with a region attribute such as <section data-br-region="results">, which the agent finds with ui_describe and writes to. |
| Shared reactive state document | One state document the app and agent both read and write (br.state), so the UI stays consistent across turns and across reconnects. |
| Capability-gated security | UI control is on by default, because its blast radius is the app's own page. files, data, compute, and the vault capability (encrypted credentials) are deny-by-default and granted explicitly, per app. |
| Theme packs | An app inherits BioRouter's look, and the agent can restyle it within allowed bounds using theme packs, accents, and custom tokens. |
| Multi-agent worker profiles | An app can declare named worker profiles, each a full alternate agent config (its own model, prompt, extensions, and KB) validated to be a capability subset of the app. The main agent consults them for self-contained sub-questions. |
Building and exporting an app
Agent Drafter exposes tools for the whole lifecycle. create_app scaffolds a project (a working starter archetype plus a manifest); configure_app and update_app set the persona, model, capabilities, and edit the source; build_app bundles src/main.ts with esbuild, refreshes the vendored SDK, and runs its lint checks; and export_app writes a standalone folder.
Exported apps are directly runnable, with no Node required
export_app writes a self-contained project that runs without a build step: a manifest.json, the bundled front-end, launch scripts (run.sh / run.command / biorouter-launch.sh), and a small loopback server that proxies to a local biorouterd daemon. The launcher locates or installs the daemon, starts it headlessly, verifies the app responds, and opens it. Exported apps carry no API keys; they inherit the credentials of whoever runs them.
Knowledge bases
A knowledge base is a personal, LLM-maintained wiki: a folder of markdown pages backed by a full git history, all on your own machine. You do not hand-edit it. You add sources (a file, a URL, or pasted text) and Biorouter converts each one to markdown, has a bounded sub-agent digest it into cross-linked pages, grades the source's credibility, and commits the change. Because a base is plain markdown under git, everything about it stays local, readable, diffable, and reversible. This section covers the whole feature, then Sol, the one knowledge base Biorouter ships and grows for you automatically. Documented for Biorouter 1.88.3.
What a knowledge base is
Each knowledge base is one directory and one git repository, stored under ~/.config/biorouter/knowledge/<kb-id>/. Inside it, the raw sources you added and the pages the agent wrote are kept separate, so you can always re-derive a page from its original:
| Path | What it holds |
|---|---|
raw/<source-id>/ | Each ingested source, untouched: the original file, the markdown Biorouter converted it to (source.md), and a meta.yaml with its title, URL, checksum, and credibility grade. |
knowledge/ | The pages the sub-agent writes: entities/ (people, tools, datasets), concepts/ (methods, ideas), sources/ (one page per source), notes/ (observations and saved answers), and cross-cutting hub pages at the root. |
index.md | An agent-maintained catalog of the pages in the base. |
log.md | A human-readable change log that mirrors the git history. |
schema.md | Per-base instructions that tell the agent how to maintain this base. You can edit it. |
.git/ | The hidden git repository. Every ingest, link, and edit is a commit. Git is statically built into Biorouter, so no system git is required. |
Creating a knowledge base
In the desktop app, open the Knowledge route in the sidebar (between Skills and Settings). The knowledge-base selector at the top opens a Cmd-K / Ctrl-K style palette where you name a new base and pick its color. From the terminal:
biorouter knowledge create my-kb --name "My KB"
Either way, Biorouter writes the directory, initializes the git repo, seeds a default schema.md, and registers the base so it appears in the selector and in chat.
The active knowledge base
One base at a time is the active base for a chat session. The active id is remembered per session and persisted at ~/.config/biorouter/knowledge/.active-kb, so the base you are working in travels with the conversation. In chat, a small KB chip sits in the composer next to the model selector; click it to open the same palette and switch bases. When a knowledge tool is called without an explicit base id, it acts on the active base.
Biorouter uses a hide-from-the-agent model rather than an opt-in one: every base is visible to the chat agent unless you hide it, and the agent may consult a visible base on any turn. Hiding a base keeps it out of the default cross-base search but you (or the agent) can still reach it by naming its id.
Ingesting sources
Ingesting is how material gets into a base. The Knowledge route has an Ingest sources panel with three ways to stage a source, and the same three are available from the CLI and to the chat agent:
- Drag and drop files onto the dropzone (or use Browse). Each file is added to a staged list.
- Paste text. Paste notes or an excerpt. Biorouter scans the text for
http(s)URLs and offers to fetch and convert each linked page as its own source; you can toggle any link off before staging. - Add a URL. Biorouter downloads the page and runs it through the same converter as a dropped file.
Supported formats for the deterministic converter: PDF, DOCX, HTML, CSV, Markdown, and plain text. Spreadsheets (.xlsx, .xls, .ods) and PowerPoint (.pptx, including speaker notes) also ingest. Conversion is one-shot and immutable, so its quality bounds everything downstream: whatever a converter drops (multi-column reading order, a table, a slide note) the digest step never sees. On the roadmap: a vision-model fallback for scanned, image-only PDFs (today they surface a quality warning rather than ingesting as empty), an optional higher-fidelity PDF sidecar, and long-tail formats such as EPUB, RTF, and plain figure images.
How the digest sub-agent works
Once a source is converted, Biorouter runs a bounded digest sub-agent. It is a small agent loop (capped at roughly 30 steps and a few minutes) that can only touch the knowledge base, and it is steered by the base's schema.md. Reading only the converted source.md, it writes a page for the source, creates or updates the entity and concept pages the source touches, and connects related pages with [[knowledge-link]] cross-references. Those wiki-links are exactly what the graph is built from, so a base whose pages carry no [[…]] references produces a graph with nodes but no edges.
Everything the sub-agent does for one source lands as one atomic git commit: it writes to a working branch and commits the whole set of page changes together (or aborts and leaves nothing behind), so the base is never half-updated. Progress streams live to the UI over server-sent events, so you watch pages and graph nodes appear as digestion runs.
The graph and credibility colors
The Knowledge route renders the base as a force-directed graph: each page is a node, each [[…]] reference is an edge. Hub pages are drawn larger and labeled. Node color encodes the page kind, and source nodes are colored by how credible their source is, so a glance separates well-supported material from anecdote:
| Node | Meaning | Color |
|---|---|---|
| Hub | A cross-cutting page at the root of the base, high in the graph's connectivity. | Gold |
| Entity | A person, tool, dataset, or other named thing. | Blue |
| Concept | A method, idea, or approach. | Green |
| Note | An ad-hoc observation or a saved query answer. | Grey |
| Flag | A page the agent marked as a contradiction to resolve. | Red |
Source nodes take their color from a credibility ladder. Biorouter grades each source deterministically before it ever calls a model: it pulls any DOI, arXiv id, ISBN, or PMID from the source, looks it up in Crossref and then OpenAlex, and falls back to host patterns (preprint servers, .gov, .edu, and the like). Only if all of that is inconclusive does a small bounded classifier weigh in.
| Tier | How it is detected | Color |
|---|---|---|
| Peer reviewed | DOI resolves to a journal article from a known publisher. | Deep blue |
| Book | ISBN present, or Crossref reports a book or book chapter. | Blue |
| Preprint | Host is a preprint server (arXiv, bioRxiv, medRxiv, etc.). | Light blue |
| Gray literature | Host matches .gov, .edu, WHO, CDC, NIH, FDA, ClinicalTrials.gov. | Pale blue |
| Web source | Any other web page. | Warm orange |
| Personal source | A local file, pasted text, or a source with no detectable provenance. | Mauve |
Retraction is a separate flag: when Crossref or OpenAlex report a source as retracted, its node carries a red badge regardless of tier. You can override any grade by hand. The graph's legend shows Entity, Concept, Hub, Peer reviewed, Web source, and Personal source so the coloring is readable in place.
Search, history, and portability
- BM25 search. Every base is indexed for BM25 keyword search across its written pages and the raw
source.mdfiles, so the agent (and the query macro) can find the right pages fast without re-reading everything. - Change log and git history. The base's history is a git log; each commit is tagged by kind (
ingest,link,flag,query,lint,restore). The change-log drawer lists these entries, andlog.mdmirrors them in plain prose. - Restoring a previous version. Pick a past commit to preview the base as it was at that point, then restore it. Restore is a new revert-style commit on top of the current state, not a destructive rewind, so the restore is itself logged and can be undone.
- Export and import a
.brkbarchive. A.brkbfile is a zip of the entire base directory, including the.githistory and the original source files. Export from the base header (Export as .brkb) to move a base between machines or hand it to a colleague; import unpacks it as a new base with a fresh id so it never collides with an existing one.
The macros
Three higher-level operations each run their own bounded sub-agent loop:
- Ingest is the digest described above: add a source, classify it, write and link pages, commit as one change.
- Query searches the base and writes a cited answer. Optionally it files the answer back into the base as a new note page and commits it, so the base learns from your questions.
- Lint is a hygiene pass that finds orphan pages, contradictions, and stale claims. It returns a report, and with autofix enabled the sub-agent repairs what it can.
All three are available in the app and from the CLI:
biorouter knowledge ingest --kb my-kb --file ./report.pdf
biorouter knowledge ingest --kb my-kb --url https://example.com/paper
biorouter knowledge query "what does the cohort show?" --kb my-kb --save
biorouter knowledge lint --kb my-kb --fix
Sol: the Soul knowledge base
Sol, the built-in knowledge base named Soul (kb_id soul), is the one base Biorouter creates and maintains for you. It is installed the first time you run Biorouter and starts empty. Its job is to accumulate durable, high-signal facts about you: how you frame scientific questions, which tools and commands you reach for, the tool responses you act on, and personal details you reveal such as your name, role, and stated preferences. Over time it becomes the agent's memory of your work, which it consults to personalize answers.
Soul grows on its own through a built-in scheduled job called Daily Meditation. Every day at 3:00 AM, that job runs the built-in Meditation workflow, which uses the update-soul skill to review your recent real chat sessions and digest what matters about you into the Soul base (it skips its own scheduled-job sessions, and greetings and one-off chatter). Because the workflow focuses on the Soul base and runs headless, you do not have to do anything for Soul to keep up with your work. See the scheduler section below for how that job is registered.
- Where it lives:
~/.config/biorouter/knowledge/soul, the same layout as any other base, in a warm parchment color that sets it apart in the selector. - How to view it: open the Knowledge route and select Soul in the base selector to browse its pages, graph, and change log. In chat, search it directly with
kb_searchusingkb_id="soul". Soul may be hidden from the default cross-base search, so name its id explicitly when you want personal context. - How to reset it: resetting Knowledge removes every base and recreates a single empty Soul, so you can clear what the agent has learned and start over. Because a reset is destructive, it is a deliberate action, not something the chat agent can do on its own.
Sol is one specific knowledge base. Everything in the rest of this section (creating a base, ingesting, the graph, the macros) applies to it exactly as it does to any base you make yourself.
Step by step
Create a knowledge base and ingest your first source
Open the Knowledge route in the sidebar. Use the base selector's Cmd-K palette to create a base and give it a name. In the Ingest sources panel, drag a PDF onto the dropzone (or paste text, or add a URL), then click Digest Staged Sources. Watch the streamed progress as the sub-agent converts the source, writes its pages, and links them; when it finishes, the new nodes appear in the graph and a new entry lands in the change log. From the terminal the same flow is biorouter knowledge create my-kb --name "My KB" followed by biorouter knowledge ingest --kb my-kb --file ./report.pdf.
Let the agent read a knowledge base in chat
In a chat session, click the KB chip in the composer and select the base you want (for example your new base, or Soul). That base becomes the active base for the session. Now ask a question that the base can answer; the agent searches the visible bases with BM25, reads the relevant pages, and answers with citations back to them. To pull in personal context specifically, ask about your own preferences or working style and the agent consults Soul by its id. Everything the agent reads stays on your machine.
Workflows and the scheduler
A workflow is a single portable file (YAML or JSON) that bundles everything an agent needs to run a task the same way every time: the instructions, an optional starting prompt, typed parameters the user fills in, the extensions and skills to enable, the model to run on, and optional structured-output and retry rules. Save one from a chat you already ran, hand it to a colleague as a file or a link, and the scheduler can run any of them unattended on a cron schedule. Documented for Biorouter 1.88.3.
What a workflow file is
Workflows are written in YAML (recommended) or JSON. One file packages an agent's whole setup, so loading it launches a pre-configured session instead of one you assemble by hand each time. A minimal workflow needs only a title, a description, and at least one of instructions or prompt:
version: "1.0.0"
title: "Summarize Research Paper"
description: "Reads a PDF and produces a structured summary"
instructions: "You are a biomedical research assistant."
prompt: "Summarize the key findings, methods, and conclusions of the attached paper."
The schema fields
| Field | Required | What it does |
|---|---|---|
title, description | Yes | A short name and a description of what the workflow does. |
instructions | Yes* | System-level instructions that set the agent's behavior. Supports templating. |
prompt | Yes* | The first message sent automatically. Required to run headless (non-interactive). |
parameters | No | Typed values the user supplies at launch, substituted with {{ name }}. |
extensions | No | The MCP servers and other extensions the workflow needs. |
settings | No | Provider, model, and temperature overrides for this workflow. |
activities | No | Clickable prompt bubbles shown when the workflow opens in the desktop app. |
response | No | A JSON schema that forces a structured final output. |
retry | No | Automatic re-run logic with success checks. |
sub_workflows | No | Other workflow files this one can call as tools. |
version | No | The workflow format version, defaults to "1.0.0". |
*At least one of instructions or prompt must be present.
Typed parameters
Parameters make a workflow reusable. Each declares a key, an input_type, and a requirement; its value is substituted into instructions, prompt, and activities with {{ key }}. The six input types are:
| Type | Value |
|---|---|
string | Used as-is (the default type). |
number | A numeric value, validated in the desktop input. |
boolean | True or false, shown as a dropdown. |
date | A date, currently entered as text. |
file | A file path; Biorouter reads the file and substitutes its contents, not the path. |
select | A dropdown; requires an options list. |
A requirement of required must be supplied at launch, optional can be omitted when a default is set, and user_prompt prompts interactively if no value is passed. Rules enforced at load time: optional parameters must have a default, required parameters and file parameters may not have one, select parameters must list options, and every {{ name }} in the templates must match a defined parameter (with no unused definitions).
parameters:
- key: gene_name
input_type: string
requirement: required
description: "Gene symbol to analyze (e.g. BRCA1)"
- key: output_format
input_type: select
requirement: required
description: "Output format"
options: [markdown, json, csv]
prompt: "Analyze {{ gene_name }} and return results in {{ output_format }} format."
Extensions, settings, activities
extensions lists the tools the workflow needs (types include stdio, builtin, platform, streamable_http, frontend, and inline_python). If an extension names a secret in env_keys that is not already in the keyring, the CLI prompts for it at launch and stores it securely. settings overrides the provider and model (biorouter_provider, biorouter_model, temperature) for this workflow only. activities are Desktop-only clickable bubbles; an entry prefixed with message: renders as an info box, the rest send their text as a first message.
Structured output and retry
The response field enforces a final structured JSON output against a json_schema, which is what makes a workflow safe to script against: the final validated JSON is emitted as the last line of output. The retry field re-runs the workflow until success: after each run it executes shell checks (each must exit 0), and if any fail while retries remain it runs the optional on_failure cleanup, resets the message history, and starts over, up to max_retries.
Templating and inheritance
The templated fields use Jinja-style syntax. Beyond simple {{ name }} substitution, a workflow can inherit from another with {% extends "parent.yaml" %} and override named {% block %} sections, so related workflows share common structure. The indent() filter keeps multi-line values valid when passing them into a subworkflow, and the built-in {{ workflow_dir }} resolves to the folder holding the workflow file so you can reference companion files.
{% extends "base.yaml" %}
{% block prompt %}
Perform a survival analysis on the provided clinical dataset.
{% endblock %}
Saving, running, and finding workflows
Save a chat as a workflow in one click
When a session has the setup you want to keep, save it as a workflow. A saved workflow captures the instructions, activities, enabled extensions, folder context, and (optionally) the model and retry rules; it deliberately excludes your memory, API keys, and system-level settings.
In the desktop app
While in the session you want to keep, click the workflow button at the bottom of the app, review and edit the fields in the dialog, then choose Create Workflow to save it to your Workflow Library or Create & Run Workflow to save and immediately start a fresh run.
From the CLI
Inside a session, run /workflow to write workflow.yaml into the current directory, or /workflow my-name.yaml to choose the path. Validate it afterward with biorouter workflow validate my-name.yaml.
Running a workflow
In the desktop app, open a workflow from a shared link, from manual URL entry, or from the Workflow Library in the sidebar (click Use). The first time you run one, a warning dialog shows its title, description, and instructions; click Trust and Execute to continue (you are not asked again unless it changes). If it has parameters, fill in the Workflow Parameters dialog, then click an activity bubble or send the prompt. From the CLI:
biorouter run --workflow workflow.yaml
biorouter run --workflow workflow.yaml --params gene_name=BRCA1
biorouter run --workflow workflow.yaml --interactive # prompt for required values
biorouter workflow validate workflow.yaml # check it loads correctly
biorouter workflow open workflow.yaml # open it in the desktop app
Where workflows are discovered
Biorouter looks for workflow files in several places, in order:
| Source | Location |
|---|---|
| Current directory | The folder you run from (*.yaml and *.json). |
| Custom paths | Directories listed in BIOROUTER_WORKFLOW_PATH. |
| Global library | ~/.config/biorouter/workflows/, available to every project. |
| Project-local | ./.biorouter/workflows/, scoped to that project. |
| GitHub repository | A repo set in BIOROUTER_WORKFLOW_GITHUB_REPO (needs the gh CLI installed and authenticated); run by name, for example biorouter run --workflow code-review. |
List everything Biorouter can find with biorouter workflow list (add --verbose or --format json). The Desktop Workflow Library shows only workflows you explicitly saved or imported, not files discovered on disk.
Sharing by file or link
Share a workflow two ways. As a file: send the .yaml or .json; the recipient runs it with biorouter run --workflow or imports it in the desktop app. As a link: copy the deeplink from the Workflow Library, or generate one with biorouter workflow deeplink <file> (optionally pre-filling parameters with --param key=value). Clicking a link opens Biorouter Desktop with the workflow loaded. Each recipient gets their own private session; nothing is shared back to you, and they supply their own credentials.
Subworkflows
A workflow can delegate parts of a task to other workflow files listed under sub_workflows. Biorouter turns each into a tool the main workflow can call; the subworkflow runs in an isolated session with its own context and returns its output to the caller. Pass fixed inputs with values (these take precedence and cannot be overridden), or let the agent infer a subworkflow's parameters from the conversation, including results from an earlier subworkflow. Subworkflows cannot nest (a subworkflow may not define its own), and this feature is experimental and may change.
The scheduler
Biorouter has a built-in cron scheduler that runs workflow files on a recurring schedule with no one present. Scheduled jobs are stored in an SQLite database, so they survive restarts, and they run headless: the workflow executes in the background with no chat window, and its results are saved to your session history. A job keeps firing as long as the Biorouter background process is running, so a schedule runs unattended even when the chat app itself is closed (a foreground job with no window available falls back to a background run).
Create a schedule in the desktop app from the Scheduler view or the Workflow Library (pick the workflow, set a frequency or a cron expression, optionally fill parameters, save), or from the CLI. Jobs use standard cron syntax; Biorouter accepts 5-, 6-, or 7-field expressions for extra precision.
# every day at 9:00 AM
biorouter schedule add --schedule-id daily-report \
--cron "0 0 9 * * *" --workflow-source ./workflows/daily-report.yaml
biorouter schedule list
biorouter schedule delete <job-id>
Because a scheduled run cannot stop to ask you anything, its workflow must include a prompt (the message that starts it), avoid user_prompt parameters, and pre-fill every required parameter either in the file's defaults or in the schedule. The provider's API key and any extensions the workflow uses must be available in the environment the background process runs in.
The built-in Daily Meditation job
Biorouter ships one schedule already registered: Daily Meditation, which runs the built-in Meditation workflow every day at 3:00 AM (cron 0 0 3 * * *). It digests your recent sessions into the Soul knowledge base described in the section above, so the agent's memory of your work stays current without any action from you. It shows up in the Scheduler view marked Built-in, and you can pause, edit, or run it on demand like any other job. The workflow and schedule are installed idempotently on startup, so they are recreated if missing but never duplicated or made to overwrite your edits.
Schedule a workflow to run nightly
Prepare a headless-safe workflow
Make sure the workflow you want to schedule has a prompt and no parameters that need interactive input. For example, a report workflow whose prompt is "Run the differential expression pipeline on today's data and save the results," with the provider and model set in settings.
Register the schedule
In the desktop app, open the Scheduler view, click Create Schedule, choose the workflow as the source, and set it to run nightly (the time picker converts to a cron expression). Or from the CLI, run biorouter schedule add --schedule-id nightly-report --cron "0 0 2 * * *" --workflow-source ./workflows/report.yaml to run it every night at 2:00 AM.
Check on it
The Scheduler view lists each job with its next run time and last run status, and controls to pause, resume, edit, delete, or run it now. Each run's output is captured in your session history, so you can open or restore any run the schedule produced. A failed run is recorded and re-attempted at the next scheduled time.
Agentic loop and orchestration
When you send BioRouter a request, it does not answer in a single step. It runs a loop: it gathers the context the model needs, asks the model what to do, runs any tool the model asks for, feeds the result back, and repeats until the work is actually finished. BioRouter, not the model, controls that loop. It decides what context is assembled, which tool calls are allowed to run, what gets saved, and whether a tool-free answer really ends the turn. This page walks through the loop from the moment a request arrives to the moment a final answer is sent, then covers the controls that keep a long-running turn safe, correct, and interruptible.
From a request to an answer
Every turn moves through the same stages. For a simple question the model may pass through them once with no tool calls. For a real task the middle stages (model call, tool routing, execution, observation) repeat many times before the loop reaches a final answer.
Receiving the request
A message arrives from the desktop app or the CLI. BioRouter allows one active turn per session: if the same turn is submitted twice it is treated as a single request, and a genuinely different turn that arrives while one is running is rejected rather than run in parallel. Slash commands can answer at once or rewrite history, and a persisted goal from an earlier turn is restored before the new reply begins.
Assembling context
Before it calls the model, BioRouter builds the full picture the model will see. This is prepared on separate paths that join only at the moment the provider request is sent:
- System prompt. A base instruction set, plus a model-specific overlay, the current permission mode, the local date, guidance from each enabled extension, and any workflow or project instructions.
- Available tools. The list of tools every enabled extension offers, described so the model knows when to reach for each.
- Active knowledge. If a knowledge base is selected, BioRouter searches it with your whole message and injects up to five relevant results (or an explicit note that retrieval failed) as agent-only context.
- Active skills. Skills you reference are loaded before the call. A skill's full body is injected once per session and later turns get a short pointer, so the same instructions are not re-sent every turn.
- Working directory. A bounded map of the project folder, which respects
.gitignoreand.biorouterignore, caps how many entries it reports, and targets roughly 2,000 tokens. - Session history. The conversation so far, projected into the form the provider expects.
As a conversation grows, its working set is measured against a context threshold (80 percent of the window by default). When it crosses that line, BioRouter compacts: older messages are summarized into a compact continuation for the model while the complete, human-readable history is kept for you. Compaction changes what the model sees, not what you can scroll back to.
The model call
BioRouter sends the assembled system prompt, message history, and tool list to the configured provider and reads back the response as it streams. It classifies what comes out: plain text (a candidate final answer), one or more tool requests, usage numbers, the finish reason, and any provider error. That classification decides what happens next.
Tool routing
When the model asks for a tool, the choice of tool follows a simple order of preference. The most basic tools handle straightforward work, and the specialized extensions are reserved for tasks that genuinely need them:
- Primitives first. Listing, reading, writing, editing, or finding files and running one-off commands go to the
developerextension'sshellandtext_editortools. These are the default for anything simple. - Specialized extensions when warranted. Real computation and multi-step chaining, figures, a knowledge base, browser automation, data queries, or building an app each have their own extension, reached only when a primitive cannot do the job.
Routing can also cross models. A lead model handling the conversation can delegate a sub-task to a worker model with a different provider and a narrower tool set, which is the basis of the multi-agent orchestration described below.
Dispatch and execution, with permission gating
A requested tool call does not run until it passes a chain of inspectors. The inspectors do not vote; their decisions merge toward greater restriction, so deny outranks ask and ask outranks allow, and no permissive layer can loosen a stricter one. The chain runs managed (administrator) policy, then a security and command policy check, then the permission gate, then repetition and hook checks. A small set of catastrophic commands is denied even in the most autonomous mode. If a hook rewrites a call's arguments, the rewritten call is sent back through the same checks before it can run.
What the permission gate does depends on the mode:
- Chat: no tools run at all.
- Auto: tools run without prompting, but managed policy, the command policy, and hooks can still escalate a call to an approval prompt or a denial.
- Approve: calls prompt unless a remembered rule already trusts them.
- Smart approve: read-only and low-risk calls run automatically while higher-risk calls ask.
Approved calls then execute. A global limit of eight concurrent tool calls keeps the system responsive, and calls that would write to the same path are serialized so they cannot clobber each other.
The observation returns to the model
Each tool's result is turned into a bounded, model-visible form and added to the conversation. An oversized result is written to disk in full, and the model gets a short preview plus the file path instead of the whole thing. Successful text can be scanned and masked for credentials, prompt-injection markers, and PII or PHI patterns. Failures are typed (for example not_found, permission_denied, timeout, or invalid_args) so the model can adapt, and a tool error is returned to the model as context rather than ending the session, which lets the model correct itself and try again.
Iterating until a stop condition
With the tool results in hand, BioRouter assembles fresh context and calls the model again. This is the cycle that repeats. It ends when the model returns an answer with no tool calls and that answer passes every completion check that is active (see structured success checks below). If a response was cut off because it hit the output length limit, BioRouter injects a hidden instruction to continue and does so up to twelve times.
Producing the final response
Once a tool-free answer clears its checks, the turn completes and the final answer is delivered. In the desktop app the whole turn (streamed text, tool activity, and the final answer) travels to the client over a live event stream; the CLI renders it directly. The full exchange is persisted so the session can be reopened, searched, and continued later.
Controlling the loop
Autonomy on a researcher's working tree is only safe if the loop has brakes. BioRouter runs several independent controllers during a turn. Most of the values below are defaults that a workflow or session setting can narrow or extend.
Budgets and token targets
A turn can be given a budget in wall-clock time, tokens, or dollars. As the budget runs low, BioRouter first warns, then asks the model to wrap up, then stops after a short grace period. The context threshold (80 percent by default) is the token target that triggers compaction rather than a hard stop, so a long session keeps working instead of failing when it fills the window.
Persistent goals
A goal set during a turn is saved with the session and restored before the next reply, so an objective survives across turns. When a goal is active, a goal judge checks whether the work actually satisfies it before the turn is allowed to finish.
Loop and stall detection
Several controllers watch for a turn going in circles and feed their evidence into one escalation path, which can nudge the model, grant a short wrap-up grace, or stop the turn outright:
| Controller | Signal | Response |
|---|---|---|
| Exact tool repetition | The same call three times (hard limit five) | Warn, then stop |
| Near-duplicate or A-B cycle | High similarity or four-step alternation | Warn |
| Repeated identical failure | Nudge at three, escalate at five, deny after six | Replan, then block the failing call |
| Periodic stall review | First review at 30 actions, then every 10 | Nudge, then wrap-up grace |
| Hard caps | 100 turns and 200 tool calls | Terminate with a clear limit result |
| Reply budget | Configured time, tokens, or cost | Warn, request wrap-up, then stop |
Cancel and interrupt mid-turn
You do not have to wait for a turn to finish. A hard cancel stops the active turn, is safe to send more than once, and unblocks anything waiting on an approval prompt. A soft interrupt is gentler: your new message enters a queue and is folded in at the next safe point, and if it arrives while the final answer is streaming it keeps the loop alive for one more iteration so the model can take your correction into account.
Structured success checks
A tool-free response is treated as a candidate, not a guarantee. Before it becomes the final answer, BioRouter runs whichever checks are enabled:
- Structured output. When a workflow defines a response schema, a dedicated tool validates and stores one JSON value; if it is missing, the model is asked to continue.
- Workflow retry. Configured checks run after apparent success, and a failed attempt can restore the starting conversation and retry within a bound.
- Done gate and self-critique. Optional passes that iterate on the current work or challenge the answer for contradictions or fabrication (both off by default).
- Stop hooks. The last gate before the answer is emitted (covered below).
Any failed check sends the turn back to work rather than letting a premature answer through.
Shadow-git checkpoints and reverting
So that aggressive edits are recoverable, BioRouter can snapshot the working directory at turn boundaries into a private git object database that lives in the app's data folder. It never commits to, or reads from, your real .git. From a checkpoint you can rewind along any of three axes: the files (check the captured tree back into the folder), the conversation (truncate history at that point), or both. A restore first takes its own snapshot, so a rewind is itself reversible.
BIOROUTER_CHECKPOINTS and is off by default, so a large data folder is not snapshotted unless you ask for it. The opposite trade-off, committing verified work to your real repository, is available through the verify-and-checkpoint Stop hook below.Hooks
Hooks let you run your own shell command, or a small model-based judge, at defined points in the loop without changing BioRouter itself. They fire everywhere the agent runs (desktop app, CLI, scheduled runs, and subagents), and they follow a fixed precedence: built-in defaults, then your global config, then opt-in project hooks, then non-overridable administrator policy. The events you are most likely to use:
- Pre-tool. Before a tool runs, a hook can allow it, ask for approval, deny it, or rewrite its arguments outright (a rewritten call is re-checked against every safety gate).
- Post-tool. After a tool runs, a hook can mark the result as an error and feed corrective context back, for example to reject a write that fails lint.
- Stop. When the agent is about to finish, a hook can block completion and return something it must address first. Repeated blocks are capped so a hook can never wedge the turn forever.
The verify-and-checkpoint Stop hook
BioRouter ships a ready-made Stop hook that refuses to let a turn end until the work is reproducible. It always runs a cheap commit check (uncommitted changes block the stop, with a nudge to add a .gitignore and commit in logical units), and, when you set BIOROUTER_VERIFY_BUILD=1, it detects the toolchain and runs the build and tests, blocking the stop on a failure. A built-in cap on consecutive blocks means it stops gracefully rather than looping if the agent truly cannot get to green.
Subagents and multi-agent orchestration
For work that is best isolated, the main agent can spawn a subagent: a temporary BioRouter instance that runs a task on its own and reports back, keeping its tool activity out of your main conversation. You ask for one in plain language ("use a code reviewer to check this function", "research this and summarize the findings"), and the agent decides when delegation helps. Subagents can run one after another or in parallel, inherit the extensions of the session that launched them (or a restricted set you name), and return either a full trace or just the result.
Subagents run under deliberate limits: 25 turns and a five-minute timeout by default, and a bounded number in flight at once. They are also restricted for safety, they cannot spawn further subagents (which prevents runaway recursion), and they cannot change extensions or schedules on the parent session. Beyond one-off delegation, a lead agent can coordinate named worker profiles, each a different model and role. Those cross-profile turns run one at a time (serialized) so their work stays ordered and legible, with parallel workers a later goal.
Memory across sessions
The loop's context is normally scoped to one session, but two mechanisms carry knowledge forward. A knowledge base (including a built-in "Soul" base for durable user facts) can be searched during context assembly and written to explicitly. Separately, past chats are indexed for relevance-ranked recall, so you can ask what was decided in an earlier conversation and get the right session back rather than merely the most recent one. Automatic distillation of durable facts from settled sessions is a planned extension of this recall path rather than current behavior.
Vaulting and security
Biorouter is built for sensitive research data, so its security model is layered and explicit. Your secrets live in the operating system's credential store, not in a config file. A permission mode decides how freely the agent may act. An administrator can pin a policy above your own settings. Your choice of provider decides where your data physically goes, and an opt-in OS sandbox can confine what a shell command may touch.
How secrets are vaulted
Provider API keys and other secrets are stored in the operating system's native credential store, never written to config.yaml in plain text. Custody stays with the OS, and access is gated by the same mechanisms the rest of the platform uses.
Biorouter reads the credential store once per process and caches secrets in memory for the rest of the run, so a single authorization covers a whole session. This matters most on macOS, the only platform that prompts.
| Platform | Credential store | Prompts |
|---|---|---|
| macOS | Keychain | Up to once per binary, ever. The OS asks you to authorize that specific executable to read the item. |
| Windows | Credential Manager | None. Protected per-user by the Windows Data Protection API. A large secret set is chunked across multiple credential entries to stay under the 2560-byte per-credential limit. |
| Linux | Secret Service (GNOME Keyring / KWallet) | None on a desktop session, which opens the store with your login. |
biorouterd) and the CLI (biorouter) are separate executables, so macOS tracks one grant per binary. In the worst case (using both, with secrets created by the other) you enter your password twice, ever.
Two escape hatches exist when the credential store is unavailable or unwanted:
BIOROUTER_DISABLE_KEYRING=truestores secrets in plaintext~/.config/biorouter/secrets.yamlinstead. Headless Linux (SSH sessions, WSL, or a host with no Secret Service daemon) falls back to this file automatically.- An environment variable for a specific key (for example
OPENAI_API_KEY) is read directly and always wins over the credential store.
Per-app secrets: the vault capability
Biorouter apps (built with Agent Drafter) can hold their own secrets, kept separate from your global keys. Per-app secrets live behind the deny-by-default vault capability: an app gets none unless its manifest lists them (for example "vault": { "encrypted": ["SPOKEAGENT_PASSCODE"] }). When an app is exported to a runnable folder, its secrets sit in a .vault/ directory that is excluded from the export archive, so credentials never travel with the shared app.
Permission modes
A permission mode sets how much autonomy the agent has when it modifies files, runs shell commands, and drives the computer. It applies to the whole session, takes effect immediately, and can change before or during a session (the /mode command in the CLI, or the mode button in the desktop app). It is the user-owned tier.
| Mode | /mode value | What it gates for shell, text_editor, and computer_control |
|---|---|---|
| Completely Autonomous | auto | Runs shell commands, text-editor writes, and computer control with no approval. This is the default. |
| Manual Approval | approve | Prompts before every write tool: shell, text-editor write/edit/insert, and computer control. Read-only calls still run. |
| Smart Approval | smart_approve | Uses a risk-based approach: auto-approves low-risk actions and flags higher-risk shell, text-editor, or computer-control calls for your approval. |
| Chat Only | chat | No tools at all. No shell, no text-editor writes, no computer control. Conversation and reasoning only. |
Set a persistent default with biorouter configure (select biorouter settings, then biorouter mode) or in Settings, Chat, Mode in the app.
Managed policy: the administrator tier
Permission modes and the user config are owned by the user, so a lab or institutional deployment has no way to enforce a rule the user cannot turn off. The managed policy tier adds a trusted, admin-owned layer that wins over user and project config. It can force specific tools to be denied, to require approval, or to be pre-approved, and it can pin mandatory lifecycle hooks. A managed deny holds even in Completely Autonomous mode; a blocked call surfaces as "Blocked by your organization's managed policy."
The policy is read from an admin-owned, per-OS location, and Biorouter verifies the file's ownership before trusting it (on Unix it must be owned by root or the current user and not be group- or world-writable). There is no environment-variable override, by design.
| OS | Managed policy path |
|---|---|
| macOS | /Library/Application Support/Biorouter/managed-policy.yaml |
| Linux | /etc/biorouter/managed-policy.yaml |
| Windows | %ProgramData%\Biorouter\managed-policy.yaml |
Deploy it through your device-management tooling (Jamf on macOS, a package postinstall or Ansible on Linux, Group Policy or an installer on Windows). A file that fails the ownership check is ignored with a warning and the agent runs normally, so a bad push cannot brick a fleet.
Data privacy and patient data
Biorouter routes your inputs and conversation context to the provider you selected, so the privacy properties of a session depend entirely on which provider you chose, not on Biorouter itself. Provider tiers differ fundamentally in where data goes:
| Provider tier | Where data goes | Suitable for |
|---|---|---|
| Local (Llama Server, Ollama) | Your device only. Nothing is transmitted to any external service. | Highest-sensitivity data and air-gapped requirements. |
| Institutional (UCSF Versa Azure, UCSF Amazon Bedrock) | Inside UCSF's own cloud tenant, governed by institutional agreements. | Institution-approved use cases. Verify the terms first. |
| Commercial cloud (Anthropic, OpenAI, Google, OpenRouter, others) | The provider's own cloud infrastructure, under their privacy terms. | Public or non-sensitive data only. |
Shell sandboxing
Beyond the permission mode, Biorouter can wrap shell commands in an OS-level sandbox that confines writes to the working directory and the temp directory and denies outbound network by default. It is opt-in through the BIOROUTER_SHELL_SANDBOX variable and off unless you set it.
| Platform | Mechanism | What it enforces |
|---|---|---|
| macOS | Seatbelt | Kernel-enforced write confinement and network deny. |
| Linux | Landlock plus seccomp, with a bubblewrap fallback | Kernel write confinement and network deny where the kernel supports it. |
| Windows | Job Object plus restricted token (containment tier) | Process and resource caps plus a real kill-the-tree primitive. It does not confine writes or block network, and Biorouter reports it honestly as such. |
Set BIOROUTER_SHELL_SANDBOX=auto to use the best available tier and run anyway if none exists, or strict to refuse the command when a full sandbox is not available. Run biorouter doctor to see which tier your host actually got. Independently of the sandbox, an always-on denylist blocks catastrophic commands (for example rm -rf / and its Windows equivalents) in every mode.
Configuration
Biorouter reads its persistent settings from YAML in your user config directory, and environment variables override those settings for a single invocation. This section covers what config.yaml holds, how the tiers resolve against each other, the environment variables worth knowing, and where every file and directory lives.
The config file
The primary file is ~/.config/biorouter/config.yaml (%APPDATA%\biorouter\config\config.yaml on Windows). It is shared by the desktop app and the CLI, and it holds:
- Provider and model settings (
BIOROUTER_PROVIDER,BIOROUTER_MODEL, temperature, planner and lead/worker models). - Extensions, declared under the
extensionskey: built-in servers and any external MCP servers you add (command, args, environment, timeout). - General settings such as the permission mode, turn limits, search paths, and workflow discovery.
API keys are the deliberate exception: they are held in the OS credential store, not here (see Vaulting and security). Changes to the config file take effect after a restart. Verify the active configuration with biorouter info -v.
Precedence
The same setting can come from several places. They resolve in this order, highest first:
- Managed policy (admin-owned) for the permissions and hooks it governs.
- Environment variables.
config.yamland the other config files.- Built-in defaults.
For settings the managed tier does not govern, the effective order is environment variables, then config file, then defaults. Where an admin-installed managed policy file is present, it is authoritative for permissions and hooks.
Useful environment variables
Every environment variable overrides the config file for one invocation. These are the ones you are most likely to reach for; see the environment-variables reference for the full list.
| Variable | Purpose |
|---|---|
ALPHA_FEATURES (also ALPHA) | Enable experimental alpha features. Off by default. |
BIOROUTER_PROVIDER · BIOROUTER_MODEL | Set the provider and model for the session. |
BIOROUTER_MODE | Permission mode: auto, approve, smart_approve, or chat. Default auto. |
BIOROUTER_DISABLE_KEYRING | Set to any value to store secrets in plaintext secrets.yaml instead of the OS credential store. |
BIOROUTER_PORT | Port the biorouterd daemon listens on. (Note the single underscore: only nested keys use the double-underscore form.) |
BIOROUTER_SERVER__SECRET_KEY | Server authentication key. The __ denotes a nested config key. |
BIOROUTER_EXTERNAL_BACKEND | Use an externally running backend rather than spawning one (front-end development). |
BIOROUTER_EXTERNAL_PORT | Port of that external backend. Default 3000. |
BIOROUTER_WORKFLOW_PATH | Extra directories to search for workflows. Colon-separated on Unix, semicolon-separated on Windows. |
BIOROUTER_MAX_TURNS | Maximum turns allowed without user input. Default 1000. |
BIOROUTER_SHELL_SANDBOX | Opt into OS shell sandboxing: off (default), auto, or strict. |
BIOROUTER_PATH_ROOT | Relocate all config, data, and state under one directory. Useful for isolated or CI environments. |
File and directory locations
Paths below are the macOS and Linux locations. On Windows, the config directory is %APPDATA%\biorouter\config\.
| Path | Contents |
|---|---|
~/.config/biorouter/config.yaml | Providers, models, extensions, and general settings. |
~/.config/biorouter/permission.yaml | Tool permission levels set via biorouter configure. |
~/.config/biorouter/secrets.yaml | API keys, only when the keyring is disabled. |
~/.config/biorouter/sessions/ | Conversation history in a SQLite database. |
~/.config/biorouter/knowledge/ | Knowledge bases (markdown trees with git history). |
~/.config/biorouter/workflows/ · skills/ | Installed workflows and skills. |
~/.config/biorouter/logs/ | Log files. |
~/Library/Application Support/Biorouter/ | Electron app state (desktop only, macOS). |
Architecture
BioRouter is built in three layers that stack cleanly: an interface you interact with, an agent that runs the reasoning loop, and a set of extensions that give the agent its tools. A request travels down through the layers and results travel back up. Understanding this shape is the fastest way to find your bearings anywhere else in the system, because every other part of BioRouter is an implementation of one of these three layers.
Three layers
The layers separate what you see from what thinks from what acts:
- Interface. The desktop GUI or the command-line interface. It accepts your input and displays responses, and nothing more; it holds no reasoning of its own.
- Agent. The core reasoning loop described earlier on this page, together with everything that supports it: session and conversation state, the connections to LLM providers, and workflow and schedule execution.
- Extensions. Pluggable servers that speak the Model Context Protocol (MCP), the open standard BioRouter uses to talk to tools. Each extension, whether shipped in the box or installed by you, hands the agent a set of tools (file operations, database queries, web access, code execution, figures, and so on).
In a typical session the interface starts an agent, the agent connects to one or more extensions at once, and it routes the model calls through whichever provider you have selected. Requests flow down from the interface into the agent and out to the extensions; tool results and the final answer flow back up.
The Rust workspace
The backend is a Rust workspace made of several crates. Four of them carry the architecture above:
| Piece | Binary | Role |
|---|---|---|
biorouter | library | The core agent library: the reasoning loop, the LLM provider integrations, session and conversation state, and workflow and schedule execution. This is the Agent layer. |
biorouter-server | biorouterd | The REST and WebSocket server that the desktop app talks to. It owns turn admission and transport and drives the core library on the client's behalf. |
biorouter-cli | biorouter | The command-line interface, one half of the Interface layer. |
biorouter-mcp | library | The built-in MCP servers, part of the Extensions layer. |
The built-in extensions shipped in biorouter-mcp include developer (shell and file editing), computercontroller, memory, autovisualiser (figures), knowledge, agent_drafter (building apps), and the data and compute servers. Because these live behind the same MCP interface as third-party extensions, the agent treats a built-in tool and an installed one the same way.
How the interface reaches the agent
The two interfaces connect to the Agent layer differently, which is the main structural distinction between them:
- CLI. The command-line binary calls the
bioroutercore library directly, in the same process. There is no server in the middle. - Desktop GUI. The app is built with Electron and React. Its main process starts
biorouterdin the background, and the React interface talks to that server over a local HTTP and WebSocket connection. Streamed turn events reach the interface over a live event stream, and calls the interface makes are type-checked against a client generated from the server's OpenAPI specification, so the two sides cannot drift out of agreement.
This layering is what makes BioRouter extensible. Adding a capability means adding an extension at the bottom layer, not changing the loop in the middle or the interface on top. The agent discovers the new tools, the routing rules decide when to use them, and the same permission and hook machinery governs them, all without touching the layers above.