Introduction Download Documentation BAAM About

Installation and setup

Get BioRouter running in three steps: download, install, and connect an AI provider. The whole process takes about five minutes.

1

Download BioRouter

Download the installer for your platform from the Download page or from GitHub Releases.

  • macOS: Open the .dmg and drag BioRouter to /Applications
  • Windows: Unzip and run BioRouter.exe
  • Linux (Debian): sudo dpkg -i biorouter_*.deb
  • Linux (RPM): sudo rpm -i BioRouter-*.rpm
macOS tip: If you see a security warning on Apple Silicon, run chmod 755 ~/.config in Terminal and relaunch.
2

Connect an LLM provider

BioRouter will guide you on first launch. Choose the option that fits your needs:

  • UCSF users: Select Azure OpenAI (UCSF ChatGPT) with endpoint https://unified-api.ucsf.edu/general, deployment gpt-5.2-2025-12-11, and your Versa API key. Or select Amazon Bedrock (UCSF Anthropic). Full details are in the UCSF setup guide.
  • Commercial API: Enter your Anthropic, OpenAI, or Google API key.
  • Fully local: Select Llama Server to use BioRouter's bundled llama.cpp runtime with no extra install, or select Ollama if you already run it. No API key, no data leaves your machine.
3

Verify and explore

Send a test message in the chat. If BioRouter responds, you're set. Open the Extensions sidebar to add agents, enable tools, and start building workflows.

Configuration file

All settings are stored in:

~/.config/biorouter/config.yaml    # macOS / Linux

API keys are stored encrypted.

Troubleshooting

IssueSolution
No window on launch (macOS M-chip)chmod 755 ~/.config then relaunch
Extension fails to activateEnsure Node.js (npx) or Python/uv (uvx) is installed
API key not workingVerify the key is valid and has available quota
Logs~/.config/biorouter/logs/

UCSF setup guide

BioRouter is built for UCSF researchers. Use your institutional AI access for secure, compliant workflows with managed models.

Option A: UCSF Versa / Azure OpenAI (recommended)

UCSF's institutional AI platform, accessed via Azure OpenAI. Get your API key at:

ai.ucsf.edu/platforms-tools-and-resources/ucsf-versa

  1. In BioRouter, go to Settings, Models, Azure OpenAI, Configure
  2. Enter the endpoint and credentials below, then click Save
  3. Click Launch to start chatting
FieldEnvironment variableValue
EndpointAZURE_OPENAI_ENDPOINThttps://unified-api.ucsf.edu/general
Deployment NameAZURE_OPENAI_DEPLOYMENT_NAMEgpt-5.2-2025-12-11
API VersionAZURE_OPENAI_API_VERSION2025-01-01-preview
API KeyAZURE_OPENAI_API_KEYYour UCSF Versa API key
Where to get your Versa API key: Sign in with your UCSF MyAccess credentials at the link above to generate or retrieve your API key.

Data stays within UCSF's Azure tenant, safe for institution-approved use cases.

Option B: Amazon Bedrock (UCSF MuleSoft proxy)

UCSF provides access to Anthropic Claude models via Amazon Bedrock, routed through the UCSF MuleSoft gateway. Your data does not leave UCSF's infrastructure. BioRouter handles credential configuration for you; you only enter two values.

Step 1: Obtain your credentials

The UCSF Bedrock proxy uses a static AWS Access Key and Secret Key pair. These are not personal AWS SSO credentials. Obtain them from your lab's BioRouter onboarding document or contact the Baranzini Lab or UCSF Research IT for access.

What you needNotes
AWS Access Key ID32-character hex string provided by UCSF
AWS Secret Access Key32-character mixed string provided by UCSF
That's it. BioRouter fills in the region (us-west-2) and UCSF proxy endpoint, and handles credential persistence across shell, ~/.aws files, and the macOS system environment. You don't need to run any scripts.

Step 2: Enter credentials in BioRouter

  1. Go to Settings, Models, Amazon Bedrock, Configure
  2. Enter a Profile Name (any name, e.g., UCSF Bedrock)
  3. Enter your AWS Access Key ID
  4. Enter your AWS Secret Access Key
  5. Click Save. BioRouter writes the necessary credential files and injects environment variables at the OS level.

Step 3: Launch and verify

  1. Set Model to us.anthropic.claude-opus-4-6-v1 (default)
  2. Click Launch and send a test message to verify

Available models

ModelModel IDNotes
Claude Opus 4.6 · defaultus.anthropic.claude-opus-4-6-v1Highest permitted UCSF Bedrock capability
Claude Sonnet 4.6us.anthropic.claude-sonnet-4-6Good speed and capability balance
Claude Opus 4.5us.anthropic.claude-opus-4-5-20251101-v1:0High-capability previous generation
Claude Haiku 4.5us.anthropic.claude-haiku-4-5-20251001-v1:0Fast, lower-cost option

Only models permitted by UCSF's IAM policy are listed; selecting others returns an authentication error.

Troubleshooting

ErrorCauseFix
"The security token included in the request is invalid"BioRouter is hitting real AWS (not the UCSF proxy) because the endpoint variable is missingRe-run the setup; quit and relaunch BioRouter
"invalid model identifier"Model ID is not one UCSF's proxy currently acceptsUse a model ID exactly as listed in the table above
Authentication error after configuringlaunchctl vars not set; the app doesn't inherit shell env until relaunchedFully quit and relaunch BioRouter
"AccessDeniedException" on a specific modelModel not permitted by UCSF IAM policySwitch to one of the four confirmed models above

Option C: Local (air-gapped)

For maximum privacy. Nothing ever leaves your device:

  1. Select Llama Server to use the bundled local runtime. BioRouter downloads the model weights on first use and runs inference on-device.
  2. Or install Ollama, pull a model such as qwen3, and select Ollama.
  3. No API key is required for either local path.

Other institutions

Check with your institution's IT or compliance office for approved AI hosting options. For institutions without managed AI services, commercial API keys (Anthropic, OpenAI) or local inference with Llama Server or Ollama are options. Always verify compliance before processing any sensitive data.

Patient data and PHI: Never use personal commercial API keys with patient data, PHI, or other regulated research data. Use UCSF-managed services (Azure, Bedrock) or a local model only. Always verify with UCSF compliance before processing regulated data.

Providers and models

BioRouter connects to a range of LLM providers. Switch providers any time from Settings → Models without changing your workflows. Defaults below reflect biorouter v1.86.0.

UCSF institutional providers

ProviderAccessDefault model
Versa Azure OpenAI (UCSF ChatGPT)UCSF Versa API key · Setup guide →gpt-5.2-2025-12-11
Versa Bedrock (UCSF Anthropic)UCSF Versa credentials · Setup guide →us.anthropic.claude-opus-4-6-v1

Commercial cloud providers

ProviderEnv variableDefault modelGet API key
AnthropicANTHROPIC_API_KEYclaude-opus-4-8platform.claude.com
OpenAIOPENAI_API_KEYgpt-5.5platform.openai.com
Azure OpenAI (own tenant)AZURE_OPENAI_API_KEYgpt-5.4-2026-03-05Your Azure portal
Google GeminiGOOGLE_API_KEYgemini-3.1-pro-previewaistudio.google.com
X.AI (Grok)XAI_API_KEYgrok-4.3console.x.ai
OpenRouterOPENROUTER_API_KEYanthropic/claude-sonnet-4.6openrouter.ai
Amazon Bedrock (own AWS)AWS IAM credentialsus.anthropic.claude-sonnet-4-6Your AWS console

Every provider exposes its full model list once configured. The defaults above are what BioRouter selects when no model is specified.

More providers

BioRouter also ships connectors for many additional platforms. Configure any of them from Settings → Models:

  • Enterprise / cloud: Databricks, Google Vertex AI (GCP), Amazon SageMaker, Snowflake Cortex, GitHub Copilot, Tetrate Agent Router, Venice.ai.
  • Proxies & gateways: LiteLLM (with prompt caching), OpenRouter.
  • Fast inference: Groq, DeepSeek, Mistral AI, Inception (Mercury).
  • Open-weight model labs: Z.AI (GLM), Xiaomi MiMo, Venice.ai.
  • Local CLI agents: Claude Code, OpenAI Codex, Cursor Agent, and Gemini CLI can be driven as providers too.

Run biorouter models providers to see the full, current list with default models. Several providers are defined declaratively, so the catalog grows without app updates.

Multimodal (image) input

Vision-capable models (across Anthropic, OpenAI, Gemini, Bedrock, and Databricks) accept image attachments in the desktop chat. BioRouter gates image upload per session based on the active model's capabilities.

Local models — zero setup

BioRouter ranks Local models ahead of institutional and commercial providers everywhere, because nothing leaves your machine. There are two ways to run them, and the first needs nothing installed at all.

Llama Server (bundled, recommended)

The desktop app ships a pinned llama.cpp llama-server binary and manages it as a sidecar process — so you can run capable local models without installing Ollama or anything else. Pick Llama Server in onboarding or Settings → Models, choose a model, and BioRouter downloads the weights from Hugging Face on first use and starts the server for you.

  • Curated catalog of Qwen 3.5 and Gemma 4 models (Q4_K_M from verified unsloth/*-GGUF repos); default qwen3.5-4b. Any other model works too as a raw owner/repo:QUANT Hugging Face spec.
  • Reasoning on by default, a model-native context window, and a q8_0 KV cache. Per-platform builds use Metal (macOS), Vulkan with CPU fallback (Windows), and CPU (Linux); CUDA is opt-in.
  • Override anything with env vars — LLAMACPP_CONTEXT_SIZE, LLAMACPP_ENABLE_THINKING, LLAMACPP_EXTRA_ARGS, or point at your own server with LLAMACPP_EXTERNAL_HOST.

Linux note: local models need glibc ≥ 2.35 plus libssl3/libgomp1 (Debian 12+/Ubuntu 22.04+). The app itself still runs on older systems; only the bundled local models require this floor.

Ollama

If you already use Ollama, BioRouter detects it automatically — install Ollama, pull any model, and select it. Everything stays on your machine. Default model: qwen3.

ollama pull qwen3           # General-purpose default
ollama pull llama3.2        # Fast lightweight option
ollama pull deepseek-r1     # Strong reasoning model

Switching providers

Open Settings → Models, select a provider card, then Configure or Launch.

Extensions, skills, and MCP

Extend BioRouter with built-in capabilities, third-party MCP servers, and reusable skill bundles. Defaults reflect biorouter v1.86.0 (ui/desktop/src/components/settings/extensions/bundled-extensions.json).

Built-in extensions

Ship with BioRouter, no install needed. Enable or disable any of them from Settings → Extensions.

ExtensionWhat it doesDefault
DeveloperFile operations, shell commands, code search, and text editing — the core agent toolkitOn
KnowledgeIngest / query / lint your personal knowledge bases (incl. the built-in Soul base) from within any chatOn
Auto VisualiserTurns structured data into self-contained interactive HTML figures (33 chart, scientific, network, diagram, and geo tools) rendered inline in chatOff
Computer ControllerGeneral computer-control tools for non-developer workflows (web, automation, files)On
MemoryPersist preferences and context across sessionsOn
Agent DrafterAuthor interactive artifacts ("Claude artifacts" for BioRouter) that can embed a live agent over ACPOff
TutorialInteractive in-app tutorials and guidesOff

Installing a .brxt extension

BioRouter extensions are distributed as .brxt bundles: a zipped manifest plus a Python MCP server entry point. Installation is drag-and-drop; no terminal needed.

  1. Download a .brxt file from the BAAM marketplace.
  2. In BioRouter, open Settings → Extensions → Add Extension.
  3. Drag the .brxt file onto the drop zone (or click Browse file…). BioRouter validates the manifest and previews the extension's name, version, tool count, and any bundled skills.
  4. Click Next: Configure → and fill in any required environment variables (API keys, endpoints). Secrets are stored in BioRouter's keyring; non-secret values are written into config.yaml.
  5. Click Install. BioRouter unpacks the bundle, runs it via uv run --directory <installDir> <entry_point>, and enables it automatically.

Any bundled skills inside the .brxt are installed alongside the extension and appear under BioRouter → Skills.

Adding an external MCP server manually

Desktop: Settings → Extensions → Add custom extension. Pick the transport (stdio / SSE / streamable HTTP), then enter ID, name, command, args, and env vars.

Config file (~/.config/biorouter/config.yaml):

extensions:
  github:
    name: GitHub
    cmd: npx
    args: [-y, "@modelcontextprotocol/server-github"]
    enabled: true
    envs:
      GITHUB_PERSONAL_ACCESS_TOKEN: "<your_token>"
    type: stdio
    timeout: 300

Skills system

A skill is a folder containing a SKILL.md file with YAML frontmatter (name, description, optional user-invocable) and freeform instructions. BioRouter loads every skill it finds under ~/.config/biorouter/skills/, ~/.claude/skills/, and ~/.config/agents/skills/.

Built-in skills

A few skills ship with BioRouter and are installed automatically (and re-created if deleted):

SkillWhat it teaches the agent
about-biorouterAuthoritative self-knowledge — the agent answers questions about BioRouter itself (features, config, CLI, the desktop app) accurately instead of guessing.
develop-biorouter-extensionHow to build, package, and publish a .brxt extension: ZIP structure, manifest.json, the Python MCP server, and bundled skills.
develop-biorouter-skillHow to author a high-quality skill: the SKILL.md format, writing descriptions that trigger reliably, progressive disclosure, and packaging.
update-soulHow the agent maintains your personal Soul base — what to capture about you and what to discard. Used by the Daily Meditation workflow.

Installing a skill (drag-and-drop)

  1. Download a skill .zip from the BAAM marketplace (or write your own SKILL.md).
  2. In BioRouter, open Skills → Add Skill.
  3. Drag the .zip (bundle of many skills) or a single .md file onto the drop zone. BioRouter parses the frontmatter, previews the skill(s), and on confirmation copies them into ~/.config/biorouter/skills/<slug>/.

Auto-applied skills activate whenever BioRouter encounters a relevant file or task. To bypass the GUI entirely, unzip a bundle and copy the folder into ~/.config/biorouter/skills/ directly. BioRouter picks it up on next launch.

Skill folders are plain text and reproducible. Share them across a lab or institution to standardize analysis style without sharing any underlying data.

Workflows and automation

A Workflow is a portable YAML file that packages a prompt, the extensions and skills it needs, and an optional schedule. Workflows are the foundation of federated research collaboration in BioRouter: instructions travel between institutions, data does not. (Schema reference: crates/biorouter/src/workflow/mod.rs.)

Workflow YAML format

A minimum workflow needs three top-level fields: version, title, description, plus at least one of instructions or prompt. Everything else is optional.

version: 1.0.0
title: Literature review
description: Summarize recent papers on a research topic.

instructions: |
  You are a scientific literature reviewer. Read the user-supplied
  topic, search for relevant publications, and write a structured
  summary focused on clinical relevance and methodology.

prompt: |
  Summarize the past {{ years }} years of work on {{ topic }}.

# pin a provider/model/temperature for reproducibility
settings:
  biorouter_provider: versa_bedrock
  biorouter_model: us.anthropic.claude-opus-4-6-v1
  temperature: 0.2

# pre-enable extensions the workflow expects to use
extensions:
  - type: builtin
    name: developer

# activity pills shown while the workflow loads
activities:
  - Fetch papers
  - Summarize findings
  - Cite sources

# typed parameters surfaced in the app
parameters:
  - key: topic
    input_type: string
    requirement: required
    description: Research topic to review.
  - key: years
    input_type: number
    requirement: optional
    default: 3

# compose larger flows from smaller ones
sub_workflows:
  - name: cite-check
    path: ./sub-workflows/cite-check.yaml

# retry policy for transient failures
retry:
  max_attempts: 3

Running a workflow

Open Sidebar → Workflows → select a workflow → fill parameters → Run. To import a workflow file, use Workflows → Import workflow.

Creating a workflow from a session

After an exploratory chat that produced a useful result, open Workflows → Create from session. BioRouter extracts the instructions, the extensions you actually used, and the model you ran on into a fresh YAML file you can edit, share, or schedule.

Scheduling workflows

Schedules are managed separately from the workflow file via BioRouter's scheduler (Sidebar → Schedules → New schedule). Pick a workflow, give it a cron expression, and BioRouter's background service runs it on cadence, even with the desktop app closed.

cron: "0 8 * * 1"   # Every Monday at 8:00 AM

Sharing workflows

Workflow files are plain YAML text. Commit them to a shared repository, publish them on GitHub, or email them. Recipients open them with Workflows → Import workflow. No data is embedded; only the instructions, extension list, and parameter schema travel.

Data privacy guide

BioRouter routes your inputs to an LLM provider. Privacy properties depend on which provider you use. Here's how to choose the right one.

Patient data and PHI: Only use UCSF-managed services (Azure OpenAI, Amazon Bedrock) or a local model (Llama Server or Ollama) when working with patient data, PHI, or any regulated research data. Never use personal commercial API keys for sensitive data. Always verify compliance with your institution before processing regulated data.

Run local models with no extra software

The strongest privacy guarantee is keeping the data on your own machine. BioRouter makes that the default-easy path: it bundles a llama.cpp llama-server and manages it for you, so you don't need to install Ollama — or anything else — to use local models. Choose Llama Server in onboarding, pick a model, and BioRouter downloads the weights once and runs inference entirely on-device. Power users can still bring Ollama or point at their own server; either way no prompt or completion ever leaves the machine. See Providers → Local models for setup.

Provider privacy properties

ProviderData stays withinBest for
Llama Server (bundled, local)Your device only, no network after model downloadMaximum privacy with zero setup — no Ollama required
Ollama (local)Your device only, no networkMaximum privacy when you already run Ollama
UCSF Azure OpenAIUCSF's Azure tenantInstitution-approved clinical use cases
UCSF Amazon BedrockUCSF's AWS environmentInstitution-approved clinical use cases
Commercial APIs (personal)Provider's cloud infrastructureDe-identified or non-sensitive data only

Best practices

  • De-identify first. Remove names, dates of birth, MRNs, and other identifiers before any AI processing.
  • Minimize data exposure. Provide only what's needed for the task.
  • Prefer local models for exploratory work with real data.
  • Protect your device. Session logs at ~/.config/biorouter/logs/ may contain your inputs.
  • Never share sessions that contain patient or sensitive data.
  • Always verify with UCSF IT or your compliance office before processing regulated data.

Where credentials are stored

API keys and secrets are never written in plaintext by default. BioRouter supports three pluggable secret backends, selectable via secrets_backend in config.yaml (or the BIOROUTER_SECRETS_BACKEND env var):

BackendWhere secrets live
keyring (default)Your OS credential store (macOS Keychain, etc.)
encrypted-fileA passphrase-encrypted secrets.enc (passphrase via prompt or BIOROUTER_SECRETS_PASSPHRASE)
filePlaintext secrets.yaml (use only on trusted, isolated machines)

Non-secret settings live in ~/.config/biorouter/config.yaml; only secret values go to the chosen backend.

Architecture

BioRouter is a modular, plugin-based system with a Rust backend and an Electron and React frontend, connected via a local REST API.

Three-layer design

  • Interface: Desktop GUI (Electron and React 19). Accepts user input and renders responses.
  • Agent Core: Rust reasoning loop managing LLM interaction, tool execution, context, and session state.
  • Extensions: Pluggable MCP servers that provide tools: file system, databases, web, code execution, and custom agents.

Backend Rust workspace

The backend is a single Cargo workspace under crates/. Three of these crates compile to the three shipping binaries — and because the version lives in exactly one place ([workspace.package].version), the CLI, the daemon, and the core library can never disagree at build time.

CrateBinaryRole
biorouterCore agent library. The main agent reasoning loop, the 40+ LLM provider implementations, the MCP extension manager, session/conversation state (SQLite), workflow definition + execution, context-window management, the scheduler, and the built-in Knowledge service (re-exported here). Everything else depends on this.
biorouter-clibiorouterThe interactive terminal app and headless runner. Calls the core library's APIs directly; subcommands live in src/commands/.
biorouter-serverbiorouterdThe local Axum REST + WebSocket server the desktop app talks to. Routes live in src/routes/; the OpenAPI spec is generated with utoipa, and the TypeScript API client is generated from it.
biorouter-mcpThe built-in MCP servers (Developer, Computer Controller, Memory, Auto Visualiser, Tutorial, Knowledge, Agent Drafter) plus the Knowledge engine (store, git, graph, credibility, file conversion, sub-agent macros).
biorouter-acpAn Agent Communication Protocol implementation for multi-agent orchestration — one BioRouter agent can drive another (used, for example, by Agent Drafter's live artifacts).
biorouter-benchA benchmarking harness for evaluating agent and provider behavior.
biorouter-testCross-crate integration tests, including VCR-style recorded MCP cassettes.

The desktop GUI keeps its own version in package.json; a CI guard (check-version-consistency.sh) fails the build if any copy drifts from the Cargo workspace version.

Key dependencies: tokio (async), axum (HTTP), rmcp (Model Context Protocol), serde/serde_json, tiktoken-rs (token counting), sqlx/SQLite (session persistence), minijinja (workflow/recipe templates), tokio-cron-scheduler (scheduling), and a vendored libgit2 (knowledge-base history, no system git needed).

Frontend Electron and React

Desktop app: Electron 39, React 19, TypeScript, built with Vite and Electron Forge. Communicates with the local biorouterd REST API.

Model Context Protocol (MCP)

All extensions use MCP, a standard protocol for LLM tool invocation. Any MCP-compatible server (local process or remote HTTP) can be added as a BioRouter extension. This enables a growing open ecosystem of research agents.

MCP agents

BioRouter connects to local and remote MCP agents for specialized research tasks. Browse the agent ecosystem in the BAAM marketplace.

Adding an agent via desktop UI

  1. Go to Sidebar, Extensions, Add custom extension
  2. Choose type: Command-line (stdio) for local agents or Streamable HTTP for remote
  3. Enter the agent name and command (e.g., uvx --from git+https://... agentname)
  4. Add any required environment variables
  5. Click Add and enable the extension

Adding an agent via config YAML

extensions:
  spokeagent:
    name: SPOKEAgent
    cmd: uvx
    args:
      - --from
      - "git+https://github.com/BaranziniLab/SPOKEAgent"
      - spokeagent
    enabled: true
    type: stdio
    timeout: 300

Remote HTTP agents

extensions:
  remote-agent:
    name: My Remote Research Agent
    url: https://my-agent.example.com/mcp
    type: streamable_http
    enabled: true
    timeout: 300

Prerequisites

Most UCSF agents use uvx, which requires Python and uv. Install with:

curl -LsSf https://astral.sh/uv/install.sh | sh   # macOS / Linux
# or: pip install uv

Playwright MCP uses npx, which requires Node.js: nodejs.org

Available agents

Browse all available agents, copy install commands, and find GitHub links in the BAAM marketplace →

Command-line interface (CLI)

Everything BioRouter does in the desktop app is also available from your terminal through the biorouter command: a full-screen interactive chat, headless scripted runs, and management commands for models, knowledge bases, extensions, skills, workflows, and schedules. The CLI and the desktop app share the same configuration, sessions, and agent core, so they stay in lockstep.

One binary, two faces. Run biorouter (or biorouter session) for the interactive terminal UI, or use a subcommand like biorouter run / biorouter models for scripted, non-interactive work.

Installing the CLI

The biorouter CLI now ships inside every desktop download (macOS, Windows, and Linux). You get it onto your PATH in any of these ways:

  • From the desktop app: on startup the app prompts you to “Install Biorouter CLI” if it isn't already on your PATH (just like installing a missing dependency). One click symlinks/copies the bundled binary into the first writable, on-PATH location (/usr/local/bin~/.local/bin, or %LOCALAPPDATA%\BioRouter\bin on Windows).
  • From a terminal: run biorouter setup-path (alias install-cli) to do the same. If the target directory isn't on your PATH, it prints the exact line to add.
  • Headless / servers: install a CLI-only Linux package (biorouter-cli_*.deb / biorouter-cli-*.rpm). These ship just the biorouter CLI and the biorouterd server daemon to /usr/bin with no desktop GUI, ideal for servers, HPC nodes, and containers.
  • From source: cargo build -p biorouter-cli.

After installing, run biorouter doctor to check your prerequisites (git, uv, python, node, AWS CLI) with per-OS install commands, confirm the CLI is on your PATH, and check for updates. The desktop dependency setup and the CLI read the same prerequisite definitions, so they never drift.

biorouter doctor                 # prerequisites + CLI-on-PATH + update check
biorouter doctor --format json --no-update   # machine-readable, no network
biorouter setup-path             # put `biorouter` on your PATH

Launching

CommandWhat it does
biorouter · biorouter sessionStart the interactive full-screen terminal UI (default on a real terminal)
biorouter session --resumeResume your most recent session (or use --name / --session-id)
biorouter run -t "your prompt"One-shot headless run that prints the response and exits
echo "prompt" | biorouter run -i -Read instructions from a file or stdin (-i -)
BIOROUTER_CLI_CLASSIC=1 biorouter sessionUse the classic line-based REPL instead of the full-screen UI

When output is piped or redirected (not a TTY), the CLI automatically uses the classic, plain-text path so it scripts cleanly.

The interactive terminal UI

A Claude-Code-style layout: a scrolling conversation that grows downward, a pinned input box, and a two-line status bar. The greeting shows the BIOROUTER wordmark, your working directory, and a tagline.

  • Status line 1: the model and provider in use.
  • Status line 2: counts of enabled skills, extensions, and knowledge bases for this chat, plus a live context-window meter (turns amber, then red, as the window fills).
  • Tool calls render as a distinct ▸ tool call badge with the tool name and namespace, so it's obvious when the model is acting.
  • Permission prompts appear as an in-place modal: choose Allow / Always allow / Deny / Cancel.

Keyboard shortcuts

KeyAction
EnterSend the message
Ctrl+JInsert a newline (compose multi-line prompts)
/ Recall previous inputs
TabAccept the dimmed slash-command "ghost" suggestion
PageUp / PageDown / mouse wheelScroll the conversation history
Ctrl+CCancel the in-flight response; clears the line, or quits when the line is empty

Multi-line text pastes as a single block (it won't submit early), and the caret stays correctly placed even with wide characters (e.g. CJK).

Slash commands

Inside the interactive UI:

CommandAction
/help, /?Show commands and shortcuts
/compactCondense the conversation to reclaim context
/clearClear the conversation (also resets the persisted session)
/exit, /quitLeave the session

The classic REPL (BIOROUTER_CLI_CLASSIC=1) additionally supports /t (theme), /r (full tool output), /mode <auto|approve|chat|smart_approve>, /plan/endplan, /prompts, /prompt <name>, /workflow, /extension, and /builtin. Use it for elicitation-style interactive forms, which the full-screen UI defers to classic mode.

Command reference

CommandPurpose
session · sStart or resume an interactive chat session
runExecute a prompt / instruction file headlessly
configureInteractive setup wizard (providers, API keys)
modelsInspect and set the provider / model
knowledge · kbManage knowledge bases (ingest, lint, query, hide)
extension · extInstall and manage extensions (.brxt bundles)
skillInstall and manage skills (.zip)
workflowInstall, validate, list, and open workflows
schedule · schedManage cron-scheduled jobs
project · projectsOpen the last project directory / list recent ones
infoShow version, config, and path information (--verbose for config)
completion <shell>Generate shell autocompletion (bash, zsh, fish, …)
doctorCheck prerequisites (git, uv, node, …), CLI-on-PATH status, and updates (--format json, --no-update)
setup-path · install-cliInstall the biorouter command onto your PATH
web · termExperimental web chat server · terminal-integrated sessions
mcp · acpRun a bundled MCP server · run as an ACP agent
updateUpdate the CLI (--canary for pre-release)

Run biorouter <command> --help for the full flags of any command.

Models and providers

biorouter models current                       # show configured provider + model
biorouter models providers                     # list available providers
biorouter models list anthropic                # known models for a provider
biorouter models set --provider versa_azure --model gpt-5.2-2025-12-11
biorouter configure                            # interactive provider / key wizard

These read and write the same ~/.config/biorouter/config.yaml the desktop app uses.

Headless runs and output formats

biorouter run -t "Summarize the file ./notes.md in 5 bullets"
biorouter run -i instructions.txt              # read instructions from a file
biorouter run -t "..." --output-format json    # structured output for scripts
biorouter run -t "..." --output-format stream-json   # streamed JSON events

Knowledge bases from the CLI

Knowledge bases use a hide-from-the-agent model: every base is available to the agent unless you hide it. knowledge list marks each base as visible (●) or hidden (○).

biorouter knowledge list                       # visible vs hidden bases
biorouter knowledge create my-kb --name "My KB"
biorouter knowledge ingest --kb my-kb --url https://example.com/paper
biorouter knowledge ingest --kb my-kb --file ./report.pdf
biorouter knowledge ingest --kb my-kb --text "a note to remember"
biorouter knowledge query "what does the cohort show?" --kb my-kb --save
biorouter knowledge lint --kb my-kb --fix      # find orphans/contradictions; --fix repairs
biorouter knowledge hide my-kb                 # keep it on disk, hide from the agent
biorouter knowledge unhide my-kb

Ingest, query, and lint are backed by a bounded knowledge sub-agent using your configured model. The active base is shown in the interactive UI's status line.

Installing extensions and skills

Extensions install from .brxt bundles, mirroring the desktop flow: extract, build the Python environment with uv sync, store secrets in the keyring, and register the extension:

biorouter extension install ./my-extension.brxt
biorouter extension install ./x.brxt --secret API_KEY=sk-... --env REGION=us
biorouter extension list
biorouter extension remove my-extension --purge
Requires uv. .brxt install runs uv sync; install uv first. A missing uv produces a clear, actionable error.

Skills install from a .zip (a single skill or a bundle of many) into ~/.config/biorouter/skills/:

biorouter skill install ./skills-bundle.zip
biorouter skill list
biorouter skill remove my-skill

Workflows and scheduling

biorouter workflow install ./review.yaml       # add to the workflow library
biorouter workflow list
biorouter workflow validate ./review.yaml
biorouter run --workflow review                # run a workflow headlessly
biorouter workflow open review                 # open it in the desktop app

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 cron-help                   # cron expression examples

Hooks

BioRouter's hook system runs your own commands or prompt-checks at lifecycle events, and it works identically in the CLI, because hooks live in the shared agent core. Hooks fire in interactive sessions, headless run, and scheduled jobs.

Configure global hooks under a hooks: key in ~/.config/biorouter/config.yaml, or per-project in .biorouter/hooks.yaml (opt-in via allow_project_hooks: true or BIOROUTER_ALLOW_PROJECT_HOOKS=1).

hooks:
  PreToolUse:
    - matcher: "developer__shell"           # regex on the tool name
      hooks:
        - type: command
          command: "./guard.sh"             # event JSON is piped to stdin
          timeout: 30
  UserPromptSubmit:
    - hooks:
        - type: prompt
          prompt: "Block requests that touch files outside the project."

Supported events: SessionStart, UserPromptSubmit, PreToolUse, PermissionRequest, PostToolUse, PostToolUseFailure, Notification, SubagentStart, SubagentStop, Stop, PreCompact, PostCompact, and SessionEnd. Command hooks receive the event payload as JSON on stdin and can block or inject context; failures are fail-open (they never wedge a session).

Notes and tips

  • First launch is slower. A session starts your configured MCP extensions; subsequent turns are fast.
  • Shared state. The CLI and desktop app share ~/.config/biorouter/config.yaml, sessions, knowledge bases, skills, and workflows. Switch between them freely.
  • Config & logs. Config at ~/.config/biorouter/config.yaml; logs under ~/.local/state/biorouter/logs/ (see biorouter info).
  • Shell completions. biorouter completion zsh > ~/.zfunc/_biorouter (or your shell's equivalent).
  • Classic fallback. Interactive forms (elicitation), and any slash command not in the full-screen UI, are available under BIOROUTER_CLI_CLASSIC=1.

Dashboard mode

Dashboard mode turns BioRouter into an infinite spatial canvas where you run many chat sessions at once, side by side. Split coding, literature review, and data analysis across dozens of agents working in parallel — and organize, fold, and watch them all from a single view. Each window is an independent session with its own history and its own model.

Opening the dashboard

Click the grid icon in the top-left of the window chrome (next to the new-session and sidebar-toggle buttons) to enter Dashboard mode. A toolbar appears across the top of the canvas; the count of open conversations is shown on the right as “N on canvas.”

The toolbar

ControlWhat it does
SpawnOpen a new conversation window on the canvas (also ⌘⇧N). It appears focused and centered.
OrganizeResolve overlaps — tidy the windows into a clean layout and re-center the camera on the focused window.
Fold (toggle)Collapse every window into a compact card so you can see them all at once; one card stays open at a time. Toggle it back off to return to full windows.
ClearClose every conversation on the canvas.

Working with a window

Each conversation is a draggable, resizable window with a colored accent (so you can tell them apart at a glance). Its title bar has four controls on the right:

ButtonAction
Fold (—)Collapse this window into a card.
Shrink (⤡)Resize down to the minimum window size.
Enlarge (⤢)Resize up to the default comfortable chat size.
Close (✕)End this conversation and remove it from the canvas.
  • Move: drag the title bar. Resize: drag the bottom-right corner handle.
  • Focus: click any background window to bring it to the front (the focused window carries a deeper shadow).
  • Rename: double-click the window's title. (New sessions are auto-named after the first exchange.)
  • Switch models per window: each window keeps its own model, so you can run a fast local model in one and a frontier cloud model in another at the same time.

Moving around the canvas

The canvas is effectively infinite. Pan by dragging any empty (dotted) area, or with a two-finger trackpad scroll. The camera auto-centers on the active window whenever you spawn, focus, enlarge/shrink, or hit Organize — so you never lose a window off-screen. Use Organize any time things get cluttered to snap everything back into a tidy, centered arrangement.

Fold mode — see everything, run one

Turn on Fold when you have many sessions and want an overview. Every window collapses into a small card showing its name, working directory, and a status indicator — a hollow ring when idle, a gently breathing dot when the agent is busy — plus a hover preview of the latest message. In fold mode:

  • Click a card to expand it into a full window (only one is open at a time).
  • Click empty canvas to refold the open one, returning to the all-cards overview.
  • Cards still expose Expand / Shrink / Enlarge / Close controls, and you can drag them to rearrange.

This makes it easy to fire off a dozen long-running agents, fold them all into cards, watch the busy indicators, and dip into whichever one needs you — then fold it away again.

Knowledge bases

A knowledge base is a personal, LLM-maintained store of structured information: a folder of markdown pages backed by a full git history. You never hand-edit it: BioRouter reads your sources, writes cross-linked pages, classifies credibility, and commits every change. Because it's plain markdown under git, everything stays local on disk, readable, diffable, and reversible.

Local by design. Knowledge bases live entirely under ~/.config/biorouter/knowledge/. The only network calls are credibility lookups (Crossref / OpenAlex) and your configured LLM provider. Git is statically built in, so no system git is required.

How it works

Each base is a folder of markdown pages organized into four namespaces, plus a hidden git repo that records every edit:

Page kindHolds
SourcesOne page per ingested source: summary, key claims, outbound links
EntitiesProper nouns: genes, drugs, datasets, people, methods
ConceptsIdeas, mechanisms, theories
Notes / hubsAd-hoc pages and cross-cutting "hub" pages at the top of the graph

Pages cross-reference each other with Obsidian-style [[wiki-links]], which form the knowledge graph. A bounded AI sub-agent does the writing; every operation commits atomically (it lands completely or not at all), so you can browse the history and roll back at any time.

The three operations

OperationWhat it does
IngestAdd a source: a URL, a file, or pasted text. BioRouter converts it (HTML, PDF, DOCX, CSV, spreadsheets, PPTX, plain text), classifies its credibility, then writes/updates source, entity, and concept pages with cross-links.
QueryAsk a question; BioRouter searches the base (BM25 + graph) and writes a cited answer. Optionally file the answer back into the base as a new page.
LintHygiene scan that finds orphan pages, contradictions, stale sources, and missing concept pages. Run with autofix to let the sub-agent repair them.

Credibility & retraction

Every source is graded on a deterministic ladder: extract identifiers (DOI / arXiv / PMID / ISBN) → look up Crossref then OpenAlex → URL host patterns → publisher allow-list → an LLM fallback. Tiers run from peer-reviewed to preprint, book, gray literature, web, and personal. Retractions are flagged and shown as a badge on the graph. You can re-classify or override any source manually.

The knowledge graph

A force-directed graph is derived from the [[links]] in your pages. Nodes are colored by credibility tier, retracted sources are badged, and clicking a node previews its markdown. (If the graph shows nodes but no edges, the pages simply don't cross-reference each other yet.)

Visibility: active and hidden bases

BioRouter uses a hide-from-the-agent model. Every base is available to the chat agent unless you hide it; hidden bases stay fully editable but aren't searched during chat. One base is the active base (the default target for ingest/query and for chat grounding), and visibility can be scoped per chat window.

Soul: a knowledge base about you

While ordinary knowledge bases hold your sources and findings, Soul holds knowledge about the user. It's a personal, initially-empty base (id soul, a warm parchment color) that BioRouter installs the first time you run it. Instead of facts about a topic, Soul accumulates durable facts about how you work:

  • the way you approach different scientific questions,
  • the tools and extensions you reach for and how you call them,
  • the commands you run and the tool responses you actually rely on,
  • and personal details you reveal — name, role, affiliations, stated preferences and working style.

Because the chat agent reads from visible bases on every turn, a well-fed Soul means the agent gradually understands you — your conventions, your stack, your standards — and needs less re-explaining over time. Soul is just a normal knowledge base underneath: plain markdown under git at ~/.config/biorouter/knowledge/soul/, fully browsable, diffable, hideable, and reversible. If you ever delete it, BioRouter recreates it on next launch.

The Daily Meditation workflow

Soul fills itself through a built-in "Meditation" workflow driven by a built-in update-soul skill, run by a built-in scheduled job called Daily Meditation (every day at 3:00 AM local time). Each run:

  1. uses the chatrecall tool to find your real recent chat sessions (skipping scheduled-job sessions),
  2. ingests the most relevant ones into the soul base with platform__ingest_conversation,
  3. distills the high-signal, durable details about you and discards the noise (greetings, chit-chat, one-off irrelevancies),
  4. keeps Soul coherent — linking related pages with [[wiki-links]] and updating existing pages instead of duplicating.

If there's nothing new worth recording, it makes no changes. You stay in control: it appears in the Scheduler with a "Built-in" badge where you can edit its cadence, pause it, or run it on demand, and you can read or roll back everything it writes from the Knowledge change-log. To take advantage of it, simply use BioRouter normally — the more you work, the better your agent understands you. You can also trigger a reflection any time by running the Meditation workflow yourself.

Private by construction. Soul lives only on your disk under git, like every other base. What the meditation sends to your configured model is governed by your provider choice — pick a local model (Llama Server or Ollama) to keep even the reflection fully on-device.

In the desktop app

Open the Knowledge route in the sidebar, near Skills, Apps, and Settings. From there you can:

  • Create or focus a base with the ⌘K / Ctrl-K palette (id, name, color).
  • Add sources by dropping files/folders, pasting text (URLs are auto-extracted), or picking a model, then Digest Staged Sources with live, streamed progress and a Stop button.
  • Explore the graph, open the change-log to preview/restore any past commit, and export / import a base as a single .brkb archive.
  • Control chat visibility from the knowledge chip in the chat bottom menu, or scope a prompt to a base with the /knowledge slash command.

From the CLI

biorouter knowledge list                       # visible (●) vs hidden (○) bases
biorouter knowledge create my-kb --name "My KB"
biorouter knowledge ingest --kb my-kb --url https://example.com/paper
biorouter knowledge ingest --kb my-kb --file ./report.pdf
biorouter knowledge ingest --kb my-kb --text "a note to remember"
biorouter knowledge query "what does the cohort show?" --kb my-kb --save
biorouter knowledge lint  --kb my-kb --fix
biorouter knowledge hide my-kb        # keep on disk, hide from the agent
biorouter knowledge unhide my-kb

Storage layout

Each base lives at ~/.config/biorouter/knowledge/<kb-id>/:

manifest.yaml          # id, name, color, created_at, schema_version
schema.md              # maintenance instructions the sub-agent follows (editable)
index.md               # catalog of pages           log.md   # change log
knowledge/             # curated pages: sources/ entities/ concepts/ notes/
raw/<source-id>/        # original upload + derived markdown + credibility meta
.git/                  # full history (vendored libgit2)

Setup

Nothing extra to install: Knowledge ships inside BioRouter. The only prerequisite is a configured provider/model, which ingest, query, and lint use. Create your first base from the ⌘K palette (or biorouter knowledge create) and ingest a source. There are no special config keys; macros use your default provider unless you pass --provider/--model.

Hooks

Hooks run your own shell command, or an LLM-judge prompt, at agent lifecycle events: before and after tool calls, when a prompt is submitted, around compaction, at session start and end. Use them to enforce guardrails, inject context, log activity, or trigger notifications. The schema mirrors Claude Code's, so existing hook scripts port over unchanged.

Fail-open and opt-in. A crashing, timing-out, or misconfigured hook never blocks the agent; only an explicit decision does. And project-level hooks are off by default, so opening a repository can't run commands on your machine without your consent.

Two kinds of hook

  • Command hook: runs a shell command (default 60 s timeout). The event payload is piped to the command as JSON on stdin, and BIOROUTER_HOOK_EVENT, BIOROUTER_SESSION_ID, and BIOROUTER_PROJECT_DIR are set in its environment. Exit 0 = allow (stdout may be a JSON decision, or, for UserPromptSubmit/SessionStart, plain text injected as context); exit 2 = block, with stderr as the reason; any other exit = non-blocking error.
  • Prompt hook: an LLM judge (default 30 s). It receives your rule plus the event payload and answers allow/deny with a reason. Uses the agent's fast model, or a provider/model you pin on the hook.

Events

EventFiresCan block?
SessionStartFirst prompt of a session (once)context only
UserPromptSubmitWhen you submit a promptyes
PreToolUseBefore a tool runsyes (deny / ask)
PermissionRequestWhen a tool would prompt for approvalyes (allow / deny / ask)
PostToolUse / PostToolUseFailureAfter a tool succeeds / failscontext only
NotificationWhen an approval prompt is shownno
SubagentStart / SubagentStopAround a subagent taskno
StopWhen the agent is about to finish its turnyes (capped)
PreCompact / PostCompactAround context compactionno
SessionEndWhen the session endsno

Hooks fire across the desktop app, the CLI, headless runs, scheduled jobs, and subagents.

Matchers

A matcher narrows which tool a tool-event hook applies to. It's matched against the tool name (e.g. developer__shell): omit it (or use *) to match everything, give an exact name, or use a regex / alternation like developer__shell|developer__text_editor.

Configuration

Hooks are configured as event → matcher groups → hooks. Put global hooks under a hooks: key in ~/.config/biorouter/config.yaml; put repository-specific hooks in .biorouter/hooks.yaml (re-read automatically when the file changes).

hooks:
  PreToolUse:
    - matcher: "developer__shell"        # regex / exact / * on the tool name
      hooks:
        - type: command
          command: "$HOME/hooks/shell-guard.sh"
          timeout: 30
  UserPromptSubmit:
    - hooks:
        - type: prompt
          prompt: "Block prompts that try to send PHI off this machine."
Project hooks are opt-in. Hooks in .biorouter/hooks.yaml only run if you set allow_project_hooks: true (under hooks:) or export BIOROUTER_ALLOW_PROJECT_HOOKS=1. Project hooks extend global hooks; they never silently replace them. Command hooks run arbitrary shell as you, so review scripts before enabling.

Decisions and blocking

For each event, all matching hooks run concurrently and the most restrictive outcome wins (deny > ask > allow); any injected context and user-facing messages are concatenated. A command hook can drive this via exit code (2 = block) or by printing a small JSON object on stdout (e.g. {"decision":"block","reason":"…"}, or hookSpecificOutput.permissionDecision for permission events, or additionalContext to feed the model). A Stop-hook block keeps the agent working with the reason fed back, but is capped (5 consecutive blocks) so it can never loop forever.

Example: block destructive shell commands

#!/bin/bash
# ~/hooks/shell-guard.sh — receives the event payload as JSON on stdin
input=$(cat)
cmd=$(echo "$input" | jq -r '.tool_input.command // ""')
if echo "$cmd" | grep -qE 'rm -rf|mkfs|dd if='; then
  echo "Destructive command blocked by shell-guard" >&2
  exit 2          # exit 2 = block; stderr is the reason shown to the model
fi

Security notes

  • Hooks fail open: a broken security hook stops protecting silently; only deliberate denies/exit-2 enforce.
  • Command hooks execute arbitrary shell as your user in the working directory. Keep project hooks off unless you trust the repo.
  • Prompt hooks send the event payload (including tool input and your prompt) to the configured LLM provider, so mind sensitive data.