Getting started

Install the app, connect a model and start a chat. These docs describe biorouter v1.94.0 on Windows, macOS and Linux.

Install

Download the file for your computer from the Download page or from GitHub Releases.

  • Windows x64. Biorouter-Setup-*.exe is the installer. A later one upgrades in place and keeps your shortcuts. A .zip of the same build is also published.
  • macOS. Open the .dmg for your Mac, arm64 for Apple silicon or x64 for Intel, and drag Biorouter to Applications.
  • Linux, Debian and Ubuntu. Run this in the folder that holds the file:
    sudo apt install ./biorouter_*.deb
  • Linux, Fedora and RHEL. Run this in the folder that holds the file:
    sudo dnf install ./Biorouter-*.rpm
  • Linux server. The biorouter-cli packages, one .deb and one .rpm, install the command line, the background service and the browser interface with no desktop app. Install one the same way. See Command line.

The app checks for new releases and tells you when one is ready. Settings → App → About shows the version and where an update stands.

When it starts, the app checks for Git, Python, uv and npm, which some extensions use, and offers to install any that are missing. The app itself runs without them. Local models on Linux need Debian 12, Ubuntu 22.04 or newer.

Install the command line

The desktop app includes the biorouter command line tool, which shares your settings and chats with the app. When the command is not on your PATH, the app offers to install it as it starts. On Windows and on the Linux desktop packages, use that prompt. On macOS you can also run the bundled copy once from a terminal:

/Applications/Biorouter.app/Contents/Resources/bin/biorouter \
  setup-path

setup-path, which the app's prompt also runs, links the command into a folder on your PATH, such as /usr/local/bin or ~/.local/bin. On Windows it copies it to %LOCALAPPDATA%\Biorouter\bin. If the folder is not on your PATH yet, it prints the line to add. Open a new terminal and run biorouter info to check.

After an update, the app offers to update the command when the copy on your PATH is older. The Linux server packages install biorouter to /usr/bin and need no setup.

Connect a model

Biorouter asks you to choose a model the first time it opens. To add or change one later, open Settings → Models and choose Manage… beside Providers. Providers sit on three tabs.

  • Local. Llama Server needs nothing installed. The first time Biorouter opens, its row lists models: pick one and choose Download & run. The model downloads once; after that it runs on this computer, so your messages never go to a model host. Later, Settings → Models → Local models installs more. Ollama needs Ollama running on this computer with a model pulled.
  • Institutional. For UCSF. Versa API Azure asks for your Versa API key. Versa API Bedrock asks for your Versa access key ID and secret access key. The endpoints are set for you.
  • Public. Claude Code and Codex use the vendor's command line tool, installed and signed in to your own plan; Biorouter never sees the credential. Anthropic, OpenAI and Google Gemini need an API key from that provider. The others ask for that provider's own key or account credentials.

Choose a provider's row, then Configure, and enter its credentials. Biorouter checks them when you save. From a terminal, run biorouter configure and choose Configure Providers. Models and providers lists every provider and its default model, and Security explains where credentials are kept.

Llama Server, Ollama running on this computer, and the two Versa providers are private. Ollama on another machine, an Ollama cloud model, and every other provider, is public. For patient data, use a private model. Once a chat uses a private model or a private data extension, it stays private, and Biorouter refuses to switch it to a public model. To change that, choose Make this chat public in Chat history, or run biorouter session declassify. See Private and public.

UCSF researchers: use the two Versa providers on the Institutional tab. Azure OpenAI and Amazon Bedrock on the Public tab stay public even if you point them at a UCSF endpoint, because Biorouter cannot check where they send data.

Start a chat

  1. Open a new chat Choose New chat in the sidebar, or press Cmd+T (Ctrl+T on Windows and Linux).
  2. Pick a working folder The folder under the text box is where the agent reads and writes files. Choose it to switch folders before you send the first message. After that the chat keeps it.
  3. Ask Type a request in plain language and press Enter, for example “List the files in this folder and summarize the README.” The agent answers and shows each tool it runs as one line.

From a terminal, biorouter session opens an interactive chat, and biorouter run -t "Summarize ./notes.md" sends one request and exits.

Where your data lives

Biorouter keeps its settings and chats as files on your computer. The app and the command line share them. On macOS and Linux:

  • Settings. config.yaml in ~/.config/biorouter/
  • Chats. sessions.db in ~/.local/share/biorouter/sessions/
  • Logs. ~/.local/state/biorouter/logs/

On Windows they sit under %APPDATA%\UCSF\biorouter. Run biorouter info to print the paths on your computer. Configuration lists every file.

Next steps

The desktop app

The app is where you chat with a model, watch the agent work and read what it makes.

The window

The sidebar runs down the left. The rest of the window shows the page you opened. In a chat, tabs run across the top, the chat fills the middle and the composer sits at the bottom. In a wide window the chat summary sits at the right of the chat.

Files, figures and apps the agent makes open in a side panel on the right. In the conversation each one is a card; choose it to open it in the panel. In a live chat the panel opens on the newest one by itself. A terminal can open below the conversation.

Drag the sidebar's edge to resize it, or press Cmd+B to hide and show it. Shortcuts on this page are shown for macOS; see Keyboard shortcuts.

The sidebar

From top to bottom:

  • Home. A greeting, a card of your recent usage and a composer. The card's Overview tab shows chats, messages, tokens, active days, your streak and your favorite model, with a heatmap of the days you used Biorouter. Its Models tab shows usage by model. Choose 1y, 30d or 7d to change the period. Typing in the composer starts a new chat.
  • New chat. An empty chat in a new tab.
  • Crew. Your lab's shared workspace: channels, files and agent tasks. See Crew.
  • Components. A group holding the six rows below. It starts collapsed and stays the way you last left it.
    • Workflows. Saved recipes that start a chat with the same instructions, tools and model. See Workflows and scheduling.
    • Scheduler. Workflows set to run on a schedule, with each one's timing and last run.
    • Extensions. The tool servers the agent can use, each with an on and off switch, plus the BAAM marketplace and custom extensions. See Extensions and skills.
    • Skills. Instruction sets the agent loads when a task calls for one.
    • Knowledge. Knowledge bases the agent writes and reads. See Knowledge bases.
    • Built apps. Apps the agent built for you. This is the only place to delete one. See Built apps.
  • Chats. Your chats, one row each. A running chat shows an indicator, and a private chat's icon carries a small lock. Chats that Crew, a schedule, a subagent or a built app started, and chats you diverged, each have their own icon. The View options menu in the header sets Group by (Date, Folder or None) and Sort by (Last activity, Created or Name). By default chats sit under Today, Yesterday, Previous 7 days, Previous 30 days and then a heading for each month. Grouped by folder, each folder has a + that opens a new chat window in it. All chats opens Chat history.
  • Settings. Pinned at the bottom. When an update is ready, an update row appears above it. See Settings.

Right click a chat, or choose ⋯ on its row, for Rename, Open in new tab, Open in new window, Diverge, Export…, Copy chat ID and Delete chat…. Rename edits the title in the row. On a focused row, F2 does the same.

Chat and the composer

Type a request and press Enter. Shift+Enter starts a new line. Type / to pick a command, workflow, skill, knowledge base or extension, or @ to mention a file or folder. Paste or drag files and images onto the composer to attach them.

To report a Biorouter bug, type /bug and a space. It becomes a Report a bug chip; describe what went wrong after it, and the agent drafts a GitHub issue for you to approve.

The composer is one card with a line under it.

  • In the card. Your message, with any attachments above it. Under the text, on the left, the + menu (Attach file…, Mention and Commands) and the Tools chip. On the right, the model chip and Send, the arrow. While the agent works and the box is empty, Send becomes Stop.
  • Tools. One figure that adds up the extensions, skills and knowledge bases this chat uses. It opens a list for each, with a switch on every row. Changes there apply to this chat only.
  • The model chip. It names the model this chat runs on. Its menu shows the provider and whether the model is private, sets Effort, which is how long the model thinks before it answers, and offers Change model… and Lead and worker…. See Switching models.
  • Under the card. On the left, the working folder the agent reads and writes in. It is fixed once you send the first message. On the right, a ring that shows how much of the context window is left, and the estimated cost of the chat so far. Choose the ring to compact the chat now, or to set when Biorouter compacts it on its own. Settings → App → General → Show costs turns the cost off. On Home the line shows only the folder.

The chat summary

Once a chat has started, the chat summary lists the agent's to do items and marks each one as it finishes. Below the list it counts tool calls, tokens and artifacts, and shows the lines of code the chat added and removed. Make workflow turns the chat into a workflow, and Diagnostics produces a bundle for a bug report. In a wide window the summary sits at the right of the chat and moves the chat a little to the left. When there is not room, the summary button at the top right of the chat opens it as a popover instead.

While the agent works

Each tool call is one line in the chat, with an icon for the kind of tool; choose it to see the arguments and the result. Messages you send meanwhile wait in a Queued list above the text box. Each one has buttons to add it to the running turn without stopping it (Cmd+Enter does the same), to stop the turn and send it as a new one, to edit it and to remove it. The agent loop explains how a turn runs.

Shell code blocks in a reply carry a Run button that sends the command to the terminal below the conversation.

Working with messages

  • Copy is on every message.
  • Edit on your own message opens it in an editor. Save changes the message and continues the chat from there. Save as new chat starts a new chat from the edited message and leaves this one as it was.
  • Diverge on a reply opens a new window holding a new chat with the full history up to that point. The original stays as it was.
  • Select text in a reply, right click, and choose Ask about it or Quote it to put the passage in the composer as a quotation.

Switching models

  1. Open the model chip Choose the model name in the composer, then Change model….
  2. Pick a provider and a model Then choose Select model. The next turn uses it; the conversation so far is unchanged.

The change applies to this chat only. Tick Also use for new chats to make it the default too. Settings → Models → Default model → Change… sets the model new chats start on, and existing chats keep their own. A private chat accepts only private models. See Private and public.

Tabs and split panes

Every chat is a tab. Open one with Cmd+T, close it with Cmd+W, and move between tabs with Ctrl+Tab and Ctrl+Shift+Tab. Drag a tab to reorder it. Opening a chat that is already open switches to its tab. Drag a tab out of the window to give it a window of its own, or onto another window's tabs to move it there. Right click a tab, or press F2 on it, to rename its chat. When there are more tabs than fit, a menu lists them all, with a filter once there are eight or more.

To split, drag a tab to the left, right, top or bottom edge of a pane. Dropping it in the middle of a pane moves it into that pane's tabs instead. A window holds up to six panes. Drag the line between two panes to resize them. Each pane has its own tabs, and each chat keeps its own model, folder and extensions, so you can watch several agents work at once.

The terminal

Choose the terminal icon at the top right of a chat (Open terminal) to open a terminal below the conversation. It starts in the chat's working folder. Each tab has its own terminal, and a hidden terminal's shell keeps running until you close its tab. + adds another terminal; Cmd+T does the same while the terminal has focus.

History

Chat history lists every chat under Today, Yesterday, Previous 7 days, Previous 30 days and then by month. Open it with the All chats button in the Chats header or with Cmd+2, and search it with Cmd+F. Choose a chat to reopen it in a tab.

Point at a row to Rename its chat, or open its menu for Diverge, Export…, Copy chat ID and Delete chat…. A private chat's menu also offers Make this chat public, which asks you to confirm. Import chat brings in a chat someone exported. Show subagent runs adds the chats that subagents ran. Chats live in a local SQLite file; see Configuration.

Settings

Settings has three tabs.

  • Models. Default model shows the model new chats start on, with Change…. Under it, after v1.93.0, Crew tasks sets the model for agent tasks in Crew; it reads "Same as new chats" until you choose one. Then come the providers, with Manage…. Local models lists the local models you have and can install, and deletes ones you no longer need. The Danger zone has Reset…, which clears the provider and model new chats start on.
  • Chat. Approvals sets how much the agent does without asking: Autonomous, Manual, Smart or Chat only (see Security), the per-tool permissions and the maximum turns. Display decides whether tool calls start expanded or collapsed and turns spellcheck on or off. Capabilities sets the built-in abilities new chats start with. The tab also holds Memory, Contexts (skills that ship with Biorouter), App SDK and Project hints (.biorouterhints).
  • App. Configuration edits the settings file. Privacy holds the private and public protection, which is on by default. General covers notifications, the menu bar icon (and the Dock icon on macOS), prevent sleep, whether agents may open tabs on their own, and showing costs. Appearance sets the theme, the color palette and the text size. Usage appears while costs are shown. Then come About (version, updates and feedback) and the Danger zone (reset).

Keyboard shortcuts

On Windows and Linux, use Ctrl for Cmd and Alt for Option. Ctrl+Tab and Shift+Enter are the same everywhere.

ActionShortcut on macOS
New chat tab, or a new terminal in the terminalCmd+T
Close the tab, or the terminal you are inCmd+W
Next tabCtrl+Tab
Previous tabCtrl+Shift+Tab
New windowCmd+N
Close the windowShift+Cmd+W
Open a folder in a new chat windowCmd+O
Home, Chat historyCmd+1, Cmd+2
Workflows, Scheduler, Extensions, SkillsCmd+3 to Cmd+6
Hide or show the sidebarCmd+B
FindCmd+F
Find next, find previousCmd+G, Shift+Cmd+G
New line in the composerShift+Enter
Add a message to the running turnCmd+Enter
Bring back a message you sent earlierCmd+Up, Cmd+Down
Settings, on macOS onlyCmd+,
Bring the Biorouter window forward, from any appOption+Cmd+G
Quick launcher: start a chat from any appOption+Shift+Cmd+G

Menu bar and tray

The menu bar repeats the sidebar and adds a few things of its own.

  • Biorouter. On macOS only: Settings, Check for Updates, Check for Dependencies, Check for Extension Updates.
  • Go. Home, New Chat, History, Workflows, Scheduler, Extensions, Skills.
  • File. New Chat, New Window, Open Directory, Recent Directories, Close Tab, Close Window, Focus Biorouter Window.
  • Edit. The usual editing items and Find.
  • Extensions. Install a .brxt file, browse BAAM, add a custom extension, check for extension updates.
  • Providers. Configure Providers, Switch Model, Reset Provider.
  • View. Light, Dark or System mode, zoom and full screen.
  • Help. These docs, Report a Bug, Request a Feature.
  • Window. Always on Top.

Settings → App → General → Show in menu bar shows or hides the tray icon (the menu bar icon on macOS). It is on by default. On macOS and Windows, clicking the icon brings the window forward. Its menu holds Home, New Chat, Settings, Extensions, Skills, Check for Updates and Quit.

Command line

The biorouter command runs the same agent as the desktop app, from a terminal. It shares your settings, chats and extensions with the app.

The desktop app includes the command; Getting started shows how to put it on your PATH. On a Linux server, install the biorouter-cli package instead. Add --help to any command to see its flags.

Everyday use

Choose a model

Run biorouter configure once before anything else. The first time, it offers a local model (Llama Server), signing in with OpenRouter or Tetrate, or setting up a provider by hand. Run it again and choose Configure Providers to change the model, or Biorouter settings for the mode, tool permissions and turn limit. It needs a terminal, so a script uses models set instead and passes the provider's key in its environment variable, such as OPENAI_API_KEY.

biorouter configure
biorouter models set --provider PROVIDER --model MODEL

Chat in the terminal

Run biorouter with no command to start a chat. On a real terminal it opens a full screen chat. Set BIOROUTER_CLI_CLASSIC to any value for the older line by line prompt, which Biorouter also uses when the output is not a terminal. When no settings exist yet, biorouter runs configure first.

# A new chat, or a new chat with a name
biorouter
biorouter session -n gwas-followup

# Continue the last chat, or a named one with its history
biorouter session --resume
biorouter session --resume -n gwas-followup --history
KeyIn the full screen chat
EnterSend. While the agent is answering, the message waits and is sent when the turn ends.
Shift+EnterNew line. Ctrl+J also works.
Ctrl+CStop the running turn. With nothing running, clear the text; on an empty line, leave. Ctrl+D also leaves.
UpRecall a message you sent earlier. Down goes back.
PageUpScroll the conversation. PageDown scrolls back.
/List commands, skills, extensions and knowledge bases. Tab or Enter picks one.

Slash commands

The desktop app, the full screen chat and the classic prompt share these commands.

CommandWhat it does
/compactSummarize the chat so far to free context.
/clearClear the chat history.
/effortHow hard the model thinks: quick, normal or deep.
/goal/goal <condition> keeps working until it holds. /goal clear drops it.
/loop/loop 5m <prompt> repeats a prompt. /loop stop <id> ends it.
/schedule/schedule @daily <prompt> schedules a prompt. /schedule list shows the jobs.
/bug/bug <what went wrong> reports a Biorouter bug. The agent checks the chat, the docs and the source code, then shows you the issue to approve. Nothing is filed without your approval.
/ext:/ext:developer points the next reply at one extension, and /skill: and /kb: at a skill or a knowledge base. A name with spaces goes in parentheses: /skill(literature review).
/<shortcut>Run a workflow you gave a slash shortcut.

The terminal adds /rename <name>, /diverge [name] to copy the chat into a new one, /help and /exit. The classic prompt also has /mode auto|approve|smart_approve|chat, /plan and /endplan, /workflow [file.yaml] to save the chat as a workflow, /builtin and /extension to add extensions, /t for the color theme and /r for full tool output.

Sessions

Every chat is a session in one local store that the app and the command line share. The session commands come in two kinds.

Stored chats. Nothing needs to run.

  • session list, export
  • session rename, diverge
  • session remove, diagnostics
  • session declassify

Live turns. A service must be running.

  • session watch: follow a turn
  • session send: send a message
  • session attach: join and type
  • session cancel: stop the turn
Past chats are stored on disk. A turn that is running exists only inside the service that runs it.
biorouter session list --limit 10
biorouter session export -n gwas-followup -o gwas-followup.md
biorouter session rename -n gwas-followup --new-name hla-loci
biorouter session remove --session-id 20260929_3

The live commands need a biorouterd this terminal can reach, on BIOROUTER_PORT (3000 unless set) with the same BIOROUTER_SERVER__SECRET_KEY it was started with. The desktop app's own service picks a random port and a new key at every launch and publishes neither, so an open app does not count. Start a service you control:

# Terminal 1: a service with a key you choose
BIOROUTER_SERVER__SECRET_KEY=KEY biorouterd agent

# Terminal 2: the same key
export BIOROUTER_SERVER__SECRET_KEY=KEY
biorouter session send 20260929_2 "Summarize your findings"
biorouter session watch 20260929_2 --follow
biorouter session attach 20260929_2
biorouter session cancel 20260929_2

On a chat that is running, use attach, not session --resume: resuming opens a second agent on the same chat. send --no-wait returns at once, but the service stops a turn that nothing has been attached to for five minutes, so leave it off for long turns. A service started by hand has no user action key, so it refuses to steer a turn already running and says so; stopping still works.

Run one task

biorouter run sends one request and exits. Use it in scripts, on a cluster or in CI.

biorouter run -t "Summarize the QC report in ./qc.html"
cat plan.md | biorouter run -i -
biorouter run --workflow variants.yaml --params gene=HLA-DRB1
biorouter run --workflow variants.yaml --explain

For an unattended run, pin the model and set a limit, as below. The flags are under Reference, and the exit code says why a run stopped (Exit codes).

biorouter run --no-session --provider llamacpp --model qwen3.8-27b \
  --output-format json --max-turns 10 \
  -t "Check samples.csv for duplicate sample IDs"

Workflows and schedules

A workflow is a saved recipe for a chat, and a schedule runs one on a cron expression. Workflows and scheduling explains how to write both.

biorouter workflow validate variants.yaml
biorouter workflow install variants.yaml
biorouter workflow open variants -p gene=HLA-DRB1
biorouter workflow deeplink variants -p gene=HLA-DRB1

biorouter schedule add --schedule-id review-weekly \
  --cron "0 8 * * 1" --workflow-source ./review.yaml
biorouter schedule list
biorouter schedule run-now --schedule-id review-weekly
biorouter schedule sessions --schedule-id review-weekly -l 10
biorouter schedule remove --schedule-id review-weekly

deeplink prints a link that opens the workflow in the desktop app. --cron takes five fields, six with seconds first, or @hourly, @daily, @weekly or @monthly; schedule cron-help prints examples. A job keeps its own copy of the workflow, so later edits to the file do not change it. --id is short for --schedule-id.

Jobs run in the background while a Biorouter service is running. When this terminal can reach a running service (the same two variables as the live session commands), that service makes the change. Otherwise add and remove ask you to confirm and write the schedule file themselves, and a running Biorouter, the desktop app included, picks up the change within 60 seconds. run-now asks, then runs the job once in this terminal. Because a job is an agent that runs unattended, none of them goes ahead without a person at a terminal.

Fix a missing tool

biorouter doctor checks the tools extensions depend on (Git and uv are required; Python 3, Node.js, the AWS CLI, llama-server and Rust are optional), whether biorouter is on your PATH, the local model server, and whether a newer release exists. --fix opens a chat that already knows the failing tool and this machine, so the agent can repair it with you. With no tool named, it takes the first missing required one. --format json prints the checks for a script, and --no-update skips the release check.

biorouter doctor
biorouter doctor --fix
biorouter doctor --fix uv

Reference

Short names: s and sessions for session, kb for knowledge, ext for extension, sched for schedule, p and ps for project and projects, install-cli for setup-path, headless for serve. The workflow, schedule and doctor commands are covered above. Environment variables are on Configuration, except terminal settings only the command line reads and the three under Browser access.

session

FlagWhat it does
--nameName a new chat (-n NAME). With --resume, pick a chat by name.
--session-idPick a chat by ID, with --resume. Also --id.
--resumeContinue the last chat, or the one named (-r).
--historyShow earlier messages when resuming.
--providerUse this provider for this chat. --model picks its model.
--with-builtinTurn on built in extensions by name, as developer,memory.
--with-extensionA local extension from a command, as "ENV=value command args", or a remote one with --with-streamable-http-extension URL. Both repeat.
--max-turnsTurns the agent may take without your input. Default 0 means Unlimited; a positive value sets a limit.
--max-tool-repetitionsLimit identical calls to one tool in a row.
--debugShow full tool output and full paths.
--shared-daemonRun in the shared background service the desktop app and biorouter crew use. It starts the service when needed and connects silently. --no-start requires an existing service; --create-only creates the chat without running it. The older --approval-key-stdin option reads and ignores the first input line.
SubcommandWhat it does
listNewest first. --format json, --ascending, -w DIR for one folder, -l N. --subagents nests subagent runs; --include-empty adds chats with no messages.
exportA Markdown transcript, or a full copy with --format json or yaml. -o FILE.
rename--new-name NAME.
divergeCopy a chat into a new one and print the new ID. --branch-name NAME.
removeDelete chats for good. It asks first unless --yes, which a script must pass. -r REGEX matches IDs; --subagents and --include-empty widen -r and the picker.
diagnosticsA zip of the chat, settings and recent logs for a bug report. Read it before you share it.
declassifyMake a private chat public, after you confirm. See Private and public.
watchPrint a live chat's events without changing it. --follow keeps watching after the turn ends.
sendSend a message and stream the turn. --no-wait returns once the turn starts.
attachFollow a running chat and send what you type. --name NAME instead of an ID, --of PARENT_ID for its running subagent, --read-only to only watch. Ctrl+C leaves the turn running, after a warning if you sent it from here.
cancelStop the running turn, like Stop in the app.

export, rename, diverge, remove and diagnostics take the chat as --session-id ID or -n NAME, and ask you to pick one when you give neither. send, attach and cancel take --user-action-key-stdin for a service started with a user action key.

run

FlagWhat it does
--textThe request as text (-t).
--instructionsThe request from a file (-i FILE). - reads standard input.
--workflowA workflow by name or path. Give one of these three.
--paramsA workflow parameter as KEY=VALUE. Repeatable, as is --sub-workflow.
--explainShow a workflow's title and parameters without running it. --render-workflow prints it filled in.
--systemExtra instructions for the agent. Not with --workflow.
--interactiveKeep chatting after the first answer (-s).
--no-sessionStore nothing. -n NAME names the session instead, and -r resumes a previous run.
--quietPrint only the answer (-q).
--output-formattext, json for one result at the end, or stream-json for events as they happen.

The model, limit and extension flags work as they do for session.

models

SubcommandWhat it does
currentThe provider and model new chats use.
providersEvery provider.
listThe models one provider offers, as models list ollama.
setSet the default, as --provider P --model M.
local listThe Llama Server catalog, what is downloaded, and which copy it starts from. Also ls.
local pullDownload a model ahead of time: a catalog name, qwen3.8-27b or gemma4-31b, or a Hugging Face owner/repo:QUANT. A name from an earlier version downloads the model it now runs.
local rmDelete a downloaded model. Also delete.

The listing commands take --format json. Models and providers lists every provider and its default model.

extension

SubcommandWhat it does
installInstall a .brxt bundle, such as one from BAAM, and ask for each secret with echo off. --env KEY=VALUE sets a setting, --secret-stdin reads secrets as KEY=VALUE lines, --no-enable installs it switched off. --secret KEY=VALUE also works but shows in ps.
configureEnter or change an installed extension's credentials.
listList extensions.
removeRemove an extension. --purge also deletes its installed files.

skill

SubcommandWhat it does
installInstall from a .zip or a repository URL. --force replaces an installed copy. --as bundle or --as individual answers when a source could be either.
listInstalled skills and whether each is on.
enableSwitch a skill on, or off with disable, without removing it.
removeRemove a skill.

See Extensions and skills.

knowledge

SubcommandWhat it does
listList knowledge bases.
activeShow or set the primary base, where writes go when no --kb is given. --set ID, --clear, --inherit; --session ID for one chat.
createA new base with an ID such as ms-genetics. --name and --color are optional.
ingestAdd a source with --url, --file or --text. --kb ID, --focus HINTS.
ingest-conversationDigest chats into a base. --session ID (repeatable; the latest chat by default), --new-kb NAME.
queryAsk a base a question. --save keeps the answer as a page.
lintCheck a base for problems. --fix lets the agent repair them.
hideHide a base from the agent; unhide brings it back.

The ingest, query and lint commands take --provider and --model. See Knowledge bases.

Settings only the command line reads

The first three settings can be written in config.yaml or set as a variable. The variable wins. BIOROUTER_CLI_CLASSIC works only from the environment.

SettingWhat it does
BIOROUTER_CLI_THEMEColors for replies in the classic prompt and in run: light, dark or ansi, the default. /t changes it and saves it.
BIOROUTER_CLI_SHOW_COSTtrue adds an estimated cost to the classic prompt's context line.
BIOROUTER_WORKFLOW_GITHUB_REPOA GitHub owner/repo to find workflows in by name. It needs the gh command, signed in. configure can set it.
BIOROUTER_CLI_CLASSICAny value selects the classic terminal prompt instead of the full screen chat.

Exit codes

CodeMeaning
0Finished.
1Any other error.
2The command needs a person at a terminal and found none, for example configure, or session remove without --yes.
70The provider call failed for a reason other than credentials, for example a network error, a server error or a rate limit.
75The provider rejected the credentials.
76The model kept calling one tool until the loop guard stopped the turn.
77A worker agent the turn consulted never answered.
78The chat store failed while saving the turn.
79The provider kept filling its output limit without finishing.
80A provider's signed reasoning from earlier in the chat could not be sent back unchanged.
81A signed turn was cut off during a tool call and rolled back. Run it again.

Browser access

biorouter serve shows the desktop app's interface in a web browser. Use it on a Linux server, in a container, or on a machine you reach over SSH. It starts its own biorouterd, which serves the interface and its API from one address.

Set it up

  1. Install On a desktop computer, the app's command already includes serve. On a server, install the command line package. It puts biorouter and biorouterd in /usr/bin and the interface in /usr/share/biorouter/web.
    # Debian, Ubuntu
    sudo apt install ./biorouter-cli_*_amd64.deb
    
    # Rocky, RHEL, Fedora
    sudo dnf install ./biorouter-cli-*-1.x86_64.rpm
  2. Choose the model Run biorouter configure, as the account that will run serve. The browser cannot change the model later; see The model is fixed.
  3. Start it Run biorouter serve --open. It opens your browser and stays in the foreground. Without --open, copy the whole address from these lines of its output:
      Biorouter is serving at
    
          http://127.0.0.1:8765/?t=1f4c9e02...

Ctrl+C stops serve and its service and frees the port. Past chats show in both serve and the desktop app, since both read the same chat store, but a turn running in one does not show in the other.

FlagWhat it does
--hostThe address to listen on, 127.0.0.1 by default. An address other machines can reach requires a token.
--portThe port, 8765 by default (-p).
--openOpen a browser when the server is ready, without putting the token on a command line.
--tokenUse a fixed token instead of a new one. Other accounts can read it in ps; The access token has a safer way.
--no-tokenServe with no token. Refused unless the address is local.
--web-dirThe folder holding the built interface, when serve cannot find it. It must contain an index.html. BIOROUTER_SERVE_UI does the same.
--public-urlThe https:// address a reverse proxy serves the interface at, path included. serve prints it with the token. BIOROUTER_PUBLIC_URL does the same. Added after v1.93.0.
--computer-use-approvalSet a Biorouter Copilot approval key of at least 16 characters, typed at the terminal. It is never saved.

The access token

  • The address ends in ?t= and a token. Unless you set a fixed one, the token is new on every launch and shown once.
  • Opening the address gives the browser a cookie and removes the token from the address bar.
  • The token is not used up. Anyone with the address can open it until serve stops, so stopping serve is how you revoke it.
  • To keep one address across restarts, set BIOROUTER_BROWSER_TOKEN to a long random value, for example from openssl rand -hex 32.

Reach it from another machine

For one person, keep the local address and forward the port over SSH, then open the printed address in a browser on your own computer.

ssh -N -L 8765:127.0.0.1:8765 user@remote-host

To reach it without SSH, put an HTTPS reverse proxy in front of it. The proxy must pass WebSocket connections through and keep the browser's Sec-Fetch-* headers. It must also forward the original Host and set X-Forwarded-Proto: https, unless you give serve the address people open with --public-url, added after v1.93.0. That address may include a path on a shared hostname, which the proxy removes before it forwards a request.

biorouter serve --port 8765 \
  --public-url https://hub.example.org/biorouter/

serve prints that address with the token; open it with its trailing slash. A link opened at another address says so and names this one. A plain http:// address on the network is refused, even with the token, so --host 0.0.0.0 is only for a proxy on another machine. On JupyterHub, jupyter-server-proxy can start serve for each person; the browser access guide has the configuration.

Exposing the port exposes the agent. The browser can do what the desktop app does: run shell commands, read and write files, and spend your model credits, on the serving machine, as the account that started serve. There is one token and no user accounts. serve itself speaks plain HTTP, so limit who can reach the port and the proxy.

For a service that restarts on its own, keep the fixed token in an environment file that only the service account can read. The headless Linux guide has a systemd unit.

The model is fixed

A browser session cannot change its model or provider. This is deliberate. A chat that has used a private model may never reach a public one, and the desktop app can switch models only because it holds proof that a person asked. A browser tab cannot hold that proof.

So the model is chosen once, at the terminal, and every chat in that serve runs on it: private for its whole life on a private model, public on a public one. A private chat started in the desktop app opens in the browser only when the host's model is private too. To change the model, stop serve, run biorouter configure and start it again.

What works in a browser

CapabilityIn a browser
Chat, history, extensions, skills, knowledge bases and workflowsYes. Private chats and knowledge bases are listed only when the configured model is private.
Several chats at once, workspace control, built apps and their agentsYes
Stop, and Stop & sendYes
Steering a turn while it runsNo. What you type waits and is sent when the turn ends.
A subagent's own tabRead only.
Changing the model or providerNo, by design. See above.
CrewNo, and it says so before you try: opening Crew shows “Crew needs the Biorouter desktop app”. Every Crew action needs proof that a person is at this computer, which the desktop app and biorouter crew supply themselves; the daemon serve starts never holds it. Use Crew in the desktop app or with biorouter crew in a terminal on your own computer.
Approvals that need proof a person actedA note takes the place of the buttons, and the agent is not offered skill or extension installs and removals. Run biorouter skill and biorouter extension on the host instead.
Browsing the marketplaceYes. After v1.93.0 the browser reads the live catalog from biorouter.ucsf.edu itself; when it cannot, it shows the catalog bundled with Biorouter. Installs download on the serving machine.
Resetting app dataNo. On the host, use biorouter session remove and the other remove commands.
File and folder pickersNo dialog. Type a path on the serving machine, not on the computer running the browser.
Biorouter CopilotOnly when serve started with --computer-use-approval. It controls the serving machine's desktop.
The app's terminal, updates, notifications, dock and menu bar icons, a second windowNo

Other commands

CommandWhat it does
--versionThe installed version.
infoWhere your settings, chats and logs are. -v also prints the settings.
usageTokens and cost per day, or per model with --by-model. --from and --to take YYYY-MM-DD; the default is the last 30 days. --json.
setup-pathPut biorouter on your PATH.
termOne chat per terminal window, and @biorouter or @g to ask from the prompt with your recent commands as context. Add eval "$(biorouter term init zsh)" to ~/.zshrc; term init also takes bash, fish and powershell.
projectContinue in your last project folder. projects lists recent ones to pick from.
appsOpen an app the agent built in your browser: apps list, then apps open ID or apps serve ID. See Built apps.
crewCrew workspaces from a terminal. See Crew.
mcpA bundled MCP server over standard input and output, for a host to start: autovisualiser, computercontroller, webdocuments, developer or memory.
acpAn Agent Client Protocol server for editors such as Zed. --ws serves a WebSocket on 127.0.0.1:11577.
completionA completion script for bash, zsh, fish, powershell or elvish.
benchBenchmark a model setup on a set of tasks.

Models and providers

Biorouter runs local models, models your institution hosts, and public cloud models. Each chat has its own model, and you can change it; a private chat can switch only among private models.

The three tabs

Open Settings → Models and choose Manage… beside Providers. Every provider sits on one of three tabs, always in this order. A one line note under the tabs gives the tab's privacy, quoted here in the app's own words.

TabHoldsThe note under the tab
LocalLlama Server, Ollama“Private because inference runs on this machine. Nothing leaves it.”
InstitutionalUCSF's Versa API Azure and Versa API Bedrock“Private because Biorouter recognizes this institutional gateway endpoint.”
PublicClaude Code and Codex, then the API providers“Public. Biorouter can't verify where this account's endpoint points, even one your institution pays for.”

Choose a provider's row, then Configure, and enter its credentials. Biorouter checks them with the provider before it saves them. In a terminal, biorouter configure lists the same providers as one list. Security explains where credentials are kept.

A chat becomes private once a turn runs on a private model. Private and public explains what that changes.

The model picker reads each provider's live list of models, so it is the place to see what you can use today. The defaults below are what Biorouter picks when you configure a provider without naming a model. The newest release is v1.94.0; where a default changed after v1.92.1, the page names both. An existing setup keeps its saved main model.

Local

Llama Server (llamacpp) comes with the desktop app and needs no setup and no key. Choose a model, then Download & run. The model downloads once, or starts from a copy already on your computer; after that, nothing leaves your computer.

Model and CLI nameDownloadNotes
Qwen3.8 27B
qwen3.8-27b
19 GBDefault on every machine after v1.92.1
Gemma 4 31B
gemma4-31b
18 GBGoogle's own 4-bit build

In v1.92.1 and earlier, Llama Server offers Gemma 4 and Qwen3.6 models and picks one by memory: Gemma 4 E4B (gemma4) below 64 GB, Gemma 4 12B (gemma4-12b) at 64 GB or more. After v1.92.1, a model name from an earlier version, such as either of those, runs Qwen3.8 27B.

Both models in the table need 32 GB of memory the GPU can use. Choose a computer for local models says what to expect at each size. Any other model works too: give a Hugging Face spec such as owner/repo:Q4_K_M as the model name. To download a model before you need it:

biorouter models local pull qwen3.8-27b
biorouter models local list

The context window is sized to your memory. After v1.92.1 it is 128k tokens at 48 GB or more, otherwise 64k; in v1.92.1 and earlier, 128k at 64 GB or more, 64k at 16 GB or more, otherwise 32k. Set LLAMACPP_CONTEXT_SIZE to fix it. Thinking is off by default; LLAMACPP_ENABLE_THINKING=true turns it on.

Ollama (ollama) uses an Ollama server you already run on this computer. Use Ollama 0.32.12 or later, which qwen3.8:27b needs, pull a model (ollama pull qwen3.8:27b) and select it. Default model: qwen3.8:27b after v1.92.1, qwen3 in v1.92.1 and earlier. Biorouter also supports gemma4:31b. Other models may write their tool calls as text instead of making them. Biorouter sets the context window it needs; OLLAMA_NUM_CTX overrides it.

Local means this computer. If OLLAMA_HOST or LLAMACPP_EXTERNAL_HOST points at another machine, Biorouter treats that provider as public. An Ollama cloud model is public too, even on this computer's Ollama, because Ollama answers it from ollama.com.

Choose a computer for local models

A local model runs in the memory the GPU can use. On a Mac with Apple silicon, that is the Mac's unified memory, and three things must fit in it at once: the model (about 22 to 25 GB for either model above, with its context window), Biorouter itself, and the data you are working on. On Windows or Linux, it is the graphics card's own memory, not the computer's RAM, and the model must fit there.

Memory the GPU can useWhat to expect
Under 32 GBNot recommended. The models are still offered, with a warning, but may fail to load or run very slowly.
32 GBThe minimum. The models run, with a 64k context window and less room for other apps.
48 GBRecommended. Llama Server uses a 128k context window (Ollama from 64 GB), so a chat holds more before it is summarized.
64 to 128 GBFor large datasets, or other demanding work running at the same time.

An Intel Mac, or any computer without a fast GPU, is slow whatever its memory, because the model runs on the processor: a few tokens per second, and many minutes before each chat's first reply. On Linux, the Llama Server that comes with Biorouter also runs on the processor, so use Ollama with GPU support there.

Each model needs about 20 GB of free disk space.

The first reply in a chat is the slowest, because the model first reads 31,000 or more tokens of Biorouter's instructions and tools. On an M4 Max, Qwen3.8 27B takes about 2.5 minutes for that; a chip with fewer GPU cores, such as a Pro or base M chip, takes longer. If a reply times out, raise OLLAMA_TIMEOUT or LLAMACPP_TIMEOUT (in seconds), or turn off extensions the chat does not need so the prompt is shorter.

Institutional

These endpoints are run by UCSF, so prompts and replies stay under UCSF's agreements. Each asks only for your Versa credentials; the endpoint is set for you.

Provider and CLI nameDefault model
Versa API Azure
versa_azure
gpt-5.6-sol-2026-07-09 after v1.92.1
gpt-5.5-2026-04-24 in v1.92.1 and earlier
Versa API Bedrock
versa_bedrock
us.anthropic.claude-opus-4-8

Versa API Azure takes your Versa API key and serves the UCSF ChatGPT models, only those UCSF has deployed. Versa API Bedrock takes your Versa access key ID and secret access key and serves the Anthropic models UCSF hosts on Amazon Bedrock.

UCSF researchers: use these two. Azure OpenAI and Amazon Bedrock on the Public tab are for your own Azure or AWS account, and they stay public even if you point them at a UCSF address.

Another institution's gateway appears on this tab once Biorouter recognizes its endpoint as private.

Public: AI agents on your subscription

The first section of the Public tab, “AI agents · your subscription”, holds Claude Code and Codex. The app says: “Biorouter drives a vendor CLI already installed and signed in on this machine; turns bill to that plan, not to an API key.” There is no key to paste, and Biorouter never sees the credential.

Agent and CLI nameDefault modelPlan
Claude Code
claude_code
claude-opus-5-5A Claude Pro or Max plan
Codex
codex
gpt-6-astraA ChatGPT plan
  1. Install the tool yourself Biorouter shows the command for your system but does not run it. The defaults above need claude 2.1.280 or newer and codex-cli 0.153.4 or newer.
    # Claude Code on macOS and Linux
    curl -fsSL https://claude.ai/install.sh | bash
    # Claude Code on Windows
    npm install -g @anthropic-ai/claude-code
    # Codex
    npm install -g @openai/codex@latest
  2. Sign in yourself Run claude auth login or codex login and sign in with your subscription.
  3. Choose it Pick it in Switch models, or choose Use Claude Code or Use Codex on its row.

The row shows where the tool stands: Not installed, Installed · not signed in, Signed in with an API key (the provider will not run, because turns would bill per token), Ready · signed in on your subscription, or Status unclear (choose Check again). If Biorouter cannot find the tool, set CLAUDE_CODE_COMMAND or CODEX_COMMAND to its path.

Biorouter's own tools reach the agent through Biorouter, so they still follow your permission mode and the privacy rules.

Both are public. A consumer plan carries no business associate agreement and no zero data retention agreement, so never use them with patient data.

Public: API providers

Paste a key or complete the provider's sign in, and Biorouter reads its list of models. Anthropic, OpenAI and Google Gemini come first, then the rest by name.

ProviderDefault model
Anthropicclaude-opus-4-8
OpenAIgpt-6-sol
Google Geminigemini-3.1-pro-preview
Amazon Bedrockus.anthropic.claude-sonnet-4-6
AWS SageMaker TGIsagemaker-tgi-endpoint
Azure OpenAIgpt-6-sol-2026-09-22
Basetenzai-org/GLM-5.3, added in v1.93.4
Databricksdatabricks-claude-sonnet-4-6
DeepSeekdeepseek-flash
GCP Vertex AIgemini-3.8-flash
GitHub Copilotgpt-5.3-codex
Groqopenai/gpt-oss-120b
Inceptionmercury-2.5
LiteLLMgpt-4o-mini
Mistral AImistral-medium-3-5
Moonshot AI (Kimi)kimi-k3
OpenRouteranthropic/claude-sonnet-5
Snowflakeclaude-sonnet-4-6
Tetrate Agent Router Serviceclaude-haiku-4-5
Venice.aillama-3.3-70b
xAIgrok-4.7
Xiaomi MiMomimo-v2.6-flash
z.aiglm-5.3

Most take one API key. Its setting is named after the provider, and an environment variable of the same name works too: ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_API_KEY, BASETEN_API_KEY (added in v1.93.4), DEEPSEEK_API_KEY, GROQ_API_KEY, INCEPTION_API_KEY, MISTRAL_API_KEY, MOONSHOT_API_KEY, OPENROUTER_API_KEY, VENICE_API_KEY, XAI_API_KEY, XIAOMI_MIMO_API_KEY and ZAI_API_KEY. The others sign in differently:

  • Amazon Bedrock and AWS SageMaker TGI (listed in the app as Amazon SageMaker TGI) use your AWS profile or credentials, including SSO. SageMaker also needs SAGEMAKER_ENDPOINT_NAME.
  • Azure OpenAI needs your endpoint and deployment name, with a key or your Azure sign in.
  • Databricks needs the workspace host, with a token or OAuth. Snowflake needs the account host and a token.
  • GCP Vertex AI needs GCP_PROJECT_ID and GCP_LOCATION, with a service account or application default credentials.
  • GitHub Copilot signs in with a device code; there is no key.
  • LiteLLM needs your gateway's address and key.
  • Tetrate Agent Router Service opens a browser sign in, or takes TETRATE_API_KEY.

The SageMaker TGI and LiteLLM defaults are placeholders: the model is whatever your endpoint or gateway serves. Run biorouter models providers for the list on your computer and biorouter models list <provider> for a provider's models.

Add a custom provider

Any endpoint that speaks the OpenAI, Anthropic or Ollama API can be added.

  1. Open the form On the Public tab, choose Add custom provider at the end of the API providers.
  2. Describe the endpoint Pick the Provider Type (OpenAI Compatible, Anthropic Compatible or Ollama Compatible), then enter a Display Name, the API URL, the API Key, and the Available Models as a comma separated list. Tick whether it streams responses.
  3. Save The provider appears on the Public tab and in the model picker from then on.

Custom providers are listed as public, because Biorouter cannot verify where a custom endpoint points. One exception: an Ollama Compatible provider on this computer (localhost) runs as private, so its chats become private. An OpenAI Compatible or Anthropic Compatible provider stays public even on localhost; ticking This is a local model (no auth required) only removes the API key.

Switch models

In a chat. Choose the model chip in the composer, then Change model…, then a provider and model in Switch models. The change applies to that chat only. Tick Also use for new chats to make it the model new chats start on. A private chat lists public models as unavailable; see Private and public.

In a terminal. biorouter models set changes the default provider and model, and the same flags on biorouter session or biorouter run change them for one chat. Name only a provider other than your default, and it runs its own default model:

biorouter models set --provider ollama --model qwen3.8:27b
biorouter session --provider llamacpp --model gemma4-31b
biorouter run --provider versa_azure -t "Summarize ./notes.md"

In a workflow. A workflow can name its own model, so everyone who opens it starts on that model if they have that provider set up:

settings:
  biorouter_provider: llamacpp
  biorouter_model: qwen3.8-27b

Lead and worker. Set BIOROUTER_LEAD_MODEL (and BIOROUTER_LEAD_PROVIDER if it is another provider) to start each chat on a lead model for its first turns, three by default, before your default model takes over. Biorouter goes back to the lead when the worker fails repeatedly. Both models see the whole chat, so the pair counts as private only when both are private.

Private and public

Every chat is private or public. Once a chat has used a private model or private data, Biorouter keeps it away from models hosted outside your institution.

What is private

Private

  • Llama Server and Ollama, running on this computer
  • Versa API Azure and Versa API Bedrock, hosted by UCSF
  • CDWAgent and UCSFOMOPAgent, marked “UCSF data” in BAAM
  • Every chat that has used one of these, and every knowledge base a private chat wrote to

Public

  • Every other provider, including Claude Code and Codex
  • Every other extension
  • Chats and knowledge bases that never touched private material
What is private, and what it makes private in turn.

A provider is private only when Biorouter can tell where inference runs. Ollama or Llama Server pointed at another machine is public, and so is an Ollama cloud model (a tag such as gpt-oss:120b-cloud), because Ollama sends it to ollama.com. Azure OpenAI and Amazon Bedrock on the Public tab stay public even when they point at a UCSF address; only the Versa providers are treated as UCSF's. Models and providers lists every provider by tab.

A private chat, model, extension or knowledge base shows a padlock and the word Private. Public ones show the word Public.

How a chat becomes private

A chat becomes private the first time either of these happens:

  1. A turn runs on a private model You send a message while Llama Server, Ollama or a Versa model is selected.
  2. A private data extension answers CDWAgent or UCSFOMOPAgent returns a result to one of the chat's tool calls.

It then stays private. The mark survives restarts and travels with the chat into diverged chats, imports, scheduled runs and subagents. Only you can remove it; see Make a chat public.

Public chatAny model can run it
Private chatAfter a private model or UCSF data
switch
Public modelRefused; the chat is unchanged
The mark only goes up. A private chat cannot move to a public model.

When you pick a private model for a public chat you have already sent a message in, Switch models says so before it applies: “After your next message this chat becomes private. Public models can't be used in it again unless you make it public from History.”

What Biorouter refuses

  • A private chat cannot switch to a public model. In Switch models each public model reads “Unavailable: this is a private chat, so only private models may run in it. Make it public from History to use this one.” The command line and other chats get the same refusal, and it names the provider. To use a public model, start a new chat.
  • A public model cannot read a private chat, through chat recall or through the tools that read other conversations.
  • A public model cannot read a private knowledge base. The refusal names the base.
  • A public model cannot use a private extension, and one cannot be turned on in a chat that runs a public model.
  • A subagent never crosses the line. See the table below.
  • A private chat writing into a public one asks you first. Before the agent in a private chat sends a message to a public chat or changes its tools, Biorouter shows you what it will send. It asks once for each pair of chats.
Parent chatSubagent's modelResult
PublicPublicRuns. The subagent is public.
PublicPrivateRefused.
PrivatePrivateRuns. The subagent is private.
PrivatePublicRefused. The task a private chat writes is private too.

A public subagent is started without the parent's private extensions, and the parent is told what was left out. If a spawn is refused, retrying will not help: switch the parent chat, or start a new chat on the model you want.

Institutions

Private is about how sensitive the data is. A second check asks whose agreements cover it, because compliance approved at one institution does not cover another institution's data.

ModelAffiliationMay use
Llama Server, Ollama on this computerLocalEvery private extension. Nothing leaves the computer, so no agreement is needed.
Versa API Azure, Versa API BedrockUCSFPrivate extensions that allow UCSF, which today are CDWAgent and UCSFOMOPAgent.
Public modelsNoneNo private extension.

By default, when a model from one institution reaches an extension that belongs to another, the call is refused before anything is sent. The refusal opens with “Cross-institutional data flow” and names both institutions, and a button, Approve this flow for followed by the extension's name, appears under it. Only you can press it; an agent cannot. “Approving records your acceptance for this chat, this extension and this model's institution only.”

Approving is not a compliance decision. Biorouter cannot know whether a BAA, DUA or IRB approval covers the flow. Your compliance office answers that.

Knowledge bases

A knowledge base takes the tier of the most sensitive chat that has written to it. Merging two bases gives the more sensitive tier of the two.

To change a base's tier, open it in the Knowledge view. Make private takes one click. Make public asks you to type the base's ID and tells you how many pages and raw sources every model will then be able to read, including anything a private chat wrote. Content that has already been read cannot be recalled.

Make a chat public

  1. Open Chat history Choose All chats in the Chats header, or press Cmd+2 (Ctrl+2 on Windows and Linux).
  2. Open the chat's menu Choose More actions (the three dots) on the chat's row, then Make this chat public. A chat opened from History also has a Make this chat public button, a globe icon in its header.
  3. Confirm What you are asked for depends on why the chat is private.
  • A chat Biorouter saw run a turn on a private model needs one click, then gives you five seconds to undo.
  • Any other private chat (it reached private data, was imported, came from a private parent, or was marked from the model it last used when privacy tiers arrived) asks you to type the last six characters of the chat's ID, then to pass your computer's own password prompt.

The contents are not changed, and the change cannot be undone once it lands. It is written to a record on your computer. An agent can ask you to do this but cannot do it. From a terminal:

biorouter session declassify SESSION_ID

Turning the protection off

Settings → App → Privacy has one switch, Privacy tiers, which is on by default. Turning it off asks you to type DISABLE PRIVACY TIERS, choose Turn off privacy tiers, then pass your computer's own password prompt. Turning it back on takes one click.

While it is off, nothing separates private chats, extensions and knowledge bases from public models, and a chat that uses a private model or private data while it is off is not marked private. Turning it back on protects what was already marked, but it cannot mark what happened in between.

The switch is kept in its own file beside config.yaml, not in it. An agent with a shell could still edit that file, which Biorouter cannot prevent, so it announces the off state instead: a note reading “Privacy tiers are off.” sits above every message box until you turn it back on. If the file was changed outside the app, the note says so.

What this does not protect

These rules govern what the agent can reach through Biorouter's own chats, knowledge bases and extensions. They prevent mistakes; they do not stop a determined person or an agent following injected instructions.

  • Files are not isolated. A public chat with a shell can read ordinary files on this computer, including files a private chat wrote and Biorouter's own chat store and knowledge base folders. The rules above cover what the agent reaches through Biorouter's tools, not through the shell.
  • The desktop is not isolated. Once you approve Biorouter Copilot for a request, the model receives screenshots and the text of other open apps. Close clinical windows first.

Every model that is not private carries this line, on the model chip, above the API providers on the Public tab, and in biorouter configure, whether or not privacy tiers are on:

“Not HIPAA-compliant, not on-premise, not local. This model can read files on this computer. Biorouter will not hand it another chat's transcript or a knowledge base marked private.”

For patient data, use a local model or an institutional one, and check with your institution before you start.

Security

Where Biorouter keeps your credentials, which files it refuses to read, and how much the agent may do without asking.

Credentials

Provider API keys and other secrets go to your operating system's credential store, not to config.yaml. Biorouter reads the store once per process and keeps the values in memory, so one authorization covers the whole run.

Credential storeWhat to expect
macOS
Keychain
macOS asks for your password the first time a program reads the item. Choose Always Allow. The background service (biorouterd) and the command line (biorouter) are separate programs, so each asks once, and a program is never asked about an item it created. The grant survives updates.
Windows
Credential Manager
No prompt. Windows protects the entries for your account.
Linux
Secret Service
GNOME Keyring or KWallet. No prompt on a desktop session, which opens the store when you log in.

Where no credential store answers, as on a Linux server, over SSH or in WSL, Biorouter keeps secrets in secrets.yaml beside config.yaml instead. Set the environment variable BIOROUTER_DISABLE_KEYRING to any value to choose that file on purpose. Prefer the credential store where there is one.

On macOS and Linux, Biorouter creates secrets.yaml readable and writable only by your account, and tightens an existing file the next time it writes it. Anyone who can act as your account, or as root, can still read the file.

An environment variable named after a key, such as OPENAI_API_KEY, always wins over the stored value.

The secret guard

A model with a shell can read any file you can. The secret guard refuses a tool call that reads or names a file whose purpose is to hold a credential. It works in every chat, in every permission mode and on every model, and it has no switch.

It protects these names in any folder:

KindNames
Secret files.env, .env.*, secrets.* (Biorouter's own secrets.yaml included)
Keys and certificatesSSH private keys such as id_rsa and id_ed25519, *.pem, *.p12, *.pfx
Tool logins.aws/credentials, .codex/auth.json, .claude/.credentials.json
More tool logins.netrc, _netrc, .pgpass, .git-credentials, .docker/config.json, .kube/config, .config/gh/hosts.yml
  • Commands are read as the shell reads them. ~, variables, globs and cd are resolved before the path is judged, so cat ~/.aws/credentials and cd ~/.aws && head cred* are both refused.
  • A match is refused whether or not the file exists. A command that only names a protected file, such as echo X=1 > .env, is refused too.
  • Results are checked as well. When a credential still reaches a tool result, the guard replaces it with a marker such as [REDACTED:aws-secret-access-key] before any model sees it. It recognizes private key blocks, AWS keys, common provider tokens, and values under names such as *_API_KEY or *_TOKEN.

To open one protected file on purpose, add a negation to .biorouterignore: the project's own file for paths inside the project, or ~/.config/biorouter/.biorouterignore for every path. For example, !**/.env.example in the project's file reopens its example env files. Any other pattern you add there keeps those files from the agent too.

The guard stops mistakes, not a determined attacker. It cannot see a path a program builds while it runs, a recursive read of a parent folder such as grep -r key ~/.aws, or text inside a screenshot.

Secrets for built apps

A built app can hold its own secrets, apart from your provider keys. Its vault capability is off unless the app's manifest names each secret, for example "vault": { "encrypted": ["SPOKEAGENT_PASSCODE"] }. The values are stored encrypted in the app's .vault/ folder, and the app refers to each one by name as {{vault:NAME}}. Biorouter fills in the value when a tool runs, so the value never reaches the model. An exported app leaves .vault/ behind.

Permission modes

The permission mode sets how much the agent does without asking. Choose it in Settings → Chat → Approvals, with /mode at the classic terminal prompt, or in the settings menu of biorouter configure. It is stored as BIOROUTER_MODE.

ModeValueWhat the agent does
AutonomousautoUses tools and edits, creates or deletes files without asking first. This is the default.
ManualapproveAsks before every tool call, unless you chose Always Allow for that tool.
Smartsmart_approveRuns calls with low risk and asks before the rest.
Chat onlychatNo tools and no extensions. The model only answers.

What asks in every mode

A few actions ask even in Autonomous, and no hook can answer for you:

  • Writing or deleting under a protected system folder, your home folder itself, or a credential store such as ~/.ssh.
  • Reading, saving or deleting a global memory, which every chat on the computer shares.
  • Observing or controlling the desktop with Biorouter Copilot.

An approval never reopens a call that was already refused, whether by your own Never allow, by a managed policy or by the block on destructive commands.

Biorouter Copilot asks for each task

Turning on Biorouter Copilot in Settings → Chat → Capabilities does not give it your desktop. Before its first capture or action for a request, Biorouter asks for approval that names the model and provider, where their data goes, and the computer to control. With a public model, the approval says that screenshots and application text can be sent to that provider. The approval covers that one request and ends when the reply finishes, when you stop it, or when the model changes. Chat only refuses every Biorouter Copilot tool.

Managed policy

An administrator can install a policy file that outranks your own settings. It can deny a tool, require approval for it or approve it in advance, and it can add hooks that always run. A deny holds in Autonomous mode too, and the call reports “Blocked by your organization's managed policy.”

ComputerPolicy file
macOS/Library/Application Support/Biorouter/managed-policy.yaml
Linux/etc/biorouter/managed-policy.yaml
Windows%ProgramData%\Biorouter\managed-policy.yaml
permissions:
  deny:
    - "developer__shell"
  ask:
    - "memory__.*"
  allow:
    - "developer__text_editor"

A tool name matches exactly or as an anchored regular expression. Deploy the file with your device management tools, such as Jamf, Ansible or Group Policy.

  • On macOS and Linux the file is read only if it and its folder belong to root or to you, and neither the group nor others can write to them. On Windows the %ProgramData% location is trusted, and ownership is not checked yet.
  • A file that fails the check or does not parse is ignored with a warning, and Biorouter runs as usual.
  • BIOROUTER_PATH_ROOT moves the file into <root>/managed/.

Shell sandbox

The shell sandbox is off by default. With the environment variable BIOROUTER_SHELL_SANDBOX set (it has no effect in config.yaml), each shell command runs in an operating system sandbox that lets it write only to the working folder and the temporary folder, and blocks outbound network where the kernel allows it. biorouter doctor shows which parts your computer gets. The sandbox is Seatbelt on macOS, and Landlock with seccomp on Linux, or bubblewrap where the kernel lacks them. Windows has no shell sandbox yet.

  • auto (or 1, true, on) uses the best sandbox available. Where there is none, it warns once and runs the command anyway.
  • strict refuses to run a command when a full sandbox is not available.
  • BIOROUTER_SHELL_SANDBOX_NETWORK=1 lets sandboxed commands reach the network.

Apart from the sandbox, a block that is always on refuses a few commands that cannot be undone, such as rm -rf /, disk wipes and fork bombs, in every mode.

Patient data

These controls decide what the agent may do on your computer. Where your data goes depends on the model. For patient data, use a local or institutional model, and read Private and public for what keeps a private chat away from public models and what it does not cover.

Extensions and skills

Extensions give the agent tools for a clinical database, a knowledge graph, Word and Excel files or a website; skills give it written methods for doing one kind of task the same way every time. Both install from BAAM, the Biorouter AI Agent Marketplace.

What an extension is

An extension is a server that speaks the Model Context Protocol (MCP), an open standard. It offers tools the agent can call, and it can also offer resources to read and prompts to start from. Any MCP server that runs as a command on this computer, or over streamable HTTP, can be added. The older SSE transport is not supported.

ModelPicks a tool
BiorouterChecks your mode and the chat's privacy
ExtensionAn MCP server runs the tool
Data or serviceA database, a graph, a site
The model never reaches an extension directly. Every call passes through Biorouter, and the result comes back the same way.

Before it starts an extension through npx or uvx, Biorouter looks the package up in the OSV database of known malicious packages and refuses to start one that is listed.

Built-in extensions

These ship with Biorouter, so there is nothing to install. Defaults are those of biorouter v1.94.0. Turn extensions on and off says where each one is switched.

ExtensionDefaultWhat it does
DeveloperOnReads, writes and edits files, searches code and runs shell commands. Its commands run with your own user account's access.
Biorouter CopilotOnLooks at and operates the apps on your desktop. It asks you to approve each task first, and Stop ends it.
Web & DocumentsOnReads web pages and works with spreadsheets, Word documents and PDFs.
Auto VisualiserOnDraws interactive figures from data: 32 kinds of chart, scientific plot, network, diagram and map, including volcano, Manhattan, Kaplan-Meier and forest plots. Several figures can form one report. Each opens in the side panel.
Code ExecutionOnLets the model write one short JavaScript program that makes many tool calls at once, so the steps in between do not fill the conversation.
Extension ManagerOnLets the agent attach or detach an extension during a chat, search BAAM, and install or delete an extension package once you approve.
SkillsOnFinds and loads the skill a task needs. It can install skills too, and each install waits for your approval in the app.
TodoOnKeeps a checklist for a task with several steps, so you can see what is done and what is left.
MemoryOnRemembers preferences and conventions you teach it, for one project or for all of them.
KnowledgeOnLets the agent build, read and search your knowledge bases from a chat. See Knowledge bases.
Agent DrafterOnBuilds apps that have their own agent, and exports them as projects that run on their own. See Built apps.
Chat RecallOffSearches your earlier chats and loads a summary of one, so earlier work can continue here. It reads only the chat history on this computer.
Workspace ControlOnLets the agent work across chats: open, read and steer another chat, and run subagents you can watch in their own tabs. See The agent loop.
CrewOnLets a chat you connect with /crew read the Crew channels you choose and post updates to them. See Crew.

Biorouter Copilot operates your real desktop. The approval names the task, the model and the computer. With a public model, screenshots and text from the apps it looks at are sent to that model's provider. Private and public chats keep separate approvals, but they share one screen, so a switch from a private chat to a public one pauses for you to confirm.

Add an extension

From BAAM

  1. Open the marketplace Choose Extensions in the sidebar, then Add → Browse marketplace.
  2. Choose Add Biorouter downloads the extension and shows its name, publisher, version, privacy tier and what it contains. Nothing is installed yet.
  3. Enter any credentials, then install If the extension needs a key, passcode or login, the next step asks for it. Values it marks as secret are kept with your model keys; see Security. Choose Install extension to finish.

Never paste a credential into a chat. A credential typed there is not used to set anything up, and every model that reads the chat would see it.

You can also download a .brxt file from BAAM and add it with Extensions → Add → Install from file (.brxt), which also takes the file dropped on it. In a terminal, the first command below installs one and asks for its credentials, hiding what you type for any value marked secret. The second asks for them again later.

biorouter extension install \
  ./cdwagent.brxt

biorouter extension configure cdwagent

The agent can install one for you. When a task needs a tool you do not have, the Extension Manager finds it on BAAM and asks you to approve that exact package before anything downloads. A chat on a public model cannot install a private extension this way.

A custom extension

Choose Extensions → Add → Custom extension… and pick a type, Command or HTTP.

  • Command, which is standard IO (STDIO), is a program Biorouter starts on this computer, usually an MCP server run with npx or uvx. Enter the command with its arguments, and any environment variables it needs.
  • HTTP, which is streamable HTTP, is a server that already runs somewhere else. Enter its endpoint URL, and any request headers.

An extension you add by hand, and any extension that is not on BAAM, is Public: any model can call it, including one hosted outside your institution.

For a STDIO extension, the app stores the value of each environment variable with your other credentials and writes only its name to config.yaml. In a terminal, biorouter configure and then Add Extension does the same. To try a server for one terminal session only:

biorouter session \
  --with-extension "uvx mcp-server-git"

biorouter session \
  --with-streamable-http-extension \
  https://mcp.example.org/mcp

In ~/.config/biorouter/config.yaml the two kinds look like this:

extensions:
  git:
    name: git
    description: My analysis code
    type: stdio
    cmd: uvx
    args:
      - mcp-server-git
      - --repository
      - /Users/me/analysis
    enabled: true
  lab-server:
    name: lab-server
    description: Our lab's MCP server
    type: streamable_http
    uri: https://mcp.example.org/mcp
    enabled: true

Turn extensions on and off

WhereWhat it changes
The switch beside an extension on the Extensions pageWhether new chats start with it.
Settings → Chat → CapabilitiesWhich built-in extensions new chats start with, Crew included.
The Tools chip in the composer, on its Extensions listThis chat only. The choice is saved with the chat. The built-in extensions under Capabilities are not in this list.
The Extension Manager, when the agent attaches oneThis chat only, until it ends.
biorouter configure, then Toggle ExtensionsWhether new chats start with it, from a terminal.

A change to what new chats start with leaves chats already open as they were. In a chat on a public model, a private extension stays in the Extensions list of the Tools chip, grayed out, with the note “Unavailable in this chat (public model)”. Hovering it explains that a private extension needs a private model.

Extension agents in the marketplace

BAAM lists extensions for biomedical data, lab systems, literature and everyday research tools. Each installs as a .brxt bundle, and six of them are below.

The Privacy column is the extension's tier, the same one BAAM shows on its card. An extension is private only when BAAM lists it as private; today that is CDWAgent and UCSFOMOPAgent. The first time one answers in a chat, the chat becomes private and stays private, and a chat on a public model cannot use its tools. The tier comes from the BAAM registry, not from the extension, so an extension cannot choose its own tier. See Private and public.

AgentPrivacyWhat it connectsCredentials
UCSFOMOPAgentPrivateThe UCSF OMOP deidentified clinical database, queried in plain language. It cannot change the data.UCSF credentials.
CDWAgentPrivateThe UCSF Clinical Data Warehouse: cohorts, labs, imaging and clinical notes. It cannot change the data.Your UCSF network login, CAMPUS\username.
SPOKEAgentPublicThe SPOKE biomedical knowledge graph of genes, proteins, drugs, diseases and pathways, queried with Cypher.A SPOKE passcode, from the UCSF wiki credentials page.
PlaywrightAgentPublicA web browser the agent drives to open, read and fill in pages.None. Needs Node.js.
CodeGraphAgentPublicAn index of a codebase in 23 languages, including R and MATLAB, that finds who calls a function and what a change would break.None.
BiorOfficePublicWord, Excel and PowerPoint files, created and edited from a chat, with four office skills.None. Microsoft Office is not needed.

The rest are listed on BAAM, where you can search them.

Skills

A skill is a folder holding a SKILL.md file: a short header with a name and a description, then plain instructions. It adds a method rather than a tool, such as a quality control checklist, a lab's plotting style or the steps for using an API. The folder can also hold scripts and templates the agent reads when it uses the skill.

---
name: rnaseq-qc
description: RNA-seq quality checks.
---

1. Drop samples under 10M mapped reads.
2. Plot a PCA and flag outliers.
3. Report what was dropped and why.

The agent reads each skill's description and loads the whole skill when a request matches it. To pick one yourself, type /skill: in the composer and choose it from the list. A skill is known by the name in its header, not by its folder's name.

Install a skill

  • From BAAM. Choose Skills in the sidebar, then Add → Browse marketplace. Tick the ones you want and choose the install button, which shows the count, such as Install 3 skills. BAAM publishes more than 120 skills in three groups: core, developer and biomedical.
  • From a repository or a .zip. Choose Skills → Add → From a repository or .zip…. Paste a repository URL and choose Look up, or drop a .zip.
  • Write your own. Choose Skills → Add → Write a skill…, fill in the SKILL.md it opens, and save. It goes in Biorouter's skills folder.
  • From a terminal. Run biorouter skill install with a repository URL or the path to a .zip.

The agent can install skills from BAAM or a URL as well. Each install or removal waits for you to approve it in the app; a reply in the chat cannot approve it.

Packages

A repository or a .zip can hold several skills that belong together. Biorouter reads the package's manifest when it has one and installs the skills as one package: a single row in every list, updated and removed as one. A package installs completely or not at all, and downloads come only over HTTPS from GitHub or biorouter.ucsf.edu.

When a .zip holds loose skills and no manifest, Biorouter asks whether to install them as one bundle or separately. In a terminal, answer with a flag:

  • --as bundle installs them as one package.
  • --as individual installs each skill on its own.

Turn skills on and off

The Tools chip in the composer, on its Skills list, turns a skill or a whole package on or off for this chat only. The switches on the Skills page, and biorouter skill enable or disable in a terminal, set the default for every chat. A choice made in a chat wins over the default.

A few skills ship with Biorouter and are called Contexts: Word, PowerPoint, Excel and PDF documents, Knowledge, and a few about Biorouter itself. Turn them on or off in Settings → Chat → Contexts. They cannot be deleted, and the office ones load only for a matching task.

Where skills live

Biorouter reads skills from these folders, in this order. When two skills share a name, the one from the folder lower in the list wins.

  1. ~/.claude/skills/ holds skills shared with Claude Code.
  2. ~/.config/agents/skills/ holds skills shared with other AI agents.
  3. ~/.config/biorouter/skills/ holds the skills you install or write in Biorouter.
  4. ~/.config/biorouter/extensions/ holds the skills that come inside an installed extension, in its skills folder.
  5. .claude/skills/, .biorouter/skills/ and .agents/skills/ hold a project's own skills, in the folder where you run biorouter.

Skills are plain text. A lab can share a skills folder to keep its analyses consistent without sharing any data.

Workflows and scheduling

A workflow is one file that starts a chat with the same instructions and tools, and optionally the same model, every time. Send it to a colleague to run on their own data, or let the scheduler run it for you.

A workflow file

A workflow is written in YAML (recommended) or JSON. It needs a title, a description, and instructions or a prompt (or both). Save this as review.yaml:

version: "1.0.0"
title: Weekly cohort review
description: Counts new enrollments
instructions: Report counts, not records.
prompt: Summarize this week's enrollments.

Running it starts a new chat with those instructions. The desktop app puts the prompt in the text box for you to send; the command line and the scheduler send it for you. Use .yaml rather than .yml: the command line reads only .yaml and .json.

The fields

FieldWhat it holds
title, descriptionRequired. A short name and one line on what the workflow does.
instructionsThe system instructions for the chat. A workflow needs instructions, prompt or both.
promptThe first message.
parametersValues filled in at launch and inserted with {{ key }}. See Parameters.
extensionsThe extensions the chat needs. An env_keys list names the secrets an extension needs, and the command line asks for any that are missing.
skillsSkills whose instructions are added before the first model call. A skill that is not installed, or is switched off in the chat, stops the run with an error. A bundle name adds every skill in the bundle.
knowledge_basesvisible: the ids of the bases the chat may search. default: the base it writes to.
settingsbiorouter_provider, biorouter_model and temperature, for this workflow only.
activitiesButtons shown when the workflow opens in the desktop app. An entry that starts with message: is shown as a note above them.
responseA json_schema the final answer must match. The validated JSON is printed as the last line of output.
retrychecks run after the chat finishes (shell, file_exists, output_contains, json_schema), with max_retries and an optional on_failure command. A failed check starts the run again from the beginning.
sub_workflowsOther workflow files this one can call as tools, each with a name, a path and fixed values. Experimental.
authorcontact and metadata about who wrote it.
versionThe file format version. Defaults to "1.0.0".

The text fields are templates:

  • {{ workflow_dir }} is the folder that holds the file, so a workflow can point at files that travel with it.
  • {% extends "base.yaml" %} builds one workflow on another.

The full reference is the workflow schema.

Parameters

Parameters make one workflow serve many studies. Each has a key, an input_type, a requirement and a description. Add these to review.yaml and replace its prompt:

parameters:
  - key: study
    input_type: string
    requirement: optional
    default: MS-2041
    description: Study name
  - key: format
    input_type: select
    requirement: optional
    default: markdown
    options: [markdown, csv]
    description: Output format
prompt: Summarize enrollments in {{ study }} as {{ format }}.
RequirementMeaning
requiredMust be given at launch. Cannot have a default.
optionalMust have a default.
user_promptAsked for when no value is given.

The input types are string (the default), number, boolean, date, select, which needs options, and file, which reads the file at the path given and inserts its contents. A file parameter cannot have a default. Every {{ key }} in the file must match a parameter, and every parameter must be used; Biorouter checks this when it loads the workflow.

Save, run and share

Save a chat as a workflow

  1. Open the chat summary In the chat you want to keep, find the chat summary. In a wide window it sits at the right of the chat. In a narrower one, choose the summary button at the top right of the chat to open it. Then choose Make workflow.
  2. Read the draft Biorouter drafts the title, instructions and prompt from the conversation and fills in the chat's extensions, skills, knowledge bases and model. Edit what you need.
  3. Save Choose Create, or Create and run. The workflow appears under Workflows in the sidebar.

You can also ask in the chat, for example “Turn this chat into a workflow.” The agent shows you the workflow and asks you to approve it before anything is saved. Saved workflows live in ~/.config/biorouter/workflows/, where the app and the command line both find them.

Run a workflow

In Workflows, choose Run on a workflow, or Run in new window from its ⋯ menu. The first time you run a workflow, Biorouter shows its title, description and instructions; choose Trust and execute to go on. If it has parameters, fill them in and choose Start workflow. Slash command… in the same menu gives a workflow a shortcut you can type in any chat.

biorouter run --workflow review.yaml --params study=MS-2107
biorouter workflow validate review.yaml    # check that it loads
biorouter workflow install review.yaml     # add it to the library
biorouter workflow list

Share a workflow

Send the file, or send a link. In Workflows, a workflow's ⋯ menu has Copy link, Copy YAML and Export to file…. The person who receives a file adds it with Import workflow, or runs it with the biorouter run command above. From a terminal, make a link that fills in parameters for them:

biorouter workflow deeplink review.yaml --param study=MS-2107

Opening the link opens Biorouter with the workflow loaded. A link encodes the workflow into a biorouter://workflow address, plus any parameter values you gave it. It does not carry files that sit next to the workflow, so send those with the file.

Share the method, not the data

A workflow carries instructions, not records. The file holds the steps, the parameters and the names of the extensions, skills, knowledge bases and model it needs. Biorouter leaves out API keys, memory and the conversation history; the file holds only the text you write or approve.

Your labyour data, your models, your chat
review.yaml
A colleague's labtheir data, their models, their chat
Only the workflow travels, as a file or a link. Each lab runs it on its own data. Nothing comes back.
  • Each run is the recipient's own chat. It starts on their computer, with their extensions, their credentials and their models, under their institution's agreements. It follows the same privacy rules as any other chat: if it uses a private model or a private data extension, it becomes Private. See Private and public.
  • Data is read where it lives. A file parameter reads a file on the computer of the person running the workflow, when the run starts.
  • Results stay with the recipient. Nothing flows back to you. They share what they choose to share.
  • Edits do not travel back. A recipient's changes stay in their copy, and your file is unchanged.

Read a workflow before you share it. It holds whatever text is in it. A draft made with Make workflow is written from the conversation, so remove any values that came from your data.

Scheduling

A schedule runs a workflow at set times with nobody watching. Each run is a new chat of its own, saved to history. Schedules run in the background while a Biorouter background service runs, such as the desktop app's or the one biorouter serve starts. They are kept in schedule.json in Biorouter's data folder, so they survive a restart, and every running service follows that file. A run that comes due while one of your chats is running a turn, or while the provider is limiting requests, is skipped and runs at its next time.

The Scheduler page

  1. Open Scheduler Choose Scheduler in the sidebar, then New schedule. From Workflows, Schedule… in a workflow's ⋯ menu does the same for that workflow.
  2. Fill in the schedule Give it a name, choose the workflow file, and set when it runs.
  3. Create it Choose Create schedule.

Each schedule shows when it runs in words and how its last run went. From its row you can edit, pause, resume or delete it. Its page has Run now and lists every chat the schedule has run. Biorouter includes one schedule, Daily Meditation, which updates the Soul knowledge base from your recent chats at 3:00 each night; see Knowledge bases.

From a chat: /schedule and /loop

/schedule @daily Summarize new preprints on remyelination
/schedule "0 9 * * 1" Draft the weekly lab update
/loop 10m Check whether the alignment job has finished
  • /schedule <when> <prompt> runs a prompt until you remove it. When is an interval (5m, 2h, 1d), @hourly, @daily, @weekly, @monthly, or a cron expression in quotes. /schedule list shows them all. /schedule remove, run, pause, unpause and sessions take a schedule id.
  • /loop <interval> <prompt> is for short polling: 30s, 5m, 2h or 1d. A run that is still going when the next is due is skipped, and the loop stops itself after 100 runs. /loop lists loops, and /loop stop <id> or /loop stop all ends them.

When the agent schedules something

You can ask the agent, for example “Run the cohort review every Monday at 8am.” Every change the agent makes to a schedule shows an approval card first: creating one, running it now, pausing or resuming it, deleting it, or stopping a run. The card appears in every permission mode, Autonomous included. It says in words when the job will run, which workflow it runs and how, and the card for a new schedule shows the whole workflow. Only a person can approve it. Listing and reading schedules asks nothing.

From the command line

biorouter schedule add \
  --schedule-id review-weekly \
  --cron "0 8 * * 1" \
  --workflow-source ./review.yaml
biorouter schedule list
biorouter schedule run-now --schedule-id review-weekly
biorouter schedule sessions --schedule-id review-weekly
biorouter schedule remove --schedule-id review-weekly
biorouter schedule cron-help    # cron examples

--cron takes five fields (minute, hour, day of month, month, day of week), or six with seconds first, in this computer's local time; "0 8 * * 1" is every Monday at 8:00. The schedule keeps its own copy of the workflow as it was when you added it.

When this terminal cannot reach a Biorouter service, which is always the case next to the desktop app and in an agent's shell, the command writes the schedule file itself, and a running service picks it up within 60 seconds. In that case add, remove and run-now ask you to confirm at the terminal, and refuse when there is no terminal to ask, so an agent's shell cannot add a schedule on its own. When BIOROUTER_SERVER__SECRET_KEY and BIOROUTER_PORT point at a running service, that service makes the change without asking, or refuses it when the schedule would run on a private model.

What a scheduled run needs

  • A prompt, since nobody is there to type the first message.
  • A value for every parameter without asking: use optional parameters with defaults, and no user_prompt ones.
  • The model's credentials, the extensions and the files the workflow uses, all in place on this computer when the run starts. A workflow that works in a chat can still fail on a schedule if it depends on something only you supply there.

A failed run is recorded on the schedule, and the schedule runs again at its next time.

Knowledge bases

A knowledge base is a folder of linked pages that the agent writes from your papers, files, links and notes.

What a knowledge base is

Each base is one folder with its own git history, at ~/.config/biorouter/knowledge/<id>/. The sources you add and the pages the agent writes are kept apart, so a page can always be traced to the file it came from.

PathWhat it holds
raw/<source>/Each source as you added it, its Markdown conversion (source.md) and meta.yaml: title, link, checksum and credibility grade.
knowledge/<type>/The pages the agent writes, one per concept, filed by type. Each page starts with a short YAML header that names its type.
index.md, log.mdA catalog of the pages and a change log, both kept by the agent.
schema.mdHow this base is written. The agent reads it on every run, and you can edit it.

A base stays on your disk. Its only network calls are credibility lookups (Crossref and OpenAlex), the links you ask it to fetch, and the model that digests your sources. Git is built in; you do not need it installed.

Create a base

  1. Open Knowledge Open the sidebar's Components group and choose Knowledge.
  2. Start a new base Choose the base's name at the top of the view. In the menu that opens, choose Create knowledge base…
  3. Name it and pick a format The format decides how pages are written and checked. Then choose Create knowledge base.
ChoiceFormatUse it for
General knowledgeOKFNotes, project context and anything that is not curated biology. Any page type and any link name; nothing is rejected.
Curated biomedicalBioOKFBiomedical literature, or a base another institution will read. The vocabulary is checked, and every link names its evidence.

The format is fixed when the base is created. The dialog says so: “You cannot change a knowledge base's format yet.” A base from an older version keeps working and is marked Legacy. biorouter knowledge create makes an OKF base; to make a BioOKF base, use the app or ask the agent.

The BioOKF vocabulary

BioOKF v0.5 is a strict biomedical profile of the Open Knowledge Format (OKF v0.2). A page's type is one of 28: 20 biomedical entity types, such as Gene, Variant, Disease and CellType, and 8 provenance and context types, such as Publication, Study and Dataset. A typed link uses one of 35 predicates: 24 positive predicates such as causes and treats, and 11 negations such as not_treats. Every link names its evidence: a knowledge level, an agent type and a primary source page. A value outside the vocabulary is flagged with the closest legal one.

Visible bases and the primary

Every base is visible to a chat unless you hide it. When the agent searches without naming a base, it searches all the visible bases and says which base each result came from.

One visible base is the primary: where the agent writes when no base is named, the base it reads by default, and the base the Knowledge view shows. Soul is the primary until you choose another.

  • Hide a base from a chat. Open the Tools chip in the composer and choose its Knowledge list. Each base has a switch, and Hide all or Show all sets them together. A hidden base stays on disk.
  • Change the primary. In the Knowledge view, choose the base's name at the top and pick another base. Manage bases… lists every base with its format, its privacy and a switch that includes it in the chat.
  • Point one message at a base. Type / in the composer and pick it, or write /kb:ID.

If you hide the primary, the next visible base takes its place. If you delete it, the chat has no primary until you choose one, and a write that names no base is refused with the list of bases to choose from.

Add sources

Open a base in the Knowledge view. Sources sit beside the graph; in a narrow window they are the Sources tab.

  1. Stage sources Drop files or folders on the dropzone, or choose it to browse. Folders and archives are unpacked, and each readable file is staged on its own. Paste text takes notes or an excerpt, and offers any links in it as sources of their own.
  2. Check the model The panel shows the model this base digests with. Change it there.
  3. Choose Digest staged sources Progress streams in as pages are written. Stop ends the run.

Readable formats: PDF, Word (.docx), PowerPoint (.pptx, speaker notes included), Excel and OpenDocument spreadsheets (.xlsx, .xls, .ods), CSV, HTML, Markdown and plain text. Save an old .ppt as .pptx first. A scanned PDF with no text layer ingests with a warning.

In a chat, ask the agent to add files, folders or links to a base. It runs the same pipeline and reports any source it could not digest. It can also digest past chats into a base.

Sourcefile, link, text
Convertto Markdown
Digestwrites pages
Committo git
Each source becomes linked pages in one git commit, and the graph is rebuilt from the links.

Conversion runs once. It also grades the source's credibility, and its result is kept. The digest is a subagent that works from that Markdown, never the original file. It reads the base's schema.md and the pages it may change, writes a page for the source, updates related pages and links them. If it fails, its changes are rolled back and the raw source is kept so you can try again.

The graph

The Graph draws each page as a node and each link as an edge. Choose a node to inspect its page. Type is the fill, credibility is the ring.

  • Fill. In a BioOKF base each of the 28 types has its own color, grouped into seven families: genomic, molecular, anatomy, clinical, exposome, physical and provenance. Provenance types are drawn as open circles, so the evidence stands apart from the science. In an OKF base the color comes from the type's name.
  • Ring. A source's ring counts its credibility in arcs, from four for peer reviewed to one for gray literature. Web and personal sources have a dashed ring and a retracted source a solid one. The legend groups them as Well sourced, Weakly sourced, Not academic and Retracted.

Biorouter grades each source when it is converted. It looks for a DOI and checks it with Crossref, then OpenAlex, then checks the host, then looks for journal markers in the text. When none of these answers, the model grades it.

TierRingHow it is detected
Peer reviewed4 arcsA DOI resolves to a journal article, or the text carries clear journal markers.
Book3 arcsCrossref or OpenAlex report a book or a chapter.
Preprint2 arcsA preprint server such as arXiv, bioRxiv or medRxiv, or a DOI registered as a preprint.
Gray literature1 arc.gov and .edu hosts, WHO, CDC, NIH, FDA, ClinicalTrials.gov, EMA and standards bodies.
WebDashedAny other page.
PersonalDashedPasted text with no stated source.
RetractedSolidCrossref or OpenAlex mark it retracted, whatever its tier.

A graph with nodes and no edges means the pages hold no links, and a lint reports each of them as an orphan.

Search, history and restore

  • Search. The agent searches the pages by keyword (BM25), and the original source text when you ask for it. In a chat it reads the pages it finds and answers from them.
  • History. Every change is a git commit tagged by kind: ingest, link, flag, query, lint, restore or manual. Change log, in the base's ⋯ menu, lists them, and log.md keeps the same record.
  • Restore. In the change log, Preview shows the base as it was at a commit, and Restore adds a new commit that returns the base to that point, so a restore can itself be undone.

Export and import

Export as .brkb, in the base's ⋯ menu, writes the whole base to one file: pages, original sources and git history. To bring one in, open Manage bases… and choose Import from .brkb. The import keeps its id, or takes a numbered suffix if that id is in use, so it never replaces a base you have. A private base stays private when it is exported and imported. A .brkb dropped on the dropzone is not imported.

Merge two bases

Ask the agent to merge one base into another. It previews the merge first: what carries over, what is renamed and what the result's privacy will be. Then it merges.

  • The destination wins every clash. An incoming page whose identifier already exists is renamed, and every link to it is rewritten.
  • Sources the destination already holds are skipped. The source base is left unchanged.
  • The merge is one commit, and any failure leaves the destination as it was.
  • A BioOKF base can merge into an OKF base. An OKF base cannot merge into a BioOKF base.
  • The result takes the more sensitive privacy of the two.

Ingest, query and lint

Three operations run on a base. When one needs a model, it runs as a subagent with a limit on steps and time: 60 steps and 15 minutes to ingest a source, and 30 steps and five minutes to answer a query or repair what a lint found.

OperationWhat it does
IngestDigests one source into linked pages, as one commit. Run it with Digest staged sources, from a chat, or with knowledge ingest.
QuerySearches the base and writes an answer that cites its pages. knowledge query --save also files the answer as a page.
LintReads every page and reports orphans, contradictions, missing pages, stale sources and anything that breaks the format's rules. In a BioOKF base that includes the vocabulary, the evidence on each link, and sources that are retracted or too weak for the claims on them. Check for problems and a chat only report; knowledge lint --fix lets the agent repair what it finds.

Soul

Soul (id soul) ships with Biorouter and starts empty. It collects lasting facts about you: how you approach research questions, the tools and commands you use, and the name, role and preferences you mention.

A schedule named Daily Meditation keeps it current. Every day at 3:00 AM, while Biorouter's background service is running, it runs the Meditation workflow, which uses the update-soul skill to read up to three recent chats and add what matters. It skips scheduled runs and small talk, and makes no change when there is nothing new. You can see and pause it in Scheduler.

The agent cannot delete Soul, and if you delete it Biorouter creates it again. Settings → App → Danger zone → Reset data → Knowledge & memory deletes every base, creates an empty Soul and clears saved memory.

Private and public bases

A new base is public. It becomes private the first time a private chat writes to it, and it stays private until you make it public. A private base shows a padlock and the word Private beside its name. A public model that tries to read it is refused, and the refusal names the base.

The control sits on the Sources side. On a private base, hovering its badge shows “Private. Biorouter only lets a private model read or write this knowledge base.” Make private takes effect at once. Make public asks you to type the base's id first, because every model, public ones included, will then be able to read everything a private chat wrote into it. See Private and public.

Command line

biorouter knowledge list
biorouter knowledge create ms-genetics --name "MS genetics"
biorouter knowledge active --set ms-genetics
biorouter knowledge ingest --file ./paper.pdf
biorouter knowledge query "What predicts relapse?" --save
biorouter knowledge lint

Once active --set has made a base the primary, commands without --kb use it. kb is a short name for knowledge. Every flag is in the command line reference.

Built apps

Agent Drafter builds apps: a small web page with its own agent, which fills panels, draws charts and asks you questions while you use it.

What an app is

An app is a TypeScript front end (index.html and src/main.ts) with a manifest.json that sets its agent: instructions, model, extensions, skills, knowledge bases and what the app may do. Apps live in ~/.config/biorouter/agent_drafter/<id>/. Biorouter's background service serves each one at /apps/<id>/ and connects the page to its agent over a WebSocket.

Build one when a task needs a working surface rather than a transcript: a cohort reviewer, a variant workbench, a knowledge graph explorer, a dashboard for one lab. To see every app you have, open the sidebar's Components group and choose Built apps.

How the agent drives the app

Each app's agent gets a set of tools that act on the page. A call becomes a message on the app's socket and the page's SDK applies it. What you do in the page, such as answering a form or selecting a row, comes back over the same socket.

ToolWhat it does
ui_describeLists the page's regions, panels, declared actions and signals, and state. The agent calls it first.
ui_panel, ui_renderOpen a panel, or render widgets (cards, tables, stats, forms, Markdown) into a target.
ui_patchChange rendered widgets in place by id, keeping scroll position and typed input.
ui_chart, ui_graph, ui_figureDraw a chart, a network graph, or an Auto Visualiser figure such as a volcano plot or a survival curve.
ui_htmlRender HTML that Biorouter has cleaned of scripts and forms. Off unless the app allows it.
ui_highlight, ui_notify, ui_suggestPoint at a region, show a short message, or offer up to five next steps the user can choose or ignore.
ui_theme, ui_layoutSwitch the theme pack, accent, light or dark mode and density, or rearrange the layout.
ui_state, ui_patch_stateRead and change the shared state the page is bound to.
ui_askShow a form and wait for the answer. See Questions that wait.
ui_subscribeListen to signals the app declares, such as a row being selected.
app_call, emit_resultCall an action the app registered, or return a structured result the app is waiting for.
consultAsk one of the app's worker profiles a question that stands on its own. Works only when the app declares worker profiles; otherwise it says there are none.

Regions

An app marks the places the agent may write with a region attribute:

<section data-br-region="results">
</section>

The agent finds regions with ui_describe and writes to @region:results. It can also target @panel:ID, @main, @chat or a CSS selector such as #out. Panels need no region: every app has a dock for them. Up to 12 panels stay open by default, and the oldest closes when a new one opens.

Questions that wait

ui_ask shows a form in the page and holds the tool call until you submit it. The answers come back as the tool's result, so the agent can act on them in the same turn. Many apps have no chat box, so the agent asks this way rather than in prose.

A form holds up to 24 fields and waits up to 300 seconds by default. If the page closes or reconnects, the waiting question is released. Unlike ui_ask, ui_suggest never makes the turn wait.

Archetypes

A new app starts from a working archetype rather than a blank page. When none is named, one is picked from the app's title and description, and dashboard is the fallback. Each starter runs as it is and passes the build checks; all but chat declare their own actions and signals.

ArchetypeShape
explorerA network graph the agent draws, with an inspector and search.
dashboardA grid of key numbers bound to state, with a refresh action.
workbenchA table, row selection and a detail pane.
wizardA form in stages that saves as it goes, then submits.
canvasA drawing surface with actions the agent calls.
chatA plain conversation panel, picked only when the description asks for a chat or an assistant.

An app starts with Biorouter's look. Six theme packs are available: biorouter, clinical, lab-notebook, terminal, journal and midnight.

Build and export an app

  1. Ask for it In a chat, describe the app, for example “Use Agent Drafter to build a dashboard app for this cohort.” Agent Drafter is on by default.
  2. Let it build The agent creates the app from an archetype, edits its source, sets its model and tools, then builds it. build_app bundles src/main.ts and runs the app's checks; an error must be fixed before the app launches or exports.
  3. Open it A preview card appears in the chat; choose it to open the app in the side panel. The agent can also open it in your browser.

In Built apps, each row has Launch, which opens the app in your browser, and a ⋯ menu with Open the chat it was built in, Export… and Delete. The card in a chat has no delete control. Delete an app here, or ask the agent to.

Biorouter checks that the chat still exists before it opens anything. When that chat was deleted, the row says Build chat deleted and the menu shows the same words, grayed out, in place of Open the chat it was built in, instead of opening an empty tab. Refresh checks again. An app built by a subagent opens the chat that started the subagent.

Exporting

Export… asks you to choose a folder and offers two modes:

  • Launcher writes the app and its launch scripts. It uses the knowledge bases, skills, extensions and models already on the computer that runs it.
  • Full also packs the app's knowledge base (as a .brkb file) and the skills you tick, and optionally biorouterd itself. BAAM extensions you tick are listed in export.json, at the top of the folder, for the recipient to install. On the first run the launcher lists the skills and knowledge base and asks first. If you agree, it installs the skills and copies the knowledge base to ~/.config/biorouter/knowledge-imports/, for you to bring in with Import from .brkb in Knowledge.

The folder runs without a build step or Node.js. On macOS open run.command, on Linux run bash run.sh, and on Windows open run.bat. The launcher uses the biorouterd bundled in a Full export, or the one Biorouter installed on the computer. If there is none, it stops and says so; install Biorouter, or set BIOROUTERD_BIN to its path. It starts biorouterd in the background when it needs to and opens the app in the browser. An export carries no API keys, so the app uses the models configured by whoever runs it. The app's vault is never exported.

Security model

Biorouter treats an app's page as untrusted.

  • The socket. Each app has its own socket token, held in memory for one run of the background service and never written to disk. The socket accepts only the app page's own origin.
  • What the page sends. Action arguments, signals and widget submissions reach the agent wrapped in <app-data>, which the agent is told to treat as data, not instructions.
  • What the agent writes. State bindings set text and a short list of attributes, never code. ui_html is off unless the app allows it, and Biorouter cleans the HTML even then.
  • Capabilities. Control of the page is on by default, since it reaches only the app's own page. Files, data sources, compute and the vault are off until the manifest grants them. A signal that starts a turn by itself is off, and only you can turn it on; the agent cannot.
  • Knowledge. An app reads only the knowledge bases its manifest names, and writes only where it is granted write access.
  • Sensitive data. An app with an OMOP or CDW source, or a knowledge base it can write, may not send work to a public model. A model route or a worker profile that names one is refused.

An app's agent is a chat like any other, so the rules in Private and public apply to it.

Command line

biorouter apps list
biorouter apps open cohort-explorer
biorouter apps serve cohort-explorer

list prints every app (--json for scripts). open and serve use the background service on BIOROUTER_PORT (3000 by default) and start one if none is running. open opens the app in your browser; serve prints its address, and when it started the service it stays in the foreground and stops it when you press Ctrl+C. Apps always open in a browser, not in the terminal.

Crew

Crew is where a lab works together in the Biorouter desktop app: channels, shared files, and agent tasks the whole channel can see. One member, the host, runs the workspace on a shared Linux server.

The examples use the workspace chen-lab on the server lab.example.edu, hosted by Alice Chen (@alice), and the member Bob Lee (@bob). A word in braces, such as {team}, is a name Crew fills in. Every dialog, message and command is in the Crew manual on GitHub.

This page describes Crew after v1.93.0, with automatic setup, open workspaces, deletion, agents that work on the server and @agent. For v1.93.0 itself, read the v1.93.0 Crew manual.

Your computerThe app, its background service and your agent
SSH
Your server accountbiorouter-crew runs here under your login
Unix socket
The host's copyStores the workspace and checks every request
Each member reaches the workspace through their own server account. Agents run on each member's own computer, with that member's model.

What Crew is

  • Open it from Crew in the sidebar, below New chat.
  • A workspace holds teams, and a team holds channels. You see only the channels you are in. There are no direct messages.
  • A new workspace is open: every member can invite people, let them in and manage teams and channels, and a person who joins is added to all of them. The host can make it managed, so that a team's creator and a channel's owner manage them and only the host invites. Only the host removes people from the workspace, changes its privacy or deletes it.
  • Privacy is Private or Public. It decides which AI models may read the workspace, not which people see it. Each channel is labeled "Restricted" or "Public-safe". Only a local model or one approved for the workspace's institution may read a Restricted channel.
  • The desktop app and the biorouter crew commands share one background service on your computer, so both show the same workspaces.

What you need

  • The desktop app. Tested on macOS. Crew does not work in a web browser opened with biorouter serve, which shows "Crew needs the Biorouter desktop app" in its place.
  • A server account. Your own login on the lab's Linux server, with an SSH key, a password or a verification code. Your IT team provides it.
  • Crew on the server. Its server program, biorouter-crew, in ~/.local/bin of every account that connects. When you join or host, Biorouter installs it in your own account, without administrator rights.
  • A verified server. The server's SSH host key in your known hosts file. Crew never accepts a new server by itself, so check the fingerprint with IT once.
  • An invitation. The host sends it. It expires after 24 hours.

The background service

On macOS and Linux, Biorouter starts the background service and connects to it automatically. You do not choose or type a daemon approval secret. Quitting the app leaves the service running, so Crew stays connected. Opening the app again uses the same service.

  • After your computer restarts, opening Biorouter or running a biorouter crew command starts the service again.
  • After an update, the app replaces the older service when you open it. This can interrupt a task or transfer, so check their status afterward.
  • On Windows, quitting the app stops the service, and the biorouter crew commands do not work.

A Crew vault has its own passphrase. Setting one up or unlocking it still asks for that passphrase; see Use an encrypted vault.

Join a workspace

Send the host your exact username on the server. The host sends back an invitation message that ends with a line starting brcrew1:. It holds no secret.

  1. Open the Join dialog In Crew, choose Join a workspace. If you already have a workspace, choose Add a workspace and then Join a workspace… in the workspace menu.
  2. Paste the invitation Paste the whole message into Invitation from your host. If the summary names the wrong workspace or host, choose Cancel.
  3. Check your username The name in Your username on lab.example.edu is your server login, not your email address.
  4. Choose what your agent may do Check Your agent on lab.example.edu. It starts at As me on the server, which lets your agent run commands as your account there. Choose In a folder or Off to give it less. See Agents on the server.
  5. Join Choose Join chen-lab. If Crew is not in your server account yet, Biorouter installs it there. If the server asks for a password or a code, type it in the Sign in window.
  6. Send your code Crew shows "Send Alice this code:" and your code. Choose Copy and send the code to the host.

When the host, or in an open workspace any member, enters your code, the workspace opens by itself. Until then the status row reads "Not joined yet". In an open workspace you are added to every team and channel. For a second computer, ask the host to invite you again with Add another device for @bob turned on.

Your code is not the fingerprint. The Join dialog can also show the workspace fingerprint. Never send it. To check an invitation, ask the host to read the fingerprint from their workspace menu. If the two differ, do not join.

More in Joining a workspace.

Host a workspace

You need a login on the server, the server in your known hosts file, and your institution's short ID, such as ucsf.

  1. Open the Host dialog In Crew, choose Host a new workspace. If you already have a workspace, choose Add a workspace and then Host a new workspace… in the workspace menu.
  2. Name it Type a Workspace name. Anyone who can sign in to the server can see it, so keep patient and sample IDs out of it.
  3. Give your login Type Your server login, such as alice@lab.example.edu. Keep Private, check the institution and Your agent on lab.example.edu, as when you join, and choose Continue.
  4. Set up and start Crew Choose Set up and start Crew. Biorouter installs Crew in your server account and starts the workspace. If the server asks for a password or a code, type it in the Sign in window. If setup stops because other accounts can change a folder above the workspace, choose Fix it for me. If setup cannot reach the server, open Run it yourself in a terminal, run the commands it shows, and paste their output into Paste what it printed.
  5. Create it Choose Create workspace. This computer becomes the workspace's first admin device. Create also makes the workspace open and drafts its workspace context from the server. With Private, it marks the workspace with your institution, which cannot be changed later.
  6. Set the institution if asked If Create did not mark the workspace and Crew asks "Mark chen-lab as a UCSF workspace?", choose Mark as UCSF. Agents cannot work in the workspace until it is set.

From a terminal, one command does all of this:

biorouter crew host \
  --name chen-lab \
  --server alice@lab.example.edu \
  --institution ucsf

The "Get chen-lab ready" checklist lists what is left. Set your name before you invite anyone, because each invitation carries it.

Invite people and let them in

  1. Invite Choose Invite people to chen-lab… in the workspace menu. Type the person's server login in Username, such as bob, and choose Invite. In an open workspace, any member can invite.
  2. Send the invitation Choose Copy and send the message to the person, with the server's SSH fingerprint from IT if they have not used this server before.
  3. Let them in When the person sends their code, choose Let in… beside their name under "Waiting to join", paste the code, and choose Let Bob in.
  4. Add them to a team In an open workspace they are already in every team and channel, so choose Done. In a managed one, when their computer checks in, tick channels under Channels in {team} and choose Add to {team}. A person in no team sees no channels.

Approve only a code the person sent you. If Crew warns that a computer showed a different code, check the code with the person directly. To correct a mistyped code, choose Let in…, enter the right one, and choose Replace code.

After the server restarts, the host starts the workspace again, as Server setup says. More in Hosting a workspace.

Delete the workspace

In the workspace menu, choose People…, then the General tab of "chen-lab settings". Under "Danger zone", choose Delete workspace…, type the workspace's name, and choose Delete workspace. This deletes it for everyone and cannot be undone. Each member's connection bar then says "The host deleted chen-lab." with Remove from this computer…, which is all they can do.

Teams, channels and people

TaskManaged workspaceOpen workspace
Create a team, or a channel in your teamAnyoneAnyone
Join a team or channelSomeone adds youAnyone, with Browse channels
Add peopleThe team's creator or the channel owner, and the host in a team or channel the host is inAny member of the team or channel
Rename, archive or delete a channel, or remove its membersThe channel ownerAny member of the channel
Delete a team, with its channelsThe team's creatorAny member of the team
Invite people and let them inThe hostAny member
Remove someone from the workspace, or delete itThe hostThe host

A workspace created with v1.93.0 or earlier stays managed. The host switches it between open and managed on the General tab of "chen-lab settings", under Who can manage teams and channels. People you add do not need to accept, and an agent cannot add people. A channel's label is chosen when it is created and cannot be changed. Archiving a channel cannot be undone. Deleting a channel or a team removes its messages and files for everyone, and nobody can bring it back. Only a channel's owner hands it over. More in Teams, channels and people.

Messages and files

  • Enter sends, and Shift+Enter starts a new line. Messages use Markdown.
  • If sending fails, your text stays in the box with the reason. Press Send again. An unchanged message is never posted twice.
  • Typing @bob mentions Bob. Bob sees the message marked for him and may get a notification.
  • Nobody can edit or delete a posted message. To search a channel, use biorouter crew search in a terminal.

Share a file

  1. Add the file Choose the paperclip, then Upload a file…, and pick the file. You can also drag a file onto the channel, or paste a copied file into the message box. For a dragged or pasted file, Crew asks, for example, 'Share "counts.csv" (55 KB) to Crew?'. Check the full path it shows, and choose Share.
  2. Wait for the upload Wait until the line "Press Send to share it." appears.
  3. Send it Press Send. The file appears in the channel as a card with its name and size.

The file leaves your computer as soon as you confirm it. A finished upload cannot be deleted, even if you remove it from your message. The × on a file still uploading is Cancel upload. If you cancel, the part already sent stays on the server for up to a day.

Crew refuses folders and credential files, such as .env or id_rsa. For a large file already on the server, choose the paperclip, then Share a server path…, and type the full path. Crew shares only the path, and others open the file only if their own server account may read it. More in Messages and files.

Privacy and institutions

SettingWho changes itValues
Your connectionYou"Private" or "Public"
WorkspaceThe host"Private for everyone" or "Allows Public"

Your privacy is Public only when your connection is Public and the workspace allows Public. A new workspace starts "Private for everyone", and only the host can allow Public. The host sets the workspace's institution once, and your connection's institution must match it.

What an agent reads is protected when your privacy is Private, when it reads a "Restricted" channel or anything marked Restricted, when it uses your remote work folder, or when its chat already holds Restricted material. Restricted content stays Restricted after the host allows Public. The background service on your computer and Crew on the server apply these rules even when Privacy tiers is off in Biorouter's settings.

What other people can see

  • Members of a channel see your display name, your username, and your messages, files and agent posts there.
  • Everyone in the workspace sees whether you are online.
  • Members never see your privacy, your institution, your devices or your connected chats.
  • The host's server account and the server's administrators can read everything the workspace stores, Restricted messages included.
  • Anyone who can sign in to the server can see the workspace's name, and who is connected to it, in the server's process list.

More in Privacy and security.

Agents in a channel

An agent can work in a channel in two ways. Both run on your computer with your model, post as your agent where everyone in the channel sees it, and have access for one hour at most.

DetailA taskA chat connected with /crew
KindOne task, from Ask my agent or @agent. The agent posts its result and its access ends.An ordinary Biorouter chat that you keep talking to.
ReadsIts channel and its files, and up to 16 more channels under Also read. In an open workspace, every channel you are in.Its channels and their files, up to 20 including its own
PostsYour task, then its resultIn its one channel
Stop itChoose Stop on its rowChoose Revoke access in the chat

Access ends for every agent in the workspace when someone is removed from a channel or the workspace, or, in a managed workspace, added to a team or channel, when a channel is archived or offered to a new owner, and when the workspace's privacy or institution changes. Deleting a channel or a team ends the access of agents that read it. A change to your own connection's privacy, settings or institution ends your own chats' access. Renaming a team, a channel or the workspace does not.

Ask my agent

  1. Open the pane In the channel that should get the result, choose Ask my agent, the robot icon left of Send.
  2. Write the task Type it in Task. Enter starts a new line.
  3. Check the model Model starts on your model for Crew tasks, which Settings → Models → Crew tasks sets. Choose Change for another. To let the agent read other channels, open Advanced and tick them under Also read.
  4. Start it Choose Start my agent and allow posting here. The task's row in the channel shows its status, such as "Working…".

Crew posts your whole task in the channel, so do not paste data you would not post there yourself. "Waiting for your approval" means the agent needs your answer: choose Review. The result ends with a line from Crew that names the shared files the task read, or says it read none. Trust that line over the agent's words.

You can also start a task from the message box: type @agent, /agent or /task at the start of a message, then the task, and press Enter. The line under the text says which model starts and what the task reads. As with Ask my agent, Crew posts the whole task in the channel.

Connect a chat with /crew

The chat needs at least one sent message, a model, no reply in progress, and no attachments in its message box.

  1. Type /crew Type /crew alone in the chat's message box and press Enter. Nothing is sent to the model.
  2. Check the pane Crew opens at the channel you last had open, with the Chat access pane. It names the channel, the workspace and the chat's model. For another channel, choose it in the Crew sidebar, then Review access. To let the chat read more channels, open Advanced and tick them under Also read.
  3. Allow Read what the pane says the chat will be able to do, then choose Allow. The pane shows "Connected." and the time access ends.
  4. Go back to the chat Choose Back to chat. The chat shows a "Crew · #methods" chip and Revoke access.

The chat can read its channels and their files, post in its one channel, and with a private model use the server as your connection allows. It cannot use other Biorouter tools, such as the shell or files on your computer, and these limits stay after its access ends. The first access fixes the chat's workspace, channel and model for good. To end access, choose Revoke access, then Revoke. Deleting a chat does not revoke its access.

Which models may read

ModelProtected contentOther content
Local, such as Llama Server or Ollama, or approved for the workspace's institutionAllowedAllowed
Private, approved elsewhere or stating no institutionRefusedAllowed
PublicRefusedAllowed, except anything on the server
Claude Code or CodexRefusedRefused

Workspaces start Private, so you usually need a local model or one approved for your institution. A model is approved when its provider carries your institution, as the Versa providers on the Institutional tab carry UCSF. You cannot approve one yourself. Both panes say why a model will be refused before you start.

Agents on the server

Each connection says what your agents may do on the lab server. Choose it when you join or host, or later in Connection settings… in the workspace menu. It applies to every task and connected chat through that connection, and only with a local model or one approved for the workspace's institution.

LevelWhat your agent may do
OffNothing on the server.
In a folderReads and writes one folder. With Let my agent run commands in this folder, it also runs commands there. They have no network, cannot start other programs, and need Linux 6.2 or newer on the server.
As me on the serverRuns commands as your own account, with your files, programs and network. Long work can run as a job that keeps running after the task ends, and the agent can copy files between the channel and the server.

A new connection starts at As me on the server. Your agent can then read and change anything your account can, and other people's messages and files can try to steer it, so use a private model you trust. If you host the workspace from that account, it can also read channels you are not in.

Before it works on the server, every member's agent reads the workspace context: a short page about the server, such as where data lives, which software is there and how jobs run. Crew drafts it from the server when the workspace is created. In an open workspace every member edits it on the Context tab of "chen-lab settings", and in a managed one only the host does. More in Agents and chat access.

Limits

A file can be up to 1 GiB, one computer runs at most four agent tasks at once, and a workspace keeps up to 16 MiB of state and 10 GiB of shared files. Workspace limits lists the rest.

Command line

The biorouter crew commands reach the same workspaces as the app, on macOS and Linux. Add --help after any command for its options.

  • setup installs Crew in your server account and connects. On a new connection it also gives agents As me on the server; add --agent-access folder or off for less. doctor --server LOGIN checks a server without changing anything. defaults set --provider PROVIDER --model MODEL sets the model Crew tasks start on, and connections set-access off, folder or full sets what agents may do on the server.
  • Workspace and credentials commands start the background service when needed and connect without a daemon approval secret. --no-start connects only to an existing service. daemon status checks the status without starting it.
  • Setting up or unlocking a Crew vault still asks for its passphrase. In a script, --passphrase-stdin reads that passphrase from the first line of standard input.
  • --approval-key-stdin remains accepted for older scripts: it reads and ignores the first line of standard input. It cannot be combined with --passphrase-stdin.
  • --connection NAME chooses a saved connection when you have more than one.
  • --output-format json prints JSON, errors included, with a code to match on. Exit status is 0 for success, 1 for a failure or refusal, and 2 for a wrong command line or a command that needed a terminal.
# Join a workspace
biorouter crew connections \
  join-invitation ./lab.txt
biorouter crew setup
biorouter crew join

# Post, then start an agent task
biorouter crew send methods \
  --text 'Plate reader data is in.'
biorouter crew ask methods \
  Summarize this week

privacy set-personal public and privacy set-workspace public ask you to type the workspace name first, as the desktop app does. In a script, add --confirm WORKSPACE. More in Command line.

When something goes wrong

If Crew says a feature needs a newer background service, quit and reopen Biorouter. On macOS and Linux it replaces the older service. For command-line use, run biorouter crew daemon stop, then your command again. An open app starts a new service and reconnects automatically.

If Crew says "Crew isn’t set up for your account on lab.example.edu", choose Set up Crew for my account, and Biorouter installs it.

The status row names your connection's state, such as Connected, Offline or Sign-in needed, and the main area or the connection bar says what to do next. After a network drop, Crew reconnects by itself for up to an hour, and it never sends a message twice. If the server's identity changed, do not connect. Copy the details for your IT team instead. Connections and troubleshooting lists every status and message.

Server setup for administrators

The host's copy of biorouter-crew keeps the workspace in files owned by the host's account and checks every request. Each member's Biorouter starts the same program in the member's own account over SSH, which passes requests to the host's copy through a Unix socket under /tmp. Crew needs no root, no system service, no open network port and no database.

  • Linux on x86_64 with glibc 2.31 or newer, and a valid /etc/machine-id owned by root.
  • A local disk for the workspace's state. NFS, CIFS and SMB are refused.
  • An ordinary account for the host, and each member's own account on the same machine.
  • Linux 6.2 or newer (Landlock ABI 3) for agents that run commands In a folder. On an older kernel, such as Ubuntu 22.04's original 5.15 kernel, they run commands only with As me on the server.

Biorouter installs biorouter-crew in ~/.local/bin of each account itself, over SSH, when that person joins or hosts. It sends its own copy, which ships with the desktop app and the biorouter-cli packages, and needs no administrator rights. biorouter crew doctor --server LOGIN checks a server first and changes nothing. Nothing starts the workspace when the server boots, so after every restart the host runs start again. Crew has no backup tool. SSH encryption alone does not make a deployment HIPAA compliant: your institution decides approval, retention and backup. Administration has the manual install, the full requirements and the upgrade steps.

The agent loop

Each request runs as a loop of model calls and tool calls. Biorouter runs the loop, so it decides what the model sees and what may run.

How a turn runs

Build contextinstructions, tools, history
Modelanswers, or asks for a tool
tool call result
Run a toolafter the permission gate
The loop ends when the model answers without asking for a tool and no check sends it back. A simple question needs one model call and no tools.
StageWhat happens
ReceiveOne turn runs in a chat at a time. A message you send while it runs waits in a queue; see Steering a running turn. Commands such as /goal and /schedule are handled before the model is called.
Build contextThe system instructions (base instructions, permission mode, date, guidance from each extension, any workflow instructions), the tool list, the skills in use, up to five passages from a knowledge base you referenced with /kb:, a map of the working folder of up to about 2,000 tokens, and the conversation so far. At 80% of the model's context window, older turns are summarized for the model; your history is kept in full.
Call the modelThe reply streams back as text, tool calls, token counts and a reason for stopping. A reply cut off at the length limit is continued up to 12 times.
Permission gateEach tool call is checked by the administrator's managed policy, the command policy, your permission mode and any hooks. Deny is checked before ask, and ask before allow; an administrator's deny or ask always wins. A few destructive commands are refused in every mode. The modes are on the Security page. Up to 8 tool calls run at once; writes to the same file run one at a time.
Run and returnThe result goes back to the model. A large result is saved to a file, and the model gets a preview. Private keys and stored credentials in a result are withheld. An error goes back as an error the model can act on, not as the end of the turn.
FinishWhen the model answers without a tool call, the active checks run: a workflow's response schema, Stop hooks and a /goal. A failed check sends the turn back to work. A Stop hook can do this 5 times, and a /goal is dropped at the limits in Goals. A workflow's retry checks run after the chat finishes, and a failure starts the run again from the beginning. The whole turn is saved to the chat.

Loop limits

Several checks watch a long turn for repetition and runaway cost. Most warn the model first.

  • Exact repeats. The same call with the same arguments and no changing result: a warning at 3, and the fifth identical call is refused. New successful results reset the count.
  • Near repeats. Nearly the same calls, or a repeating sequence of calls, with no progress: a warning at 4 and a persistent cycle is refused at 8. Changing successful results and waits on running work reset the count.
  • Repeated failure. The same failure from the same tool: a nudge at 3, then “change approach or ask the user” at 5. After 6, the next call to that tool is refused.
  • Failures in a row. Failed calls to any tool: a nudge at 3. At 6, the model is told to change route or hand the work back to you.
  • Stalls. A check for a stall after 30 actions in one turn, then every 10. A confirmed stall gets a short grace period to answer, then the turn stops.
  • Work without your input. Ordinary chats have no fixed turn or tool-call limit by default. Existing positive limits are kept. Choose Unlimited in Settings → Chat → Approvals, or set either limit to 0, to remove it. Quick reasoning effort halves positive limits, and Deep doubles them; Unlimited stays unlimited. Set BIOROUTER_MAX_TURNS or BIOROUTER_MAX_TOOL_CALLS to change them; the command line also takes a turn limit for one run (see Command line). A message you add to the turn resets both counts.
  • Reply budget. A limit on the time, tokens or cost of one reply. Off by default. Set BIOROUTER_REPLY_BUDGET_SECONDS, BIOROUTER_REPLY_BUDGET_TOKENS or BIOROUTER_REPLY_BUDGET_USD for a warning, a request to wrap up, then a stop.

Delegation and several chats

Subagents

Ask in plain language, for example “Have a subagent check the QC report while you draft the methods.” A subagent is a separate chat that runs one task and reports back to the chat that started it. Several can run one after another or in parallel. In the desktop app each one opens in a background tab marked as a subagent, where you can read it as it works, type to steer it, and stop it. Closing the tab does not stop it. If you typed into it, the parent is told.

  • A subagent has the parent's extensions unless you name fewer, 25 turns (BIOROUTER_SUBAGENT_MAX_TURNS) and 5 minutes by default.
  • It cannot start subagents of its own, change the parent's extensions, or change schedules.
  • It never moves work across the privacy boundary. A public chat cannot start a subagent on a private model, and a private chat cannot start one on a public model. A public subagent is given no private data extensions, and the parent is told which were left out. See Private and public.

The subagent tool is offered only when all five of these hold. If a request for a subagent gets an ordinary answer, check them in order.

  1. The permission mode is Autonomous (the default).
  2. The model's name does not start with gemini.
  3. The chat is not itself a subagent.
  4. At least one extension besides Workspace Control is turned on.
  5. The chat is not a built app that delegates to its own worker profiles.

Workspace Control

Workspace Control lets the agent work across your chats. It is on by default. To turn it off for new chats, use Settings → Chat → Capabilities in the app, or run biorouter configure in a terminal and choose Toggle Extensions, then workspace. The agent can:

  • open a new chat in a tab, a split pane or a new window. New tabs open in the background and start in your working folder.
  • list what is running, and read another chat as a summary, a transcript, its tool calls or a subagent's starting instructions. A public chat cannot read a private one.
  • send a prompt into another chat and wait for it to finish.
  • change another chat's extensions, skills, model or knowledge bases.

Some changes show a confirmation card in every permission mode: giving a chat an extension that can start programs, removing one that matters for security, switching its model provider, or adding a skill. The changed chat shows who changed what. The first time a private chat writes into a public chat, Biorouter shows you what it would send and asks first.

LimitValue
Panes in one window6
Subagent tabs from one parent at once4. More subagents run without a tab. Turn on Show subagent runs in History to see them under the parent.
Subagents running at once8. More wait for a free slot.
Chats one chat can drive at once4

From a terminal:

# chats, with their subagents
biorouter session list --subagents
# follow a running chat
biorouter session attach <id>

attach needs a biorouterd this terminal can reach, and the desktop app's own service is not one. Command line covers the session commands.

Steering a running turn

You do not have to wait for a turn to finish. A message you send while it runs waits in a queue above the text box. Each queued message has two buttons, named by their hover text:

  • Add now, “Add to the running turn without stopping”, adds the message to the running turn without stopping it. With the text box empty, Cmd+Enter (Ctrl+Enter on Windows and Linux) does the same for the first message in the queue.
  • Stop & send, “Stop the running turn, then send this”, stops the turn and sends the message as a new one.

An added message reaches the model at the next safe point. A running tool is never cut off for it. If an approval card is waiting, the message waits until you answer the card, because a message never answers a card. If the turn ends before the model reads it, the message stays in the chat marked as not answered. A message with attachments cannot be added to a running turn; it waits, or you can use Stop & send.

A browser opened with biorouter serve cannot add messages to a running turn, and neither can any other client of that service. Stop still works. Use the desktop app. biorouter session attach can add to a running turn only on a service started with a user action key; see Command line.

Goals: /goal

/goal keeps the agent working until a condition you can check is true.

/goal the notebook runs with no errors

Work starts at once. Each time the agent tries to finish, an evaluator reads the recent part of the chat and checks the condition. If it is not met, the evaluator's feedback goes back to the agent and the turn continues. After 20 evaluations, or when the evaluator gives nearly the same feedback 3 times in a row, the goal is dropped and the agent reports what it did, what is unfinished and what stands in the way.

/goal on its own shows the active goal, and /goal clear removes it. The goal is saved with the chat, so it survives a restart. Write the condition as an end state the agent can show, such as a file that exists or a test that passes.

Configuration

Biorouter keeps its settings in one YAML file that the app and the command line share. This page lists the files Biorouter writes, the environment variables it reads, and which source wins.

The settings file

~/.config/biorouter/config.yaml holds the provider and model, the permission mode, turn limits, the extensions under the extensions key, and the other general settings. The app writes it when you change Settings, biorouter configure writes it from a terminal, and you can edit it by hand.

BIOROUTER_PROVIDER: llamacpp
BIOROUTER_MODEL: qwen3.8-27b
BIOROUTER_MODE: smart_approve
BIOROUTER_MAX_TURNS: 0

Credentials are kept elsewhere; see Security. biorouter info -v prints the values stored in config.yaml.

Where files live

The paths below are for macOS and Linux. On Windows, the settings sit in %APPDATA%\UCSF\biorouter\config, everything else, logs included, in %APPDATA%\UCSF\biorouter\data, and the cache in %LOCALAPPDATA%\UCSF\biorouter\cache. Earlier releases used a different folder on Windows. The desktop app moves it there when it starts, once no other Biorouter program is using it, and updates the paths saved inside it. If both folders exist, Biorouter uses the new one, leaves the old one as it was, and says so when it starts. biorouter info prints the paths on your computer.

WhatPath
Settings~/.config/biorouter/config.yaml
Tool rules~/.config/biorouter/permission.yaml: always allow, ask or never allow, for single tools
Secrets~/.config/biorouter/secrets.yaml, only without a credential store
Privacy switch~/.config/biorouter/privacy-tiers.json: whether private and public protection is on
Workflows~/.config/biorouter/workflows/
Skills~/.config/biorouter/skills/
Installed extensions~/.config/biorouter/extensions/
Knowledge bases~/.config/biorouter/knowledge/
Global memories~/.config/biorouter/memory/
Built apps~/.config/biorouter/agent_drafter/
Chats~/.local/share/biorouter/sessions/sessions.db
Schedules~/.local/share/biorouter/schedule.json, with a copy of each scheduled workflow in scheduled_workflows/ beside it
Logs~/.local/state/biorouter/logs/

An administrator's policy file sits outside your profile; see Managed policy. BIOROUTER_PATH_ROOT moves everything above under one folder, in config/, data/ and state/.

Which setting wins

When the same setting comes from several places, the first of these wins:

  1. Managed policy, for the tool permissions and hooks it names.
  2. Environment variables, for the program that starts with them.
  3. config.yaml.
  4. Defaults.

For example, BIOROUTER_MODE=chat biorouter starts a terminal chat in Chat only mode and leaves the file alone. Most settings in config.yaml, such as those in the first table under Environment variables, can also be set as a variable of the same name. The variables in the second table work only from the environment.

When a change takes effect

  • config.yaml is checked each time a setting is read, so a change from the app, biorouter configure or an editor is seen at the next read, without a restart.
  • A chat takes its permission mode and the managed policy when its agent starts. Open a new chat to be sure a change applies.
  • Environment variables are read by each program when it starts. A command sees your shell's variables. When the desktop app starts its background service, it passes the environment it was opened from, so an app opened from the Dock or the Start menu does not see a variable set only in a terminal.
  • Secrets are read from the credential store once per process. A key saved in the app is used at once. A key changed by another program is read when Biorouter's background service next starts.
  • On macOS and Linux the background service keeps running after you quit the app, until the computer restarts. It keeps the environment and the secrets it started with, so a variable or a key changed by another program reaches it only once the service restarts. To restart it, run biorouter crew daemon stop; an open app starts a new service and reconnects. See The background service.

Environment variables

These settings can be written in config.yaml or set as a variable. The variable wins.

SettingWhat it does
BIOROUTER_PROVIDERThe provider, for example llamacpp. Names are on Models and providers.
BIOROUTER_MODELThe model, for example qwen3.8-27b.
BIOROUTER_MODEThe permission mode: auto (the default), approve, smart_approve or chat. See Permission modes.
BIOROUTER_MAX_TURNSTurns the agent may take without you. Default 0 means Unlimited; a positive value sets a limit.
BIOROUTER_AUTO_COMPACT_THRESHOLDThe share of the context window at which a chat is summarized. Default 0.8; 0 turns it off.

These work only as environment variables. Written in config.yaml, they have no effect.

VariableWhat it does
BIOROUTER_MAX_TOOL_CALLSTool calls the agent may make without you. Default 0 means Unlimited; a positive value sets a limit.
BIOROUTER_SUBAGENT_MAX_TURNSThe turn limit for a subagent. Default 25.
BIOROUTER_CONTEXT_LIMITOverrides the model's context window, in tokens. Useful for a model Biorouter does not know.
BIOROUTER_DISABLE_KEYRINGAny value keeps secrets in secrets.yaml instead of the credential store.
A key's own name, such as OPENAI_API_KEYSupplies that secret, ahead of the stored one.
BIOROUTER_SHELL_SANDBOXoff (the default), auto or strict. See Shell sandbox.
BIOROUTER_WORKFLOW_PATHMore folders to search for workflows, separated by : on macOS and Linux and by ; on Windows.
BIOROUTER_WORKFLOW_SCAN_WORKING_DIR1 also lists workflows found loose in the working folder. Off by default.
BIOROUTER_PORTThe port of the biorouterd that live session commands reach. Default 3000.
BIOROUTER_SERVER__SECRET_KEYThe API key those commands and that service share. See Sessions.
BIOROUTER_PATH_ROOTKeeps all settings, data and logs under one folder. Useful for tests and for separate setups.

The variables for browser access are on Browser access. Settings for single providers, such as OLLAMA_HOST, are on Models and providers.

Architecture

Biorouter has three layers: the interface you use, the agent that reasons and acts, and the extensions that give it tools. In the desktop app and the browser, the agent runs inside a background service, biorouterd.

Three layers

Desktop appElectron and React
Browserbiorouter serve
Command linelive session commands
biorouterdThe background service, reached over HTTP and WebSocket. The agent runs here: the loop, chats, model calls, workflows and schedules.
ExtensionsMCP servers that give the agent its tools
Model providersLocal, Institutional or Public
Crew brokerbiorouter-crew on a lab server, over SSH
Model providers and the Crew broker are services biorouterd connects to. They are not extensions.
  • Interface. The desktop app, a browser opened with biorouter serve, or the biorouter command line. It shows the conversation and holds no reasoning of its own.
  • Agent. The loop that sends the conversation to a model, runs the tools the model asks for and returns the answer, together with chat history, the connections to model providers, and the running of workflows and schedules. See The agent loop.
  • Extensions. Servers that speak the Model Context Protocol (MCP), the open standard for giving a model tools. An extension that ships with Biorouter and one you install look the same to the agent. See Extensions and skills.

The background service

biorouterd serves the agent over local HTTP and WebSocket. The desktop app starts one for all of its windows. Schedules run inside it, so they run while it runs.

On macOS and Linux the background service keeps running after you quit the app, until the computer restarts; see Crew. On Windows it stops when you quit. The shared service starts and connects automatically, without a daemon approval secret. After an update, opening the app replaces the older service; this can interrupt a running task or transfer.

The same release adds Crew, which connects the service to a lab workspace. The host runs the workspace with biorouter-crew on a shared Linux server, and each member's service reaches it over SSH through that member's own account on the server. Each member's agent still runs on their own computer, with their own model.

How each interface connects

InterfaceHow it reaches the agent
Desktop appThe app's main process starts biorouterd, and each window talks to it over HTTP and WebSocket, through a client generated from the service's OpenAPI description.
Browserbiorouter serve starts biorouterd, which serves the same interface from its own address. See Browser access.
Command line, on its ownBy default, biorouter session and biorouter run start the agent inside the terminal's own process. session list, export, rename and remove use the chat store directly. Nothing else needs to run.
Command line, livesession send, watch, attach and cancel talk to a running biorouterd, because a turn in progress exists only inside the service running it. See Sessions.
Command line, sharedWith --shared-daemon, biorouter session and biorouter run use the same background service as the desktop app, as biorouter crew does.

The app and the command line share one settings file, one credential store and one chat store, so a provider, an extension or a chat set up in one appears in the other. See Where files live.

The code

The backend is a Rust workspace. The desktop app is Electron, React and TypeScript, in ui/desktop.

PartCrate
Agent librarybiorouter holds the loop, model providers, chats, privacy, workflows and schedules, and capabilities such as Code Execution, Skills, Todo, Chat Recall and Workspace.
Background servicebiorouter-server builds biorouterd and its HTTP and WebSocket API.
Command linebiorouter-cli builds biorouter.
Bundled extensionsbiorouter-mcp holds Developer, Biorouter Copilot, Web & Documents, Memory, Auto Visualiser, Knowledge and Agent Drafter, plus the data, files and compute servers that built apps use.
Shell sandboxbiorouter-sandbox. See Shell sandbox.
Crew brokerbiorouter-crew builds the biorouter-crew program for Linux.
Editor supportbiorouter-acp adds Agent Client Protocol support, so programs such as code editors can drive Biorouter through biorouter acp.
macOS promptbiorouter-authprompt shows the macOS authentication prompt that the background service cannot show itself.
Testsbiorouter-bench holds benchmarks, and biorouter-test holds integration tests.

The source is on GitHub, under the Apache 2.0 license.

Community

Ask on Slack.

Researchers and the developers who build Biorouter answer there.

Join the Slack