Documentation menu

Commands

embr tool

Last updated August 24, 2026

Pins GitHub-released binaries per project (or globally) and puts them on PATH via shims.

Subcommands#

  • embr tool add <name> [--version <v>] [--global|-g] — <name> is owner/repo or a shorthand: create-chief-project, darklua, lest, luau-lsp, rojo, stylua. Without --version, the latest release is pinned. Writes alias = "owner/repo@version" under [tools] (or to the global ~/.ember/tools.toml with --global). tool add never downloads — embr install is the one place tools get installed.
  • embr tool remove <name> [--global] — unpins.
  • embr tool update — bumps every pinned tool to its latest release.
  • embr tool list — pinned and installed tools, per scope (project/global).
  • embr tool delete <name> [--version <v>] — deletes downloaded binaries from ~/.ember/tools/; manifest pins remain. Without --version, all versions go.
  • embr tool cache clean — wipes the whole tool store (~/.ember/tools), including binaries embx downloaded. Pins and shims survive; everything reinstalls or re-downloads on demand.

embr and embx are reserved and can't name a tool — a shim under either name would shadow Ember's own binaries. Both embr tool add someone/embx and a hand-written [tools] embx = "..." fail with:

Alias 'embx' is reserved for embr itself and can't name a tool

How shims work#

~/.ember/bin contains copies of embr named after each alias (rojo, stylua, ...). Invoked under such a name, Ember dispatches to the version pinned by the nearest enclosing ember.toml, falling back to the global pin — so typing rojo inside a project runs that project's exact rojo. Tool runs don't print Ember's timer.

  • Storage: ~/.ember/tools/{owner}_{repo}/{version}/.
  • Asset selection matches the platform (os/arch) automatically; releases without a matching asset are an error.
  • A GITHUB_TOKEN in the environment is used for GitHub API rate limits if present.

Archive formats#

.zip, .tar.gz, .tar.xz and plain .tar are unpacked; an asset that is just the binary is used as-is. The format is decided by the file's magic bytes, not its name, because the download layer transparently decodes Content-Encoding: gzip and a .tar can arrive already gzipped. A single compressed file with no tar inside (tool.xz holding just the binary) works too — what comes out of the decompressor is checked for a tar header before being treated as one.

An asset compressed with something Ember can't unpack (zstd, bzip2, 7z, rar) is a clear error naming the format, not a silent install. That is worth stating because it replaced a bug: unrecognized compression used to fall through to "this asset is the executable", so the archive was written to the binary's path and every run of the tool failed with cannot execute binary file, pointing nowhere near the cause.

See also#

  • embr run — pinned tools are on PATH inside scripts.
  • embx — run a tool once without pinning it at all.
  • Installing Ember — why ~/.ember/bin must be on PATH.