Getting Started

Quick Start

Go from a fresh install to a running workspace — configure a project, materialize a branch, run its dev server, and clean up.

By the end of this page you will have a configured project, a materialized workspace, a command running inside it, and a clean machine again. It takes about ten minutes.

You need uxd installed and a git repository you can clone.

Scaffold your first project

uxd setup creates the config directory (~/.uxd by default), sets a base root for repos and worktrees, and writes your first project file. On a terminal it prompts for each field; every prompt is also a flag, so the same command runs unattended.

uxd setup

Not sure what it will write? --dry-run prints the plan and changes nothing:

uxd setup --name my-project --repo git@github.com:my-org/my-project.git --dry-run --yes
mkdir -p ~/.uxd
write ~/.uxd/defaults.toml
  root = "~/dev/uxd"
write ~/.uxd/my-project.toml
  repo = "git@github.com:my-org/my-project.git"

Teach the project how to run

setup writes the minimum. Open the project file and add the two things uxd needs to make a workspace runnable — how to install dependencies, and what your commands are:

uxd config edit my-project
~/.uxd/my-project.toml
repo = "git@github.com:my-org/my-project.git"
editor = "code"

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

[env]
PORT = "{port}"

[commands.dev]
run = "pnpm dev"

{port} is a template variable. Each workspace gets its own port, so two dev servers never collide.

repo_path and worktrees_path are left out on purpose — they default to {root}/{project}/repo and {root}/{project}/trees. See Configuration.

Check your environment

doctor inspects your tools, your config directory, and every project you have configured. Run it before you trust a setup:

uxd doctor
OK   git version: git 2.50.1
OK   gh (github cli): authenticated
OK   config dir: ~/.uxd
OK   state dir: ~/.local/state/uxd
OK   project my-project: config: schema-valid
OK   project my-project: repo: bare repo at ~/dev/uxd/my-project/repo
OK   project my-project: fetch refspec: remote.origin.fetch configured

doctor exits non-zero if any check fails, so it works in CI. To validate only the config files, use uxd config validate.

Materialize a workspace

Now the pipeline. Pick any ref — a branch name, a PR number, a full commit SHA:

uxd my-project feat/login checkout
→ cloning git@github.com:my-org/my-project.git (bare, partial)
→ fetching origin/feat/login
→ worktree ready: ~/dev/uxd/my-project/trees/feat-login
~/dev/uxd/my-project/trees/feat-login

The first run clones once. Every later ref reuses that bare repo, so the second workspace is fast.

checkout prints the worktree path on stdout and nothing else, which makes it the scriptable primitive:

cd "$(uxd my-project feat/login checkout)"

Do something in it

run materializes the workspace, executes [setup], then runs a configured command inside the worktree:

uxd my-project feat/login run dev
→ worktree ready (reused)
→ running setup
...
listening on 3053

Other ways to act on the same workspace:

uxd my-project feat/login code               # open it in your editor
uxd my-project feat/login shell              # interactive shell, uxd env exported
uxd my-project feat/login exec -- git log --oneline -2
uxd my-project feat/login diff --stat

See what you have

uxd my-project list
SLUG        KIND    BRANCH      STATUS  PORT  AGE  LAST USED
feat-login  branch  feat/login  clean   3053  0m   0m

On a terminal, a bare uxd my-project turns that list into a picker and prints the chosen path — so cd "$(uxd my-project)" walks you into a workspace.

Clean up

uxd my-project clean --all --yes
→ plan:
  feat-login (clean, 16 KB)
feat-login
→ freed 16 KB

clean prints its plan and asks for confirmation first; --yes skips the prompt. In day-to-day use you will reach for the filters instead — --merged, --closed, --older-than 7d. See cleaning up workspaces.

Where to go next