Core Concepts
WorkFlow has a small object model. Understanding these five ideas explains every command.
Project a git repo at a path on this host
└─ Workspace a git worktree on a branch (with a base branch, status)
└─ Terminal a tracked shell — a real tmux window when in tmuxProjects
A project is a registered git repository. Projects are the top-level unit: every workspace belongs to one. Registering a repo just records its name and path in the registry — it never modifies the repo on disk.
wf project add [path] # register (default: current directory)
wf project ls # list projects with their workspace counts
wf project rename <old> <new> # rename (retargets its worktrees)
wf project rm <name> # unregister (leaves the repo on disk)A project's name defaults to the repo's directory name; if that's taken, WorkFlow appends -2, -3, and so on. Override it with --name. Rename or unregister a project later from the command line or straight from the dashboard.
Workspaces
A workspace is a git worktree on its own branch — an isolated working directory you can build in without touching your main checkout. Each workspace records its project, path, branch, base branch, and creation time.
wf add <branch> # create branch + worktree (+ setup)
wf list # list workspaces with live status
wf merge <branch> # merge into base, then clean up
wf rm <branch> # remove without mergingA workspace is referenced by its branch name. If the same branch exists in two projects, disambiguate with --project <name>.
Worktree placement
By default, worktrees are created as siblings of the repo, never nested inside it:
~/code/myrepo # the project
~/code/myrepo_worktrees/feature-x # a workspace (worktree) on branch feature-xBranch names are slugified for the directory (e.g. feature/login → feature-login). Change the location with worktree_dir in config.
Active vs. clean
Every workspace is either active or clean — this is the dashboard's key column and drives cleanup nudges. A workspace is active when it still holds work that isn't in its base branch:
active = uncommitted changes or commits ahead of base or an open PR
When none of those hold — the branch is clean and merged — the workspace is clean (shown as done in wf list) and safe to remove.
Why "behind" isn't a risk signal
A workspace that is merely behind its base still shows a non-zero diff, but it holds no work of its own. WorkFlow only treats uncommitted changes and unmerged commits (ahead of base) as work that removal would discard.
Base branch
Each workspace has a base — the branch it was created from and will merge back into. When you don't pass --base, WorkFlow resolves it in this order:
- The
--base/-bflag onwf add. base:in the repo's.workFlow.yaml.default_basein the global config.- The repo's detected default branch —
origin/HEADif set, otherwise the first ofdevelopment,main, ormasterthat exists. - The currently checked-out branch, as a last resort.
If you're creating a new branch and the resolved base doesn't exist, wf add stops with a clear message listing the available branches — rather than surfacing git's raw fatal: invalid reference error.
The registry
The registry is WorkFlow's only persisted state: a small JSON file listing registered projects and tracked worktrees. Everything else — git stats, whether a tmux window is open, active/clean status — is derived live on every command and dashboard refresh.
It lives under your config directory:
$XDG_CONFIG_HOME/workFlow/registry.jsonBecause the registry is the source of truth, WorkFlow can reconcile it against live tmux after a restart — see wf resurrect. You rarely touch this file directly; the wf project and workspace commands manage it for you.
Terminals
A terminal is a tracked shell for a workspace. Inside tmux it's a real window at the worktree's path, tracked by name; outside tmux it's whatever your universal launcher opens (your editor, a copied path, etc.). Terminals are always derived live — WorkFlow asks tmux what's open rather than storing it.