The command line
replicator is one program with a verb per job. This page lists every verb, what it reads, its
options and how it exits. The guides explain the ideas: Modular repositories
for init, doctor and fleet bump, Environments for infra,
The fleet file and Host specs for hosts and pods.
replicator <verb> [arguments] [--option value] [--flag]
Options are --name value, --name=value or a bare --flag. replicator help (or --help)
prints the list; running it with no verb at all prints it and exits 2.
Exit codes
Every verb follows the same convention, so a workflow can tell a failure from a mistake:
| Code | Meaning |
|---|---|
0 | Done: the files are valid, the check passed, the change was made. |
1 | The verb ran and said no: a validation error, a policy violation, skew between files, a missing secret, a failed run. |
2 | The command was wrong: a missing or contradictory option, an unknown verb. Nothing was read or changed. |
Two verbs add a meaning, and say so below: infra drift exits 2 for drift it found (a failure
to run is still 1), and doctor --strict exits 1 for a warning. An unexpected error exits 1
with its stack on standard error.
What the verbs read
| Variable | Used by | Meaning |
|---|---|---|
REPLICATOR_STATE_TOKEN | infra, host, secrets | The one credential that opens the state and the stored secrets. Read from the environment, never from an argument. |
REPLICATOR_STATE_ACCOUNT | infra, doctor | The account the token belongs to. A config naming another account is refused. |
REPLICATOR_WORKDIR | infra | Where a run keeps its working files. Default: the runner’s temporary folder. |
REPLICATOR_ENGINE_VERSION | every verb that reads a range | Overrides the engine’s own version, for a dry run against a repository’s declared range. |
FACTORY_ROOT | --host <id> | The folder that holds hosts/<id>.yml. Default: the engine’s own checkout. |
FACTORY_GITHUB_TOKEN | fleet bump, fleet reads | A token of yours for private repositories (GITHUB_TOKEN is the fallback). |
A host given as --host is a host id (hosts/<id>.yml), a path to a .yml file, or a
host.ref (a repository reference).
Starting and checking a repository
init
replicator init [--dir <repo>] [--name <app>] [--zone <dns zone>]
[--profile static-site|worker|site-and-worker]
[--account <id>] [--ref <sha>] [--release <tag>]
Writes the files a repository owns and prints what to do next. It never overwrites: if any file it would write exists, it writes nothing, lists them and exits 1.
| Option | Meaning |
|---|---|
--dir <repo> | The repository’s root. Default: the current folder. |
--name <app> | The app’s name; the state is kept under it. Default: the folder’s name, made lowercase and dashed. |
--zone <zone> | The DNS zone the stages’ names live in. Default: a placeholder doctor refuses. |
--profile <name> | What kind of repository: static-site (a site and its publishing contract), worker (an edge Worker) or site-and-worker (both). Without it, the bare config. |
--static | The same as --profile static-site. Refused beside a different profile. |
--account <id> | The account that holds the state, 32 hex characters. Default: a placeholder doctor refuses. |
--ref <sha> | The release commit the caller workflow pins, 40 hex characters. Default: a placeholder doctor refuses. |
--release <tag> | The release’s name, written as a comment beside each pin. |
Every profile writes the dev-container file, replicator.config.ts (with its secrets block)
and the caller workflow; static-site adds a static block to the config, worker adds
worker/index.mjs, and site-and-worker adds both. Exit 0 written, 1 refused or invalid.
doctor
replicator doctor [--dir <repo>] [--fleet <fleet file>] [--strict] [--json]
replicator doctor [<fleet file>] [--host <id>] [--strict] [--json]
The first form checks that a repository’s files agree with each other, with the engine and with the
state account; --fleet does the same for every repository of a fleet and reports which share an
account. The second form is the skew report for a checkout: the engine’s pins, the caller’s pins,
the base image, the gateway tag and the host. Both are read-only.
Each finding is ok, warn or SKEW. In the repository form the secrets are checked too: a name
the environments read that the config’s secrets block does not declare, a name read with
ctx.secret that the block marks required: false, and a declared name nothing reads are warnings.
| Option | Meaning |
|---|---|
--dir <repo> | Check one repository, offline. |
--fleet <file> | Check a fleet file and each enabled repository at its pinned ref. |
--host <id> | The host to check against (the skew form). |
--strict | Count warnings as failures. |
--json | Print the findings as JSON (findings, ok, and under --strict the warning count). |
Exit 0 when there is no skew (and, under --strict, no warning), 1 otherwise, 2 for a
missing path.
fleet bump
replicator fleet bump --to <release> [--fleet <file>] [--repos <owner/name,…>]
[--open-prs] [--widen-range] [--json]
Moves every repository’s caller workflows to a release’s commit. A dry run listing every file and
pin unless --open-prs, which opens one branch and one pull request per repository with your own
token (FACTORY_GITHUB_TOKEN or GITHUB_TOKEN). --widen-range raises an excluded upper bound of
a repository’s engine range. Exit 0 when every repository was handled, 1 when one was blocked,
unreachable or failed, 2 for a missing --to, a missing token under --open-prs, or --dry-run
beside --open-prs.
Running a repository’s environments
Every infra verb needs --config <replicator.config.ts> --stage <stage> and the state
token. The stage is a name the config lists, or a preview’s name such as pr-12.
| Verb | What it does |
|---|---|
infra stage | Prints what the stage name is (a listed stage or a preview, protected or not) as JSON. Reads the config only; no credential. |
infra diff | Prints every step a deploy would take and any policy violation. Never applies. |
infra deploy | Applies the diff, only if it passes the policy. Publishes the stage’s plain outputs for other apps. |
infra remove | Tears the stage down. A protected stage needs --allow-destroy '*'. |
infra drift | Refreshes the stage’s state from the cloud and compares it with the program. Never applies. |
infra secrets set <NAME> | Stores one secret of the stage; the value is read from standard input. |
infra secrets get <NAME> --out <file> | Writes one stored value to a file (mode 0600, masked in logs, never printed). |
infra secrets check | Lists the required secrets the stage lacks, by name only. |
infra secrets ensure | Stores what the secrets block declares: given in a values file, else generated. |
infra diff and infra deploy first check the declared secrets (when the config has a secrets block): if any
required secret is missing, they stop before planning, name every missing secret at once and print
the exact replicator infra secrets set NAME … line for each.
| Option | Verbs | Meaning |
|---|---|---|
--config <file> | all | The environments file. |
--stage <stage> | all | The stage to act on. |
--allow-destroy <a,b,…> | diff, deploy, remove, drift | Names of the resources this run may delete or replace; * means every resource and works with remove alone. |
--policy <fleet file> | diff, deploy, drift | Adds the host owner’s policy: rules (regions, labels, protected kinds, stage count). |
--import <name=id,…> | diff, deploy, drift | Adopts live resources the program declares instead of creating them. |
--env-out <file> | deploy | Writes the reserved __env output to a private file; --env-format shell (default) or docker picks the line format. |
--outputs-out <file> | deploy | Writes the stage’s plain outputs as JSON. |
--summary-out <file.md> | drift | Writes a short Markdown table for the job summary. |
--if-absent | secrets set | Leaves a stored value alone. |
--all-stages | secrets set, ensure | Stores (or looks at) the app-wide value every stage reads until it stores its own. |
--values-file <file> | secrets ensure | NAME=value lines. The file must be readable by its owner only (mode 0600); anything else is refused before a byte is read. |
--json | secrets check | Prints ok, present, missing and optionalMissing as JSON — names only. |
Exit codes: 0 done; 1 a policy violation, a missing required secret, a refused values file or
a failed run; 2 wrong arguments. infra drift exits 0 when the stage matches its program, 2
when it found drift and 1 when the run itself failed, so a scheduled job can tell a finding from a
failure.
Starting a host
Four verbs take a new host from nothing to a spec the engine accepts, with its secrets stored
and its sign-in created, and two more write the files that name the repositories it runs. None of
them creates or changes a server; host up does that.
init host
replicator init host --profile own-server|aws|hetzner --id <id> --zone <dns zone> [--gateway] [--private-images] [--dir <repo>]
Writes hosts/<id>.yml for one kind of host, checks it against the schema before writing, and
prints what is left for a person: the secrets to store, by name, and the commands to run. It
never overwrites.
| Profile | The host | Also needs |
|---|---|---|
own-server | A server you already run, on any cloud: the engine logs in over ssh, the server answers 80 and 443 itself, and you create one wildcard record. No vendor account is named. | --address, --email; optional --ssh-user, --state local|aws|cloudflare |
aws | One cloud account: the instance, its firewall, a static address, one wildcard record and the state. | --region, --hosted-zone, --email; optional --instance-type |
hetzner | The reference host: no public port, web traffic through an outbound tunnel, ssh over a private network. | --account; optional --server-type, --location, --tag |
--gateway adds the gateway: block: the sign-in service the host runs, which every public name needs
(--gateway-tag <release tag> names the image release; the default is the release of the engine you run).
On own-server and aws it also turns on app.serve: host, so the host serves the web app people sign in
through, out of the same image. The list it prints then replaces the sign-in secrets with two commands:
setup github-app creates the App and stores four of them, secrets rotate GATEWAY_BROKER_SECRET mints the
fifth.
--private-images adds image.pull: the images the host pulls are private, so it stores a registry read token
(ghcrPullToken, a read:packages token) and logs in to the registry with it only while it pulls.
--state says where an own-server host keeps its state: a folder on this machine (the default),
or a bucket (aws with --region, cloudflare with --account).
init fleet
replicator init fleet --host <id> --repo <owner/name>[@<ref>] [--repo …]
(--users <login,login,…> | --org <organisation>)
[--workspace <owner/name>[@<ref>] …] [--default <owner/name>] [--dir <folder>]
Writes clanker.yml, the fleet file of a host that gives each engineer a pod, checks it
against the schema before writing, and prints what is left for a person. It never overwrites.
| Option | Meaning |
|---|---|
--host <id> | The host spec the file names, hosts/<id>.yml. The file need not exist yet; if it does not, the steps say how to write it. |
--repo <owner/name>[@ref] | A repository that gets a container. Repeat the option or give a comma list; at least one is required. The ref is a branch, main unless given (nothing is pinned). |
--workspace <owner/name>[@ref] | A repository that is cloned into every pod and gets no container (devcontainer: false). Repeats the same way. |
--default <owner/name> | The repository a fresh pod shows first; one of the --repo entries. Default: the first. |
--users <login,…> | Who may hold a pod, by login. |
--org <organisation> | Who may hold a pod: the members of this organisation. Exactly one of --users and --org is required. |
--dir <folder> | Where the file is written. Default: the current folder. |
The ssh ports are not written: they follow the entries’ positions. The steps that follow are read
from what was written: a dev-container file for each container repository
(init devcontainer), the host spec if it is not there yet, the check with
replicator validate (--offline reads no repository), and, when the host spec beside the file
has a gateway: block, installing the host’s GitHub App on the repositories. Exit 0 written, 1
refused.
init devcontainer
replicator init devcontainer [--dir <repo>] [--name <repo name>] [--image <image>]
[--port <label>=<number>[:public][:<health path>] …]
[--postgres] [--engine <range>]
Writes .devcontainer/devcontainer.json for one repository: the standard file, with the block the
engine reads under customizations.replicator (the dev-container file). It is
read back through the same reader validate uses before anything is written, and it never
overwrites.
| Option | Meaning |
|---|---|
--dir <repo> | The repository’s folder. Default: the current folder. |
--name <repo name> | The repository’s short name: lowercase letters, digits and single dashes. Default: the folder’s name, lowercased and dashed. |
--image <image> | The image the container runs. Default: the base image, which holds none of the repository; replace it with the image the repository’s own build makes. |
--port <label>=<number>[:public][:<health>] | A forwarded port. Repeat for several; the first is the default port. public makes it reachable from a browser at its hostname; <health> (a path starting with /, the default port only) is probed after provision and must answer HTTP 200. Default: web=3000:public:/. |
--postgres | Adds the container’s own database (services.postgres). |
--engine <range> | The engine versions the file is written for. Default: the running engine’s major version. A range the running engine is outside of is refused. |
Exit 0 written, 1 refused. The steps that follow are read from the ports and options given:
what public and health mean for them, replacing image when none was given, and the
validate --host check.
secrets import
replicator secrets import --host <id> --env-file <file> [--map <secret>=<VARIABLE>,…] [--dry-run] [--overwrite]
Stores every secret the host’s spec asks for that a private NAME=value file holds, so a
credentials file another tool wrote reaches the host’s store without a value passing through a
terminal. The file must be readable by you alone (chmod 600). A secret is looked up under its
own name, its upper-case form (hetznerToken is HETZNER_TOKEN) and the usual variable names
of its vendor; --map names any other. A secret already stored is kept unless --overwrite.
Only names are printed. Exit 1 when a required secret is in neither the file nor the store.
setup github-app
replicator setup github-app --host <id> [--org <organisation>] [--name <app name>]
[--print | --code <code>] [--port <n>] [--github-url <url>]
Creates the one GitHub App the host’s gateway acts as, from the host spec, with one approval in
a browser. It prints a link to a page served on this machine only; the page shows what the App
will ask for and has one button. You confirm on GitHub, and the App’s id, private key and
sign-in client are stored under the names the host’s gateway: block reads. Only names are
printed.
The App asks for what the gateway hands out and nothing else: contents and workflows (a
developer container pushes), actions and issues (its other scopes), metadata, and organisation
members only on a host that admits people by organisation. It subscribes to no event and has no
webhook. --org creates it in an organisation you administer; without it, in your own account.
Two things stay yours, and the command prints both: install the App on the repositories a developer container may push to, and, only if people sign in from a terminal, tick “Enable Device Flow” on the App’s settings page (there is no way to set that from a command).
| Flag | What it does |
|---|---|
--print | Shows the App that would be created, where it would be created and the names it would store. No change. |
--code <code> | For a machine with no browser: take the code from the address GitHub sends you back to, and pass it in. |
--name <name> | The App’s name (GitHub requires it to be unique). Default: <host id>-replicator. |
--github-url <url> | A GitHub server of your own instead of github.com. |
setup stripe-projects
replicator setup stripe-projects --id <id> [--zone <dns zone>] [--dir <folder>] [--bucket <name>]
[--sign-in] [--apply] [--accept-tos] [--confirm-paid] [--json]
Opens the edge account a host can keep its state, its names and its tunnel in, through Stripe Projects: one sign-in, no console. It needs the Stripe command line with its Projects plugin, and a person signed in to it; an API key is not accepted, and one in the environment is kept from the tool.
- A plan by default. Every step is asked of Stripe’s tool in its check-only mode, and each thing in the way is listed with what to do about it. Nothing is created.
--sign-inasks Stripe’s tool for a link and a short code, and prints them. A person opens the link and approves with the code; nothing is created. Run the plan again afterwards.--applycreates the project and the resources, pulls the credentials into a private file in--dir(default.replicator-setup/<id>), then measures what the returned token can do with read-only requests and tells you which host that supports and theinit hostline to run.- It never accepts terms (
--accept-tos), never confirms a paid service (--confirm-paid; a bucket is one) and never signs in on your behalf.
Stripe Projects sells accounts and services, not servers: the machine is yours, on any cloud,
through init host. Keep --dir out of version control; it holds a credentials file.
Running hosts, pods and the fleet
These verbs act on the host owner’s files: a host spec (hosts/<id>.yml) and a fleet file
(clanker.yml). The quickstart runs them from a workflow.
| Verb | What it does |
|---|---|
validate [<file>] [--host <ref>] [--offline] [--json] | Checks a fleet file or a dev-container file (which needs --host). --offline reads no repository. |
plan [<file>] --user <login> [--host <ref>] [--entry <owner/name>] [--offline] [--json] | Renders what a developer’s container or pod would be, without changing anything. |
plan host <id> [--json] | Previews the host’s resources behind the DNS gate. No apply. |
host up|converge --host <id> [--fleet <file>] [--sysbox] | Creates the host, or brings a running one up to date. With a gateway block, the fleet file says who may sign in. |
host down --host <id> [--dry-run] | Removes the host. --dry-run lists the steps. |
host diagnostics --host <id> | Read-only logs of the tunnel, the proxy and the gateway. |
host outputs --host <id> | Prints the stack’s outputs as JSON, never decrypted — what the outputs gate reads. |
container provision|sync|teardown|purge --host <id> --user <login> [--repo <file>] [--entry <owner/name>] | A developer’s container or, with a pod: block, their whole pod. purge alone removes volumes. sync takes --branch; teardown and purge take --by <admin>. |
container access-check --host <id> --user <login> [--repo <file>] [--entry <owner/name>] | A read-only preflight of the pod’s access to its repositories. |
container select --host <id> --user <login> --repo <file> --entry <owner/name> | Moves the pod’s public name and port 22 to one member. Restarts nothing. |
fleet sync --host <id> [--fleet <file>] | Converges every container on the host from the fleet file. Never restarts a running container. |
fleet status [--host <id>] [--fleet <file>] [--offline] [--no-records] [--json] | Every entry’s owner, kind, commit, and how many pods hold it. Reads only. |
resources destroy --host <id> --name <resource> | The only verb that empties and deletes a bucket. |
secrets set <NAME> --host <id> [--developer <login>] | Stores a host secret; the value is read from standard input. --developer stores it as that developer’s own. |
secrets import --host <id> --env-file <file> | Stores the host’s secrets from a private file (Starting a host). |
setup github-app --host <id> [--org <organisation>] | Creates the gateway’s GitHub App with one approval in a browser and stores it (Starting a host). |
secrets list --host <id> | The names the host’s store holds, never a value. |
secrets rotate <NAME> --host <id> --yes | Mints a fresh gateway secret and stores it; never printed. Invalidates every pod’s broker capability, so it needs --yes. |
tailnet cleanup --host <id> --names <a,b,…> | Removes exactly the named device registrations from the private network. |
Exit codes follow the table at the top: 1 for a refused or failed run, 2 for a missing
--host, --user, --entry or --name.