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,XPO_CHAT_AGENT=codex). Every key can be set this way; list keys take a comma-separated value. Map keys, such aslabels, can only be set in a config file. - 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-a1b2c3). xpo init suggests one from your folder name, but you can change it anytime. Store it without a trailing dash — xpo adds the separator itself, and normalizes older configs that still have one.
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, without a trailing dash. IDs become <prefix>-<hash>, e.g. myproject-a1b2c3. |
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 in a terminal status by the end of a cycle automatically roll forward. Closed 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] | Built-in labels, shown in the web board's label picker. Read-only in the board. |
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 and the last child reaches a terminal status (DONE, CANCELED, or DUPLICATE), the parent automatically moves to DONE.
| 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 reaches a terminal status (DONE, CANCELED, or DUPLICATE), move parent to DONE. |
See Parent & Sub-Issues for how these interact with the issue hierarchy.
Drive (autonomous agents)
drive:
supervisor:
agent: claude
model: sonnet
coder:
agent: claude
max_retries: 3
timeout: 30m
# test_cmd: make test
Configuration for the xpo drive autonomous agent loop. Both supervisor and coder are nested objects with an agent key and an optional model override.
| Key | Type | Default | Description |
|---|---|---|---|
drive.supervisor.agent | string | claude | Agent for evaluation steps. |
drive.supervisor.model | string | sonnet | Model override for the supervisor. Optional. |
drive.coder.agent | string | claude | Agent for the implementation step. |
drive.coder.model | string | — | Model override for the coder. Optional. |
drive.max_retries | integer | 3 | Max implementation attempts before marking BLOCKED. |
drive.test_cmd | string | — | Shell command to verify implementation. Skipped with a hint when omitted. |
drive.timeout | string | 30m | Max wall-clock time per drive run. |
See AI Agents for the full drive workflow.
Agent chat
chat:
agent: claude
model: opus
Defaults for the board's agent chat. The model and effort pickers in the composer override them per chat.
| Key | Type | Default | Description |
|---|---|---|---|
chat.agent | string | first installed | Default agent: claude or codex. An unknown or uninstalled agent logs a warning and falls back to the first installed one. |
chat.model | string | agent's default | Default model for that agent. |
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