Skip to main content

The ados-deploy tool

ados-deploy is a Rust terminal tool in the Mission Control repo at tools/deploy/. It brings up the self-hosted stack (Convex backend and dashboard, the Mission Control web GCS, Mosquitto, the MQTT bridge and the video relay) through a guided flow, then keeps the lifecycle commands in one place. It is not a second stack. It drives the same Compose project documented on All-in-one stack: tools/selfhost/docker-compose.yml. What it adds is the ordering, the generated config, the secret handling and the verification, so you do not run the ten steps by hand.

When to use which path

ados-deploy operates on a repo checkout, because it builds the Mission Control image from the repo and pushes Convex functions from it. There is no checkout-free mode.

Invoke it

From a checkout, through the npm script:
Everything after -- goes to ados-deploy. The script is cargo run --release --quiet --manifest-path tools/deploy/Cargo.toml --. Directly with cargo:
Through the bootstrap, which will fetch a checkout if you do not have one:
The bootstrap uses the current checkout when it finds tools/selfhost/docker-compose.yml, otherwise it clones to $HOME/ADOSMissionControl. Override with ADOS_DIR and ADOS_REPO_URL. It then launches in preference order: a cached or committed ./ados-deploy binary, a best-effort fetch of the matching release asset, then a cargo build. Extra arguments pass through. Running with no action opens the interactive menu. On a non-terminal (CI, or a piped invocation) the menu is unavailable and the tool tells you to pass an action instead.

Actions

An unrecognised action falls through to the menu.

Dry-run first

--plan (alias --dry-run) prints the exact files the deploy would write and the exact commands it would run, in order, then exits without touching anything. Secrets are always redacted in the plan output. This is the right way to review a deploy before you let it run, and it is the same ordering the real state machine executes.

Flags

Rendering and interactivity

Deploy answers

Supply these to run the whole flow without prompts. An unknown flag is ignored rather than rejected, so a newer wrapper script stays forward-compatible with an older binary.

What a deploy runs

The state machine is ordered and idempotent:
  1. Preflight checks (Docker, Node, toolchain).
  2. Write the generated config files.
  3. Bring up the Convex backend.
  4. Wait for it to answer.
  5. Generate the admin key.
  6. Push the Convex functions.
  7. Write the auth keys.
  8. Write the MQTT password file.
  9. Bring up the rest of the stack.
  10. Verify, then print the reach links.
Because it is idempotent, upgrade reuses the same graph: it reconstructs the config from the deployed .env and runs the whole thing again.

Files it writes

All paths are relative to the repo root; commands run with the root as their working directory.

Services and default ports

These mirror tools/selfhost/docker-compose.yml. The tool detects a port conflict before it starts anything.

Check and tear down

teardown runs docker compose down. Purging the volumes is a separate opt-in, so a teardown does not silently destroy your Convex data. To roll back a bad upgrade, check out the previous commit of the repo and run upgrade again: the image is rebuilt from the checkout and the functions are re-pushed from it, so the checkout is the version you are running.