Deployment Manager
The deployment manager (agentx-manager) owns cluster lifecycle for both deployment
flavors — local source-built clusters and isolated image deployments — through one tested
core, exposed as a CLI and a web GUI. You never assemble docker compose -f …
chains by hand.
| CLI | agentx-manager — repo: uv run --project manager agentx-manager, or the task cluster:* wrappers · bundle: docker compose exec manager agentx-manager … |
| GUI | http://127.0.0.1:12320 — task manager:serve (repo) or the manager compose profile (bundle) |
| Image | qrmadness/agentx-manager (~370 MB; python-slim + docker CLI + built GUI) |
What it does
- Explicit overlay specs. Each deployment’s shape lives in
.manager-state.json(kindsource|image; gateway; tunnelnone|token|named; expose; gpu; shell) — edited viaagentx-manager setor the GUI, not inferred from which files happen to exist. Pre-manager clusters are bootstrapped from the old file-presence rules automatically. - Per-cluster compose projects. Everything runs under
-p agentx-<name>, so clusters can’t cross-target each other’s containers or share a default network. Migrate an existing running cluster once withagentx-manager adopt <name>(brief downtime). - Config-aware restarts. Tracked single-file bind mounts (
.env,nginx.conf,cloudflared/config.yml,credentials.json) are hashed; when one changed,restart/upforce-recreates exactly the affected services — a plain restart would keep serving the old file’s pinned inode. - First-boot patience. A fresh deployment downloads models for minutes before the API
healthcheck passes;
uprecognizes the initializing state (running + init markers in logs), waits it out, and finishes bringing up dependents like the gateway instead of failing with “dependency failed to start”. - Resource visibility.
agentx-manager usage/ the GUI’s per-cluster gauges aggregatedocker stats(CPU %, memory % + bytes, network ↓/↑ totals — plus a loose live ↓/↑ rate in the GUI, handy for watching the first-boot model download) over the cluster’s compose project, with per-service breakdown. Status and usage cover only the app stack’s own services — the manager’s own container (which shares the bundle’s compose project by design) is excluded, so a stack that isn’t running reads down, not degraded. - Destroy, safely.
agentx-manager destroy <name> --confirm <name>=down --volumes+ data-directory removal; the GUI requires typing the cluster name. Bundle mode never deletes the deployment root itself. - Day-2 passthrough.
agentx-manager agentx <name> -- migrate|setup-auth|warmup|status|…execs the in-image ops CLI, so behavior always matches the deployed image.
CLI reference
Shown in repo mode form (agentx-manager <command>, e.g. via uv run --project manager agentx-manager <command>). On a bundle, run the exact same command inside the container
instead — prefix it with docker compose exec manager:
# repo mode # bundle mode: docker compose exec manager …
agentx-manager list # deployments + spec tags
agentx-manager status [name] # phase (down|initializing|degraded|up) + services
agentx-manager usage [name] # CPU% / memory / network ↓↑ per cluster (docker stats)
agentx-manager new <name> [--gateway] [--tunnel token|named] [--gpu] [--kind source|image]
agentx-manager gateway-enable [name] [--tunnel …]
agentx-manager up|down|restart|rebuild [name]
agentx-manager set [name] --gateway/--no-gateway --tunnel … --gpu/--no-gpu --shell/--no-shell --expose/--no-expose
agentx-manager adopt [name] # one-time move onto the agentx-<name> project
agentx-manager destroy <name> --confirm <name> [--keep-data]
agentx-manager logs [name] [service]
agentx-manager agentx [name] -- <ops-cli command>
agentx-manager serve [--host …] [--port …] # the web GUI / REST server — this is the one
# already running as the bundle's `manager`
# container; you won't run this one yourself
For example, on a bundle, checking cluster status is:
cd agentx-deploy # wherever your .env / docker-compose.yml live
docker compose exec manager agentx-manager status
In bundle mode (an untarred deploy bundle is exactly one deployment) the name is optional
everywhere — agentx-manager status alone is enough, no cluster name needed. The root is
auto-detected by walking up to the nearest docker-compose.yml; force it with --root or
AGENTX_MANAGER_ROOT. For almost everything day-to-day, the web GUI at
http://127.0.0.1:12320 is the easier path — the CLI is mainly useful for scripting or when
you can’t open a browser to the host.
The web GUI
Cluster cards with live phase badges (initializing is first-class — an amber pulse, not a false alarm), CPU/memory gauges (5s polling), per-service state + usage drill-in, lifecycle buttons, a live log stream with service filter, typed-confirmation destroy, and (repo mode) a New Cluster form that shows generated secrets exactly once.
Share (per cluster) builds a connection link without
touching .env by hand: server URL (prefilled from AGENTX_PUBLIC_HOST, editable), display
name, and the web-app base where your deployed client lives (remembered per browser). The
link embeds the cluster’s gateway token — treat it like a secret; the recipient’s password is
never included. The modal warns inline about the classic foot-guns: a localhost URL that
won’t travel, a missing gateway token, a web-app origin absent from CORS_ALLOWED_ORIGINS
(browsers would block every call), and auth being disabled.
Enable gateway… appears on cards without a token gateway: pick a tunnel flavor
(none / Cloudflare token / named), and it scaffolds nginx.conf + generates
AGENTX_GATEWAY_TOKEN (shown once), same as task cluster:gateway:enable. Run Up to
apply — Restart won’t create the gateway service or re-read env.
Version chips keep the build→tag→restart loop honest: the header shows the checkout’s
versions.yaml version (repo mode), each running cluster shows the version its API actually
reports, and an amber checkout v… chip appears when the two differ (rebuild, then Up, to
roll the image out). The manager’s own version lives in the muted header caption
(manager v0.x.y) — it versions independently of the platform.
In bundle mode the GUI drops the docker vocabulary entirely and becomes a plain-language single-deployment dashboard: a status hero (Stopped / Starting up… / Running / Needs attention) with Start / Stop / Restart and an Open AgentX link, resource tiles (processor, memory, network — including a live ↓ rate while the first start downloads AI models), a components list with friendly names (AgentX Server, Knowledge Graph, Memory Store, Cache…), connection details, and a typed-confirmation Reset. A fresh bundle reads Stopped until you press Start; creating additional clusters stays a source-checkout (repo mode) feature. Polling pauses automatically in background tabs.
Lifecycle actions run as background jobs — the GUI stays responsive and toasts the result.
Security posture
- **Keep the loopback bind.** Run a *host-level* `cloudflared` (or a standalone tunnel
container with `extra_hosts: ["host.docker.internal:host-gateway"]`) whose ingress
points at `http://127.0.0.1:12320` (`http://host.docker.internal:12320` from a
container). No `AGENTX_MANAGER_BIND` needed, and no CORS setup either — the GUI is
served by the manager itself, so everything stays same-origin.
- **Give the manager its own tunnel**, not a hostname on a cluster's `cloudflared` —
otherwise downing that cluster takes your remote control plane with it.
- **Front the hostname with Cloudflare Access** (email OTP / identity provider). The
bearer token is strong, but a root-equivalent endpoint on the public internet deserves
a second gate; with Access in place the token becomes your second factor.
- Side benefit: the tunnel's HTTPS makes the browser treat the GUI as a secure context,
so Share-modal clipboard copies work remotely.
Running it
Repo (dev):
task manager:serve # GUI at http://127.0.0.1:12320
task cluster:new CLUSTER=prod GATEWAY=1 # thin wrapper over agentx-manager new
Bundle (isolated): the manager is the only thing in the bundle’s default
COMPOSE_PROFILES — a plain docker compose up -d starts only it. Use the
dashboard’s Up button (or docker compose exec manager agentx-manager up)
to bring up the actual stack; see
Self-Hosting, step 3.
Testing
The manager is covered by a unit suite (overlay truth table, scaffold rendering, config-hash
change detection, registry parsing, server auth — all against a recorded fake compose runner)
and a Docker integration suite (task manager:test:integration) that stands up the real
nginx gateway with a lightweight fake API upstream and asserts the token gate (401/200),
rate-limit 429s, and the edit-config→restart→live behavior end-to-end.