Project structure
In your project
ant nest init writes a single file, ant.yaml:
app: my-app
deploy:
build: dockerfile # dockerfile | nixpacks | buildpacks | railpack | none
run: container # container | compose | stack
port: 3000
# keep_images: 3
# use_machine_network: true # join the machine-wide network
# rollback:
# keep_releases: 5 # releases retained for `ant trail rollback`
# machine: prod # uncomment to target a remote nest
buildselects the builder.nonemeans the image is pre-built or comes from the compose file.runselects how it runs: a single container, a compose project, or a stack.machine(optional) targets a registered remote machine by name.rollbackconfigures release retention and the optional rollback hooks; image retention iskeep_images, falling back torollback.keep_releases.- Environments (
local,dev, …) layer env vars, secrets, ports, and domains on top of the base config.
See Configuration for the full ant.yaml reference.
Under ~/.ant
Ant keeps its state in ~/.ant, split by role: the client state that ant
and ant ui own, and the worker state ant-worker owns under
~/.ant/worker/.
Client
| Path | Holds |
|---|---|
~/.ant/config.json | Machines (including the roster mirror), groups, project roots, UI settings, notifications, relay |
~/.ant/identity | Your account keypair (written by ant colony signup, restored by login/import) |
~/.ant/machines/<id>/identity | The client-side copy of a machine's keypair, used to provision it |
~/.ant/deployments.json | The deploy history shown by ant trail history |
~/.ant/deploy-logs/ | Captured output per deploy event (history is capped at 200 entries, 500 lines each) |
~/.ant/templates, ~/.ant/templates-dokploy, ~/.ant/dokploy-index.json | Your templates and the imported Dokploy catalog |
~/.ant/locks/ | Transient operation locks (caddy-<hash>, local-deploy-<hash>), removed after use |
~/.ant/known_hosts | SSH host keys pinned during provisioning |
~/.ant/caddy/ | The managed local Caddy's PID (and a transient config while it starts) |
~/.ant/local/<app>/<env>/ | Legacy working directory; only read and removed by ant trail destroy |
Worker
A machine running ant-worker keeps its own state under ~/.ant/worker/
(system installs run it as user ant, so /home/ant/.ant/worker/):
| Path | Holds |
|---|---|
agent-identity | The machine's keypair, its NodeID |
agent-state.json | The authoritative roster, used/revoked invites, and the bootstrap marker (a state import keeps the previous file as .bak) |
audit.log | Hash-chained log of privileged RPCs (rotates to audit.log.1) |
remote-compose/<project>/ | Stored compose and stack files, plus secrets.env (0600) for a compose project |
The roster shown by the CLI and dashboard is a mirror of agent-state.json,
refreshed from the machine after each change; authorization always happens
against the machine's copy. The worker's paths can be overridden with
--identity / --state; provisioning sets them explicitly.
A worker started with the default paths adopts pre-existing state after an
upgrade: a ~/.ant/agent-identity, agent-state.json, audit.log, and
remote-compose/ left by an older build move into ~/.ant/worker/. Explicit
--identity/--state flags are never moved, and a compose project deployed
before the move is still found in place.
Config, identity, state, audit, and secret files are written 0600 (their
directories 0700). The imported Dokploy catalog (~/.ant/dokploy-index.json
and ~/.ant/templates-dokploy/) is world-readable by design. Nothing is written
into your project except ant.yaml.
Machine config schema
~/.ant/config.json is schema v2. Projects, groups, and Caddy settings nest
under the machine they belong to:
{
"version": 2,
"machines": {
"local": {
"caddy": { "auto_start": true },
"groups": { "backend": { "domains": ["example.com"] } },
"project_dirs": ["/home/me/code/api", "/home/me/code/worker"]
}
}
}
v1 configs are migrated on load: a top-level local object is folded into
machines.local, and the old flat groups/project_dirs/caddy are nested.
See Configuration for the full reference.