Project Configuration
Settings live in .xpo/config.yaml, created by xpo init. View the current configuration with:
xpo config
Precedence
Configuration is resolved in this order (highest priority first):
- Environment variables — prefixed with
XPO_, dots become underscores (e.g.XPO_AUTO_COMMIT=true) - Project config —
.xpo/config.yaml, committed to git - User config —
~/.config/xpo/user.yaml, per-user, not committed
Core
prefix: myproject-
name: My Project
auto_commit: false
editor: nvim
user: "Alice <alice@example.com>"
These are the foundational settings for your project. The prefix determines how issue IDs look (e.g. myproject-1, myproject-2). It's derived from your folder name when you run xpo init, but you can change it anytime.
auto_commit controls whether xpo writes are committed to git automatically. When false (the default), changes accumulate in the working tree for you to commit on your own schedule. Set it to true for automatic commits after every change — convenient for solo work, but for teams, manual commits let you batch related changes.
| Key | Type | Default | Description |
|---|---|---|---|
prefix | string | <folder>- | Issue ID prefix. IDs become <prefix>1, <prefix>2, etc. |
name | string | — | Project display name, shown in the web board sidebar when running multiple projects. |
version | integer | — | Data model version. Managed by xpo migrate — don't edit by hand. |
user | string | — | Default identity for local operations, in "Name <email>" format. Falls back to git config if not set. |
editor | string | $EDITOR or vim | Editor command for interactive input (e.g. xpo update <id> without flags). |
auto_commit | boolean | false | Automatically git-commit after every xpo write. |
Estimation
estimation_system: fibonacci
count_unestimated: true
Story points quantify effort. The estimation_system determines which scale is available — both for xpo estimate on the CLI and the estimate picker in the web board. When count_unestimated is true, children without an explicit estimate count as 1 point toward the parent's rollup.
| Key | Type | Default | Description |
|---|---|---|---|
estimation_system | string | fibonacci | Scale for story-point estimates. Values: fibonacci, exponential, linear, shirt. |
count_unestimated | boolean | true | Count unestimated children as 1 point in parent rollup. |
Available scales
| Value | Point values | Display |
|---|---|---|
fibonacci | 1, 2, 3, 5, 8 | Numeric |
exponential | 1, 2, 4, 8, 16 | Numeric |
linear | 1, 2, 3, 4, 5 | Numeric |
shirt | 1, 2, 3, 5, 8 | XS, S, M, L, XL |
The shirt system stores numeric values internally but renders as t-shirt sizes. Both forms work as input — xpo estimate <id> M and xpo estimate <id> 3 are equivalent.
Cycles
cycles:
enabled: true
duration: 2w
start_day: monday
anchor_date: "2025-01-06"
Cycles give your team a regular sprint rhythm with automatic rollover and velocity tracking. When enabled, issues not marked DONE by the end of a cycle automatically roll forward. Completed issues retain their original cycle ID so historical metrics stay accurate.
The anchor_date pins cycle numbering to a specific date — useful for aligning with an existing sprint calendar. If omitted, xpo anchors to the nearest start_day before now.
| Key | Type | Default | Description |
|---|---|---|---|
cycles.enabled | boolean | false | Enable sprint/iteration tracking. |
cycles.duration | string | — | Cycle length. Values: 1w, 2w, 3w, 4w. Required when enabled. |
cycles.start_day | string | — | Day each cycle begins. Values: monday, tuesday, wednesday, thursday, friday, saturday, sunday. Required when enabled. |
cycles.anchor_date | string | — | YYYY-MM-DD reference date to pin cycle numbering. Optional. |
See Cycles for usage.
Labels
default_labels:
- bug
- feature
- epic
- improvement
- chore
labels:
bug: "#e11d48"
feature: "#2563eb"
epic: "#7c3aed"
improvement: "#0891b2"
Labels are freeform tags for categorizing issues. default_labels controls which labels appear in the web board's label picker. labels maps label names to CSS hex colors — entries here override the built-in colors for that label.
| Key | Type | Default | Description |
|---|---|---|---|
default_labels | list of strings | [bug, feature, epic, improvement] | Labels shown in the web board's label picker. |
hide_default_labels | boolean | false | Hide the built-in labels and only show custom ones. |
labels | map of name → hex color | built-in colors | Custom label colors. Case-sensitive keys. |
See Labels for usage.
Contributors
contributors:
- "Alice <alice@example.com>"
- "Bob <bob@example.com>"
Team members available for assignment in the web board's assignee picker. Each entry must be in "Name <email>" format.
| Key | Type | Default | Description |
|---|---|---|---|
contributors | list of strings | — | Team members. Format: "Name <email>". |
See Contributors for details.
Automations
automations:
first_start: true
last_completed: true
Automations propagate status changes between parent and child issues. When first_start is enabled, starting any child automatically moves the parent to DOING. When last_completed is enabled, completing the last child automatically moves the parent to DONE (if it was DOING).
| Key | Type | Default | Description |
|---|---|---|---|
automations.first_start | boolean | true | When any child starts (→ DOING), move parent to DOING. |
automations.last_completed | boolean | true | When the last child is DONE and parent is DOING, move parent to DONE. |
See Parent & Sub-Issues for how these interact with the issue hierarchy.
Drive (autonomous agents)
drive:
supervisor: claude
coder: claude
max_retries: 3
test_cmd: make test
timeout: 30m
Configuration for the xpo drive autonomous agent loop. The supervisor handles evaluation steps — spec analysis, context gathering, and review. The coder handles implementation. If the coder fails, it retries up to max_retries times before marking the issue BLOCKED.
The test_cmd is the shell command run to verify the implementation. If omitted, the supervisor agent detects the project's test setup automatically.
| Key | Type | Default | Description |
|---|---|---|---|
drive.supervisor | string | claude | Agent for evaluation steps. |
drive.coder | string | claude | Agent for the implementation step. |
drive.max_retries | integer | 3 | Max implementation attempts before marking BLOCKED. |
drive.test_cmd | string | — | Shell command to verify implementation. Auto-detected if omitted. |
drive.timeout | string | 30m | Max wall-clock time per drive run. |
See AI Agents for the full drive workflow.
Permissions
permissions:
roles:
admin: ["*"]
member: ["issue.read", "issue.create", "issue.update", "issue.comment", "issue.start"]
viewer: ["issue.read"]
users:
alice@example.com: admin
bob@example.com: member
Role-based access control, only enforced in Distributed Mode. When this block is absent, all authenticated users have full access. Use ["*"] to grant all capabilities to a role.
| Key | Type | Description |
|---|---|---|
permissions.roles | map of role → list of capabilities | Define named roles. |
permissions.users | map of email → role | Assign users to roles by email address. |
Available capabilities
issue.read, issue.create, issue.update, issue.comment, issue.start, issue.merge, issue.delete, issue.link
Remote
remote:
url: https://xpo.example.com
Configuration for connecting to a remote xpo server. The token is usually populated automatically by xpo login in the user config (~/.config/xpo/user.yaml) — you don't need to set it by hand.
| Key | Type | Description |
|---|---|---|
remote.url | string | URL of a remote xpo server. |
remote.token | string | Auth token. Usually set by xpo login. |
See Distributed Mode for server setup.
Style
style:
theme: default
UI theming for the web board.
| Key | Type | Default | Description |
|---|---|---|---|
style.theme | string | default | UI theme name. |
Troubleshooting
Validate your configuration and fix common issues:
xpo doctor
Upgrade the data model after updating xpo:
xpo migrate