Repository navigation
CLI
ac is the command line for Apple container, the macOS native container
runtime. It replaces both halves of the docker CLI: the plain container verbs
(run, build, logs, exec) and the compose-style stack orchestration that
Apple container does not ship at all.
Everything ac does ends in a call to container. Every one of those calls is
echoed to stderr, dimmed and prefixed with $ , before it runs, so any step can
be copied and re-run by hand. Suppress the echo with --quiet or AC_QUIET=1.
$ ac shop start
$ container system status
$ container volume create shop-postgres-data
$ container run -d --name shop-postgres --label ac.project=shop ...There are two forms and they are not aliases of each other.
ac <project> <action> [services...] acts on SERVICES resolved through a manifest
ac <verb> <container|image> acts on ONE container or image by its real name
The project form is the compose surface. It needs a manifest (a JSON file under
~/.config/ac/projects/ or <repo>/projects/), and only it does ordered
startup gated on readyCmd, named volume creation, registry login filtered to
the images actually involved, and short service name resolution.
The global form is the docker surface. It needs no manifest and knows nothing
about readiness or ordering. It is a thin, faithful pass to container with
ac's daemon ownership contract, command echo and --json handling layered on.
$ ac shop start # compose: the whole stack, in order, ready-gated
$ ac shop restart redis # compose: one service, by short name
$ ac build -t app:dev . # docker: a Dockerfile with no project around it
$ ac run -d -p 3000:3000 app:dev
$ ac logs -f shop-redis # docker: one container, by its real name-
The thing is in a manifest: use the project form.
ac shop restartrestarts a stack in dependency order and waits for each service to report ready.ac restart shop-redisrestarts one container and knows nothing about readiness. -
The thing is not in a manifest: use the global form. A one-off
ac run, a container someone else created, an image operation, a Dockerfile sitting on its own. -
Do not write a manifest to run one container.
ac runis what that is for. A manifest earns its keep when several services must come up in order. -
Both forms reach the same container, with different amounts of work.
ac stop shop-redisandac shop stop redisboth stop it and both use the same stop escalation ladder, but only the project form resolves the short name and reports against the manifest. -
When in doubt,
ac ps --json. It lists everything on the daemon and attributes what it can to a project.ac lsandac <project> ...only ever see what a manifest declares, so a container fromac runshows up inac pswith an empty PROJECT column and nowhere else.
ac <project> with no action is rewritten to ac <project> status, which is an
alias of ac <project> ls: one container ls -a --format json joined against
the manifest, with services that were never created shown as absent.
$ ac shop
$ ac shop status --jsonThe same rule applies to the explicit form: ac -p shop means
ac project shop status.
ac <project> <action> is a shorthand. Before clap sees the arguments, ac
rewrites ac shop start into ac project shop start (rewrite_argv in
src/main.rs). The rewrite only fires when the first non-flag word is not
one of ac's own commands and is the name of a discoverable manifest. A word
that is neither produces an error listing both the known projects and the known
commands.
When a project really is named after one of ac's commands, name it explicitly:
$ ac -p status start # project called "status"
$ ac --project status start
$ ac --project=status start
$ ac project status start # the long form the shorthand expands to-p / --project must come first, after the global flags and before the
action, because it is consumed by rewrite_argv rather than by clap. That also
means --project=<name> is a valid spelling while -p=<name> is not, and that
ac -p with no name is the error -p requires a project name. ac -p build
with no action means ac project build status.
The reserved words, in full, from src/cli/reserved.rs. A project named after
any of them is reachable only via -p:
ls projects status daemon ps image
images volume volumes network networks system
registry df prune config schema guide
completions version project rmi help run
build create start stop restart rm
delete exec sh shell logs inspect
kill cp copy export stats top
port pull push tag save load
login logout builder machine machines __supervise
__supervise is the hidden detached supervisor loop and is never typed by hand.
A word starting with - is also never treated as a project name, so
ac --help and ac --json status behave as written.
The global verbs take a container by its real name, which is the name ac ps
prints. Three spellings reach the same container:
| You type | Resolves to |
|---|---|
shop-redis |
shop-redis, used as is |
shop/redis |
shop-redis, the slash is rewritten to a dash |
angry_torvalds |
itself, whatever Apple container named it |
The rewrite is purely textual: the first / becomes - when both sides are
non-empty. No manifest is consulted, so shop/redis works even without a
manifest, as long as a container by that name exists.
The resolved name is then checked against a live container ls -a. Three
failure modes, all loud:
$ ac logs shop
err 'shop' is a project, not a container
try: ac shop status, or name a service directly (ac logs shop-<service>)
$ ac logs shop-redsi
err no such container: shop-redsi
containers: shop-postgres shop-redis
$ ac stop
err stop needs a container name, or --all
for a whole project stack: ac <project> stopThe last one is deliberate: a bare ac stop is an error rather than a silent
no-op, so nobody reaches for -a to make it do something. --all on stop,
rm and kill acts on every container the daemon has, including other
projects' and other people's.
In the project form the rules are different: services resolve from either
spelling, redis or shop-redis, and naming a service that does not exist
fails and lists the valid ones.
Drop the word docker. Nearly every plain docker command works as written.
| docker | ac |
|---|---|
docker run -d -p 3000:3000 img |
ac run -d -p 3000:3000 img (prints the URL) |
docker run --rm -it img sh |
ac run --rm -it img sh |
docker create img |
ac create img |
docker start c |
ac start c |
docker stop [-t N] c |
ac stop [-t N] c |
docker restart [-t N] c |
ac restart [-t N] c |
docker rm [-f] c |
ac rm [-f] c |
docker kill -s TERM c |
ac kill -s TERM c |
docker exec -it c sh |
ac exec -it c sh, or ac sh c
|
docker logs -f --tail 100 c |
ac logs -f -n 100 c |
docker inspect c |
ac inspect c |
docker cp c:/path ./local |
ac cp c:/path ./local |
docker export c -o f.tar |
ac export c -o f.tar (container must be stopped) |
docker stats [--no-stream] |
ac stats [--no-stream] |
docker top c |
ac top c |
docker port c |
ac port c |
docker ps [-a] [-q] |
ac ps [-a] [-q] (adds PROJECT and SERVICE columns) |
docker attach c |
no equivalent |
docker pause / unpause
|
no equivalent |
docker rename |
no equivalent |
docker commit / diff
|
no equivalent |
docker wait c |
no equivalent (ac <project> wait is readiness polling, not the same) |
docker events |
no equivalent |
docker update |
no equivalent |
docker run --restart=always |
no equivalent, Apple container has no restart policies |
docker run --health-cmd ... |
no equivalent, use readyCmd in a manifest |
| docker | ac |
|---|---|
docker build -t app:dev . |
ac build -t app:dev . |
docker build --cache-from ... |
no equivalent, container build has no --cache-from
|
docker buildx ... |
ac builder status|start|stop|delete, one shared builder |
docker images |
ac image ls (sizes shown by default), or ac images
|
docker images -q |
ac image ls -q |
docker rmi ref |
ac rmi ref, or ac image rm ref
|
docker pull ref |
ac pull ref, or ac image pull ref
|
docker push ref |
ac push ref, or ac image push ref
|
docker tag src dst |
ac tag src dst, or ac image tag src dst
|
docker image inspect ref |
ac image inspect ref |
docker save -o f.tar ref |
ac save -o f.tar ref, or ac image save -o f.tar ref
|
docker load -i f.tar |
ac load -i f.tar, or ac image load -i f.tar
|
docker image prune [-a] |
ac image prune [-a] |
docker login -u user server |
ac login -u user server, or ac registry login -u user server
|
docker logout server |
ac logout server, or ac registry logout server
|
| (no equivalent) |
ac registry ls, the stored logins |
docker history |
no equivalent |
docker manifest ... |
no equivalent |
| docker | ac |
|---|---|
docker volume ls/create/rm/inspect/prune |
ac volume ls/create/rm/inspect/prune |
docker network ls/create/rm/inspect/prune |
ac network ls/create/rm/inspect/prune |
docker system df |
ac system df, or ac df
|
docker system prune [-a] |
ac system prune [-a], or ac prune
|
docker system info |
ac system info, or ac daemon status
|
docker version |
ac version |
docker help <cmd> |
ac help <cmd>, or ac <cmd> --help
|
| (no docker equivalent) |
ac system start / ac system stop, daemon lifecycle |
| (no docker equivalent) |
ac daemon status / ac daemon stop, ownership aware |
| (no docker equivalent) |
ac machine ..., passed through verbatim |
docker context ... |
no equivalent |
docker ps --filter ... |
no equivalent, the listings take no --filter
|
| Command | What it does |
|---|---|
ac ls (alias projects) |
List the manifests ac can see. |
ac status |
Daemon, supervisor and every project in one view. |
ac config |
The resolved ~/.config/ac/config.json. |
ac schema |
The manifest JSON Schema, for authoring a project file. |
ac guide / ac guide claude
|
The built-in manual, and a CLAUDE.md snippet for another repo. |
ac completions <shell> |
A static completion script. See Shell completion. |
| docker compose | ac |
|---|---|
docker compose up -d |
ac <project> start (alias up; -d accepted and ignored) |
docker compose up --force-recreate |
ac <project> start --recreate |
docker compose down |
ac <project> down (containers removed, volumes survive) |
docker compose down -v |
ac <project> down -v (volumes and their data deleted) |
docker compose stop / start
|
ac <project> stop / start (restart in place) |
docker compose restart |
ac <project> restart |
docker compose ps |
ac <project> ls (aliases ps, status) |
docker compose logs -f |
ac <project> logs -f (fans out across services) |
docker compose run --rm svc cmd |
ac <project> run svc cmd (--rm is the default, --keep retains) |
docker compose exec svc cmd |
ac <project> exec svc cmd |
docker compose create |
ac <project> create |
docker compose rm -f |
ac <project> rm |
docker compose pull |
ac <project> pull |
docker compose build |
ac <project> build (profiles, interpolation, rollout) |
docker compose push |
ac <project> push -P <profile> |
docker compose top |
ac <project> top |
docker compose kill |
ac <project> kill |
docker compose cp |
ac <project> cp |
docker compose port |
ac <project> port |
docker compose config |
ac <project> config |
docker compose images |
ac <project> images |
docker compose ls |
ac ls (aliases projects) |
| (no compose equivalent) |
ac <project> wait, gate scripts on readiness |
| (no compose equivalent) | ac <project> rollout -P <profile> |
docker compose watch |
no equivalent |
docker compose events |
no equivalent |
docker compose --profile |
no equivalent (ac profiles are build profiles, not service filters) |
list for ls, delete and remove for rm, copy for cp, shell for
sh, up for <project> start, ps and status for <project> ls,
images/volumes/networks/machines as plural aliases of their noun groups,
remove alongside delete for image rm, volume rm and network rm, and
--format json as a spelling of --json anywhere outside the run, exec,
cp and machine passthrough zone. Any other --format value is an error
that points at --json.
-it parses on ac run and ac exec, and -t is honoured only when stdin
and stdout are terminals, because Apple container fails with ENODEV
otherwise.
Three flags are global and apply to every command. They must come before the
verb when the verb forwards its trailing arguments (run, create, exec,
machine, and the project-scoped run and exec): write
ac --json machine ls, not ac machine --json ls.
| Flag | Default | What it does |
|---|---|---|
--json |
off | Machine readable JSON on stdout. Implies --quiet and moves human log lines to stderr. |
--quiet |
off | Do not echo the underlying container commands. Same as AC_QUIET=1. No short form. |
--no-color |
off | Disable ANSI colour. Colour is off anyway when stdout is not a terminal or NO_COLOR is set. |
-q is deliberately not a short form of --quiet: it means "names only" on
ac ps and ac image ls, and --build-quiet on ac build. See
Global flags and environment for the full list of flags,
environment variables and exit behaviour.
Every other page in this reference, and what it is for.
| Page | What it covers |
|---|---|
| Global flags and invocation-wide behaviour |
--json, --quiet, --no-color, -p, the three meanings of -q, every AC_* environment variable, colour and TTY detection, exit codes and daemon gating. |
| Project commands | Every ac <project> <action>, from start and down through wait, logs, exec, env, ip and manifest scripts, with readiness semantics and service name resolution. |
| Container commands | The manifest-free docker verbs: run, create, start, stop, restart, rm, exec, sh, logs, inspect, kill, cp, export, stats, top, port. |
| Images and registries |
ac build, ac pull/push/tag/save/load/rmi, the ac image and ac registry groups, and ac login/logout. |
| Builds |
ac <project> build and push: profiles, setting precedence, build root resolution, {{...}} interpolation, parallelism, progress modes and the summary. |
| Rollouts | Profile rollout hooks, when each list runs, the environment and interpolation handed to them, --rollout / --no-rollout and --dry-run. |
| The project manifest | Field-by-field schema reference: discovery and shadowing, validation, every top level field, scripts, and a worked manifest. |
| Daemon, system and host-level commands | The daemon ownership contract and supervisor, plus ac status, ac ps, ac daemon, ac system, ac volume, ac network, ac builder, ac machine, ac config, ac schema, ac guide. |
| ac for scripts, CI and agents | The --json contract and the shape each command emits, which stream carries what, exit codes, gating on readiness, and non-TTY behaviour. |
| Shell completion | The COMPLETE=<shell> hook versus the static script, what completes where, the bounded daemon-backed completers, AC_COMPLETE_OFFLINE, and troubleshooting. |
Outside this directory: the project README for install and a
quickstart, and docs/guide.md for the manual ac guide prints
from inside the binary.
Auto-generated from docs/; edit the docs in the repo, not the wiki.