Skip to content

Commands

Every ixt command, every flag, copy-paste ready.


Tool Targets

Commands that operate on an already installed tool use a <target> selector:

Form Meaning
<spec> User-facing install spec, such as ruff, mikefarah/yq, @scope/pkg
@id:<installed-id> Exact installed id, such as @id:yq.mikefarah.github
<id-prefix> Short id prefix, such as yq or yq.mikefarah, only if unambiguous

Use @id:<installed-id> when two installed tools would otherwise match the same short spec or id prefix.

Global Flags

Option Description
-v / --verbose Increase diagnostic output. Repeat as -vv for per-package resolver traces

Global verbosity can be placed before the command:

ixt -v tool upgrade --all

For upgrade, it can also be placed after the subcommand:

ixt tool upgrade --all -v
ixt tool upgrade --all -vv

ixt tool list -v is the exception: there, -v means "show exact installed ids", not global resolver diagnostics.


tool add

Add a tool to ixt.toml without installing it.

ixt tool add <package> [options]

tool add only edits the declarative manifest. It does not install tools, does not touch ixt.lock, and does not query package registries. Simple names use the local registry first, then fall back to PyPI.

Option Description
--bare Persist the tool without exposing any binary (expose = [])
--slot <slot> Persist as a side-by-side slot. Writes <slot> = { install = "..." }
--runtime <mode> Runtime for npm packages. bun-strict writes node_shim = false; node writes runtime = "node"
--asset-pattern <PATTERN> Persist a forced binary asset pattern. Supports {version}, {tag}, {os}, {arch} placeholders
ixt tool add ruff
ixt tool add @biomejs/biome --runtime node
ixt tool add ruff==0.5.7 --slot ruff-old --bare
ixt tool add BurntSushi/ripgrep \
    --asset-pattern 'ripgrep-{version}-{os}-{arch}.tar.gz'

tool install

Install a tool in isolation.

ixt tool install <package> [options]
Option Description
--from <path> Install from a local directory (auto-detected backend). Mutually exclusive with <package>. See Local installs below
--bare Install the env without exposing any binary (configure later with ixt tool config)
--reinstall Reinstall if the tool is already installed
--slot <slot> Install into a side-by-side slot. The installed id becomes <slot>.<base-id>
--runtime <mode> Runtime for npm packages — see Runtime modes below
--asset-pattern <PATTERN> Force the asset selection pattern (binary backend only). Supports {version}, {tag}, {os}, {arch} placeholders
--save Add tool to ixt.toml
--dry-run Print the install plan (backend, spec, env_dir, expose) without installing — no network, no disk writes

Post-install configuration (expose, inject, uninject) goes through ixt tool config.

Runtime modes

Mode Behavior
bun (default) Uses bun, rewrites #!/usr/bin/env node shebangs to bun so the host doesn't need node installed
bun-strict Uses bun without rewriting shebangs — host must have node available
node Uses node natively, no bun involved

Only applies to npm packages; ignored for python and binary backends.

ixt tool install ruff                        # Python
ixt tool install @biomejs/biome              # Node
ixt tool install BurntSushi/ripgrep          # Binary
ixt tool install sharkdp/fd@10.2.0           # pinned version
ixt tool install ruff --bare                 # env created, no shim yet
ixt tool install biome --runtime bun-strict  # bun without shebang rewrite
# When scoring picks the wrong asset on a binary release, force the pattern.
# Persisted in the tool's ixt.json — survives upgrades,
# lost on uninstall (re-specify on next install).
ixt tool install oddproject/weirdtool \
    --asset-pattern 'weird-{version}-{os}-{arch}.tar.gz'
# preview without touching anything
ixt tool install my-tool --dry-run

See also: Recipes → side-by-side versions.

Local installs

ixt tool install --from <path> installs a tool from a local directory. The backend is auto-detected from the directory contents:

Marker file Backend selected
pyproject.toml / setup.py pythonuv pip install <path> in an isolated venv
package.json nodebun add <path> in an isolated node_modules
(none of the above) binary — copy directory contents to env, auto-expose binaries
ixt tool install --from ./my-tool                    # id = directory basename
ixt tool install --from ./my-tool --slot myalias     # id = myalias.my-tool
ixt tool install --from /tmp/repro-bug --reinstall   # reinstall over existing env

Local installs are recorded with version="local" and source="local". They are autonomous copies — moving or deleting the source path after install does not break the tool.

Lifecycle differences vs. registry installs:

  • ixt tool export skips local installs (not reproducible cross-machine, so they don't appear in ixt.toml).
  • ixt tool apply ignores them (no entry in ixt.toml to reproduce).
  • ixt tool upgrade refuses local installs and points back to ixt tool install --from <path> --reinstall to update.

Use cases: developing an ixt-installable tool before its first release, local fork of a published tool for debugging, reproduction fixtures shared in bug reports.


tool uninstall

Remove an installed tool.

ixt tool uninstall <target> [options]
Option Description
--all Remove all installed tools
--save Remove tool from ixt.toml
--yes / -y Skip the confirmation prompt for --all
--dry-run Print what would be removed (env directory + shims) without touching anything
ixt tool uninstall ruff
ixt tool uninstall @id:old.ruff.pypi      # exact installed id
ixt tool uninstall --all                  # prompts before removing everything
ixt tool uninstall --all --yes            # non-interactive / recovery scripts
ixt tool uninstall ruff --dry-run            # preview

To remove an injected package from a tool, use ixt tool config <target> uninject <pkg>.


tool list

List installed tools.

ixt tool list
  ruff          0.5.0   pypi     [ruff]
  gemini-cli    0.1.12  npm      [gemini]
  fd            10.2.0  github   [fd]

tool info

Show details about an installed tool.

ixt tool info <target>
ixt tool info @id:old.ruff.pypi

Displays: spec label, exact installed id, version, backend, exposed binaries, and environment path.


tool upgrade

Upgrade an installed tool, respecting any constraint declared in ixt.toml.

ixt tool upgrade <target>
ixt tool upgrade @id:old.ruff.pypi
ixt tool upgrade --all
ixt tool upgrade <target> --dry-run      # resolve latest, print, no side effects
ixt tool upgrade --all --no-cache        # bypass the latest-version TTL cache
ixt tool upgrade --all -v                # print a compact resolution summary
ixt tool upgrade --all -vv               # add per-package resolver/API traces
Option Description
--all Upgrade every installed tool
--dry-run Resolve latest versions and print old → new without installing
--no-cache Ignore the resolve cache and force a fresh upstream latest-version check

Shows the version change (e.g., 0.5.0 → 0.6.0) or indicates the tool is already up-to-date. With --all, progress is printed as each tool finishes ([i/N] name: state) instead of waiting for the whole batch to complete. The final --all footer reports the cache state when the latest-version TTL cache is active; use --no-cache when you need a fresh check now.

-v adds a final resolver summary for latest-version lookups:

[INFO] resolution: version: GitHub latest redirect 38/38 hit, 0 GitHub API calls, 1 GitLab API call, 1 PyPI registry call, 2 npm registry calls

The GitHub latest redirect count is the cheap github.com/.../releases/latest redirect path. GitHub API calls are counted separately, so 0 GitHub API calls means no api.github.com release endpoint was needed during version resolution. Cache hits are not counted as upstream calls. -vv adds per-package debug lines for the same resolver activity.

Behavior with ixt.toml

  • version = "==X.Y.Z" — upgrade is refused; the latest upstream version is shown as info so you can decide whether to bump the pin.
  • Range (">=1.0,<2.0", "~=1.2", …) — the range is forwarded to the backend so the resolved version stays in-bounds.
  • No version declared — upgrades to latest, as expected.

tool apply

Sync installed tools with an ixt.toml file. The toml is the source of truth; apply makes reality match it.

ixt tool apply [file] [options]
Option Description
--remove Also uninstall tools not listed in the file
--yes / -y Skip the y/N confirmation before removals (non-interactive / CI)
--dry-run Print the plan (install / reinstall / inject / reexpose / policy / remove) without touching anything
ixt tool apply                       # reads ./ixt.toml
ixt tool apply team.toml             # reads a specific file
ixt tool apply --dry-run             # preview the diff
ixt tool apply --remove              # prompts before destroying anything
ixt tool apply --remove --yes

ixt.toml keys are written for humans and resolved to installed ids when applying:

[tools]
"@pypi:ruff" = {}                         # target id: ruff.pypi
old = { install = "@pypi:ruff", version = "==0.5.0" } # target id: old.ruff.pypi

How drift is detected and fixed

Drift Action
Tool missing install
Version pinned == and differs, or outside declared range reinstall from the declared spec
Inject list differs only inject / uninject delta (env is not wiped)
Expose rules differ only re-link shims (cheap)
Runtime policy differs (env_*, fs_*) update policy and regenerate affected shims
Installed tool not listed, with --remove uninstall (after confirmation)

tool export

ixt tool export writes installed tools as ixt.toml on stdout. Unlike a raw snapshot, it preserves each tool's original install intent: the version constraint is whatever you gave at install time (range, exact pin, or nothing), so the produced toml stays truthful to what you declared instead of force-pinning every tool to its currently-resolved patch version. Generated entries use explicit backend prefixes such as @pypi:ruff and @npm:@openai/codex.

ixt tool export                  # all installed tools
ixt tool export > ixt.toml       # redirect to a file
ixt tool export ruff @id:bat.sharkdp.github  # subset by target selector

asset-index export

Export portable binary-resolution metadata.

ixt asset-index export > asset_index.json
ixt asset-index export --from-registry src/ixt/data/registry.toml --all-platforms

ixt asset-index export writes GitHub binary-resolution metadata from the local cache. --from-registry generates pattern entries from a registry.toml by calling GitHub Releases during generation. Without --from-registry, --all-platforms warns and exports only current-platform cache metadata.

Asset index details


registry list

List registry short names and their canonical install specs.

ixt registry list

The registry is local resolution metadata only: it maps names such as ripgrep to specs such as @gh:BurntSushi/ripgrep. It does not contain asset patterns, checksums, exposure rules, or descriptions.

Registry details


tool config

Change settings on an installed tool — exposure rules, injected packages, runtime policy. tool config never writes to ixt.toml; use tool apply + ixt.toml for the declarative path, or tool export to snapshot the current state.

ixt tool config <target> <action> [args...]
Action Purpose
expose <rules...> Replace the tool's exposure rules and re-link its shims
inject <pkg> Install a package into the tool's isolated env
uninject <pkg> Remove a previously injected package
env <action> Manage the env-var policy — base, allow, deny, list, reset (details)
fs <action> Manage the filesystem policy — base, ro, rw, scratch, list, reset (details)

Exposure & injection

ixt tool config ruff expose __all__
ixt tool config httpie expose http https
ixt tool config ripgrep expose rg:ripgrep
ixt tool config httpie inject rich            # pull rich into httpie's venv
ixt tool config httpie uninject rich

Use __all__ as the tool name to apply an expose rule to every installed tool at once:

ixt tool config __all__ expose __main__       # restore default exposure everywhere

__all__ is only valid with the expose action.

Runtime policy (env + fs)

Runtime policy applies when a command is launched through its ixt shim. It does not sandbox package installation or npm lifecycle scripts. On Linux, filesystem policy requires bubblewrap; without bubblewrap, env policy is hygiene-only.

# Lock environment variables — only OS vars + RUFF_*
ixt tool config ruff env base os-common
ixt tool config ruff env allow '*RUFF*'
ixt tool config ruff env deny '*TOKEN*' --except GH_TOKEN
ixt tool config ruff env list

# Lock filesystem — read-only host, hide secrets
ixt tool config ruff fs base app-common
ixt tool config ruff fs scratch ~/.aws ~/.ssh
ixt tool config ruff fs list

# Inspect at runtime
IXT_SHIM_DEBUG=1 ruff check .

Env policy reference · Filesystem policy reference · Real-world scenarios


environment

Show ixt configuration and paths.

ixt environment
ixt environment --sizes

--sizes adds a storage summary for config, installed tools, runtimes, and cache subdirectories. It is read-only.


runtime

Inspect and prune ixt-managed runtimes under $IXT_HOME/installed/runtimes/.

ixt runtime info
ixt runtime prune
ixt runtime prune --all
ixt runtime upgrade uv
ixt runtime upgrade bun
ixt runtime upgrade all
  • info reports known ixt-managed runtimes (uv, bun), their paths, size, version when readable, and whether they are currently considered used.
  • prune removes unused ixt-managed runtimes. uv is prunable after Python tools are installed because Python tool shims do not execute through uv. bun is kept when an installed Node tool may run through the managed bun binary.
  • prune --all removes every known ixt-managed runtime. Use it only when the final image or host does not need those managed runtimes at execution time.
  • upgrade <uv|bun|all> installs or replaces ixt-managed runtimes. This is the repair path printed by ixt doctor when the managed uv or bun runtime is missing, broken, or behind the latest available release.

This command never touches $IXT_HOME/installed/envs, $IXT_HOME/installed/bin, $IXT_HOME/config, or $IXT_CACHE_HOME. Later installs or upgrades can bootstrap missing runtimes again from cache or network as needed.


cache

Inspect and clean regenerable cache content.

ixt cache info
ixt cache prune
ixt cache prune --keep 3
ixt cache clear downloads
ixt cache clear metadata
ixt cache clear tmp
ixt cache clear all
  • info shows $IXT_CACHE_HOME plus downloads/, metadata/, and tmp/ sizes.
  • prune removes old indexed download artifacts and keeps the newest two per repository by default: current + previous. Unindexed files are left alone.
  • clear deletes the selected cache subtree. It never touches $IXT_HOME/config, $IXT_HOME/installed/envs, $IXT_HOME/installed/bin, or $IXT_HOME/installed/runtimes.

The download index lives in $IXT_CACHE_HOME/metadata/downloads.json. Binary release downloads record their forge, repo, tag, normalized version, asset name, URL, local path, and download timestamp.


tool shell

Open a subshell in a tool's environment directory — not activated (no PATH patch, no venv activate, no NODE_PATH). Binaries must be called by explicit path.

ixt tool shell <target>

tool where

Print the absolute path to a tool's environment directory. This command is stdout-only on success, so it is safe in scripts.

ixt tool where <target>
cd "$(ixt tool where ruff)"

doctor

Check ixt health and environment.

ixt doctor
ixt doctor --no-network

Reports:

  • OS, architecture, detected shell, and Python runtime
  • PATH configuration in the current shell
  • Shell init configuration in the right file for the detected shell
  • Home directory structure
  • $IXT_HOME writability and available disk space
  • Install mode — detects whether ixt was installed via uv tool, pipx, or pip --user, and prints the matching upgrade command. Multiple modes detected → flagged as ambiguous; not detected → likely a dev install
  • ixt-managed runtimes (uv, bun): local version, latest release when network checks are enabled, and the exact upgrade command (ixt runtime upgrade <name>)
  • system runtimes (uv, bun) on PATH. If one is too old or broken, doctor suggests the tool's self-upgrade command (uv self update, bun upgrade) plus the ixt-managed alternative
  • GitHub token status
  • GitHub, PyPI, and npm registry connectivity by default. Use --no-network to skip these probes and latest-runtime lookups
  • Installed tools count
  • Pattern cache — number of learned GitHub asset patterns and its on-disk path
  • Downloads cache — size of $IXT_CACHE_HOME/downloads/ (downloaded archives and runtime archives)

Cache mutation is intentionally outside doctor. Use ixt cache info, ixt cache prune, or ixt cache clear <target> for operational cache work.


setup path

Add $IXT_HOME/installed/bin to your shell PATH.

ixt setup path
ixt setup path --check          # just check, don't modify
ixt setup path --shell pwsh     # override shell detection

Detects your shell from $SHELL and writes a guarded, idempotent block to the right config file:

Shell Target file
bash ~/.bashrc
zsh ~/.zshenv (covers interactive and non-interactive shells)
fish ~/.config/fish/conf.d/ixt.fish
pwsh ~/.config/powershell/profile.ps1 (Documents/PowerShell/profile.ps1 on Windows)

The new block prepends $IXT_HOME/installed/bin (so ixt shims shadow same-named binaries elsewhere on PATH) and is guarded by a directory check so the block is a no-op after uninstall. Re-running is safe — repeats are detected and skipped. Old single-line ixt blocks are migrated automatically when their content matches; divergent blocks are left in place with a warning. If the target file is a symlink (Nix, home-manager, chezmoi), setup path refuses to write and prints the snippet to apply manually.


setup completions

Print a shell completion script for the ixt CLI.

eval "$(ixt setup completions --shell zsh)"
eval "$(ixt setup completions --shell bash)"
ixt setup completions --shell fish | source

Supported shells: bash, zsh, fish.

The script is generated from ixt's own argparse command tree, so commands, subcommands, options, fixed choices, and file/directory hints stay aligned with the CLI parser. Zsh and fish also receive descriptions from the parser help text. This is for completing the ixt command itself; it does not install third-party tool completion files.