Status
Status values
Every issue moves through a simple lifecycle. Active statuses track work in progress; terminal statuses close the issue.
BACKLOG → PLANNED → DOING → DONE
↘ BLOCKED ↗ ↗
any active → CANCELED
any active → DUPLICATE
Active statuses:
| Status | Meaning |
|---|---|
BACKLOG | Captured but not yet spec'd or prioritized |
PLANNED | Spec'd and ready for work |
DOING | Actively in progress |
BLOCKED | Stuck on something |
Terminal statuses (issue is closed):
| Status | Meaning |
|---|---|
DONE | Shipped — counts toward velocity and burndown |
CANCELED | Won't fix, no longer relevant, or descoped |
DUPLICATE | Already covered by another issue |
Any active status can transition to any terminal status. Any terminal status can transition back to an active status (reopen).
Transition commands
xpo planned <id> # → PLANNED
xpo start <id> # → DOING (creates worktree + branch)
xpo blocked <id> # → BLOCKED
xpo done <id> # → DONE
Or set status directly:
xpo update <id> --status PLANNED
xpo update <id> --status CANCELED
xpo update <id> --status DUPLICATE
Worktrees
Every issue is worked in its own git worktree. xpo start sets the status to DOING and creates a worktree at .xpo/worktrees/<branch>/ with a new branch named after the issue. The primary checkout (the hub) stays on main, so multiple agents or developers can work on different issues simultaneously without interfering with each other.
xpo start <id> # creates worktree + branch
xpo start <id> --force # take over (removes and recreates the worktree)
The worktree path is printed on success and returned by the MCP start tool, so agents can cd into it automatically.
start assigns the issue to you (or, for an agent, to the person it works for). An issue that's already DOING needs --force to take over. One exception: running start again from inside the issue's own worktree is safe — it resumes the existing worktree, moves the issue back to DOING if needed, and doesn't recreate anything or re-run the setup hook. This lets an orchestrator start an issue and hand it to an agent that calls start itself.
You can configure a setup hook that runs after worktree creation:
worktree_setup: "make deps" # runs in the new worktree directory
Merging
When the work is done, merge the branch back and close the issue in one step. The merge always runs from the hub, which must be on the default branch, and the issue's worktree is cleaned up automatically:
xpo merge <id> # prompts for a strategy (default: squash)
xpo merge <id> --squash # squash-merge + close + remove worktree
xpo merge <id> --ff # fast-forward only
xpo merge <id> --keep-branch # keep branch (worktree still removed)
You can run xpo merge from inside the issue's worktree too — it always operates on the hub checkout.
Migrating from branch mode
Earlier versions could work an issue on a plain branch in the primary checkout (--no-wt, worktrees: false). That mode is gone: --no-wt now fails with "unknown flag", and worktrees: false in config.yaml is ignored with a warning. Before upgrading:
- Merge or park any issue you started in branch mode.
- Check out the default branch in the primary checkout —
xpo mergerefuses to run while the hub is on another branch, andxpo startrefuses an issue whose branch is checked out there.
Branches without a worktree still merge normally from the hub.
Review the diff before merging:
xpo review <id>
Blocked issues
An issue with blocked_by relationships cannot move to DOING until every blocker is DONE. A CANCELED or DUPLICATE blocker still blocks: the work it stood for never happened. Remove the link, or point it at the issue that does the work. xpo start refuses a blocked issue and says which link to remove, and drive skips it.
On the board, Start Work is disabled while any blocker is unresolved. Hover it to see each blocker and its status, with a one-click Remove link for canceled and duplicate blockers. Start Work is also disabled on BACKLOG issues ("Move the issue to Planned to start work"), since start requires PLANNED. See Relationships for details.
Status cascading
Status changes can cascade between parent and child issues through automations — for example, completing all children automatically completes the parent. See Parent & Sub-Issues for details.
In the web board
Drag issues between status columns to transition them. The board view shows issues grouped by status in a Kanban layout.
On an issue's detail page, press s (or click the status in the sidebar) to pick a new status — or press 1–5 to jump straight to one.