CLI reference
z4j ships a CLI named z4j. Runs inside the container or from a local pip install.
z4j --helpServing
Section titled “Serving”z4j serve [--host 0.0.0.0] [--port 7700] [--workers 1]Starts the FastAPI application via Uvicorn. This is the container entrypoint.
Health and diagnostics
Section titled “Health and diagnostics”z4j checkValidates that the configuration loads and the database answers, then prints whatever migration revision it finds. Non-destructive.
It does not confirm Alembic is at head, despite an earlier version of this page saying so. It never compares the stored revision against the head your build expects, and a database with no alembic_version table at all still exits 0. Use z4j migrate current --check-heads, which exits non-zero unless every head is applied. z4j doctor is not a substitute either: it runs check and returns its exit code.
doctor
Section titled “doctor”z4j doctorRuns check first and returns its exit code, then adds configuration warnings that check cannot raise because they are not failures. It takes no options.
What it actually warns about: Z4J_ENVIRONMENT=dev with a non-loopback Z4J_BIND_HOST, Z4J_DEBUG_HOST_ERRORS being on, secrets having been auto-minted into ~/.z4j/secret.env, Z4J_METRICS_PUBLIC being on, and an install with no users, no projects or no agents yet.
It inherits check's blind spot and adds nothing to it: no Alembic head comparison, no registry probe, no scheduler reachability check, no mTLS validation, and no --json output. An earlier version of this page claimed all five, and z4j doctor --json exits 2 with "unrecognized arguments". For the schema head, use z4j migrate current --check-heads.
status
Section titled “status”z4j statusPrints a summary of current brain state: version, Alembic head, environment, database URL, and row counts (users, projects, agents, tasks, active sessions, audit rows).
version
Section titled “version”z4j versionPrints the installed z4j version.
First-boot setup
Section titled “First-boot setup”z4j initScaffolds $Z4J_HOME/config.env as a mode 0644, tunables-only starter file.
It intentionally excludes credentials, tokens, secrets, and other bootstrap
values that belong in $Z4J_HOME/secret.env or the process environment. It is
not a complete runnable configuration. The command refuses to overwrite an
existing file unless --force is supplied.
bootstrap-admin
Section titled “bootstrap-admin”printf '%s\n' "$ADMIN_PASSWORD" | \ --password-stdinCreates the initial admin user and the default project. First-boot only. A
password is required; prefer --password-stdin with a value obtained from a
secret manager so it is not exposed in the process list or shell history.
createsuperuser
Section titled “createsuperuser”Django-friendly alias for bootstrap-admin. Use --password-stdin to pipe the password in from a secret manager.
changepassword
Section titled “changepassword”Changes a user's password. Intended for admin recovery / CLI-only ops when the user cannot reach the dashboard reset flow.
reset-mfa
Section titled “reset-mfa”Operator escape hatch for the lost-phone-AND-lost-recovery-codes case. Clears the user's MFA secret, recovery codes, and trusted devices in one transaction; writes a user.mfa_reset_by_admin audit row attributed to the OS user running the CLI. Shell-only by design -- there is no REST surface so an attacker who has only the dashboard cannot trigger it. See Multi-factor authentication for context.
Configuration
Section titled “Configuration”config show
Section titled “config show”z4j config showPrints the resolved effective settings (post-env-var, post-defaults,
post-~/.z4j/config.env). Fields typed as SecretStr are masked unless
--reveal-secrets is passed. Plain URL fields such as database_url and
scheduler_trigger_url are printed as configured and can contain credentials,
so treat the entire output as sensitive. The admin settings endpoint exposes
the same effective settings but applies additional secret-name masking.
config validate
Section titled “config validate”z4j config validateSafely captures the candidate tunables file, rejects unknown Z4J_* keys, and
validates the values through the runtime settings decoder without booting the
app. Because config.env is a tunables-only layer, the command supplies inert
bootstrap placeholders for required secrets, hosts, public URL, and, when
absent, the database URL. A zero exit therefore means the candidate tunables
are valid. It does not validate the process environment or secret.env,
prove that the effective runtime configuration will load, or test database
connectivity.
Backups
Section titled “Backups”backup
Section titled “backup”z4j backup --output /var/backups/z4j-$(date +%Y-%m-%d).dbSnapshots the brain database to a single file. On SQLite, a VACUUM INTO clone; on PostgreSQL, a pg_dump custom-format archive.
--output / -o is the only option, and it is required. An existing destination is always refused, and there is no flag to override that - move or delete the old file, or pick a different path. The output is created private to its owner, so no umask is needed. (An earlier version of this page described the opposite behaviour and offered a --no-clobber flag; that flag does not exist and passing it aborts the command with exit 2.)
restore
Section titled “restore”z4j restore /var/backups/z4j-pre-upgrade.db --forceRestores from a backup file produced by z4j backup. --force is required, and it records your assertion that the brain is stopped rather than verifying it: there is no liveness detection, so stopping the brain first is your responsibility.
The target must already be a provisioned z4j database at the current migration head, with an audit chain that verifies under the local keyring. An empty database is refused. Restore is also forward-only, so an archive from a previous release is migrated up rather than taking you back to it. See backup and restore for the full ceremony.
Maintenance and upgrades
Section titled “Maintenance and upgrades”migrate
Section titled “migrate”z4j migrate upgrade headz4j migrate currentz4j migrate historyz4j migrate downgrade <revision>Runs an Alembic command against the brain database.
Schedules
Section titled “Schedules”misfires
Section titled “misfires”z4j misfires --project my-appz4j misfires --project my-app --limit 200z4j misfires --project my-app --jsonLists a project's detected schedule misfires across ALL of its schedules, newest first. A misfire is a system-detected "this enabled interval or cron schedule missed its expected slot past the grace window" event, recorded by the brain's misfire detector (see misfire detection). The default output is an aligned text table (schedule id, detected-at, name, engine, kind, lateness, grace); --json emits {"project": <slug>, "misfires": [...]} for scripting. --limit defaults to 50 and is capped at 1000. This is the shell-side twin of the VIEWER-facing GET /api/v1/projects/{slug}/schedules/misfires endpoint, so an operator can triage missed slots without the dashboard. Exit 0 on success (including an empty history); exit 2 on a bad slug, unknown project, or unreachable database.
upgrade
Section titled “upgrade”z4j upgradez4j upgrade --applyWithout flags, checks PyPI for newer releases of the packages in z4j's bundled
release catalogue and changes nothing. --apply runs pip install -U z4j,
which lets the umbrella package pull compatible adapters forward. There is no
--check option because check-only is the default. Mirrors
POST /api/v1/admin/system/versions/check on the API side.
Allowed hosts
Section titled “Allowed hosts”allowed-hosts list / add / remove / path
Section titled “allowed-hosts list / add / remove / path”z4j allowed-hosts listz4j allowed-hosts add z4j.example.comz4j allowed-hosts remove old-host.example.comz4j allowed-hosts pathManages the persistent Host header allow-list (Z4J_ALLOWED_HOSTS). path prints the file the brain reads from so operators can edit it directly. See allowed hosts.
Audit log
Section titled “Audit log”audit verify
Section titled “audit verify”z4j audit verifyWalks the full HMAC-chained audit log. Exit 0 on success, 1 on broken chain.
Pass --known-head with an envelope recorded earlier to detect a log that was
rolled back to an older authentic state, which the chain alone cannot show. The
result is one of CURRENT_MATCH, PRUNE_MATCH, CURRENT_PRUNE_MATCH,
VERIFIED_ANCESTOR, INVALID or UNPROVABLE, and anything other than a match
exits nonzero.
audit export-head
Section titled “audit export-head”z4j audit export-head > /secure/last-known-headz4j audit export-head --verify > /secure/last-known-headPrints the authenticated current chain head as the JSON envelope
audit verify --known-head accepts. The state row is proved against the
configured keys first, and a head that cannot be authenticated is refused rather
than exported.
The envelope goes to stdout and every other message to stderr, so the redirect
above yields a complete file. --verify walks the active generation first and
refuses to export a head from a chain that did not verify clean, which is the
right choice for an unattended job: anchoring a compromised chain would record
it as the trusted state.
Anchor that file somewhere the database role cannot rewrite. A head kept only in the same database proves nothing, because a writer can restore an older copy of it. Write the file exactly as emitted: the parser's key set is closed, so appending anything makes it unreadable.
The audit group also carries the chain-key lifecycle commands
(rotate-chain-key, retire-chain-key) and the chain-state operations
(activate-chain-state, reseal-watermark, export-and-delete-frozen,
fork-cleanup). Each takes --help. See
HMAC audit chain for the rotation ceremony.
Tokens and certs
Section titled “Tokens and certs”metrics-token
Section titled “metrics-token”z4j metrics-token # print the active tokenz4j metrics-token rotate # update the managed store; restart is requiredManages the bearer that gates /metrics. Resolution order is an explicit
Z4J_METRICS_AUTH_TOKEN, then $Z4J_HOME/secret.env, then first-boot
auto-minting. rotate works only when the effective source is the managed
secret.env; it refuses to rewrite a lower-precedence file when an explicit
environment value wins. The command writes and prints the new token, but a
running brain keeps the old token in memory. Update the Prometheus scrape
credential, then restart every brain replica. The old token stops working only
after those restarts.
mint-scheduler-cert
Section titled “mint-scheduler-cert”z4j mint-scheduler-cert \ --name scheduler-prod-1 \ --ca-cert /etc/z4j/pki/ca.crt \ --ca-key /etc/z4j/pki/ca.key \ --out-dir /etc/z4j/pki/scheduler-prod-1/Mints scheduler-prod-1.crt and scheduler-prod-1.key for a
z4j-scheduler instance to authenticate to the brain. The command does not
modify the brain configuration. Add scheduler-prod-1 to the JSON
Z4J_SCHEDULER_GRPC_ALLOWED_CNS value and restart every brain replica before
deploying the client certificate. See production hardening.
Destructive
Section titled “Destructive”reset-setup
Section titled “reset-setup”z4j reset-setup --forceDeletes pending first-boot tokens, preserves existing signed setup audit rows,
and appends a signed setup.tokens_reset row. It refuses if any user
exists. Without --force, it exits nonzero without changing the database. Use
reset --force for a full wipe.
z4j reset # refuses without --forcez4j reset --forceWipes every runtime table (users, sessions, projects, agents, tasks, events, schedules, audit, ...). Schema stays; Alembic does not re-run. Leaves z4j in a pre-first-boot state.
Global flags
Section titled “Global flags”| Flag | Description |
|---|---|
-h, --help |
Show help for the command |
Per-command flags surface with z4j <command> --help.
z4j-scheduler CLI
Section titled “z4j-scheduler CLI”When you run the standalone scheduler service, the z4j-scheduler CLI ships these commands. See z4j-scheduler for deployment context.
z4j-scheduler serve # run the scheduler processz4j-scheduler version # print installed versionz4j-scheduler check --brain-grpc-url ... # one-line pass/fail healthz4j-scheduler status # local introspection: version + configured brain URLs + mode (no network)z4j-scheduler info [--json] # live runtime snapshot from the running scheduler's GET /infoz4j-scheduler doctor # comprehensive diagnosticsz4j-scheduler restart # informational stub (delegates to systemd / k8s)z4j-scheduler import --from <tool> ... # migrate from celery-beat / rq / apscheduler / cronz4j-scheduler export --to <tool> ... # reverse-exportz4j-scheduler schedules add / list / trigger / disable / enable / edit / history ...All commands accept --help. Most read configuration from Z4J_SCHEDULER_* env vars; explicit flags win where provided.
Framework adapter CLIs
Section titled “Framework adapter CLIs”Each framework adapter ships its own doctor plus a few helpers under python -m z4j_<framework>:
python -m z4j_bare doctor # canonical implementationpython -m z4j_flask doctor # same checks; reads Flask app.config or envpython -m z4j_fastapi doctor # same checks; reads envpython -m z4j_django doctor # equivalent Django management command: ./manage.py z4j_doctorAll four implement doctor with the same probes (buffer dir writable, brain DNS / TCP / TLS, WebSocket upgrade) and accept the same flags (--no-websocket, --json). See frameworks/bare for the canonical reference.