Agent of Empires

A terminal session manager for AI coding agents on Linux and macOS, built on tmux and written in Rust.

AoE lets you run multiple AI agents in parallel -- each in its own tmux session, optionally on its own git branch, optionally inside a Docker container. A TUI dashboard shows you what every agent is doing at a glance.

Agent of Empires Demo

Why AoE?

The problem: You're working with AI coding agents (Claude Code, OpenCode, Codex, etc.) and want to run several in parallel across different tasks or branches. Managing multiple terminal windows, git branches, and container lifecycles by hand gets tedious fast.

AoE handles it for you:

  • One dashboard for all agents. See status (running, waiting, idle, error) at a glance. Toggle to paired shell terminals with t.
  • Git worktrees built in. Create a session and AoE creates a branch + worktree automatically. Delete the session and AoE cleans up.
  • Docker sandboxing. Run agents in isolated containers with your project mounted and auth credentials shared across containers.
  • Per-repo configuration. Drop a .aoe/config.toml in your repo for project-specific settings and hooks that run on session creation or launch.
  • Sessions survive everything. AoE wraps tmux, so agents keep running when you close the TUI, disconnect SSH, or your terminal crashes.

Supported Agents

Claude Code, OpenCode, Mistral Vibe, Codex CLI, and Gemini CLI. AoE auto-detects which are installed.

Documentation

Getting Started

Guides

Reference

Contributing

  • Development -- building, testing, and generating demo assets

Installation

Prerequisites

  • tmux (required)
  • Docker (optional, for sandboxing agents in containers)

Install Agent of Empires

Run the install script:

curl -fsSL \
  https://raw.githubusercontent.com/njbrake/agent-of-empires/main/scripts/install.sh \
  | bash

Homebrew

brew install njbrake/aoe/aoe

Update via brew update && brew upgrade aoe.

Build from Source

git clone https://github.com/njbrake/agent-of-empires
cd agent-of-empires
cargo build --release

The binary will be at target/release/aoe.

Verify Installation

aoe --version

Uninstall

To remove Agent of Empires:

aoe uninstall

This will guide you through removing the binary, configuration, and tmux settings.

Quick Start

Launch the TUI

aoe

This opens the dashboard. You'll see an empty session list on first run.

Create Your First Session

From the TUI: Press n to open the new session dialog. Fill in the path to your project (or leave it as . for the current directory) and press Enter.

From the CLI:

aoe add /path/to/project

The session appears in the dashboard with status Idle.

Attach to a Session

Select a session and press Enter to attach. You're now inside a tmux session running your AI agent (Claude Code by default).

To return to the TUI, press Ctrl+b d (the standard tmux detach shortcut).

Use the Terminal View

Press t to toggle between Agent View and Terminal View. Each agent session has a paired shell terminal where you can run builds, tests, and git commands without interrupting the agent.

Review Changes with Diff View

Press D to open the diff view. This shows changes between your working directory and the base branch. Navigate files with j/k, press e to edit, and Esc to close.

Create a Worktree Session

To work on a new branch with its own directory:

# CLI
aoe add . -w feat/my-feature -b

# TUI: press n, fill in the worktree branch field

This creates a new git branch, a worktree directory, and a session pointing at it. When you delete the session, AoE offers to clean up the worktree too.

Create a Sandboxed Session

To run an agent inside a Docker container:

aoe add --sandbox .

In the TUI, toggle the sandbox checkbox when creating a session. The agent runs in an isolated container with your project mounted at /workspace and authentication credentials shared via persistent Docker volumes.

Requires Docker to be installed.

Choose a Different Agent

By default, AoE uses Claude Code. To use a different tool:

aoe add -c opencode .
aoe add -c vibe .
aoe add -c codex .
aoe add -c gemini .

In the TUI, select the tool from the dropdown in the new session dialog.

TUI Keyboard Reference

KeyAction
nNew session
EnterAttach to session
dDelete session
tToggle Agent/Terminal view
DOpen diff view
/Search sessions
?Show help
qQuit
Ctrl+b dDetach from tmux session

Next Steps

Workflow Guide

This guide covers the recommended setup and daily workflow for using aoe with git worktrees.

Project Setup: Bare Git Repos

The recommended way to set up a project is using a "bare repo" structure. This keeps your main repository and all worktrees organized under a single directory:

my-project/
  .bare/               # Bare git repository
  .git                 # File pointing to .bare
  main/                # Worktree for main branch
  feat-api/            # Worktree for feature branch
  fix-bug/             # Another worktree

Initial Setup

# Clone as bare repo
git clone --bare git@github.com:user/repo.git my-project/.bare

cd my-project

# Create .git file pointing to bare repo
echo "gitdir: ./.bare" > .git

# Configure fetch to get all branches
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
git fetch origin

# Create your main worktree
git worktree add main main

Now when you run aoe from my-project/, new worktrees are created as siblings (e.g., my-project/feat-api/) rather than in a separate directory.

Why Bare Repos?

  • Clean organization: Everything lives under one project directory
  • Sandbox-friendly: All paths stay within the project root (important for Docker sandboxing)
  • Easy navigation: Switch between branches by switching directories

Single-Window Workflow

Run aoe in a single terminal and toggle between views:

KeyViewPurpose
(default)Agent ViewManage and interact with AI coding agents
tTerminal ViewAccess paired terminals for git, builds, tests

Daily Workflow

1. Start your day

cd ~/scm/my-project
aoe

You'll see your sessions in Agent View. Keep one session on main for general questions and pulling updates.

2. Update main (Terminal View)

  • Press t to switch to Terminal View
  • Select your main session, press Enter to attach to its terminal
  • Run git pull origin main
  • Detach with Ctrl+b d
  • Press t to return to Agent View

3. Create a new session

  • Press n to open the new session dialog
  • Fill in the worktree field with your branch name (e.g., feat/auth-refactor)
  • Press Enter

This creates:

  • A new branch from your current HEAD
  • A new worktree at ./feat-auth-refactor/
  • A new session with an agent working in that worktree

4. Work on your feature (Agent View)

  • Select your session and press Enter to attach
  • Interact with the agent
  • Detach with Ctrl+b d when done

5. Run builds/tests (Terminal View)

  • Press t to switch to Terminal View
  • Select the same session, press Enter
  • Run your build commands, tests, git operations
  • Detach with Ctrl+b d

6. Clean up when done

  • In Agent View, select the session and press d to delete
  • Answer Y to also remove the worktree

Tips

  • Keep one session on main: Use it for codebase questions and its terminal for git pull
  • One task, one session: Each worktree maps to one aoe session. Keeps context isolated.
  • Pull before creating: Always update main before creating new sessions so branches start fresh
  • Let agents stay focused: Git operations happen in the paired terminal, not in agent sessions

Keyboard Reference

KeyAction
tToggle between Agent View and Terminal View
DOpen Diff View to review git changes
EnterAttach to agent (Agent View) or terminal (Terminal View)
nCreate new session
dDelete session (Agent View only)
?Show help
Ctrl+b dDetach from tmux (return to aoe)

Non-Bare Repos

If you're not using a bare repo setup, aoe defaults to creating worktrees in a sibling directory:

~/scm/
  my-project/              # Your repo (stays on main)
  my-project-worktrees/    # Worktrees created here
    feat-auth-refactor/
    fix-bug/

You can customize this with path_template in your config. See the Worktrees Reference for details.

Docker Sandbox: Quick Reference

Overview

Docker sandboxing runs your AI coding agents (Claude Code, OpenCode, Mistral Vibe, Codex CLI, Gemini CLI) inside isolated Docker containers while maintaining access to your project files and credentials.

Key Features:

  • One container per session
  • Shared authentication across containers (no re-auth needed)
  • Automatic container lifecycle management
  • Full project access via volume mounts

CLI vs TUI Behavior

FeatureCLITUI
Enable sandbox--sandbox flagCheckbox toggle
Custom image--sandbox-image <image>Not supported
Container cleanupAutomatic on removeAutomatic on remove
Keep container--keep-container flagNot supported

One-Liner Commands

# Create sandboxed session
aoe add --sandbox .

# Create sandboxed session with custom image
aoe add --sandbox-image myregistry/custom:v1 .

# Create and launch sandboxed session
aoe add --sandbox -l .

# Remove session (auto-cleans container)
aoe remove <session>

# Remove session but keep container
aoe remove <session> --keep-container

Note: In the TUI, the sandbox checkbox only appears when Docker is available on your system.

Default Configuration

[sandbox]
enabled_by_default = false
yolo_mode_default = false
default_image = "ghcr.io/njbrake/aoe-sandbox:latest"
auto_cleanup = true
cpu_limit = "4"
memory_limit = "8g"
environment = ["ANTHROPIC_API_KEY"]

Configuration Options

OptionDefaultDescription
enabled_by_defaultfalseAuto-enable sandbox for new sessions
yolo_mode_defaultfalseSkip agent permission prompts in sandboxed sessions
default_imageghcr.io/njbrake/aoe-sandbox:latestDocker image to use
auto_cleanuptrueRemove containers when sessions are deleted
cpu_limit(none)CPU limit (e.g., "4")
memory_limit(none)Memory limit (e.g., "8g")
environment[]Env var names to pass through from host
environment_values{}Env vars with explicit values to inject (see below)
volume_ignores[]Directories to exclude from the project mount via anonymous volumes
extra_volumes[]Additional volume mounts
default_terminal_mode"host"Paired terminal location: "host" (on host machine) or "container" (inside Docker)

Volume Mounts

Automatic Mounts

Host PathContainer PathModePurpose
Project directory/workspaceRWYour code
~/.gitconfig/root/.gitconfigROGit config
~/.ssh//root/.ssh/ROSSH keys
~/.config/opencode//root/.config/opencode/ROOpenCode config
~/.vibe//root/.vibe/RWVibe config (if exists)

Persistent Auth Volumes

Volume NameContainer PathPurpose
aoe-claude-auth/root/.claude/Claude Code credentials
aoe-opencode-auth/root/.local/share/opencode/OpenCode credentials
aoe-vibe-auth/root/.vibe/Mistral Vibe credentials
aoe-codex-auth/root/.codex/Codex CLI credentials
aoe-gemini-auth/root/.gemini/Gemini CLI credentials

Note: Auth persists across containers. First session requires authentication, subsequent sessions reuse it.

Container Naming

Containers are named: aoe-sandbox-{session_id_first_8_chars}

Example: aoe-sandbox-a1b2c3d4

How It Works

  1. Session Creation: When you add a sandboxed session, aoe records the sandbox configuration
  2. Container Start: When you start the session, aoe creates/starts the Docker container with appropriate volume mounts
  3. tmux + docker exec: Host tmux runs docker exec -it <container> <tool> (claude, opencode, vibe, codex, or gemini)
  4. Cleanup: When you remove the session, the container is automatically deleted

Environment Variables

These terminal-related variables are always passed through for proper UI/theming:

  • TERM, COLORTERM, FORCE_COLOR, NO_COLOR

Pass additional variables (like API keys) through containers by adding them to config:

[sandbox]
environment = ["ANTHROPIC_API_KEY", "OPENAI_API_KEY", "GEMINI_API_KEY"]

These variables are read from your host environment and passed to containers (in addition to the terminal defaults above).

Sandbox-Specific Values (environment_values)

Use environment_values to inject env vars with values that AOE manages directly, independent of your host environment. This is useful for giving sandboxes credentials that differ from (or don't exist on) the host:

[sandbox.environment_values]
GH_TOKEN = "ghp_sandbox_scoped_token"
CUSTOM_API_KEY = "sk-sandbox-only-key"

Values starting with $ are read from a host env var instead of being used literally. This lets you store the actual secret in your shell profile rather than in the AOE config file:

[sandbox.environment_values]
GH_TOKEN = "$AOE_GH_TOKEN"   # reads AOE_GH_TOKEN from host, injects as GH_TOKEN
# In your .bashrc / .zshrc
export AOE_GH_TOKEN="ghp_sandbox_scoped_token"

If the referenced host env var is not set, the entry is silently skipped.

To use a literal value starting with $, double it: $$LITERAL is injected as $LITERAL.

Available Images

AOE provides two official sandbox images:

ImageDescription
ghcr.io/njbrake/aoe-sandbox:latestBase image with Claude Code, OpenCode, Mistral Vibe, Codex CLI, Gemini CLI, git, ripgrep, fzf
ghcr.io/njbrake/aoe-dev-sandbox:latestExtended image with additional dev tools

Dev Sandbox Tools

The dev sandbox (aoe-dev-sandbox) includes everything in the base image plus:

  • Rust (rustup, cargo, rustc)
  • uv (fast Python package manager)
  • Node.js LTS (via nvm, with npm and npx)
  • GitHub CLI (gh)

To use the dev sandbox:

# Per-session
aoe add --sandbox-image ghcr.io/njbrake/aoe-dev-sandbox:latest .

# Or set as default in ~/.agent-of-empires/config.toml
[sandbox]
default_image = "ghcr.io/njbrake/aoe-dev-sandbox:latest"

Custom Docker Images

The default sandbox image includes Claude Code, OpenCode, Mistral Vibe, Codex CLI, Gemini CLI, git, and basic development tools. For projects requiring additional dependencies beyond what the dev sandbox provides, you can extend either base image.

Step 1: Create a Dockerfile

Create a Dockerfile in your project (or a shared location):

FROM ghcr.io/njbrake/aoe-sandbox:latest

# Example: Add Python for a data science project
RUN apt-get update && apt-get install -y \
    python3 \
    python3-pip \
    python3-venv \
    && rm -rf /var/lib/apt/lists/*

# Install Python packages
RUN pip3 install --break-system-packages \
    pandas \
    numpy \
    requests

Step 2: Build Your Image

# Build locally
docker build -t my-sandbox:latest .

# Or build and push to a registry
docker build -t ghcr.io/yourusername/my-sandbox:latest .
docker push ghcr.io/yourusername/my-sandbox:latest

Step 3: Configure AOE to Use Your Image

Option A: Set as default for all sessions

Add to ~/.agent-of-empires/config.toml:

[sandbox]
default_image = "my-sandbox:latest"
# Or with registry:
# default_image = "ghcr.io/yourusername/my-sandbox:latest"

Option B: Use per-session via CLI

aoe add --sandbox-image my-sandbox:latest .

Worktrees and Sandboxing

When using git worktrees with sandboxing, there's an important consideration: worktrees have a .git file that points back to the main repository's git directory. If this reference points outside the sandboxed directory, git operations inside the container may fail.

The Problem

With the default worktree template (../{repo-name}-worktrees/{branch}):

/projects/
  my-repo/
    .git/                    # Main repo's git directory
    src/
  my-repo-worktrees/
    feature-branch/
      .git                   # FILE pointing to /projects/my-repo/.git/...
      src/

When sandboxing feature-branch/, the container can't access /projects/my-repo/.git/.

The Solution: Bare Repo Pattern

Use the linked worktree bare repo pattern to keep everything in one directory:

/projects/my-repo/
  .bare/                     # Bare git repository
  .git                       # FILE: "gitdir: ./.bare"
  main/                      # Worktree (main branch)
  feature/                   # Worktree (feature branch)

Now when sandboxing feature/, the container has access to the sibling .bare/ directory.

AOE automatically detects bare repo setups and uses ./{branch} as the default worktree path template, keeping new worktrees as siblings.

Quick Setup

# Convert existing repo to bare repo pattern
cd my-project
mv .git .bare
echo "gitdir: ./.bare" > .git

# Or clone fresh as bare
git clone --bare git@github.com:user/repo.git my-project/.bare
cd my-project
echo "gitdir: ./.bare" > .git
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
git fetch origin
git worktree add main main

See the Workflow Guide for detailed bare repo setup instructions.

Repository Configuration & Hooks

AoE supports per-repo configuration via a .aoe/config.toml file in your project root. This lets you define project-specific defaults and hooks that apply to every team member using AoE on that repo.

Getting Started

Generate a template config:

aoe init

This creates .aoe/config.toml with commented-out examples. Edit the file to enable the settings you need.

Configuration Sections

Hooks

Hooks run shell commands at specific points in the session lifecycle.

[hooks]
# Run once when a session is first created (failures abort creation)
on_create = ["npm install", "cp .env.example .env"]

# Run every time a session starts (failures are logged but non-fatal)
on_launch = ["npm install"]

on_create runs only once, when the session is first created. If any command fails, session creation is aborted. Use this for one-time setup like installing dependencies or generating config files.

on_launch runs every time a session starts (including the first time, and every restart). Failures are logged as warnings but don't prevent the session from starting. Use this for things like ensuring dependencies are up to date.

For sandboxed sessions, hooks run inside the Docker container.

Session

[session]
default_tool = "opencode"   # Override the default agent for this repo

Available tools: claude, opencode, vibe, codex, gemini.

Sandbox

Override sandbox settings for this repo:

[sandbox]
enabled_by_default = true
default_image = "ghcr.io/njbrake/aoe-dev-sandbox:latest"
environment = ["NODE_ENV", "DATABASE_URL"]
environment_values = { CUSTOM_KEY = "value" }
volume_ignores = ["node_modules", ".next", "target"]
extra_volumes = ["/data:/data:ro"]
cpu_limit = "8"
memory_limit = "16g"
auto_cleanup = true
default_terminal_mode = "host"   # "host" or "container"

Worktree

Override worktree settings for this repo:

[worktree]
enabled = true
path_template = "../{repo-name}-worktrees/{branch}"
bare_repo_path_template = "./{branch}"
auto_cleanup = true
show_branch_in_tui = true
delete_branch_on_cleanup = false

Hook Trust System

When AoE encounters hooks in a repo for the first time, it prompts you to review and approve them before execution. This prevents untrusted repos from running arbitrary commands.

  • Trust decisions are stored globally (shared across all profiles)
  • If hook commands change (e.g., someone updates .aoe/config.toml), AoE prompts for re-approval
  • Use --trust-hooks with aoe add to skip the trust prompt (useful for CI or repos you control)
# Trust hooks automatically
aoe add --trust-hooks .

Config Precedence

Settings are resolved in this order (later overrides earlier):

  1. Global config (~/.agent-of-empires/config.toml)
  2. Profile config (~/.agent-of-empires/profiles/<name>/config.toml)
  3. Repo config (.aoe/config.toml)

Only settings that are explicitly set in the repo config override the global/profile values. Unset fields inherit from the higher-level config.

Example: Full Repo Config

[hooks]
on_create = ["npm install", "npx prisma generate"]
on_launch = ["npm install"]

[session]
default_tool = "claude"

[sandbox]
enabled_by_default = true
default_image = "ghcr.io/njbrake/aoe-dev-sandbox:latest"
environment = ["DATABASE_URL", "REDIS_URL"]
environment_values = { NODE_ENV = "development" }
volume_ignores = ["node_modules", ".next"]

[worktree]
enabled = true

Checking Into Version Control

The .aoe/config.toml file is meant to be committed to your repo so the entire team shares the same configuration. The hook trust system ensures that each developer explicitly approves hook commands before they run.

Worktrees Reference

Reference documentation for git worktree commands and configuration in aoe.

For workflow guidance, see the Workflow Guide.

CLI vs TUI Behavior

FeatureCLITUI
Create new branchUse -b flagAlways creates new branch
Use existing branchOmit -b flagNot supported
Branch validationChecks if branch existsNone (always creates)

CLI Commands

# Create worktree session (new branch)
aoe add . -w feat/my-feature -b

# Create worktree session (existing branch)
aoe add . -w feat/my-feature

# List all worktrees
aoe worktree list

# Show session info
aoe worktree info <session>

# Find orphaned worktrees
aoe worktree cleanup

# Remove session (prompts for worktree cleanup)
aoe remove <session>

# Remove session (keep worktree)
aoe remove <session> --keep-worktree

TUI Keyboard Shortcuts

KeyAction
nNew session dialog
TabNext field
Shift+TabPrevious field
EnterSubmit and create session
EscCancel

When creating a session with a worktree branch name in the TUI, it automatically creates a new branch and worktree.

Configuration

[worktree]
enabled = false
path_template = "../{repo-name}-worktrees/{branch}"
bare_repo_path_template = "./{branch}"
auto_cleanup = true
show_branch_in_tui = true
delete_branch_on_cleanup = false

Template Variables

VariableDescription
{repo-name}Repository folder name
{branch}Branch name (slashes converted to hyphens)
{session-id}First 8 characters of session UUID

Path Template Examples

# Default (sibling directory) - used for non-bare repos
path_template = "../{repo-name}-worktrees/{branch}"

# Bare repo default (worktrees as siblings)
bare_repo_path_template = "./{branch}"

# Nested in repo
path_template = "./worktrees/{branch}"

# Absolute path
path_template = "/absolute/path/to/worktrees/{repo-name}/{branch}"

# With session ID for uniqueness
path_template = "../wt/{branch}-{session-id}"

Cleanup Behavior

ScenarioCleanup Prompt?
aoe-managed worktreeYes
Manual worktreeNo
--keep-worktree flagNo (skips prompt)
Non-worktree sessionNo

Auto-Detection

AOE automatically detects bare repos and uses bare_repo_path_template instead of path_template, creating worktrees as siblings within the project directory.

File Locations

ItemPath
Config~/.agent-of-empires/config.toml
Sessions~/.agent-of-empires/profiles/<profile>/sessions.json

Error Messages

ErrorSolution
"Not in a git repository"Navigate to a git repo first
"Worktree already exists"Use different branch name or add {session-id} to template
"Failed to remove worktree"May need manual cleanup with git worktree remove
"Branch already exists" (CLI)Branch exists; remove -b flag to use existing branch

Diff View

The diff view lets you review changes between your working directory and a base branch (like main), then edit files directly.

Opening Diff View

From the main screen, press D to open the diff view. It shows:

  • Left panel: List of changed files with status indicators (M=modified, A=added, D=deleted)
  • Right panel: Diff content for the selected file

The diff is computed against the base branch (defaults to main or your repo's default branch).

KeyAction
j / k or / Navigate between files
Scroll wheelScroll through diff content
PgUp / PgDnPage through diff
g / GJump to top / bottom of diff

Editing Files

Press e or Enter to open the selected file in your editor ($EDITOR, or vim/nano if not set).

After saving and exiting, the diff view refreshes automatically to show your changes.

Other Commands

KeyAction
bChange base branch
rRefresh the diff
?Show help
EscClose diff view

Configuration

In your config file (~/.config/agent-of-empires/config.toml on Linux, ~/.agent-of-empires/config.toml on macOS):

[diff]
# Default branch to compare against (auto-detected if not set)
default_branch = "main"

# Lines of context around changes (default: 3)
context_lines = 3

Tips: See Changes While Editing

The diff view shows you where changes are before you edit. For an even better experience, you can install editor plugins that show git diff markers in the gutter while you edit:

Vim

Install vim-gitgutter or vim-signify. These show +, -, and ~ markers in the sign column for added, removed, and modified lines.

With vim-plug:

Plug 'airblade/vim-gitgutter'

Nano

Nano doesn't have a plugin system, so there's no equivalent. Use the diff view to note line numbers before editing, or consider switching to vim for this workflow.

Other Editors

Workflow Example

  1. Press D to open diff view
  2. Use j/k to browse changed files
  3. Scroll to review each file's changes
  4. Press e to edit a file that needs work
  5. Save and exit the editor
  6. Continue reviewing (diff auto-refreshes)
  7. Press Esc when done

tmux Status Bar

Agent of Empires can display session information in your tmux status bar, showing:

  • Session title: The name of your aoe session
  • Git branch: For worktree sessions
  • Container name: For sandboxed (Docker) sessions

How It Works

When you start a session, aoe sets tmux user options (@aoe_title, @aoe_branch, @aoe_sandbox) and configures the status bar to display this information with aoe's phosphor green theme.

Example status bars:

aoe: My Session | 14:30                           # Basic session
aoe: My Session | feature-branch | 14:30          # Worktree session
aoe: My Session ⬡ aoe_my_container | 14:30        # Sandboxed session
aoe: My Session | main ⬡ aoe_container | 14:30    # Worktree + sandbox

Auto Mode (Default)

By default, aoe uses "auto" mode for the status bar:

  • If you don't have a ~/.tmux.conf: aoe automatically styles the status bar for aoe sessions
  • If you have a ~/.tmux.conf: aoe assumes you prefer your own configuration and does not modify the status bar

This ensures beginners get a helpful status bar out of the box, while experienced tmux users retain full control.

Configuration

Configure the status bar behavior in ~/.agent-of-empires/config.toml:

[tmux]
# "auto" (default) - Apply only if no ~/.tmux.conf exists
# "enabled"        - Always apply aoe status bar styling
# "disabled"       - Never apply, use your own tmux config
status_bar = "auto"
mouse = "auto"    # Same modes: auto, enabled, disabled

Values

ValueDescription
autoApply status bar if user has no tmux config (default)
enabledAlways apply aoe status bar to aoe sessions
disabledNever modify tmux status bar

Custom Integration

If you have your own tmux configuration but want to display aoe session info, use the aoe tmux status command.

Basic Integration

Add this to your ~/.tmux.conf:

set -g status-right "#(aoe tmux status) | %H:%M"

This will show the aoe session title and branch when attached to an aoe session, and nothing when in other tmux sessions.

JSON Output

For more advanced scripting:

aoe tmux status --format json

Output:

{"title": "My Session", "branch": "feature-branch", "sandbox": null}

For a sandboxed session:

{"title": "My Session", "branch": null, "sandbox": "aoe_my_container"}

Returns null if not in an aoe session.

Example: Conditional Display

# Only show aoe info if in an aoe session
set -g status-right "#{?#{==:#(aoe tmux status),},,%#(aoe tmux status) | }%H:%M"

tmux User Options

When aoe starts a session with status bar enabled, it sets these tmux options:

OptionDescription
@aoe_titleSession title
@aoe_branchGit branch (worktree sessions only)
@aoe_sandboxContainer name (sandboxed sessions only)

You can reference these in your own tmux config:

set -g status-right "#{@aoe_title} #{@aoe_branch} #{@aoe_sandbox} | %H:%M"

Troubleshooting

Status bar not showing

  1. Check if you have a ~/.tmux.conf or ~/.config/tmux/tmux.conf
  2. If so, either:
    • Set status_bar = "enabled" in your aoe config
    • Or add aoe tmux status to your tmux.conf manually

Status bar shows old info

The tmux user options are set when the session starts. If you rename a session in aoe, the status bar will show the old name until you restart the session.

Branch not showing

Branch is only displayed for worktree sessions (sessions created with aoe add --worktree). Regular sessions don't have a fixed branch.

Container not showing

Container name is only displayed for sandboxed sessions (sessions created with aoe add --sandbox). The container name follows the pattern aoe_<session_id>.

Sound Effects

Agent of Empires can play sound effects when agent sessions change state, providing audio feedback for transitions like starting, running, waiting, idle, and error states.

Features

  • 🔊 State transition sounds (start, running, waiting, idle, error)
  • 🎵 Multiple installation options (bundled, AoE II extraction, custom)
  • 🎨 Fully customizable - use any .wav/.ogg files
  • ⚙️ Configurable via Settings TUI
  • 🎯 Per-transition sound overrides
  • 🎲 Random or specific sound modes

Quick Start

  1. Install sounds:

    aoe sounds install
    

    This downloads and installs CC0 fantasy/RPG sounds from GitHub to your config directory.

  2. Enable sounds in settings:

    • Launch aoe (TUI mode)
    • Press s to open Settings
    • Navigate to the Sound category
    • Enable sounds
  3. Test it: Start an agent session and listen for the transition sounds!

Available Sounds

Agent of Empires can download 10 CC0 (public domain) fantasy/RPG sound effects from GitHub:

Default State Transition Sounds

  • start.wav - Spell fire sound (session starting)
  • running.wav - Blade sound (agent actively working)
  • waiting.wav - Misc sound (agent waiting for input)
  • idle.wav - Book sound (agent idle)
  • error.wav - Roar sound (error occurred)

Additional Variety Sounds

  • spell.wav - Alternative spell/magic effect
  • coins.wav - Coin/reward sound
  • metal.wav - Metal impact sound
  • chain.wav - Chain/lock sound
  • gem.wav - Gem/crystal sound

All sounds are from the 80 CC0 RPG SFX pack by SubspaceAudio.

Installation

Install Sounds from GitHub

aoe sounds install

This downloads and installs 10 CC0 (public domain) fantasy/RPG sounds from the GitHub repository to:

  • Linux: ~/.config/agent-of-empires/sounds/
  • macOS: ~/.agent-of-empires/sounds/

Note: Requires an internet connection for the initial download. Sounds are downloaded from: https://github.com/njbrake/agent-of-empires/tree/main/bundled_sounds

Useful Commands

Check installed sounds:

aoe sounds list

Test a sound:

aoe sounds test start

Sound Modes

Random Mode (default)

Picks a random sound from your sounds directory for each transition.

Specific Mode

Always plays the same sound file. Useful if you want one signature sound for all transitions.

Configuration

Global Settings

Configure sounds for all profiles:

  1. Launch aoe TUI
  2. Press s for Settings
  3. Select "Sound" category
  4. Configure:
    • Enabled: Turn sounds on/off
    • Mode: Random or Specific
    • Per-transition overrides: Set specific sounds for each state

Profile Settings

Override sound settings per profile:

  1. In Settings, toggle to "Profile" scope (top-right)
  2. Configure sound overrides for this profile only

TOML Configuration

You can also edit configuration files directly:

Global: ~/.config/agent-of-empires/config.toml (Linux) or ~/.agent-of-empires/config.toml (macOS)

[sound]
enabled = true
mode = "random"
on_error = "error"  # Use specific sound for errors

Profile: ~/.config/agent-of-empires/profiles/<profile>/config.toml

[sound]
enabled = true
on_start = "spell"
on_running = "metal"
on_error = "error"

Custom Sounds

Add your own sounds to ~/.config/agent-of-empires/sounds/:

  1. Supported formats: .wav, .ogg
  2. File naming: Use descriptive names (e.g., wololo.wav, rogan.ogg)
  3. Reference in config: Use the filename without extension

Example:

# Linux
cp ~/Downloads/wololo.wav ~/.config/agent-of-empires/sounds/

# Then in settings, set "On Start" to "wololo"

Audio Playback

Sounds are played using platform-native audio players:

  • macOS: afplay
  • Linux: aplay (ALSA) or paplay (PulseAudio)

If sounds don't play, ensure you have audio tools installed:

# Debian/Ubuntu
sudo apt install alsa-utils pulseaudio-utils

# Arch Linux
sudo pacman -S alsa-utils pulseaudio

Troubleshooting

Sounds not playing?

  • SSH Session: Audio doesn't work over SSH - you need a local terminal with speakers/headphones
  • Check that sound files exist in ~/.config/agent-of-empires/sounds/
  • Verify sounds are enabled in Settings
  • Test audio with: aplay ~/.config/agent-of-empires/sounds/start.wav (Linux)
  • Check logs: AGENT_OF_EMPIRES_DEBUG=1 aoe

Want Age of Empires II sounds? If you own AoE II, manually copy the taunt files to your sounds directory.

Custom sounds aren't listed?

  • Ensure files have .wav or .ogg extension
  • Check file permissions are readable
  • Restart the TUI to refresh the sound list

License

Bundled sounds are CC0 1.0 Universal (Public Domain) - no attribution required. You are free to use, modify, and distribute them for any purpose, including commercial use.

Source: OpenGameArt.org - 80 CC0 RPG SFX by SubspaceAudio

Command-Line Help for aoe

This document contains the help content for the aoe command-line program.

Command Overview:

aoe

Agent of Empires (aoe) is a terminal session manager that uses tmux to help you manage and monitor AI coding agents like Claude Code and OpenCode.

Run without arguments to launch the TUI dashboard.

Usage: aoe [OPTIONS] [COMMAND]

Subcommands:
  • add — Add a new session
  • init — Initialize .aoe/config.toml in a repository
  • list — List all sessions
  • remove — Remove a session
  • status — Show session status summary
  • session — Manage session lifecycle (start, stop, attach, etc.)
  • group — Manage groups for organizing sessions
  • profile — Manage profiles (separate workspaces)
  • worktree — Manage git worktrees for parallel development
  • tmux — tmux integration utilities
  • sounds — Manage sound effects for agent state transitions
  • uninstall — Uninstall Agent of Empires
Options:
  • -p, --profile <PROFILE> — Profile to use (separate workspace with its own sessions)

aoe add

Add a new session

Usage: aoe add [OPTIONS] [PATH]

Arguments:
  • <PATH> — Project directory (defaults to current directory)

    Default value: .

Options:
  • -t, --title <TITLE> — Session title (defaults to folder name)
  • -g, --group <GROUP> — Group path (defaults to parent folder)
  • -c, --cmd <COMMAND> — Command to run (e.g., 'claude', 'opencode', 'vibe', 'codex', 'gemini')
  • -P, --parent <PARENT> — Parent session (creates sub-session, inherits group)
  • -l, --launch — Launch the session immediately after creating
  • -w, --worktree <WORKTREE_BRANCH> — Create session in a git worktree for the specified branch
  • -b, --new-branch — Create a new branch (use with --worktree)
  • -s, --sandbox — Run session in Docker sandbox
  • --sandbox-image <SANDBOX_IMAGE> — Custom Docker image for sandbox (implies --sandbox)
  • --trust-hooks — Automatically trust repository hooks without prompting

aoe init

Initialize .aoe/config.toml in a repository

Usage: aoe init [PATH]

Arguments:
  • <PATH> — Directory to initialize (defaults to current directory)

    Default value: .

aoe list

List all sessions

Usage: aoe list [OPTIONS]

Options:
  • --json — Output as JSON
  • --all — List sessions from all profiles

aoe remove

Remove a session

Usage: aoe remove [OPTIONS] <IDENTIFIER>

Arguments:
  • <IDENTIFIER> — Session ID or title to remove
Options:
  • --delete-worktree — Delete worktree directory (default: keep worktree)
  • --keep-container — Keep container instead of deleting it (default: delete per config)

aoe status

Show session status summary

Usage: aoe status [OPTIONS]

Options:
  • -v, --verbose — Show detailed session list
  • -q, --quiet — Only output waiting count (for scripts)
  • --json — Output as JSON

aoe session

Manage session lifecycle (start, stop, attach, etc.)

Usage: aoe session <COMMAND>

Subcommands:
  • start — Start a session's tmux process
  • stop — Stop session process
  • restart — Restart session
  • attach — Attach to session interactively
  • show — Show session details
  • current — Auto-detect current session

aoe session start

Start a session's tmux process

Usage: aoe session start <IDENTIFIER>

Arguments:
  • <IDENTIFIER> — Session ID or title

aoe session stop

Stop session process

Usage: aoe session stop <IDENTIFIER>

Arguments:
  • <IDENTIFIER> — Session ID or title

aoe session restart

Restart session

Usage: aoe session restart <IDENTIFIER>

Arguments:
  • <IDENTIFIER> — Session ID or title

aoe session attach

Attach to session interactively

Usage: aoe session attach <IDENTIFIER>

Arguments:
  • <IDENTIFIER> — Session ID or title

aoe session show

Show session details

Usage: aoe session show [OPTIONS] [IDENTIFIER]

Arguments:
  • <IDENTIFIER> — Session ID or title (optional, auto-detects in tmux)
Options:
  • --json — Output as JSON

aoe session current

Auto-detect current session

Usage: aoe session current [OPTIONS]

Options:
  • -q, --quiet — Just session name (for scripting)
  • --json — Output as JSON

aoe group

Manage groups for organizing sessions

Usage: aoe group <COMMAND>

Subcommands:
  • list — List all groups
  • create — Create a new group
  • delete — Delete a group
  • move — Move session to group

aoe group list

List all groups

Usage: aoe group list [OPTIONS]

Options:
  • --json — Output as JSON

aoe group create

Create a new group

Usage: aoe group create [OPTIONS] <NAME>

Arguments:
  • <NAME> — Group name
Options:
  • --parent <PARENT> — Parent group for creating subgroups

aoe group delete

Delete a group

Usage: aoe group delete [OPTIONS] <NAME>

Arguments:
  • <NAME> — Group name
Options:
  • --force — Force delete by moving sessions to default group

aoe group move

Move session to group

Usage: aoe group move <IDENTIFIER> <GROUP>

Arguments:
  • <IDENTIFIER> — Session ID or title
  • <GROUP> — Target group

aoe profile

Manage profiles (separate workspaces)

Usage: aoe profile [COMMAND]

Subcommands:
  • list — List all profiles
  • create — Create a new profile
  • delete — Delete a profile
  • default — Show or set default profile

aoe profile list

List all profiles

Usage: aoe profile list

aoe profile create

Create a new profile

Usage: aoe profile create <NAME>

Arguments:
  • <NAME> — Profile name

aoe profile delete

Delete a profile

Usage: aoe profile delete <NAME>

Arguments:
  • <NAME> — Profile name

aoe profile default

Show or set default profile

Usage: aoe profile default [NAME]

Arguments:
  • <NAME> — Profile name (optional, shows current if not provided)

aoe worktree

Manage git worktrees for parallel development

Usage: aoe worktree <COMMAND>

Subcommands:
  • list — List all worktrees in current repository
  • info — Show worktree information for a session
  • cleanup — Cleanup orphaned worktrees

aoe worktree list

List all worktrees in current repository

Usage: aoe worktree list

aoe worktree info

Show worktree information for a session

Usage: aoe worktree info <IDENTIFIER>

Arguments:
  • <IDENTIFIER> — Session ID or title

aoe worktree cleanup

Cleanup orphaned worktrees

Usage: aoe worktree cleanup [OPTIONS]

Options:
  • -f, --force — Actually remove worktrees (default is dry-run)

aoe tmux

tmux integration utilities

Usage: aoe tmux <COMMAND>

Subcommands:
  • status — Output session info for use in custom tmux status bar

aoe tmux status

Output session info for use in custom tmux status bar

Add this to your ~/.tmux.conf: set -g status-right "#(aoe tmux status)"

Usage: aoe tmux status [OPTIONS]

Options:
  • -f, --format <FORMAT> — Output format (text or json)

    Default value: text

aoe sounds

Manage sound effects for agent state transitions

Usage: aoe sounds <COMMAND>

Subcommands:
  • install — Install bundled sound effects
  • list — List currently installed sounds
  • test — Test a sound by playing it

aoe sounds install

Install bundled sound effects

Usage: aoe sounds install

aoe sounds list

List currently installed sounds

Usage: aoe sounds list

aoe sounds test

Test a sound by playing it

Usage: aoe sounds test <NAME>

Arguments:
  • <NAME> — Sound file name (without extension)

aoe uninstall

Uninstall Agent of Empires

Usage: aoe uninstall [OPTIONS]

Options:
  • --keep-data — Keep data directory (sessions, config, logs)
  • --keep-tmux-config — Keep tmux configuration
  • --dry-run — Show what would be removed without removing
  • -y — Skip confirmation prompts

This document was generated automatically by clap-markdown.

Configuration Reference

AoE uses a layered configuration system. Settings are resolved in this order:

  1. Global config -- ~/.agent-of-empires/config.toml (or ~/.config/agent-of-empires/config.toml on Linux)
  2. Profile config -- ~/.agent-of-empires/profiles/<name>/config.toml
  3. Repo config -- .aoe/config.toml in the project root

Later layers override earlier ones. Only explicitly set fields override; unset fields inherit from the previous layer.

All settings below can also be edited from the TUI settings screen (press S or access via the menu).

File Locations

PlatformGlobal Config
Linux$XDG_CONFIG_HOME/agent-of-empires/config.toml (defaults to ~/.config/agent-of-empires/)
macOS~/.agent-of-empires/config.toml
~/.agent-of-empires/
  config.toml              # Global configuration
  trusted_repos.toml       # Hook trust decisions (auto-managed)
  .schema_version          # Migration tracking (auto-managed)
  profiles/
    default/
      sessions.json        # Session data
      groups.json          # Group hierarchy
      config.toml          # Profile-specific overrides
  logs/                    # Session execution logs

Environment Variables

VariableDescription
AGENT_OF_EMPIRES_PROFILEDefault profile to use
AGENT_OF_EMPIRES_DEBUGEnable debug logging (1 to enable)

Session

[session]
default_tool = "claude"   # claude, opencode, vibe, codex, gemini
OptionDefaultDescription
default_tool(auto-detect)Default agent for new sessions. Falls back to the first available tool if unset or unavailable.

Worktree

[worktree]
enabled = false
path_template = "../{repo-name}-worktrees/{branch}"
bare_repo_path_template = "./{branch}"
auto_cleanup = true
show_branch_in_tui = true
delete_branch_on_cleanup = false
OptionDefaultDescription
enabledfalseEnable worktree support for new sessions
path_template../{repo-name}-worktrees/{branch}Path template for worktrees in regular repos
bare_repo_path_template./{branch}Path template for worktrees in bare repos
auto_cleanuptruePrompt to remove worktree when deleting a session
show_branch_in_tuitrueDisplay branch name in the TUI session list
delete_branch_on_cleanupfalseAlso delete the git branch when removing a worktree

Template variables:

VariableDescription
{repo-name}Repository folder name
{branch}Branch name (slashes converted to hyphens)
{session-id}First 8 characters of session UUID

Sandbox (Docker)

[sandbox]
enabled_by_default = false
yolo_mode_default = false
default_image = "ghcr.io/njbrake/aoe-sandbox:latest"
cpu_limit = "4"
memory_limit = "8g"
environment = ["ANTHROPIC_API_KEY", "OPENAI_API_KEY"]
environment_values = { GH_TOKEN = "$AOE_GH_TOKEN" }
extra_volumes = []
volume_ignores = ["node_modules", "target"]
auto_cleanup = true
default_terminal_mode = "host"
OptionDefaultDescription
enabled_by_defaultfalseAuto-enable sandbox for new sessions
yolo_mode_defaultfalseSkip agent permission prompts in sandbox
default_imageghcr.io/njbrake/aoe-sandbox:latestDocker image for containers
cpu_limit(none)CPU limit (e.g., "4")
memory_limit(none)Memory limit (e.g., "8g")
environment["TERM", "COLORTERM", "FORCE_COLOR", "NO_COLOR"]Host env var names to pass through
environment_values{}Env vars with explicit values (see below)
extra_volumes[]Additional Docker volume mounts
volume_ignores[]Directories to exclude from the project mount via anonymous volumes
auto_cleanuptrueRemove containers when sessions are deleted
default_terminal_mode"host"Paired terminal location: "host" or "container"

environment vs environment_values

  • environment passes host env vars by name. The host value is read at container start.
  • environment_values injects fixed values. Values starting with $ reference a host env var (e.g., "$AOE_GH_TOKEN" reads AOE_GH_TOKEN from the host). Use $$ for a literal $.

tmux

[tmux]
status_bar = "auto"
mouse = "auto"
OptionDefaultDescription
status_bar"auto""auto": apply if no ~/.tmux.conf; "enabled": always apply; "disabled": never apply
mouse"auto"Same modes as status_bar. Controls mouse support in aoe tmux sessions.

Diff

[diff]
default_branch = "main"
context_lines = 3
OptionDefaultDescription
default_branch(auto-detect)Base branch for diffs
context_lines3Lines of context around changes

Updates

[updates]
check_enabled = true
auto_update = false
check_interval_hours = 24
notify_in_cli = true
OptionDefaultDescription
check_enabledtrueCheck for new versions
auto_updatefalseAutomatically install updates
check_interval_hours24Hours between update checks
notify_in_clitrueShow update notifications in CLI output

Claude

[claude]
config_dir = "~/.claude"
OptionDefaultDescription
config_dir(none)Custom Claude Code config directory. Supports ~/ prefix.

Profiles

Profiles provide separate workspaces with their own sessions and groups. Each profile can override any of the settings above.

aoe                 # Uses "default" profile
aoe -p work         # Uses "work" profile
aoe profile create client-xyz
aoe profile list
aoe profile default work   # Set "work" as default

Profile overrides go in ~/.agent-of-empires/profiles/<name>/config.toml and use the same format as the global config.

Repo Config

Per-repo settings go in .aoe/config.toml at your project root. Run aoe init to generate a template.

Repo config supports: [hooks], [session], [sandbox], and [worktree] sections. It does not support [tmux], [updates], [claude], or [diff] -- those are personal settings.

See Repo Config & Hooks for details.

Development

Building

cargo build                    # Debug build
cargo build --release          # Release build (with LTO)
cargo build --profile dev-release  # Optimized build without LTO (faster compile)

The release binary is at target/release/aoe.

Running

cargo run --release            # Run from source
AGENT_OF_EMPIRES_DEBUG=1 cargo run  # With debug logging
RUST_LOG=agent_of_empires=debug cargo run  # With env_logger debug output

Requires tmux to be installed.

Testing

cargo test       # Unit + integration tests
cargo fmt        # Format code
cargo clippy     # Lint
cargo check      # Fast type-check

Some integration tests require tmux to be available and will skip if it's not installed.

Generating the Demo GIF

The demo GIF in the docs is created using VHS.

# Install VHS
brew install vhs

# Clear the demo profile
rm -rf ~/.agent-of-empires/profiles/demo

# Ensure demo directories exist
mkdir -p /tmp/demo-projects/api-server /tmp/demo-projects/web-app

# Generate the GIF (from repo root)
vhs assets/demo.tape

This creates docs/assets/demo.gif. The demo uses -p demo to run in a separate profile.