Tool Index
The tool index is the mapping from tool names (rg, python, curl) to the container images boks runs. boks consults a local cache of a global index, plus any overrides in your boks.toml. You rarely need to think about it — but it's the mechanism that makes boks rg resolve to a real image.
How resolution works
When you run boks <tool>, boks resolves the image in this order:
- Local
boks.toml— the[tools]section (see Tool Mappings) - Cached global index —
~/.cache/boks/index/index.json - Fallback —
boks.sh/<tool>:latest
The first match wins. Overriding a tool from the global index is just a matter of adding it to your local [tools].
The global index
The global index is a single JSON file published at https://index.boks.sh/index.json. It currently maps 236 tools to images across categories: programming languages, network utilities, devops tools, databases, text processing, system monitors, and AI tools (model hubs, agentic coding CLIs, local LLM hosting). Each entry can carry:
| Field | Purpose |
|---|---|
image | OCI image reference |
bin | Binary to run (for multi-tool images, e.g. dig/nslookup/host from one bind image) |
description | One-line synopsis shown by boks --search and boks --info |
tags | Searchable keywords |
category | Broad grouping for display |
lifecycle | runtime (multiple maintained version lines) or rolling (:latest is the primary tag); absent = rolling |
versions | Selectable tags for tool@version (e.g. Python's 3.12, 3.13, latest) — any tool may declare them, not just runtimes |
capabilities | Runtime capabilities boks enables automatically (e.g. net, browser, pid) |
dotfiles | Host paths to mount read-write into the container (e.g. ~/.aws), each declared as a file or a directory so a missing path is bootstrapped correctly on first run |
package_rules | Per-package effects keyed on (provider, package): a dotfiles host-path mount and/or an auto-enabled capabilities entry, triggered when a specific package is installed rather than the tool itself (e.g. huggingface_hub under pip mounts ~/.cache/huggingface; requests under pip auto-enables net) — see Package managers |
Every container gets HOME=/boks/home, backed by an ephemeral tmpfs: tool-written files like shell history and caches succeed and vanish with the container instead of failing against the read-only image or landing in your project directory. Declared dotfiles are mounted under /boks/home (e.g. ~/.aws → /boks/home/.aws), so the tool finds its persisted config via $HOME while everything undeclared stays ephemeral. package_rules dotfiles mounts land the same way, confined to ~/.cache/ or ~/.config/ (where XDG_CACHE_HOME/XDG_CONFIG_HOME already point); their capabilities are applied with the same precedence as any other auto-capability — explicit CLI flags always win.
Using the index
Search
boks --search <query> matches tool names, descriptions, and tags. Local boks.toml entries are listed first:
boks --search dns
boks --search python
boks --search kubernetesShow details
boks --info <tool> prints the index entry plus — if the image is pulled locally — labels read from the image itself:
boks --info curlRefresh the index
The index is fetched on demand and cached. To pull the latest version from index.boks.sh/index.json:
boks --updateVersion selection
Tools that declare a versions list can be pinned with @version:
boks python@3.12 --version
boks node@22 --version
Tools without a versions list still accept @<tag>, but the tag must be one the image actually publishes.
Lifecycle: runtime vs rolling
Each tool follows one of two versioning lifecycles, shown by boks --info <tool>:
-
runtime— a tool with multiple maintained version lines (python, node). The tag model is the one IMAGE-REQUIREMENTS.md §18 defines: each active upstream maintenance line publishes an exact build-version tag (python 3.14.6,node 22.23.2) plus a major/minor floating tag (and a major-only float for the current line:python 3.14ANDpython 3), withlatestpointing at the newest/default line only. The floating tags move forward on each rebuild (the3.12line's tag advances 3.12.x → newer 3.12.y), which is what keeps a maintained line patched. For bit-for-bit reproducibility, pin a digest in yourboks.tomlinstead (the exact build-version tag for node is immutable; python's is rebuilt within the same version — see §18 item 1). A digest-pinned entry looks like:[tools] python = { image = "boks.sh/python@sha256:…", command = "python3" } -
rolling(the default) —:latestis the primary tag and whatboks <tool>gives you: always the current build. Versioned tags may exist alongside it and are selected the same way (tool@version).
Old version lines are kept, and they age. A version line that upstream
stops maintaining keeps its tag but stops receiving rebuilds: known CVEs in
it stay open, permanently. This is deliberate — version history exists so
you can reproduce a bug or test against several versions of a tool
(especially in CI/CD), not to be a maintained distribution channel. Reach
for an old line when you need that version, and expect it to be
vulnerable. The vulnerability scan still runs on old lines by default and
blocks on CRITICAL findings; a testing setup that accepts the risk opts out
per-run with --skip-scan, or globally with security_scan_enabled = false
in boks.toml.
Automatic capabilities
Some index entries declare capabilities, which boks enables automatically so you don't have to pass a flag. For example, the system-monitor tools (htop, ps, top) declare capabilities = ["pid"], so boks shares the host PID namespace for them without requiring --cap pid. Likewise, a tool that needs the browser relay can declare capabilities = ["browser"], or a GPU-only tool can declare capabilities = ["gpu"] (podman/docker only — see Security Layers > GPU device passthrough).
Adding a tool to the index
The index source lives in boks-index/tools/*.toml of the boks repo (this repo holds only the documentation), grouped by category. To add a tool, edit the relevant file in a boks checkout:
# boks-index/tools/text.toml
[ripgrep]
image = "boks.sh/rg:latest"
bin = "/usr/bin/rg"
description = "Fast regex search tool"
tags = ["rg", "ripgrep", "search", "grep", "text"]
category = "text"
Then compile and push — the CI workflow (.forgejo/workflows/deploy-index.yml) recompiles index.json and deploys it on any push to main that touches boks-index/. To test locally first:
# in a checkout of the boks repo:
cd boks-index
./compile.py # the shebang runs python through boks itself
cp index.json ~/.cache/boks/index/index.json
boks --search ripgrep
See Tool Mappings for overriding a tool in your personal config without changing the global index.