# How omarchy-default-agent Integrates with XDG Defaults: A Complete Technical Guide

> Learn how omarchy-default-agent integrates with XDG defaults. Discover how it stores and exposes your default agent for seamless system integration. Get the complete technical guide.

- Repository: [Omacom/omarchy](https://github.com/omacom/omarchy)
- Tags: how-to-guide
- Published: 2026-09-06

---

**The `omarchy-default-agent` wrapper stores the user's chosen default agent in `$XDG_STATE_HOME/omarchy/default-agent` and exposes it via command substitution to the rest of the Omarchy system.**

The **omarchy-default-agent** utility in the [omacom/omarchy](https://github.com/omacom/omarchy) repository provides a clean, XDG-compliant mechanism for persisting and retrieving the user's preferred AI agent. This small but critical component bridges high-level user selection with standards-compliant state management.

## XDG State File Location and Fallback Behavior

The canonical storage path follows the XDG Base Directory Specification precisely:

```

$XDG_STATE_HOME/omarchy/default-agent

```

When `$XDG_STATE_HOME` is unset, the specification's fallback applies automatically:

```bash
~/.local/state/omarchy/default-agent

```

This automatic fallback ensures **omarchy-default-agent** works out-of-the-box while respecting custom XDG layouts. Test suites frequently override `XDG_STATE_HOME` to achieve isolation, and the script handles this transparently.

## Reading the Default Agent Value

The script's read operation is intentionally minimal—a simple `cat` of the state file. The implementation returns an empty string when the file doesn't exist, allowing safe command substitution.

From `default/omarchy/omarchy-menu.jsonc`, the menu system queries the current selection:

```bash
[[ "$(omarchy-default-agent)" == "pi" ]]

```

This pattern appears throughout the codebase for conditional check-marks and agent-specific behavior.

Practical read example:

```bash

# Query the current default agent

current=$(omarchy-default-agent)
echo "Current default agent: $current"

```

## Writing and Updating the Agent Selection

Setting a new default persists immediately to the XDG state file. The write completes before any subsequent command executes, ensuring consistency across the system.

```bash

# Set a new default agent

omarchy-default-agent copilot   # writes "copilot" to $XDG_STATE_HOME/omarchy/default-agent

# Install an agent and auto-select it

omarchy-default-agent --install openclaw   # writes "openclaw" after successful mise install

```

The `--install` flag combines agent installation via **mise** with automatic default selection, streamlining the setup workflow.

## Integration Points Across Omarchy

### Menu System Wiring

The **Waybar/rofi menu** defined in `default/omarchy/omarchy-menu.jsonc` drives its check-marks and installation triggers through direct `$(omarchy-default-agent)` calls. Each menu entry evaluates the current selection to display visual state.

### Migration Compatibility

The migration script [`migrations/1786719479.sh`](https://github.com/omacom/omarchy/blob/main/migrations/1786719479.sh) explicitly documents its alignment with this approach:

```bash

# Reads default agent the same way omarchy-default-agent does

```

This comment ensures future maintainers preserve the XDG state file contract during data migrations.

### First-Run Onboarding

The hook at `install/user/first-run/setup-agent.hook` determines whether to prompt for initial selection:

```bash
[[ -z $(omarchy-default-agent) ]]

```

An empty result triggers the interactive setup flow; an existing value allows silent continuation.

## Complete Working Examples

Custom XDG layout during CI or testing:

```bash

# Respect a custom XDG layout

XDG_STATE_HOME=/tmp/xdg_state omarchy-default-agent   # reads/writes under /tmp/xdg_state/omarchy/default-agent

```

Full workflow demonstration:

```bash
#!/bin/bash

# Typical agent selection workflow

# 1. Check current default

current=$(omarchy-default-agent)
echo "Current: ${current:-'(none set)'}"

# 2. Set new default

omarchy-default-agent pi

# 3. Verify persistence

echo "Updated to: $(omarchy-default-agent)"

```

## Key Implementation Files

| File | Role |
|------|------|
| `bin/omarchy-default-agent` | Core wrapper implementing read/write logic and agent forwarding |
| `default/omarchy/omarchy-menu.jsonc` | Menu entries using `$(omarchy-default-agent)` for state display |
| [`migrations/1786719479.sh`](https://github.com/omacom/omarchy/blob/main/migrations/1786719479.sh) | Migration script with explicit XDG path documentation |
| `install/user/first-run/setup-agent.hook` | First-run hook checking for empty state |
| [`test/shell.d/default-agent-test.sh`](https://github.com/omacom/omarchy/blob/main/test/shell.d/default-agent-test.sh) | Test suite verifying XDG override handling |

## Summary

- **omarchy-default-agent** persists agent selection to `$XDG_STATE_HOME/omarchy/default-agent` with automatic fallback to `~/.local/state`
- The script exposes a simple read interface via `cat` and write interface via argument passing
- Menu system, migrations, and first-run hooks all consume the same command substitution interface
- XDG environment variable support enables seamless test isolation and custom directory layouts
- The implementation follows XDG Base Directory Specification without hardcoded paths

## Frequently Asked Questions

### What happens if XDG_STATE_HOME is not set?

The script automatically falls back to `~/.local/state/omarchy/default-agent` per the XDG Base Directory Specification. No configuration is required for standard operation.

### How do other Omarchy components read the default agent?

Components use command substitution: `$(omarchy-default-agent)`. The menu JSON, migration scripts, and first-run hooks all employ this pattern for consistent state access.

### Can I use omarchy-default-agent in CI or testing environments?

Yes. Override `XDG_STATE_HOME` to any writable directory. The test suite at [`test/shell.d/default-agent-test.sh`](https://github.com/omacom/omarchy/blob/main/test/shell.d/default-agent-test.sh) demonstrates this pattern for isolated test execution.

### Does the script handle concurrent writes safely?

The write operation completes atomically before returning, ensuring subsequent reads see the updated value. For production deployments with high concurrency, filesystem-level atomicity depends on the underlying `write` syscall behavior.