An AI research harness for Galaxy bioinformatics, built on Pi.dev.
Loom turns a working directory into a co-scientist project: ad-hoc exploration, plans, executed steps, interpretations, and follow-up plans all accumulate as markdown in a single, durable, git-tracked notebook.md. The agent reads and writes that notebook directly; there is no parallel structured-state store. When Galaxy is configured the agent surveys the workflow registry and tool catalog while drafting plans and routes individual steps to Galaxy or local execution as appropriate.
Loom is the agent brain — the Pi.dev runtime in extensions/loom/, the system-prompt context, Galaxy invocation tracking, the skills system, and the RPC contract. Run it directly from the terminal with loom (npm install -g @galaxyproject/loom) or through Orbit (in app/), the Electron desktop shell with a chat + tabbed-artifact layout.
The names trace real cosmology. The universe's large-scale structure is the cosmic web -- galaxies strung along filaments of dark matter, woven into sheets and voids. Loom weaves your research record the way the cosmic web weaves galaxies; Orbit is the electron shell you observe it from.
Future shells — a Galaxy-embedded web UI, a hosted server mode, anything else — talk to the same brain over RPC.
That web shell already has a working seed today: a browser-served build of the Orbit renderer, running the same brain over RPC, reachable from another device on your LAN -- handy for chatting from a phone, and a natural home for Galaxy interactive tools later on. It's an unauthenticated single-user dev tool for now, so keep it on a trusted network; setup and the security caveats are in web/README.md.
- You open Orbit (or run
loom) in an analysis directory. Anotebook.mdis created on first launch and committed to git. - You chat with the agent: ask questions, drop file paths, request data lookups. None of this requires a "plan" — the conversation is just a conversation.
- When you ask for a plan, the agent drafts it in chat as a markdown section, then waits for you to approve. Once you approve, it asks you to review parameters; once you approve those too, it writes the plan section into
notebook.mdand starts executing. - If Galaxy is connected, the agent considers per-step routing during drafting (does an IWC workflow match? does Galaxy have the heavy tool installed?) and tags each step
[local],[hybrid], or[remote]in the markdown. - While a Galaxy step runs, a
loom-invocationYAML block in the notebook tracks the invocation. The polling tool reads those blocks, queries Galaxy, and updates them in place when jobs finish or fail. - Multiple plans coexist in the notebook. After interpreting one analysis, ask for another — the new plan section appends below the previous one.
- Come back the next day, open the same directory, the notebook is the project. Sessions resume automatically.
Engineer-facing architecture reference: docs/architecture.md Repo conventions and developer workflow: CLAUDE.md
Brain (Loom) Shells
──────────── ──────
extensions/loom/ bin/loom.js terminal CLI
index.ts extension entry app/ Orbit Electron shell
state.ts session state (no plan) src/main/ Node.js main process
tools.ts LLM-callable tools src/preload/ window.orbit bridge
context.ts system prompt + skills router src/renderer/ chat + artifact panes
ui-bridge.ts notebook → widget chat/ streaming messages
notebook- artifacts/ notebook + activity tabs
writer.ts notebook I/O + invocation YAML files/ file tree + viewer
profiles.ts Galaxy server profiles
teams/ team_dispatch (experimental)
~/.loom/config.json shared brain config
~/.loom/cache/skills/ per-repo skills cache (24h TTL)
~/.orbit/ Orbit-specific state (window geometry, etc.)
The notebook is the durable state. Plans, decisions, results, and interpretation all live as markdown sections inside notebook.md — the agent maintains them via the standard Edit/Write tools. The only structured side-records are loom-invocation YAML blocks for in-flight Galaxy work.
Implemented and locally tested.
- TypeScript typecheck passes (root + Orbit).
- Local automated suite: 261 tests passing (notebook I/O, invocation YAML round-trip, profile / credential handling, team-dispatch, session-index, Galaxy config).
- Notebook is the source of truth -- there is no parallel plan struct to drift from it.
- Galaxy invocation polling is exercised against the deterministic state-transition rules (
all-ok → completed,any-error → failed). - Skills system fetches on demand from
galaxyproject/galaxy-skills(shipped as default). Additional skill repos are restricted togithub.com/galaxyproject/*(skill content is treated as authoritative agent instructions, so an arbitrary third-party repo would be a prompt-injection vector). - Galaxy API keys are encrypted at rest in Orbit via Electron
safeStorage; the brain receives the decrypted key as an env var at spawn time. CLI users withoutsafeStoragefall back to plaintext on disk. - End-to-end validation against a live Galaxy server is in progress.
- Three-pane layout: file tree on the left, chat in the center, tabbed artifact pane on the right (Notebook, Activity, File).
- Notebook tab: live
notebook.mdrendered as markdown with auto-refresh on file changes. Project log accumulates over time. - Activity tab: split horizontally — agent shell stream on top (live tool calls, status, stdout from
run_command), proc-monitor on the bottom (live CPU / memory / runtime for every subprocess the agent spawns). - File tab: appears when you open a file from the left tree, dismissable via
×. Previews text (Markdown, code, JSON/YAML, FASTA / FASTQ / VCF / BED / GFF / GTF / SAM / Newick / etc.), images, and PDFs. - Chat: streaming responses with thinking indicator; markdown-rendered with proper tables;
team_dispatchrich card; queue-while-streaming; numbered prompt turns (/summarize 3 5works against those numbers). - Slash-command popup appears as you type
/. Tab to autocomplete; Enter still submits past it; Esc dismisses. - Prompt history: ↑ / ↓ in the input recalls previously-submitted prompts (per-cwd, persistent).
- Galaxy connection indicator in the footer (RED dot if no API key, GREEN dot if connected). Click to open Preferences.
- Cost / token header: live in-flight cost (computed from Pi-reported
usage.cost) and token totals. - Preferences dialog (
Cmd/Ctrl+,): provider / model / API key, Galaxy credentials, default working directory, package manager, and a configurable list of skill repositories (galaxy-skills shipped as default). - First-run welcome screen: one-page setup. Skippable — you can configure later from Preferences.
- Responsive layout: at narrow widths the file tree (<900 px) and artifact pane (<700 px) auto-collapse so the chat stays usable. Toolbar buttons re-expand them.
- Keyboard accessibility:
Cmd/Ctrl+\toggles the artifact pane;Cmd/Ctrl+Btoggles the file tree;Cmd/Ctrl+,opens Preferences;Cmd/Ctrl+Oswitches working directory;Escdismisses modals; gold focus-ring on every Tab-reachable control. - Galaxy brand dark theme with Inter (body) + JetBrains Mono (code) bundled locally.
- Session continuity:
--continueon restart preserves chat history;/newstarts a clean slate; first launch in a directory with an existing Pi session auto-resumes.
Everything brain-side works through the CLI. The display is a terminal UI instead of a tabbed artifact pane; structured widget events collapse down to text summaries. Slash commands behave the same. You can use loom without ever launching Orbit.
A "project" is a working directory. notebook.md in that directory is the chronological project log: ad-hoc exploration notes, plan sections, executed steps, interpretations, new plans, and so on. Multiple plans coexist over a project's lifetime.
Plans are markdown sections like:
## Plan A: chrM Variant Calling [hybrid]
Goal: identify variants in chrM across 4 paired-end samples, compare allele
frequencies across tissues.
### Steps
- [ ] 1. **QC FASTQ** {#plan-a-step-1} — fastp adapter trim + per-base QC
- Routing: local
- Tool: fastp
- Verification: confirm fastp HTML/JSON report exists and includes per-base quality metrics
- [x] 2. **Reference index** {#plan-a-step-2} — bwa index of chrM
- Routing: local
- Tool: bwa index, samtools faidx
- Verification: confirm BWA index sidecar files and `.fai` exist
- [ ] 3. **Read alignment** {#plan-a-step-3} — BWA-MEM, paired collection
- Routing: Galaxy
- Tool: bwa-mem2/2.2.1
- Verification: poll Galaxy invocation to `ok` and inspect BAM outputs
- ...
### Parameters
| Step | Tool | Parameter | Default | Value | Description |
| ---- | ----- | --------- | ------- | ----- | -------------------- |
| 1 | fastp | min_qual | 20 | 20 | minimum base quality |Conventions:
- Routing tag in the section header:
[local],[hybrid], or[remote]. Literal so future tooling can grep. - Step status by the checkbox:
- [ ]pending,- [x]verified completed,- [!]failed. - If verification is blocked or inconclusive but the step itself has not failed, leave the step pending and record the blocker.
- Anchors
{#plan-X-step-N}so Galaxy invocation YAML can reference individual steps. - Multiple plans coexist; new plan sections append at the bottom. Old plans aren't deleted.
See docs/agent/notebook-schema.md for verification evidence requirements.
Plans don't land in the notebook on first draft. The agent is instructed to follow this order:
- Draft in chat as a markdown plan section. Not in the notebook yet.
- Wait for plan approval ("yes", "go", "looks good", etc.). If you ask for changes, the agent revises the draft in chat and asks again.
- Show the parameter table in chat, accepting inline edits ("set min_qual to 30, leave others"). Default behavior is to show all parameters per tool, not a curated subset — you decide what's worth changing.
- Wait for parameter approval.
Only after both gates pass should the agent write the plan section into notebook.md and start executing. This is prompt-level discipline, not a hard runtime lock; manual override: tell the agent "save this plan to the notebook even though I haven't approved it" if you really want to.
When Galaxy is connected, the agent surveys Galaxy resources before drafting:
- A full IWC workflow match → propose the plan as a single Galaxy invocation (mode: remote).
- Otherwise step-by-step: heavy compute (alignment, large variant calling, big assemblies) → Galaxy if the tool is available; light/exploratory (parsing, awk/sed/jq, small scripts) → local.
The three operating modes (local / hybrid / remote) are an outcome of the plan, not a configuration setting.
When an agent invokes a Galaxy workflow it embeds a fenced YAML block in the notebook:
invocation_id: abc123
galaxy_server_url: https://usegalaxy.org
notebook_anchor: plan-a-step-3
label: BWA alignment
submitted_at: 2026-04-25T15:30:00Z
status: in_progress
summary: ""
The polling tool galaxy_invocation_check_all scans the notebook for in-flight blocks, polls Galaxy for each, and applies deterministic state transitions (all-jobs-ok → completed, any-error → failed) by rewriting the YAML in place. No external state store; the notebook is authoritative.
When Loom starts in a directory that isn't already a git repo, it runs git init, drops a bioinformatics-friendly .gitignore, and marks the repo with git config loom.managed true. From then on every notebook write triggers an auto-commit, giving you:
- Full undo history.
git logshows what changed and when. - Reproducibility evidence. Timestamped, immutable record of every decision.
- Branch-based exploration. Try an alternative on a branch; compare with
git diff. - Collaboration. Push the repo to GitHub; collaborators pull, review, and continue.
If you start Loom in an existing git repo, auto-commit stays off by default -- Loom won't write commits into a project it didn't create. Opt in with:
git config loom.managed trueThe auto-created .gitignore excludes large bioinformatics files (FASTQ, BAM, VCF, etc.) plus the per-session activity.jsonl and session.jsonl sidecars, so only the notebook markdown and small artifacts get tracked.
Loom can fetch operational know-how from curated GitHub repos following the Claude-Code skills convention (top-level AGENTS.md router + nested SKILL.md files). The agent calls skills_fetch({ repo, path }) on demand.
galaxyproject/galaxy-skills is shipped as the default — when no skills are configured, Loom seeds it on first read. It covers:
- Collection manipulation (paired collections from PE FASTQ, mapping a tool over a collection, Apply Rules DSL, Galaxy Tools API patterns)
- Galaxy MCP usage and gotchas
- Workflow report templates
- Nextflow → Galaxy conversion
- Galaxy tool development
- Updating ToolShed tool revisions
Add your own repos in Preferences → Skills. Each entry is { name, url, branch?, enabled? }. The URL allowlist is https://github.com/galaxyproject/* (the agent treats fetched SKILL.md content as authoritative instructions, so arbitrary repos are a prompt-injection vector). Example:
{
"skills": {
"repos": [
{
"name": "galaxy-skills",
"url": "https://github.com/galaxyproject/galaxy-skills",
"enabled": true
},
{
"name": "galaxy-genome-skills",
"url": "https://github.com/galaxyproject/galaxy-genome-skills",
"branch": "main",
"enabled": true
}
]
}
}Loosening the allowlist means editing ALLOWED_SKILLS_PREFIX in shared/loom-config.js. Plan: a per-repo signing / pinning model before opening this up.
Fetched files cache to ~/.loom/cache/skills/<repo-name>/<path> with a 24-hour TTL -- covers offline use and reduces network round-trips on repeated reads.
Three paths, depending on what you want.
Orbit ships as a native installer that bundles its own Node runtime, uv, and Loom -- no separate prerequisites. The macOS (Apple Silicon) build is Developer ID signed + notarized, so it opens with a normal double-click; Linux ships .deb/.rpm/.zip. Both are attached to each release. Windows runs via WSL2. See INSTALL.md for per-platform steps and RELEASING.md for how a release is cut. Intel Macs and other unpackaged targets can use the developer install below.
Run the brain on the command line without Orbit. Requires Node 22.19+ and (for Galaxy MCP) uv.
npm install -g @galaxyproject/loom
loomOr run without installing:
npx @galaxyproject/loomPop into Orbit any time. Once Orbit is installed, type /orbit inside
the Loom CLI to open the current analysis in the desktop app -- same analysis
directory, same notebook, just a richer view. Orbit opens on that directory;
close the CLI (Ctrl-D or /exit) once it's up so the two don't both write the
same notebook. If Orbit isn't installed, /orbit will point you at the release
page.
Install uv if you don't already have it:
curl -LsSf https://astral.sh/uv/install.sh | shClone the repo and install both workspaces:
git clone https://github.com/galaxyproject/loom.git
cd loom
npm install
cd app && npm installLaunch Orbit:
npm start # from app/Or use the CLI:
node bin/loom.js # from repo rootFor a browser-based dev loop with hot reload (the Orbit renderer served over
the web, against the same brain), see web/README.md.
The developer install needs Node 22.19+ (matching .nvmrc) and uv on PATH. Per-OS bootstrap below.
sudo apt update
sudo apt install -y git curl build-essential
# Node.js via nvm (if not already installed)
curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
source ~/.bashrc
nvm install --lts
# uv (for galaxy-mcp)
curl -LsSf https://astral.sh/uv/install.sh | shThen the developer install steps above.
# Homebrew, if not already installed
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install node git uvThen the developer install steps above.
Orbit runs on Windows inside WSL2. From an elevated PowerShell:
wsl --install --web-download -d UbuntuReboot, set up your Ubuntu user, then inside the Ubuntu terminal:
curl -fsSL https://raw.githubusercontent.com/galaxyproject/loom/main/scripts/setup-wsl.sh | bash
source ~/.bashrc
cd ~/loom/app && npm startIf the script fails with
Could not get lock /var/lib/dpkg/lock-frontend, Ubuntu's automatic updater is running in the background. Stop it first, then re-run:sudo systemctl stop unattended-upgrades curl -fsSL https://raw.githubusercontent.com/galaxyproject/loom/main/scripts/setup-wsl.sh | bash
Keep your analysis data inside ~/ (the Linux filesystem) — /mnt/c/ paths are significantly slower across the filesystem boundary.
In Orbit, on first launch, the welcome screen asks for an LLM provider + key and (optionally) a Galaxy server. You can also click Skip — set up later and configure things from Preferences when you're ready. You need at least one of: Anthropic, OpenAI, or Google AI. Local providers like Ollama and LiteLLM work too.
In loom, the equivalent is editing ~/.loom/config.json (see Configuration) or running loom --provider anthropic and following the OAuth prompts.
loomYou: I have RNA-seq data from a drug treatment experiment — 6 samples,
3 treated and 3 control HeLa cells. The data is at GEO accession GSE164073.
Pi: I'll help you set up a structured analysis. Let me check what's
available.
[searches Galaxy IWC, finds RNA-seq DE workflow]
[searches Galaxy tool catalog for fastp, hisat2, featureCounts, DESeq2]
Drafting plan in chat — review before I write to notebook.md:
## Plan A: HeLa Drug Treatment RNA-seq DE [hybrid]
### Steps
- [ ] 1. **Quality + trimming** — fastp paired collection
- Routing: Galaxy (fastp/0.23.4)
- [ ] 2. **Alignment** — HISAT2 to hg38 paired collection
- Routing: Galaxy (hisat2/2.2.1)
- [ ] 3. **featureCounts**
- Routing: Galaxy (featurecounts/2.0.3)
- [ ] 4. **DESeq2 differential expression**
- Routing: Galaxy (deseq2/1.40.2)
Approve and I'll show you the parameter table next.
You: looks good
Pi: [shows parameter table per tool]
[...iterates with you on min-quality, threshold...]
[on approval: writes plan to notebook.md, begins execution]
Come back the next day to the same directory and everything resumes:
$ loom
Pi: Loaded notebook: HeLa Drug Treatment RNA-seq DE
Plan A is in progress (1 of 4 steps complete).
The fastp invocation finished successfully. HISAT2 alignment is queued.
Should I check_all to advance, or do you want to review the QC report first?
You can also load just the extension into Pi directly:
pi --no-extensions -e ./extensions/loomIf you're debugging the terminal path, prefer these commands before using Orbit.
cd app && npm startThe artifact pane reveals on the first agent turn. Switch tabs with the buttons at the top of the pane:
- Notebook — live
notebook.md. - Activity — agent shell stream + proc-monitor.
- File — appears when you open a file from the left tree.
Keyboard shortcuts:
Cmd/Ctrl+\— collapse / expand the artifact paneCmd/Ctrl+B— collapse / expand the file treeCmd/Ctrl+,— open PreferencesCmd/Ctrl+O— switch working directory and restart into a fresh agent session for that directory↑/↓in the chat input — recall previous prompts/— open the slash-command autocompleteEsc— dismiss modal prompts; close slash popup; cancel mid-response
Loom uses a single brain-level config at ~/.loom/config.json. Every consumer (the loom CLI, Orbit, any future shell) reads and writes it:
{
"llm": {
"provider": "anthropic",
"apiKey": "sk-ant-...",
"model": "claude-sonnet-4-6"
},
"galaxy": {
"active": "default",
"profiles": {
"default": {
"url": "https://usegalaxy.org",
"apiKey": "abc123"
}
}
},
"skills": {
"repos": [
{
"name": "galaxy-skills",
"url": "https://github.com/galaxyproject/galaxy-skills",
"branch": "main",
"enabled": true
}
]
},
"defaultCwd": "~/analyses",
"condaBin": "auto"
}All sections are optional. If llm is missing, consumers fall back to environment variables or OAuth login. If galaxy is missing, use /connect to add a server interactively -- credentials save to the config automatically. Galaxy MCP registers whenever credentials are present; the agent decides per-plan whether to use Galaxy. If skills is missing or empty, galaxy-skills is lazy-seeded.
Galaxy profiles are stored in ~/.loom/config.json under galaxy.profiles.<name>. The exact field depends on which shell wrote them:
- Orbit -- writes
apiKeyEncrypted(base64 ciphertext from ElectronsafeStorage). The decrypted key is injected into the brain process asGALAXY_API_KEYat spawn time. If a brain-side/connectwrites a plaintextapiKey, Orbit's config watcher re-encrypts it within milliseconds. - CLI (no
safeStorageavailable) -- writesapiKeyin plaintext. The file mode is tightened to0600, but the key sits at rest. Acceptable for a workstation; not appropriate for shared hosts.
The brain itself never decrypts. If only apiKeyEncrypted is present and GALAXY_API_KEY isn't in the environment, the brain logs a clear warning at startup and refuses to send Galaxy requests rather than firing the wrong key.
Orbit-specific state (window geometry, pane preferences, prompt history) lives in ~/.orbit/ so multiple shells can coexist without stepping on each other.
Environment variable overrides:
export ANTHROPIC_API_KEY="sk-ant-..."
export GALAXY_URL="https://usegalaxy.org"
export GALAXY_API_KEY="your-api-key"Galaxy credentials can also be provided via environment variables (GALAXY_URL, GALAXY_API_KEY) for CI or testing, but ~/.loom/config.json is the primary source.
If you have a tester ID, you can set it like this:
/tester-id orbit-007
Run /tester-id with no argument to see the current value. It writes only the testerId key to ~/.loom/config.json (the rest of the file is left untouched), and Orbit attaches it to any feedback you send so reports can be traced back to your session. It can also be supplied via the LOOM_TESTER_ID environment variable.
Loom works with any OpenAI-compatible API -- a hosted service like Jetstream, or a local backend like LiteLLM or Ollama.
In Orbit, open Preferences, set the provider to OpenAI-compatible endpoint, enter the base URL + API key (or click the Jetstream preset), and pick a model. The key is stored encrypted.
For the CLI, add a provider entry with a baseUrl to ~/.loom/config.json:
{
"llm": {
"active": "openai-compatible",
"providers": {
"openai-compatible": {
"baseUrl": "http://localhost:4000/v1",
"model": "your-model-name",
"apiKey": "your-key"
}
}
}
}The baseUrl marks the entry as a custom endpoint: Loom registers it with Pi for you (writing the matching ~/.pi/agent/models.json entry, with sensible metadata defaults) and passes the key to Pi at runtime, so the key never lands in models.json. The provider name is yours to choose -- "openai-compatible" is just a convention.
Loom drives a real coding agent: alongside the Galaxy tools, the model has bash, write, edit, and read on your machine. That's the point -- local analysis needs it -- but it means a misreading model, or one that's been prompt-injected by untrusted content (a Galaxy dataset, tool output, a fetched page), could run something destructive as you. This risk is higher with cheaper, less-capable models, which Loom lets you pick to save money.
So Loom gates the model's local actions by default (the "exec-guard"):
- Workspace jail. Reads, writes, and edits inside your analysis directory (plus the OS temp dir) are silent; anything that resolves outside -- including via
.., a symlink, or~/$HOME-- prompts, or is denied for weak models. So the model reads and writes freely in your project but must ask to reach anything else on disk. Writes to control locations (.git,.loom/) always prompt, even inside the workspace -- a.git/hooksscript would run on your next commit. - Risk-classified
bash. Read-only/analysis commands (ls,cat,grep, ...) run without friction when they stay in the workspace. Catastrophic patterns (rm -rf /,sudo,curl | sh,dd of=/dev/..., fork bombs, ...) are always blocked -- including path-prefixed (/usr/bin/sudo), long-flag (rm --recursive --force /), wrapper-hidden (env rm -rf ~), explicit-home (rm -rf $HOME), and multi-line variants, plus any attempt to edit the gate's own config. Anything else prompts -- and any compound, redirected, or multi-line command (;,&&,|,$(...),>, a newline) drops to a prompt rather than being trusted. - Sensitive paths.
~/.ssh,~/.aws,.env,*.pem/*.key,~/.loom/config.json, OS keychains, and similar always prompt (or are denied for weak models) even inside the workspace -- whether the model usesread,grep,ls,find, or acatinbash. - Model-tier aware. Every model is gated. Weaker models (Haiku / GPT-4o-mini / Flash class, or unknown / local / low-cost models) get stricter defaults: a sensitive path or anything resolving outside the workspace is denied outright rather than offered for approval, and they never earn the silent auto-allow a capable model gets in a trusted workspace. An ordinary unrecognized command, though -- running a script it just wrote, or a compound/redirected command -- still drops to the same approval prompt a capable model would get, so scripting in explicit local mode works once you approve it. (Headless/scripted runs have no one to approve, so anything that would prompt is denied there for every tier.)
- Fail-closed. With no interactive session to approve (headless / scripted runs), anything that would prompt is denied. A one-time consent notice is shown on the first gated action, and every decision is recorded in
activity.jsonl.
When a command needs approval you can allow it once, allow it for the session, or trust the workspace (which stops prompting for routine commands there).
If you fully control the environment and want the agent to run unattended (CI, a trusted pipeline, your own box), you can turn the gate off:
- Config: set
"guardian": { "dangerouslyBypassPermissions": true }in~/.loom/config.json. - CLI:
loom --dangerously-bypass-permissions(one invocation; does not persist).--safe(orLOOM_SAFE=1) forces the gate back on and wins over everything. - Orbit: Preferences -> Safety -> "Dangerously bypass permissions" (a native confirm appears first; a red banner stays up while it's active).
Bypass is total -- it removes all prompts and the workspace jail. It can only be enabled by a human through one of those channels: the agent can't turn it on itself, because writing ~/.loom/config.json is blocked whether it uses the file tools or bash, and Orbit's toggle requires an OS-level confirmation the renderer can't forge. The default (guardian.enabled: true, not bypassed) is secure; relaxing it is always an explicit choice.
To be precise about the boundary: the workspace jail (default-on, every platform) confines the AI's file writes via the write and edit tools. Those tools can create or modify files inside your analysis directory (where notebook.md lives), plus the OS temp dir and Loom's own .loom state; writing anywhere else, or to a credential-shaped path (private keys like id_rsa/id_ed25519, *.pem, *.key, .env, and ssh/aws/gcloud/kube/docker/keychain dirs), prompts for approval.
Shell (bash) commands are not OS-sandboxed by default -- they're gated per action by the same approval flow (catastrophic patterns blocked outright, everything else prompts), but a bash command that writes a file or touches the network doesn't go through the write-jail path. To also confine bash writes and limit its network access inside a real OS sandbox, enable the opt-in bash sandbox (--sandbox / LOOM_SANDBOX=1 / guardian.sandbox), available on macOS and Linux/WSL2.
What this does not confine: reading files (the write-jail is not an exfiltration control), and data leaving via remote channels -- syncing the notebook to a Galaxy Page, Galaxy MCP operations (uploads, running tools), skills_fetch's cache writes under ~/.loom, or web fetches. Treat the working-dir confinement as "the AI's edits stay in your analysis directory," not "your data cannot leave the machine."
Orbit's footer shows live in-flight cost for the active session (computed from usage.cost returned per stream event by pi-ai). For accurate historical / per-project / per-model reporting across all your sessions, run CodeBurn in a separate terminal:
npx codeburn # interactive TUI dashboard
npx codeburn today # today's spend
npx codeburn month # this month
npx codeburn status # one-liner: today + month totalsCodeBurn auto-detects Loom/Pi sessions under ~/.pi/agent/sessions/ (Pi is a first-class supported provider — no configuration needed) and pulls model pricing from LiteLLM's catalog, so newly-released models work without a Loom update. Each Loom project (= cwd) shows up as a separate row, so you can see what each analysis cost. CSV / JSON export is built in.
Type / in the chat to open the autocomplete popup. Tab to accept; Enter still submits past it.
| Command | What it does |
|---|---|
/model <name> |
Switch the LLM model (e.g. /model sonnet, /model claude-opus-4-6) |
/new |
Start a fresh session (Orbit only). Confirms before deleting the existing notebook |
/resume |
Restart the agent and replay the prior session's chat |
/chat |
Restore the chat pane from the session transcript without restarting the agent |
/notebook |
Show the notebook content in the Notebook tab |
/status |
Galaxy connection + notebook path summary |
/summarize [N [M]] |
Append a summary of prompts N..M into the notebook |
/cost |
Append the session token/cost breakdown to the notebook |
/connect [name] |
Open Galaxy connection settings (or switch to an existing profile) |
/profiles |
List saved Galaxy server profiles |
/execute (alias /run) |
Tell the agent to advance the next pending step in the latest plan section |
/help |
Show this list |
Loom registers a small set of extension tools. Plans, decisions, results, and interpretation all live as markdown sections in notebook.md — the agent maintains them via the standard Edit/Write tools.
| Category | Tools |
|---|---|
| GTN tutorials | gtn_search, gtn_fetch |
| Galaxy invocations | galaxy_invocation_record, galaxy_invocation_check_all, galaxy_invocation_check_one |
| Skills | skills_fetch (fetch SKILL.md / reference docs from configured repos) |
| Multi-agent (experimental) | team_dispatch (gated by LOOM_TEAM_DISPATCH=1) |
Galaxy MCP (registered separately when credentials are present) provides galaxy_connect, galaxy_search_tools_by_name, galaxy_run_tool, galaxy_invoke_workflow, galaxy_search_iwc, get_iwc_workflows, import_workflow_from_iwc, user-defined tool lifecycle (galaxy_create_user_tool, galaxy_list_user_tools, galaxy_run_user_tool, galaxy_delete_user_tool), history/dataset operations, and more.
| Component | Technology |
|---|---|
| Agent | Pi.dev (@earendil-works/pi-coding-agent) |
| MCP bridge | pi-mcp-adapter, uvx galaxy-mcp |
| Language | TypeScript (strict) |
| Tests | Vitest |
| Desktop | Electron 35 |
| Build | Vite + electron-forge |
| Markdown | marked |
| Fonts | Inter (body), JetBrains Mono (code) |
| Theme | Galaxy brand dark (#2c3143 + gold accent #ffd700) |
For non-Electron validation:
npm run typecheck
npm test
pi --no-extensions -e ./extensions/loomThen validate the wrapper in a plain working directory:
mkdir -p /tmp/loom-cli-validation
cd /tmp/loom-cli-validation
node /path/to/loom/bin/loom.js --provider anthropic --model claude-sonnet-4-6For a full terminal-only runbook, see docs/terminal-validation.md.
- Galaxy — open-source platform for data-intensive biomedical research
- galaxy-mcp — MCP server for the Galaxy API
- galaxy-skills — curated operational skills the agent fetches on demand
- Pi coding agent — the Pi.dev agent framework
- CodeBurn — TUI dashboard for AI-coding cost observability (Pi is a first-class provider)
MIT