The Dashboard
Run wf with no command to open the dashboard — an interactive TUI ledger of every project and its workspaces, with live git status, a scrollable diff viewer, and actions wired straight to the engine. It works in any terminal; when stdout isn't a TTY (e.g. wf | cat), wf prints the plain list instead so it stays scriptable.
wf # open the dashboard (on a TTY)
wf dashboard # explicit; aliases: wf dash, wf uiHere's the ledger layout — projects as headers, workspaces beneath, with a legend and a context-sensitive help line:
About the panel above
The panel is a styled, hand-built stand-in for the real layout — the project header, the ◆ base row, a workspace with its agent-status icon, and the legend and help line. Genuine captures of the live lipgloss dashboard can be generated with the procedure in docs/capture/ — capture target: dashboard-ledger.
Reading the ledger
Each project is a block: a header line (name (count) path), then the project's base checkout on its own row, then its workspaces as aligned tree children — all under one dim column heading:
| Column | Meaning |
|---|---|
| (agent) | The live agent-status icon — working / waiting — when an agent is active in the workspace; blank when idle |
● / ○ | active (green) — holds work not yet in base · clean (blue) — merged, nothing outstanding |
branch | The workspace's branch name (its identity) |
state | The word active or clean |
behind|ahead | Commit gap to base: ↓ commits on base this branch lacks, ↑ commits it has on top |
diff | +added -removed lines vs base, with a trailing * when the working tree is dirty |
base | The base branch this workspace merges into |
A trailing ▣ marks a row whose tmux window is open right now — derived live on every refresh. The selected row is highlighted and prefixed with ❯.
The base row
Every project shows its base checkout — the repository root — on its own row, marked with a ◆, listing the branch the root is currently on and its clean/dirty state. (The ahead/behind, diff, and base columns are blank for it.) It makes the trunk a launch target without first creating a worktree: the launch keys act on it just like a workspace —
- t opens a tmux window on the base branch at the project root,
- e / o open it in an editor,
- c copies the root path,
- Enter shows the root's uncommitted diff.
Merge and remove don't apply to the base row (it isn't a workspace).
Glyph legend
The legend beneath the ledger keys every glyph, including the active agent-status icons (shown here with the emoji preset; the default is Nerd Font):
🤖 working ⏳ waiting ● active ○ clean ▣ tmux open ↓behind|↑ahead vs base +added -removed * uncommittedKeybindings
Ledger (default)
| Key | Action |
|---|---|
| ↑ / k, ↓ / j | Move the cursor |
| g / Home, G / End | Jump to top / bottom |
| Enter | On a workspace: its diff. On a base row: the root's uncommitted diff. On a project header: the project menu |
| d | View the selected workspace's diff (same as Enter, but no menu on a header) |
| a | Add a workspace in the selected project (opens a branch-name prompt) |
| e | Edit — open the editor: autolaunch the project default if set, else a picker |
| o | Configure the editor — always opens the picker (set the default / autolaunch) |
| t | Jump to the workspace's tmux window (tmux only) |
| c | Copy the workspace path to the clipboard |
| m | Merge the workspace (asks to confirm) |
| x | Remove the workspace (asks to confirm; f on the prompt forgets instead) |
| r | Refresh status now |
| q / Ctrl+C | Quit |
The launch keys (e / o / t / c / Enter) act on the base row too, targeting the project root. The help line at the bottom adapts to your environment — the t term hint only appears inside tmux.
Diff viewer
Selecting a workspace opens a scrollable, syntax-colored diff against its base (additions green, deletions red, hunks cyan, metadata dim):
| Key | Action |
|---|---|
| ↑ / ↓ | Scroll |
| r | Reload the diff |
| q / Esc | Back to the ledger |
When a workspace has no changes against base, the viewer shows (no changes against base).
Add prompt
Pressing a opens an inline branch-name input: type a name and press Enter to create the workspace, or Esc to cancel.
Confirmations
Merge and remove ask for a y/n confirmation. Remove is risk-aware — it inspects the workspace first and warns in red when removal would discard uncommitted changes or unmerged commits, and reassures in green when the branch is safe to drop:
Remove acme-api/feature-login? This discards uncommitted changes and 3 unmerged commits — work will be lost. Are you sure? [y/n]The remove prompt also offers f to forget the workspace instead: unregister it but leave its files and branch on disk. It's the way out when a removal is blocked because the worktree holds files wf can't delete (for example root-owned files left by a Docker container) — see Troubleshooting.
Managing projects
Press Enter on a project header row to open a popup action menu for that project:
| Key | Action |
|---|---|
| ↑ / ↓ | Move between options |
| Enter | Choose the highlighted option |
| Esc / q | Dismiss the menu |
The two options are:
- Rename — opens a text input pre-filled with the current name; edit it and press Enter to rename the project (its worktrees are retargeted to the new name). Same as
wf project rename. - Delete — unregisters the project from WorkFlow (the repository on disk is untouched). It asks to confirm, warning in red when the project still has registered workspaces that would be dropped.
Live refresh
While you're idle on the ledger, the dashboard re-derives git status (and the open-window markers) every 4 seconds, so edits in a workspace show up without pressing r. The cursor stays on the same workspace across refreshes.
Actions run the real CLI
The dashboard isn't a separate code path — its actions invoke the same engine as the CLI. Creating, merging, and removing briefly suspend the TUI to stream git and setup output, then return you to an updated ledger. Anything you can do here, you can also script with the commands.