Bulker Skill Reference
Bulker manages multi-container computing environments. You define a “crate” — a YAML manifest listing Docker images and the commands they provide. Activate a crate and bulker creates symlinks that dispatch each command to the right container at runtime. Commands appear on your PATH as if natively installed. No install step needed — just
bulker activateand go.
Documentation links: Links below point to
.mdfiles atbulker.io(e.g.,https://bulker.io/guides/shell.md). These return raw markdown that AI agents can fetch and read directly.
Install
Section titled “Install”# One-liner install (Linux/macOS), installs binary to ~/.local/bin/bulker and adds shell function to ~/.bashrc or ~/.zshrccurl -sL https://bulker.io/install.sh | bashbulker --version # verify installationNo configuration step is needed. Bulker auto-detects your container engine and creates a config file on first use. To customize, see the Configuration reference.
Using an existing crate
Section titled “Using an existing crate”Activate a crate (interactive shell):
bulker activate databio/pepatac# Auto-fetches from registry if not cached locally# You're now in a shell where samtools, bowtie2, etc. are on PATHbulker crate inspectsamtools --versionbulker deactivateactivate auto-fetches the manifest from the registry on first use, creates symlinks for each command, and prepends them to your PATH. deactivate restores the original PATH. No separate install step needed. For a step-by-step walkthrough, see the Tutorial.
Pre-cache for offline use (optional):
bulker crate install databio/pepatac:1.0.13 # cache manifestbulker crate install databio/pepatac:1.0.13 -b # cache manifest + pull imagesRun a single command (non-interactive, for scripts/AI):
bulker exec databio/pepatac -- samtools view -h input.bamexec is the preferred method for AI agents and scripts — it runs a single command in the crate’s environment without modifying your current shell. See also Shell Debugging for interactive container inspection.
See what’s cached:
bulker crate list # list all cached cratesbulker crate list --simple # space-separated, for scriptingbulker crate inspect databio/pepatac # show commands in this cratebulker crate clean databio/pepatac # remove a cached cratebulker crate clean --all # clear entire cacheCreating a crate manifest
Section titled “Creating a crate manifest”For a guided walkthrough, see Write a Manifest. For the complete field reference, see Manifest Format.
Minimal manifest — one tool
Section titled “Minimal manifest — one tool”manifest: name: my-tools commands: - command: samtools docker_image: quay.io/biocontainers/samtools:1.9--h91753b0_8Each field:
command— the name you’ll type on the command linedocker_image— the full Docker image reference (registry/repo:tag)
Multiple tools
Section titled “Multiple tools”manifest: name: biotools version: "1.0" commands: - command: samtools docker_image: quay.io/biocontainers/samtools:1.9--h91753b0_8 - command: bedtools docker_image: quay.io/biocontainers/bedtools:2.29.2--hc088bd4_0 - command: python docker_image: python:3.11 docker_command: pythondocker_command— what to run inside the container. Defaults to thecommandvalue. Use when the container command name differs from what you want the user to type.docker_args— extra Docker flags. Bulker auto-detects TTY and always keeps stdin open, so-iand-tare not needed here (they are stripped if present).
Volumes and mounts
Section titled “Volumes and mounts”manifest: name: data-tools commands: - command: mytool docker_image: myimage:latest volumes: - /data/shared - /scratchHow mounting works (see Volumes and Environment Variables for details):
- By default,
$HOMEand the temp directory ($TMPDIR, or/tmpif unset) are always mounted. - Each volume entry becomes
--volume "/path:/path"— same path inside and outside the container. - The working directory is automatically set to
$(pwd)so relative paths work. - User ID mapping is automatic (
--user=$(id -u):$(id -g)) so files are owned by you, not root. - Additional system mounts are added automatically:
/etc/passwd,/etc/group,/etc/shadow,/etc/sudoers.d(read-only),/tmp/.X11-unix(for GUI apps).
When you need extra volumes:
- Data directories outside
$HOME: add them tovolumes: - Shared network mounts: add them to
volumes: - You do NOT need to mount
$HOME— it’s already mounted globally
Environment variables
Section titled “Environment variables”manifest: name: display-tools commands: - command: firefox docker_image: jess/firefox envvars: - DISPLAY - XAUTHORITY no_network: falseenvvars— allowlist of environment variable names for--strict-envmode. In normal mode, all host env vars are passed automatically. See Strict Environments.DISPLAYis in the default allowlist (in bulker config).no_network: false(the default) adds--network=host. See Container User and Network Settings.
Advanced options (Entrypoints)
Section titled “Advanced options (Entrypoints)”manifest: name: advanced commands: - command: redis-server docker_image: redis:7 docker_command: redis-server docker_args: "--name redis -p 6379:6379" workdir: /data no_user: true no_network: false - command: jq docker_image: ghcr.io/jqlang/jq docker_args: "--entrypoint jq" docker_command: " "Field reference:
| Field | Type | Default | Description |
|---|---|---|---|
command | string | required | Executable name created on PATH |
docker_image | string | required | Docker image reference |
docker_command | string | command | Command to run in container |
docker_args | string | none | Extra docker run flags (note: -i/-t are auto-managed) |
volumes | list | [] | Additional mount paths |
envvars | list | [] | Env var allowlist for --strict-env mode |
no_user | bool | false | If true, run as root (not current user) |
no_network | bool | false | If true, don’t add --network=host |
workdir | string | $(pwd) | Working directory in container |
apptainer_args | string | none | Extra apptainer exec flags (Apptainer only; analogous to docker_args) |
apptainer_command | string | command | Command to run inside the Apptainer container (Apptainer only; analogous to docker_command) |
no_default_volumes | bool | false | If true, skip the config-level volumes list for this command (useful for containers that conflict with $HOME mounts) |
Host commands and imports
Section titled “Host commands and imports”manifest: name: pepatac version: "1.0.14" imports: - bulker/coreutils - databio/bedstuff host_commands: - python3 - perl - git commands: - command: samtools docker_image: quay.io/biocontainers/samtools:1.9--h91753b0_8imports— other crates whose commands are included when this crate is activated. Resolved at runtime — updating an imported crate propagates automatically. See Import Crates.host_commands— commands from the host system (not containerized) that should be available in the crate. Symlinks to the host binary are created in the crate directory. See Host Commands.- Use
host_commandsfor tools that don’t need containerization (python3, perl, git) or that need direct host access.
Using a local manifest
Section titled “Using a local manifest”# Activate directly from a local filebulker activate ./my-manifest.yaml
# Pre-cache a local manifest (optional)bulker crate install ./my-manifest.yaml
# Pre-cache and pull all Docker imagesbulker crate install ./my-manifest.yaml -b
# Exec with a local manifestbulker exec ./my-manifest.yaml -- samtools --version
# Override the cached identity with --namebulker crate install --name myorg/mytool:2.0 ./manifest.yamlbulker activate myorg/mytool:2.0When the argument starts with ./, /, or ends in .yaml/.yml, it is treated as a local manifest file. The manifest is cached using its name field (parsed as namespace/crate). If the name has no namespace (no /), the default_namespace from config is used. Use --name to override the cached identity. Otherwise the argument is treated as a registry shorthand (namespace/crate:tag).
Publishing a crate to the registry
Section titled “Publishing a crate to the registry”The registry is a static collection of YAML files served from GitHub via hub.bulker.io. Publishing means adding your manifest file to this repository. See the Registry guide for more on configuring registries.
# 1. Write your manifestcat > my-crate.yaml << 'EOF'manifest: name: my-crate version: "1.0" commands: - command: mytool docker_image: myorg/mytool:1.0EOF
# 2. Fork or clone the hub.bulker.io repogit clone git@github.com:databio/hub.bulker.io.gitcd hub.bulker.io
# 3. Add your manifest under your namespacemkdir -p mynamespacecp ../my-crate.yaml mynamespace/my-crate.yaml# For versioned: mynamespace/my-crate_1.0.yaml
# 4. Commit and pushgit add mynamespace/my-crate.yamlgit commit -m "Add mynamespace/my-crate"git push origin main
# 5. Open a pull request to databio/hub.bulker.ioFile naming convention: Always use versioned filenames: namespace/crate_name_1.0.yaml. The build system automatically creates the default tag (namespace/crate_name.yaml) as a symlink to the latest version.
After merge, the crate is available via: bulker activate mynamespace/my-crate:1.0
Configuration reference
Section titled “Configuration reference”See the full Configuration reference for all config keys and their defaults. See also: Multi-user Environments for shared/HPC setups, Shell Completions for tab completion, and Command Dispatch for how shimlinks route commands at runtime.
Config file location lookup order:
-cflag on any command$BULKERCFGenvironment variable~/.config/bulker/bulker_config.yaml- No file found — use built-in defaults with auto-detected engine (config is cached to
~/.config/bulker/bulker_config.yamlon first use)
Setting config values from the CLI:
bulker config show # view current configbulker config get container_engine # get a specific valuebulker config set volumes=$HOME,/data/shared,/scratch # set a value (comma-separated lists)bulker config add volumes=/data/new_mount # add to a list fieldbulker config remove volumes=/data/old_mount # remove from a list fieldApptainer/Singularity support
Section titled “Apptainer/Singularity support”# Bulker auto-detects apptainer if docker is not available.# To force apptainer when both are installed:bulker config set container_engine=apptainer
# Or regenerate the config with apptainer:bulker config init -e apptainer --forceDifferences from Docker:
- Images are stored as
.siffiles inapptainer_image_folder. $HOMEis always mounted by Apptainer (not listed separately).- Uses
-Bfor bind mounts instead of--volume. - First run pulls and converts the Docker image (cached for future runs).
- Same manifests work for both engines — no changes needed.
Integration testing with bulker
Section titled “Integration testing with bulker”To test a process that runs multiple tools, create a manifest listing the commands your tests need and keep it alongside your test script:
tests/├── test-manifest.yaml└── run-tests.sh# tests/test-manifest.yamlmanifest: name: myproject/tests commands: - command: samtools docker_image: quay.io/biocontainers/samtools:1.17--hd87286a_2 - command: bedtools docker_image: quay.io/biocontainers/bedtools:2.31.0--hf5e1c6e_2#!/bin/bash# tests/run-tests.shset -ebulker activate ./tests/test-manifest.yaml# ... run your tests ...bulker deactivateWhen a test fails because a command is missing, add it to the manifest — just another entry in the YAML.
Common patterns for AI agents
Section titled “Common patterns for AI agents”Permission pattern for Bash commands. Users typically allow Bash(bulker:*) so that all bulker commands run without prompting. This means every Bash command must start with the word bulker. Violations:
R_PROFILE_USER=/tmp/x bulker exec ...— env var prefix breaks the matchexport VAR=x && bulker exec ...— chained non-bulker command breaks the matchls /some/path— not a bulker command at all
Instead:
- Set environment variables inside the R/Python expression:
bulker exec crate -- Rscript -e 'Sys.setenv(FOO="bar"); ...' - For file inspection, use the agent’s built-in tools (Read, Glob, Grep), not
ls/cat/grepvia Bash - Route ALL Bash commands through
bulker execor otherbulkersubcommands
Pattern: Set up a bioinformatics environment
# Run a single command with exec — auto-fetches manifest on first usebulker exec databio/pepatac -- samtools view -h input.bam > output.samPattern: Create a custom crate for a project
cat > manifest.yaml << 'EOF'manifest: name: my-analysis commands: - command: samtools docker_image: quay.io/biocontainers/samtools:1.17--hd87286a_2 - command: bedtools docker_image: quay.io/biocontainers/bedtools:2.31.0--hf5e1c6e_2 - command: R docker_image: r-base:4.3 docker_command: R host_commands: - python3 - gitEOF
# Activate directly from local filebulker activate ./manifest.yamlsamtools --versionbulker deactivate
# Or exec without activatingbulker exec ./manifest.yaml -- samtools --versionPattern: Run a pipeline step
# Non-interactive, for scripts -- no shell function neededbulker exec databio/pepatac -- trim_galore --paired R1.fastq.gz R2.fastq.gz -o trimmed/bulker exec databio/pepatac -- bowtie2 -x /data/genomes/hg38 -1 trimmed/R1.fq.gz -2 trimmed/R2.fq.gz -S aligned.samPattern: Check what’s available before running
bulker crate listbulker crate inspect databio/pepatac# Shows: samtools, bowtie2, trim_galore, bedtools, ...Pattern: Multiple crates at once
# Activate multiple crates (commands from all are on PATH)bulker activate databio/pepatac,bulker/coreutils
# Exec with multiple cratesbulker exec databio/pepatac,bulker/coreutils -- samtools --versionPattern: Strict mode (only crate commands on PATH) — see Strict Environments
# No host commands leak into the environmentbulker activate -s databio/pepatacbulker exec -s databio/pepatac -- samtools --versionPattern: Strict-env mode (clean container environment) — see Strict Environments
# Only allowlisted env vars passed to containersbulker activate --strict-env databio/pepatacbulker exec --strict-env databio/pepatac -- samtools --version
# Combine both: strict PATH + strict envbulker activate -s --strict-env databio/pepatacMock mode for CI testing
Section titled “Mock mode for CI testing”Mock mode replays pre-recorded container outputs without Docker or Apptainer. Use it in CI or when containers are unavailable. See the Mock Mode guide for a full walkthrough.
# Record: run with real containers, capture outputsbulker mock record databio/pepatac:1.0.13 outputs.json -- python pipeline.py sample1
# Replay: interactive shell with mock commandsbulker mock run databio/pepatac:1.0.13 outputs.json
# Replay: for scripts/CI (print exports, no shell)eval "$(bulker mock run databio/pepatac:1.0.13 outputs.json --echo)"python pipeline.py sample1Deprecated commands (Python-era — do not use)
Section titled “Deprecated commands (Python-era — do not use)”Bulker was rewritten from Python to Rust. Old commands like bulker load, bulker run, bulker init, bulker list, and bulker inspect no longer exist. The key replacements: load → crate install (but usually unnecessary — activate auto-fetches), run → exec, init → config init (auto-generates on first use). Manifests are unchanged. See the Migrating from Python guide for the full mapping.
Glossary
Section titled “Glossary”See the full Glossary for additional terms. Also see the CLI Reference for complete command documentation and Troubleshooting for common issues.
| Term | Definition |
|---|---|
| Crate | A loaded collection of containerized commands, identified by namespace/name:tag |
| Manifest | YAML file defining the commands in a crate, their Docker images, and configuration |
| Namespace | Organizational prefix (e.g., databio, bulker). Like a GitHub org. |
| Tag | Version identifier for a crate (e.g., 1.0.13, default) |
| Registry | HTTP endpoint serving manifest YAML files (default: hub.bulker.io) |
| Shimlink | A symlink to the bulker binary. When invoked (e.g., as samtools), bulker checks argv[0] and dispatches to the right container at runtime. |
| Strict mode | Activation mode (-s) where only crate commands are on PATH — no host commands leak through. The container engine still works via its absolute engine_path. |
| Activate | Auto-fetch a manifest, create shimlinks, and put them on your PATH. Works with registry crates and local files. |
| Deactivate | Restore the original PATH, removing crate commands. |
| Exec | Run a single command in a crate’s environment without modifying your shell |
| Host commands | Commands from the host system (not containerized) included in a crate via host_commands in the manifest. |
| Mock mode | Record and replay container command outputs without a container runtime. For CI/testing. |
| Auto-mount | Automatic volume mounting triggered by file path arguments. When a shimlinked command receives a non-flag argument that looks like a path, bulker resolves it to an absolute path and mounts its parent directory into the container. No configuration required. |
| Manifest cache | The filesystem directory (~/.config/bulker/manifests/) where fetched manifest YAML files are stored. Acts as the source of truth for installed crates; there is no separate crates map in the config file. |