galaxyproject / galaxyproject/loom
Orbit: biocontainer-first tool resolution (apptainer) with conda fallback
- Dominant language
- TypeScript
- Stars
- 14
- Forks
- 12
- Avg merge
- 6d 5h
- Merged PRs (30d)
- 17
Description
## Idea
Switch Orbit's local tool resolution from "create conda env, install tools" to "pull the BioContainer image, run the tool inside it." Conda stays as a fallback for tools without a container or for ad-hoc scripting glue.
## Why
Live observation that prompted this: a `conda install -p .loom/env -c bioconda -c conda-forge -y pggb vg samtools bcftools seqkit fastix tabix multiqc` took 17+ minutes, 99.7% CPU on the solver — entirely on the dependency graph, not the actual binaries. Most of that pain disappears with containers.
Concrete wins:
- **Speed.** `apptainer pull` is bandwidth-bound (~10–60s per tool). No SAT solver, no conflict resolution, no env activation.
- **Reproducibility.** BioContainer images are content-addressed (digest = exact bits). The same image Galaxy uses for a tool invocation runs locally — bit-identical results between local Orbit and Galaxy execution.
- **Isolation.** Tool A's libssl conflict doesn't break tool B. No `LD_LIBRARY_PATH` archaeology.
- **Caching.** Single SIF file per tool version on disk. Trivial to share across projects, no `.loom/env` per project.
- **Galaxy alignment.** Galaxy already resolves tools via BioContainers in many deployments. Using the same artifact locally means the project's `notebook.md` "I ran fastp 0.24.0 from `quay.io/biocontainers/fastp:0.24.0--...`" is verifiable in either environment.
- **Survives suspend / network blips better.** No half-installed env state to recover from.
## Why Apptainer (Singularity) over Docker
- No daemon → no root-owned service to manage.
- Rootless by default → safe on shared workstations, HPC nodes, laptops.
- Single SIF file per image → easy to inspect, cache, copy, delete.
- Bind mounts the host filesystem by default → `cwd` and `$HOME` just work, fewer path-translation surprises.
- Galaxy's preferred container runtime for non-Docker deployments.
Docker should be a secondary option (for users on macOS where Apptainer is awkward, or in CI).
## Proposed shape
### Resolution order
1. **Container** (`quay.io/biocontainers/:`) — pull if absent, run via apptainer.
2. **Conda** (current path) — for tools without a container, or when user explicitly opts out.
3. **System binary** — last resort, with explicit notebook annotation.
The brain's tool-resolution helper picks #1 by default; falls back automatically.
### Local cache layout
```
~/.cache/orbit/containers/
fastp_0.24.0.sif
hisat2_2.2.1.sif
...
```
Per-version SIFs, not per-project. Project `.loom/` only stores a manifest mapping `tool@version → image digest` for reproducibility.
### Tool invocation wrapper
Replace direct `fastp ...` with:
```bash
apptainer exec --bind "$PWD:$PWD" --pwd "$PWD" \
~/.cache/orbit/containers/fastp_0.24.0.sif \
fastp ...
```
Wrapped by a helper so the brain still emits plain `fastp ...` in its bash; the wrapper layer rewrites at exec time.
### Where this lives
- `extensions/loom/tool-resolver.ts` (new) — resolve `tool@version` → image URI, pull if missing, return invocation prefix.
- `extensions/loom/index.ts` — bash-tool intercept that recognizes known tool names in commands and rewrites the invocation. Brain stays unaware.
- Project `notebook.md` annotation: every container-resolved tool gets a `[image: quay.io/biocontainers/...@sha256:...]` line so reproducibility is recorded.
## Tradeoffs
- **Prerequisite:** apptainer must be installed on the host. First-run check + clear install instructions if missing. (Conda has this same prereq.)
- **Per-invocation overhead:** ~0.1–1s startup per `apptainer exec`. Negligible for `fastp` on a 10GB FASTQ; painful for a tight loop calling `samtools view` 10k times. Mitigation: detect inner-loop patterns and cache an interactive shell, or fall back to conda for those scripts.
- **Bind-mount corner cases:** symlinks pointing outside `cwd`, network mounts, `/tmp` semantics inside vs outside. Apptainer's defaults handle 95% of cases; document the rest.
- **Disk usage:** SIF files accumulate. ~50–500 MB per tool. A `~/.cache/orbit/containers` GC ("remove SIFs unused for N days") solves this.
- **Image availability lag:** brand-new tool versions may not have a BioContainer yet. Conda fallback covers this.
- **Auth for private images:** out of scope for v1 — only use public BioContainers.
## Edge cases
- Tool not in BioContainers: fall back to conda silently, log it.
- Multiple tools chained in one bash line (`samtools view ... | bcftools call ...`): each invocation gets its own container exec; pipe between host stdouts. Apptainer handles this fine, but worth testing.
- User explicitly wants conda (e.g., editable install of a forked tool): per-project setting `toolResolution: "conda"` overrides.
- Container vs. conda version drift: image digest pinned, conda version pinned separately — pick one as source of truth (image), record both in `notebook.md`.
## Migration
- Existing projects with `.loom/env` keep working (conda fallback path).
- New tool installs default to containers.
- Surface a `/migrate-to-containers` command that reproduces the current env's tool list as a container manifest.
## Related
- #72 — resume hardening: containers help here too (no half-installed env state to reconcile after suspend).
- #69 — Galaxy history context stash: the container manifest fits naturally alongside.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.