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>isowner/repoor a shorthand:create-chief-project,darklua,lest,luau-lsp,rojo,stylua. Without--version, the latest release is pinned. Writesalias = "owner/repo@version"under[tools](or to the global~/.ember/tools.tomlwith--global).tool addnever downloads —embr installis 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_TOKENin 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/binmust be on PATH.