Documentation menu

Commands

embx

Last updated October 23, 2026

embx [--refresh] <spec> [args...]
embr execute [--refresh] <spec> [args...]   # same thing
embr x [--refresh] <spec> [args...]         # alias

embx is npx for the Luau toolchain: it downloads a GitHub-released executable the first time, caches it, and hands the terminal straight to it. Nothing is added to any manifest.

embx create-chief-project my-game    # scaffold a project, zero setup
embx stylua --check .                # one-off run of any released tool
embx JohnnyMorganz/StyLua@2.0.2 .    # any GitHub repo, exact versions too

Where embx comes from#

embr self install writes two binaries into ~/.ember/bin: embr and embx. embx is a copy of embr that dispatches on its own name, so embx <args> is exactly embr execute <args>.

  • embr self update refreshes the embx copy and creates it if missing, so existing installs gain embx from a plain update — no self install re-run needed.
  • embr self uninstall removes it along with everything else.
  • Never ran self install (a cargo install embr setup, say)? The command is still there as embr execute / embr x.

What the spec can be#

<spec> is name or owner/repo, each optionally with @version (a leading v on the version is accepted and ignored). First match wins:

  1. A pinned [tools] alias — if the bare name matches an alias in the nearest ember.toml walking up from the current directory, or in the global ~/.ember/tools.toml, embx runs exactly the pinned version.
  2. A shorthand — the same curated list embr tool add accepts: create-chief-project, darklua, lest, luau-lsp, rojo, stylua.
  3. An explicit owner/repo — any GitHub repository with releases.

An @version that disagrees with a pin is an error, not an override:

'rojo' is pinned to 7.7.0 here; drop '@7.6.0' to run the pin, or use the full owner/repo form for another version

Any other bare name is an error too:

'wally' is not a pinned tool alias or a known shorthand; use the full 'owner/repo' GitHub name

Versions, caching, and the network#

  • @version runs that exact release. It downloads once into ~/.ember/tools/<owner>_<repo>/<version> — the same store embr install uses — and every later run is offline.

  • No @version runs the latest release, and the answer is cached: Ember asks GitHub at most once per TTL (EMBER_INDEX_TTL_SECS, default 300 seconds, 0 = always ask — the same knob as index refreshes). Within the TTL, repeat runs make zero network requests.

  • --refresh asks GitHub now, ignoring the cached answer. It goes before the spec (embr x --refresh stylua) and does nothing for @version specs or pinned aliases, which are already exact.

  • Offline grace: past the TTL, if the latest-release check fails (offline, rate-limited) but a version is already stored, embx warns and runs the stored one instead of dying:

    warning: could not check johnnymorganz/stylua for a newer release (...); running 2.5.2
    

Arguments and exit codes#

Everything after the spec is forwarded to the executable verbatim, flags included: embx stylua --check . passes --check . to stylua, and even embx stylua --refresh forwards --refresh. Ember's own flags must come before the spec. The exit code is the executable's own, so embx is safe to use in CI.

Reclaiming disk#

Unlike embr install, an embx run is ephemeral: nothing is written to ember.toml and no shim is created. Downloads do persist in the tool store, and embr cache clean does not touch it. To reclaim that space:

  • embr tool delete owner/repo — removes one tool's binaries.
  • embr tool cache clean — wipes the whole store (~/.ember/tools).

Manifest pins and shims survive either one: pinned tools reinstall with embr install, and embx runs re-download on demand.

Trust#

embx executes code fetched from GitHub by name — the same trust decision as installing a dependency. Prefer @version pins in scripts and CI.

See also#

  • embr tool — pin a tool for the whole project instead.
  • embr cache — the package caches, which are separate.