$ tebako-shim install-shell # detects your shell
$ tebako-shim install-shell --shell zsh # or name it: bash|zsh|fish|csh
GUIDES · 11
Shims & versions.
A shim is an ordinary command on PATH. Behind it sits a link in ~/.tebako/shims that points at the dispatcher, and the link's own name serves as the selector: argv0 decides which payload, which version, and which runtime each invocation receives.
The shim directory on PATH, once.
install-shell prepends ~/.tebako/shims to PATH inside a managed block in the shell startup file — idempotent, and removed by tebako-shim uninstall-shell. On Windows the shim directory goes on the user PATH in the registry (HKEY_CURRENT_USER, HKCU). Open a new shell afterwards.
Where shims come from.
tebako install registers them — registry installs always do; installing a local package file does it only with --shims. tebako uninstall <name> removes the shims and the cache entry. There is no tebako shim add/remove/list — the read-side verb is tebako-shim list.
Two classes of shim share the directory. A payload shim dispatches to a packaged payload, which is the class the rest of this guide describes. A runtime-own shim dispatches to an engine’s own tool with no payload in between, and tebako install <engine>[:<command>] creates it: the bare form registers the interpreter’s own name, and the colon form registers the declared command’s name.
$ tebako install node:node
node 24.22.0 is already installed (~/.tebako/runtimes/node-24.22.0-2.8.49-macos-arm64)
shim ~/.tebako/shims/node
$ node --version
v24.22.0
The claims live in ~/.tebako/shims/.runtime-own.yaml, a map from each registered name to the engine and the entry token it boots. tebako-shim list reports them beside the payload shims and marks them [runtime-own]. When a payload provides a name that a runtime-own claim also carries, the payload’s name wins on every dispatch, and a later payload claim displaces the runtime-own one loudly.
The version chain: four levels, first hit wins.
Every invocation re-evaluates the chain. The environment beats the project, the project beats the config, and the config beats the publisher’s default.
1. Environment — one shell, one pin.
$ export TEBAKO_METANORMA_VERSION=1.2.2
The variable name is the tool name uppercased, with non-alphanumerics replaced by underscores — a tool mn-cli answers to TEBAKO_MN_CLI_VERSION. The environment holds the highest precedence and is the easiest to undo.
2. Project file — pinned with the code.
# .tebako-tools.yaml, at the project root
metanorma: 1.2.1
The dispatcher walks up from the current directory; the nearest file that pins the command wins. A nearer file that does not mention the command does not shadow a farther one that does. Commit the file with the project.
3. Defaults in ~/.tebako/config.yaml.
defaults:
metanorma: 1.2.3
The file is hand-edited. Two commands write it: tebako add-registry, and tebako shim use <tool> <pin>, which sets a tool’s default; there is no top-level tebako use.
4. Registry default — the publisher’s word.
If nothing above pins a version, the registry’s own default: entry decides.
Then the runtime.
The chosen entrypoint declares a runtime requirement. The dispatcher picks the newest compatible runtime already in the cache — no download — or, if none fits, downloads, verifies, and caches one. Pure-language payloads declare a range (>= 3.3, < 5.0); native-extension payloads pin an application binary interface (ABI) line (~> 3.3.0) plus a platform ABI string, and a wrong line is a named error, never a segfault. Entrypoints that need no interpreter — native tools — declare no runtime and get none.
Preview and diagnose.
$ tebako-shim which metanorma
payload metanorma 1.2.3
version defaults: in ~/.tebako/config.yaml
image ~/.tebako/payloads/metanorma/1.2.3.tfs
entrypoint /bin/metanorma — ruby >= 3.3, < 5.0
runtime ruby 3.3.7 (cached)
mounts / (app) · /opt/inkscape · /opt/openjdk
exec tebako-runtime-… --tebako-image … --tebako-entry metanorma
which is read-only: it shows what this invocation would dispatch — payload, where the version came from, image, entrypoint, runtime, mounts, and the final exec argv — without running anything. Output above is representative.
$ tebako-shim doctor
doctor checks that the shim directory is on PATH, that every shim resolves, that payload records and their trust anchors exist, that the config parses, that registries are fresh, and that the runtime cache is intact. It ends with no problems found (exit 0) or a problem count (exit 1). The store-wide diagnostic is tebako doctor, which carries this same report as its dispatch section; tebako-shim doctor remains the dispatcher’s own verb.
Park a version, or a whole tool.
$ tebako-shim disable metanorma@1.2.2 # one version
$ tebako-shim disable metanorma # every version
$ tebako-shim enable metanorma # bring it back
disable parks a version — or the whole tool — so dispatch no longer selects it, and enable restores it. The state lives in ~/.tebako/shims/.disabled.yaml: a plain YAML file that can be read or edited.
Per-run overrides at the shim.
$ metanorma --jail deny:arg compile site.adoc
$ metanorma --mount "$HOME/extra:/extra:ro" compile site.adoc
Leading --jail, --mount, and --no-host tokens are consumed by the dispatcher; everything after them reaches the payload verbatim. The policy grammar is in the jails guide.
See also: Set a jail policy · Debug & logging · Dispatch, in the architecture docs.