Installation
Prerequisites: tmux. Docker (or another container runtime) is optional, for sandboxing, and Node.js is needed only to build the web dashboard from source. Building also needs a C toolchain for native dependencies; a stock cc covers most platforms, and targets without pre-generated AWS-LC bindings also need CMake.
Install
# Quick install (Linux and macOS)
curl -fsSL \
https://raw.githubusercontent.com/agent-of-empires/agent-of-empires/main/scripts/install.sh \
| bash
# Homebrew
brew install aoe
Build from Source
git clone https://github.com/agent-of-empires/agent-of-empires
cd agent-of-empires && cargo build --release
Add --features web for the dashboard, which requires Node and npm. The default-enabled vendored feature selects OpenSSL and SQLite vendoring.
For system libraries, install pkg-config and compatible libgit2, OpenSSL and SQLite development packages. SQLite must provide JSON functions. Then build with vendoring disabled and system libgit2 required:
LIBGIT2_NO_VENDOR=1 cargo build --release --no-default-features --features default-plugins
--no-default-features disables all defaults; explicitly selecting default-plugins retains that default feature selection independently of vendored. Add web to the feature list for the dashboard. LIBGIT2_NO_VENDOR=1 fails the build if compatible system libgit2 is unavailable, instead of falling back to a source build. Other native dependencies are unaffected, and system libgit2 may still link OpenSSL transitively.
A source build leaves the binary at target/release/aoe. Verify any install with aoe --version.
Updating
aoe update
aoe update detects how aoe was installed (Homebrew, the install script, Nix, or Cargo) and dispatches to the right mechanism. For Nix and Cargo it prints the manual command instead, since those need external tooling. In the TUI, press u while the update bar is visible to run the same flow, or Ctrl+x to dismiss the bar.
If you installed shell completions as a static file, regenerate it afterwards so it picks up new commands and flags; see Shell completions for the always-fresh setup that avoids this.
Downgrading
Downgrades are not supported: the older build refuses to start when .schema_version records a newer data schema, and that refusal is the safe outcome, because a migration that retypes a persisted field writes a shape the previous release cannot read.
Finding out whether an older build can read your data
- Copy every
profiles/<name>/sessions.jsonand thegroups.jsonbeside it out of the app directory, plus the top-levelsessions.jsonif the pre-profiles layout left one. A retype migration rewrites no other file;groups.jsoncomes along so a return trip restores a matching pair. - With that same older build, run
aoe psand read the number it prints when it refuses, its own schema version. A command that returns before the migration gate prints nothing, soaoe updateandaoe uninstallare no use here. Then copy.schema_versionas a record and edit it in place down to that number. Deleting it is not the safer variant: a missing file reads as version 0, so the older build re-runs every migration it has. - Move any
sessions.corrupt.jsonlorgroups.corrupt.jsonlaside rather than deleting it, so step 4 can tell a new one from an old one. - With that same older build, run
aoe ps. It lists the running sessions, not every row in the registry, so read it for nothing: what matters is what it leaves on disk. The only file it adds beside asessions.jsonis a quarantine file, and a pending sandbox-store transition, which the migrations reconcile on start, can also leave a.storage.lockbeside it; neither file is created by reading, and only the quarantine one says anything about readability. Look forsessions.corrupt.jsonlorgroups.corrupt.jsonlbeside eachsessions.json: one appears as soon as that build reads a row it cannot decode, and asessions.jsonit cannot parse at all leaves nothing behind either. A profile whose directory is a symlink is skipped by a bareaoe ps, so runaoe ps -p <name>, or setAGENT_OF_EMPIRES_PROFILE, once more for each of those. The top-levelsessions.jsonfrom step 1 gets no verdict: the session list only ever readsprofiles/<name>/sessions.json, so nothing quarantines it, but the sandbox migrations do read and rewrite it, so treat it as unchecked by this procedure. The TUI is not a probe: it reconciles duplicates and rewrites the registry on start. - If either quarantine file appeared, put your copies back and stay on the current release.
When an older build could not read your sessions
The quarantine file is a copy of those rows, and it holds one load’s worth of them: that load writes the whole batch it could not decode, and a later load replaces the file, so whatever that later load no longer saw is gone from it.
A migration that retypes a persisted field also leaves a sessions.json.pre-migration-<stamp> beside the file, holding the bytes from just before that rewrite. When one upgrade retypes more than one field each rewrite leaves its own, and only the first one still holds a shape the older release reads, so restore that one. Rank them by stamp: each copy is named above every sibling that existed when it was taken, so the lowest stamp is the oldest, and the one exception is a sibling at u128::MAX, which no real clock produces. Three are kept per file in all, counting the one just taken and counting an entry the prune could not remove, and the oldest goes first, so a fourth retype landing in one upgrade evicts the copy the older release reads. Anything else carrying one of those names spends one of the three and does the same. They are the only copies a downgrade is served from: repairing an interrupted session move keeps its own sessions.json.pre-recovery-<stamp> set, and a repair never evicts a migration backup.
Check that the backup is there rather than assuming it: an upgrade that could not take one says so in its startup output and in the log. These retypes shipped in 1.17.0, so an install that already ran them has no backup of the older shape, and one only helps an install still on 1.16.x that upgrades into a build carrying them. Using it means editing .schema_version as in step 2.
Uninstalling
aoe uninstall
It prompts before removing the binary, the app data directory, and the tmux settings.