Commands
Everything the mai CLI does. Install it with npm install -g telemai or prefix each command with npx telemai. Run commands from inside the repository unless noted. Configuration lives in ~/.mai; set MAI_HOME to put it elsewhere.
On the host machine
mai host [--tunnel | --cloudflare-token <token> --public-url <url>] [--port <n>] [--image <ref>] [--no-fetch] [--telemetry | --no-telemetry]
Runs the server and Postgres for this repo in Docker (a compose project under <MAI_HOME>/host), builds the dependency graph from the repo's origin/main, and prints the server's build. Keep the terminal open while a tunnel is in use.
| Flag | Effect |
|---|---|
--tunnel | Opens a Cloudflare quick tunnel. No account needed; the hostname changes on every start, so teammates need fresh invites after a restart. For trials. |
--cloudflare-token <t> --public-url <url> | Runs a named Cloudflare tunnel on your own domain, the stable mode. Map the hostname to the server's port in the Cloudflare dashboard. |
| (no tunnel flag) | The server is reachable only on this machine. Fine for trying Telemai alone. |
--port <n> | The local port the server listens on (default 4000). |
--no-fetch | Don't git fetch origin every 30 seconds for the graph. The graph then follows origin/main as of whenever you last fetched by hand. |
--image <ref> | Run a specific server image, for example ghcr.io/emaiiii/mai-server:<version>. The default matches the CLI's version; mai host warns when the two differ. |
--telemetry / --no-telemetry | Opt this host in to, or out of, the daily telemetry ping. Off until you pass --telemetry; the setting sticks until you change it. See telemetry & privacy. |
mai host status
The server's health, its build (version and commit), the graph's ref and commit, the last commit the safety net scanned, and the tunnel address.
mai host stop [--purge]
Stops the containers. --purge also deletes the database volume: every event, decision, claim and engineer for this project is gone.
mai invite <email> [--expires <hours>] [--server <url>] [--public-url <url>]
Mints a single-use invite for one engineer and prints it as a mai://… string. Good for 24 hours unless --expires says otherwise (up to 14 days). The admin token comes from the host config written by mai host, or from MAI_ADMIN_TOKEN. --server and --public-url override the local and public addresses from that config.
mai revoke <email>
Refuses that engineer's tokens everywhere (hooks, MCP, channel) and closes their channel. A new invite lets them back in.
On every engineer's machine
mai join <invite> [--team <name>] [--name <n>] [--force]
Redeems an invite and writes your tokens and the server address to ~/.mai. --team is required on the first join and kept on a re-join; --name defaults to your git user.name. Joining again as an existing engineer, with a fresh invite, rotates your tokens, so it retires a leaked one. --force replaces a ~/.mai that already exists; it is refused while mai start is running on it. For a second identity on one machine, set MAI_HOME instead.
mai own <path> [<path> ...]
Declares your team's areas. Paths are relative to the repo root; the longest matching prefix wins. A path another team owns is refused. Other leads are notified (ownership_declared).
mai disown <path> [<path> ...]
Removes areas again. Each path must match an area exactly as declared; a path that is merely inside an area is refused. Other leads are notified (ownership_removed). Existing claims are untouched.
mai start [-- <claude args>]
Launches Claude Code at the repo root with the Telemai plugin, your lead agent, agent teams, the mai MCP tools and the channel. Run it in a real terminal. Anything after -- is passed to Claude Code.
mai status
Is the host up, and what build is it running? The graph's commit, your team, your areas, the claims that touch you, whether a lead session is running, and whether this machine is the host. Exits with status 1 when the host is down, and says so plainly with a note that your side keeps working.
mai log [--type <t>] [--team <n>] [--since 2h|30m|3d|<iso>] [--limit <n>]
The shared log, oldest first: team, type, a CRITICAL marker where it applies, and a one-line gist. Other teams' escalations are never shown. Types you can filter on:
| Type | Meaning |
|---|---|
file_edited | A worker edited a file (hook or shell). |
contract_changed | An exported API changed; breaking marks the ones that matter. Source is hook or merge (the safety net). |
schema_changed | A new migration file. Always critical. |
claim_placed, claim_released | A team took or gave up a temporary hold on files. |
task_status | A worker's task was created, completed, or the worker went idle. |
announcement | A lead told the other leads what it's doing. |
decision_recorded | A lead logged its engineer's decision. |
escalation | Your own team's open or resolved escalations. |
ownership_declared, ownership_removed | mai own and mai disown. |
mai claims [<path> ...]
Every team's active claims, yours marked. With paths, only the claims under them.
mai escalations [--all]
Your team's open escalations: what your lead is waiting on you to decide. Answer in the lead chat. --all includes resolved ones.
Environment
| Variable | Where | Effect |
|---|---|---|
MAI_HOME | Any machine | Where the CLI keeps its config instead of ~/.mai. Useful for running two engineers on one machine. |
MAI_ADMIN_TOKEN | Host | The admin token for mai invite and mai revoke when it isn't in the host config. |
MAI_TELEMETRY_URL | Host | Where mai host --telemetry sends the daily ping, instead of our collector. mai host writes the chosen address into the server's environment; empty means no ping. |