Skip to content

mwolson/aubeshim

Repository files navigation

aubeshim

aubeshim installs PATH shims that let existing bun, bunx, npm, npx, pnpm, pnpx, pnx, and yarn commands use aube when the command shape is compatible.

The goal is to get aube's fast installs, strict layout, and run-time auto-install checks without editing each project's scripts.

For developers with many JavaScript checkouts using several different package managers, that can mean hundreds of gigabytes of duplicate dependencies saved.

Note: aubeshim is a third-party project and is not associated with jdx or the aube project.

Install

The recommended install path is Cargo:

cargo install aubeshim
aubeshim install --force

That installs the aubeshim binary with Cargo and creates bun, bunx, npm, npx, pnpm, pnpx, pnx, and yarn shims in ~/.local/share/aubeshim/shims.

From a source checkout, use the development installer instead:

./install.sh

That builds the checkout, copies aubeshim to ~/.local/bin, and replaces shims in ~/.local/share/aubeshim/shims.

Activate aubeshim after mise activate or any other tool manager that rewrites PATH. mise installs its own package-manager shims, so aubeshim must activate last for bun, bunx, npm, npx, pnpm, pnpx, pnx, and yarn to resolve to aubeshim.

For zsh:

eval "$(mise activate zsh --shims)"
eval "$(aubeshim activate zsh)"

For bash:

eval "$(mise activate bash --shims)"
eval "$(aubeshim activate bash)"

For fish:

mise activate fish --shims | source
aubeshim activate fish | source

For POSIX profile files:

eval "$(aubeshim activate sh)"

aubeshim activate removes existing aubeshim shim-dir entries before prepending the shim directory, so it is safe to run more than once.

For zsh, put the activation in .zshrc for interactive terminals. If non-interactive zsh processes also need the shims, for example editors or agents that invoke zsh, add a guarded activation to .zshenv too:

if (( $+commands[aubeshim] )); then
  eval "$(aubeshim activate zsh)"
fi

Prefer mise activate <shell> --shims so mise keeps a single shims directory on PATH instead of prepending every tool install path on each prompt. With that setup, aubeshim activate is enough.

If you use full mise activate without --shims, add --persistent so aubeshim re-prepends its shims after mise hook-env runs:

eval "$(mise activate zsh)"
eval "$(aubeshim activate zsh --persistent)"

On Linux desktops, adding the POSIX activation to .profile can help GUI applications launched by the session inherit the shims too, even if your interactive shell is zsh. Many desktop sessions use .profile through sh semantics rather than zsh startup files, depending on how your display manager starts the user session:

if command -v mise >/dev/null 2>&1; then
  eval "$(mise activate sh --shims)"
fi
if command -v aubeshim >/dev/null 2>&1; then
  eval "$(aubeshim activate sh)"
fi

Keep the shell-specific activation in .zshrc, .bashrc, or equivalent for interactive terminals, since .profile is not sourced by every shell startup path.

Configuration

aubeshim reads a TOML config file from:

  • AUBESHIM_CONFIG, when set.
  • $XDG_CONFIG_HOME/aubeshim/config.toml, when XDG_CONFIG_HOME is set.
  • ~/.config/aubeshim/config.toml, otherwise.

The config file controls whether a directory uses the aube shim or passes through to the real package manager:

enabled = true
default = true
global_packages = "auto"

ignore = [
  "~/devel/work/broken-expo",
  "~/devel/work/legacy/**",
]

shim = [
  "~/devel/work/*",
  "~/devel/projects/**",
]

enabled controls whether aubeshim does any shimming at all and defaults to true. When enabled = false, every invocation passes through to the real bun, bunx, npm, npx, pnpm, pnpx, pnx, or yarn.

global_packages controls global package add/install/remove/outdated/list operations and defaults to "auto". With "auto", aubeshim inspects the configured global stores and routes each command to the backend that owns the requested package. When no package is named, it prefers aube if aube's global store is non-empty and otherwise falls back to mise. With "mise", commands such as npm install -g prettier run through mise use -g npm:prettier, letting mise manage tool inventory and PATH exposure. With "aube", they run through aube add -g prettier or aube remove -g prettier; make sure aube's global bin dir, such as the path printed by aube bin -g, is on PATH.

ignore is a list of directory globs that should pass through to the real package manager. shim is a list of directory globs that should use aube. default controls what happens when no directory glob matches and defaults to true.

Precedence is:

  1. enabled
  2. ignore
  3. shim
  4. default

Globs match the current working directory or any ancestor directory. This means a command run from packages/app still matches a glob for the package, workspace, or parent directory that contains it. Use absolute paths or ~ so the config keeps working no matter where the command starts.

* matches within a single path component. Because globs are checked against the current directory and its ancestors, ~/devel/work/* matches commands run inside any immediate child directory of ~/devel/work. ** is recursive and can match zero or more path components, so use it for directories that may live under nested paths, such as ~/devel/projects/**. A trailing /** also matches the base directory itself.

For a config managed by ~/dotfiles, symlink it into the default location:

mkdir -p ~/.config/aubeshim
ln -s ~/dotfiles/config/aubeshim/config.toml ~/.config/aubeshim/config.toml

Environment variables can override tool discovery:

  • AUBESHIM_CONFIG: path to the aubeshim config file.
  • AUBESHIM_AUBE: path to the aube binary.
  • AUBESHIM_REAL_BUN: path to the real Bun binary.
  • AUBESHIM_REAL_BUNX: path to the real bunx binary.
  • AUBESHIM_REAL_NPM: path to the real npm binary.
  • AUBESHIM_REAL_NPX: path to the real npx binary.
  • AUBESHIM_REAL_PNPM: path to the real pnpm binary.
  • AUBESHIM_REAL_PNPX: path to the real pnpx binary.
  • AUBESHIM_REAL_PNX: path to the real pnx binary.
  • AUBESHIM_REAL_YARN: path to the real Yarn binary.
  • AUBESHIM_SHIM_DIR: path to the installed shim directory.

By default, real package-manager discovery asks mise which first, then falls back to PATH.

If mise is installed, aubeshim requires mise 2026.5.6 or newer so aube-aware tool discovery is available.

Global npm Tools

global_packages defaults to "auto". Commands such as npm install -g prettier, pnpm add -g eslint, bun add -g typescript, yarn remove -g cowsay, and npm outdated -g route to mise or aube based on which store owns the package.

With mise-backed globals, aubeshim translates those commands to mise use -g npm:<package>, mise unuse -g npm:<package>, or mise outdated --bump -C "$HOME". A typical workflow looks like:

mise use -g npm:prettier@latest
mise use -g npm:@anthropic-ai/claude-code@latest

With aube-backed globals, the same package-manager commands use aube's global store instead (aube add -g, aube remove -g, aube outdated -g). Add the path from aube bin -g to PATH so installed binaries are available to shells and tools.

aubeshim keeps registry metadata working by sending commands such as npm view ... --json to the real npm binary. That lets mise and other tools consume npm's registry response format even when installs route elsewhere.

Set global_packages = "mise" or "aube" to force a backend. Override the configured value for one shell session or command with AUBESHIM_GLOBAL_PACKAGES_BACKEND=auto, =mise, or =aube.

Behavior

  • Local npm installs and scripts run through aube. That includes npm install, npm ci, npm run build, npm test, and npm start.
  • npm package edits are normalized to aube's command names: npm install <package> becomes aube add <package>, and npm uninstall <package> becomes aube remove <package>.
  • npm-shimmed aube commands set AUBE_NODE_LINKER=hoisted for that invocation unless a node-linker env var is already set. This matches npm's hoisted node_modules shape without writing .npmrc.
  • pnpm commands pass through to aube, since aube already presents a pnpm-compatible command surface.
  • yarn routes common package-manager commands and script names to aube; Yarn-specific management commands fall back to the real Yarn binary.
  • bun routes package-manager commands such as bun install, bun add, and bun run to aube; runtime commands and unknown commands fall back to the real Bun binary.
  • One-off runner shims route compatible commands to aube dlx. That includes bunx, npx, pnpx, pnx, bun x, bun dlx, and pnpm dlx.
  • For pnpm dlx, pnpx, and pnx, --allow-build <package> flags are normalized to aube's --allow-build=<package> form.
  • One-off runner no-install modes use aube exec --no-install. That includes bunx --no-install, bun dlx --no-install, and npx --no-install.
  • Runner flags that need exact package-manager behavior fall back to the real tool. Examples include bunx --bun and npx --workspace.
  • --version and -v print the real package manager version. In repos where aubeshim is configured to shim, they also print the aubeshim and aube versions in a parenthesized hint.

Global package commands route through global_packages, which defaults to "auto":

  • With "auto", aubeshim inspects whether mise or aube owns the requested package and routes add/install/remove/outdated/list to the matching backend. When no package is named, it prefers aube if aube's global store is non-empty and otherwise falls back to mise.
  • With mise-backed globals, npm install -g prettier becomes mise use -g npm:prettier, npm outdated -g becomes mise outdated --bump -C "$HOME", and remove operations use mise unuse -g npm:<package>.
  • With aube-backed globals, add/install/remove/outdated use aube's global package store (aube add -g, aube outdated -g, and so on).
  • Set global_packages = "mise" or "aube" to force a backend, or override for one session with AUBESHIM_GLOBAL_PACKAGES_BACKEND.

Commands that need npm's exact registry or account behavior fall back to the real npm:

  • npm view, npm show, and npm info with --json fall back so tools such as mise can consume npm's registry metadata format.
  • npm publish and npm unpublish fall back to preserve npm's registry, auth, access, provenance, OTP, tag, workspace, and lifecycle semantics.
  • npm-only commands such as npm pkg, npm search, and npm whoami fall back to the real npm.

Compatibility Notes

Known package-manager interop findings that need later upstream reports are tracked in aube-issues.

About

Replace all {bun, npm, pnpm, yarn} with aube

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages