unpack · execute · debug

Any git ref, running locally in one command

Point uxd at a pull request, a branch, or a link someone pasted in chat. You get the code checked out, dependencies installed, and a port of your own — while the work you already have open stays exactly where it is.
Terminal
uxd my-project 42 code
uxd my-project 42 run dev
uxd my-project clean --merged

Every command is the same three steps

Learn it once and the whole tool is predictable. There is no special case to remember.
  • resolve the ref
    You point at something — a pull request number, a branch, a commit, a link from chat. uxd works out what you meant.
  • materialize the workspace
    A folder appears with the code checked out, dependencies installed, your local files copied in, and a free port reserved. Ask again and you get the same folder back straight away.
  • act on it
    Open your editor, start the dev server, run a one-off command, or just print the path. Whatever you asked for, the workspace is ready before it runs.

Any ref you can name

If you can point at it, uxd can run it. No cloning, no stashing, no "let me finish what I'm doing first".
  • Six kinds of ref
    Pull request numbers, branch names, commit hashes, GitHub links, local paths — and a dash when you mean the one you were just on.
  • Paste the link
    A GitHub link already says which project and which pull request. Paste it in and that is the entire command.
Six ways to name the same thing
uxd my-project 42            # pull request
uxd my-project feat/login    # branch
uxd my-project 1a2b3c…       # 40-char SHA
uxd my-project - shell       # last used ref
uxd …/pull/42 code           # straight from a URL

Run three at once, nothing collides

Three branches can run at the same time without fighting over a port, a node_modules, or a database file.
  • A port of its own
    Every workspace gets its own free ports, and uxd hands them to your commands. Ask for two if your app needs an API alongside it.
  • The files git never sees
    Your local env file, a certificate, a scratch config — copied into every new workspace, and never written over one you already have. How seeding works.
  • Setup that remembers
    Dependencies install on the first checkout and stay installed. uxd only runs them again when your lockfile actually changes.
~/.uxd/my-project.toml
ports = 2

[setup]
run = "pnpm install --frozen-lockfile"
cache_key = ["pnpm-lock.yaml"]
seed_files = [".env.local"]

[env]
PORT = "{port}"
API_PORT = "{port+1}"

Your commands know where they are

Paths, ports and your own variables are worked out before anything runs, so one command behaves correctly in every workspace.
  • The details, handed over
    Everything uxd runs for you — setup, hooks, your dev server, a shell — is told the workspace's path, ports, branch and data directory. Anything you set yourself sits on top and wins.
  • Write it once, with placeholders
    Drop a placeholder for the port, the path or the branch into any command, environment value or hook, and uxd fills it in per workspace. Template variables.
  • See it before you run it
    A dry run prints the exact environment and the exact command, then stops. Useful on the day something behaves differently than you expected.

From opened to cleaned up

A workspace has a lifespan. uxd covers all of it, and clears up after itself at the end.
  • One word per intent
    Open an editor, start a server, get a shell, read the diff. Each one sets the workspace up first, so there is no wrong order to do things in.
  • See the whole board
    One list of everything you have open — the branch, the port, how old it is, and whether its pull request is still alive.
  • Catch up without starting over
    Pull a workspace back up to date with its branch. If you have uncommitted work, uxd stops and tells you, rather than quietly throwing it away.
  • Room for your own steps
    Start a container before the dev server, drop a scratch database on the way out, or block a removal that is not safe yet. Commands and hooks.
  • Get the disk back
    Clear out the workspaces whose pull requests have merged or closed. uxd shows you the list, asks before deleting, and skips anything with uncommitted work in it.
  • Fine inside your own scripts
    The commands that produce data can print JSON instead, with progress kept out of the way — so you can wrap uxd without parsing around it. Script with uxd.

Runs on the stack you already have

No new runtime, no daemon, no account.
  • Stock Node, plain git
    Node 18 or newer and git 2.38 or newer. Install it with npm, pnpm or yarn — there is nothing else to add.
  • GitHub's CLI, if you have it
    With it you get pull request status, CI results, and true pull request diffs. Without it, everything else still works.
  • One small file per project
    Your commands, environment and hooks live in one readable text file, and uxd can check it for mistakes before you rely on it.

Try it on the next pull request you review

One setup command writes your config, scaffolds your first project, and tells you exactly what to run next.