arizuko › reference › CLI commands
CLI commands
Every subcommand of the arizuko binary, grouped by concern. Each entry shows the exact signature, the flags flag.NewFlagSet registers, what state changes where, and a source link pointing at the dispatch site. Ground truth is cmd/arizuko/main.go; the dispatch map sits at main.go:54.
The CLI uses Go's standard flag package plus a hand-rolled positional dispatcher — no cobra. Top-level verb is os.Args[1]; subcommand verb (where applicable) is args[1] after the instance name. <instance> is the data-dir suffix; resolved via $ARIZUKO_DATA_DIR/arizuko_<name> or ${PREFIX:-/srv}/data/arizuko_<name> (main.go:146).
Index
- Instance lifecycle —
create,generate,run,status,pair - Config manifests —
export,apply,plan,get - Operator chat & messaging —
chat,send,token - Groups & grants —
group list|add|rm|grant|ungrant|grants - Identities —
identity list|link|unlink - Invites —
invite create|list|revoke - Gates (rate limits) —
gate list|add|rm|enable|disable - Budget (cost caps) —
budget set|show folder|user - Network allowlist —
network allow|deny|list|resolve - Routes —
route list|add|rm - Secrets (folder & user) —
secret,user-secret
Instance lifecycle
arizuko create <name> [--product <product>]
Seed an instance data dir, write .env with a generated CHANNEL_SECRET, open store/, insert the default main group, set up its group folder, and seed default tasks. If --product is given, reads ant/examples/<product>/PRODUCT.md, prints the env checklist, and copies the product's skills/facts into the new group.
| Flag | Type | Default | Effect |
|---|---|---|---|
--product | string | "" | Product template name; looked up under $HostAppDir/ant/examples/<product>/PRODUCT.md. On miss, prints known products and exits non-zero. |
State touched: creates ${PREFIX:-/srv}/data/arizuko_<name>/, writes .env (mode 0600), opens store/messages.db, inserts main group, calls container.SetupGroup for folder skeleton, seeds default tasks. Idempotent on .env (only written when missing).
arizuko create solo
arizuko create launch --product strategy
Source: cmd/arizuko/main.go:161
arizuko generate <instance>
Generate docker-compose.yml in the instance dir from compose.Generate. Atomic write via tempfile + rename; mode 0644.
State touched: writes <data-dir>/docker-compose.yml only.
arizuko generate krons
Source: cmd/arizuko/main.go:100
arizuko run <instance>
Generate the compose file (same path as generate), then docker compose -f <compose> up --remove-orphans. Foreground process; SIGINT propagates to the compose stack.
State touched: writes the compose file, then leaves long-lived docker state under control of docker.
arizuko run krons
Source: cmd/arizuko/main.go:89
arizuko status <instance>
docker compose ps against the instance compose file, then GET http://localhost:<APIPort>/v1/channels on the router with a 10s timeout. Prints registered channel name → URL pairs, or a "router API unreachable" / "no channels registered" line.
State touched: read-only. Requires docker-compose.yml to exist (will die with a "run 'arizuko generate' first" hint).
arizuko status krons
Source: cmd/arizuko/main.go:721
arizuko pair <instance> <service> [args...]
Run a one-shot pairing/admin shell against a compose service: docker compose -f <compose> run --rm <service> [args...]. Used for interactive setup of channel adapters (e.g. whapd QR pairing).
State touched: whatever the chosen service does. --rm removes the container on exit.
arizuko pair krons whapd
arizuko pair krons mastd login --instance mas.to
Source: cmd/arizuko/main.go:699
Config manifests
The cold-tier config of an instance — groups, acl, routes, web_routes, secrets, scheduled tasks, network rules, onboarding gates, proxyd routes — reads and writes as one YAML document. The same resreg engine that serves these resources over REST, MCP, and /openapi.json also drives export, apply, plan, and get, so the YAML shape matches the schema exactly. Spec specs/5/8-yaml-manifests.md.
arizuko export <instance> [output.yaml]
Dump the instance's cold-tier resources as one YAML document. Keys sort deterministically — config_version first, then resources by name — so re-exporting an unchanged store yields byte-identical output, which makes the file diffable in git. Writes to the named file if given; otherwise to stdout (the byte-count line goes to stderr so a redirect captures only YAML).
State touched: read-only.
arizuko export krons > krons-config.yaml
arizuko export krons krons-config.yaml
Source: cmd/arizuko/apply.go:69
arizuko apply <instance> <manifest.yaml> [--force]
Replace the instance's cold-tier resources with the manifest's. For each resource named in the file, the engine runs DELETE FROM <table> then re-inserts the manifest rows — all in one transaction. A resource absent from the manifest is left untouched; a resource present but empty is cleared. The manifest's config_version must match the store's, or apply exits 2 and tells you to re-export and re-apply — this is the guard against overwriting a change made since you exported. Validation runs before the DB is touched, so a malformed file changes nothing. On success the config_version bumps by one.
| Flag | Type | Default | Effect |
|---|---|---|---|
--force | bool | false | Skip the config_version match check and apply anyway. The version still advances. Use when you intend to overwrite concurrent edits. |
State touched: rewrites every table named in the manifest, in one transaction. Deleting a group cascades to its web_routes and route_tokens (declared FKs, migrations 0068/0069) — the URL routes pinned to a removed group go with it.
arizuko export krons > krons.yaml
# edit krons.yaml
arizuko apply krons krons.yaml
arizuko apply krons krons.yaml --force
Source: cmd/arizuko/apply.go:29
arizuko plan <instance> <manifest.yaml>
Show what apply would change, without touching the DB. Prints one block per resource: + for rows the manifest adds, ~ for rows it updates, - for rows it removes. Secrets never mutate via apply, so they print as informational (N set (not applied)) rather than as deltas. If the manifest's config_version doesn't match the store's, the last line says so — that's the same mismatch apply would reject without --force.
State touched: read-only.
arizuko export krons > krons.yaml
# edit krons.yaml
arizuko plan krons krons.yaml
Source: cmd/arizuko/apply.go:120
arizuko get <instance> <resource>
Emit one resource from the live store as a YAML fragment — the same shape apply accepts, so re-applying the fragment is a no-op. Use it to pull one table (say routes or web_routes) out of the store without exporting the whole config. Secret rows emit metadata only; the encrypted value never leaves the DB.
State touched: read-only.
arizuko get krons routes
arizuko get krons web_routes
Source: cmd/arizuko/apply.go:196
Operator chat & messaging
arizuko chat <instance>
Launch claude (Claude Code CLI) wired via socat to the instance's root MCP socket at <data-dir>/ipc/main/gated.sock. Writes a temporary mcpServers config pointing at socat STDIO UNIX-CONNECT:<sock> and execs claude --mcp-config <tmp>. Local-operator only — socket-fs access is the auth.
State touched: none on disk beyond a deleted-on-exit tempfile. Anything the agent does via MCP tools mutates the store as usual.
Prereqs: instance running (socket exists), claude and socat on $PATH.
arizuko chat krons
Source: cmd/arizuko/main.go:657
arizuko send <instance> <folder> [<message>] [--wait | --stream] [--stdin] [--topic <t>]
POST a message to a group's chat endpoint, optionally blocking until the agent's turn finishes. Resolves a web:<folder> token from route_tokens and reads WEB_HOST from .env; scheme is http for localhost/127.0.0.1, otherwise https. See specs/5/W-webhook-routes.md for the token model.
| Flag | Type | Default | Effect |
|---|---|---|---|
--wait | bool | false | After POST, poll /chat/<token>/<turn_id>?after=<seq> at 1s cadence, print frames, exit 0 on success / 1 on failed. |
--stream | bool | false | Same as --wait but subscribes to .../sse instead of polling. Exit codes: 0 success, 1 failed, 2 transport error. |
--stdin | bool | false | Read message body from stdin (trimmed) instead of the positional arg. |
--topic | string | auto-gen | Conversation thread id. Reuse the same value across calls to keep the agent in the same context. |
State touched: opens the instance store read-only to look up the chat token; everything else happens server-side via the /chat/<token>/ endpoint.
arizuko send krons main "hello from cli"
arizuko send krons main "what's the status?" --stream
echo "long body" | arizuko send krons main --stdin --wait
Source: cmd/arizuko/send.go:29
arizuko token <instance> <issue|list|revoke> ...
Manage the route tokens that back /chat/<token>/ visitor chat and /hook/<token> webhook ingest. Each token is one row in route_tokens mapping an opaque URL token to a JID and owner folder. issue mints a token for a web: or hook: JID and prints both the JID and the raw token (the token is shown once). list tabulates a folder's tokens. revoke deletes one by JID; pass <owner_folder> when the token was minted on behalf of a descendant or under a nested folder (the owner can diverge from the JID's folder), since the JID alone can't recover it.
| Subcommand | Form |
|---|---|
issue chat | arizuko token <instance> issue chat <folder> [<suffix>] |
issue webhook | arizuko token <instance> issue webhook <folder> <label> [<suffix>] |
list | arizuko token <instance> list <folder> |
revoke | arizuko token <instance> revoke <jid> [<owner_folder>] |
State touched: issue inserts a route_tokens row; revoke deletes one; list is read-only. issue and revoke write an audit row.
arizuko token krons issue chat support
arizuko token krons issue webhook eng github
arizuko token krons list support
arizuko token krons revoke web:support
Source: cmd/arizuko/token.go:20
Groups & grants
All group verbs share the same store and dispatch under cmd/arizuko/main.go:256.
arizuko group <instance> list
List all groups as tab-separated folder\tname.
State touched: read-only.
arizuko group krons list
Source: cmd/arizuko/main.go:268
arizuko group <instance> add <jid> <folder> [--product <name>]
Create a group bound to a channel JID. Folder is validated via groupfolder.IsValidFolder. Calls container.SetupGroup for the folder skeleton (optionally seeded from a product template under $HostAppDir/ant/examples/<product>/), seeds default tasks, inserts the group row, then adds a route room=<JidRoom(jid)> -> <folder>. For Discord guild channels (jid prefix discord: but not discord:dm/) the route is scoped to verb=mention so only mentions fire; other messages fall through to a catch-all #observe row.
| Flag | Type | Default | Effect |
|---|---|---|---|
--product | string | "" | Product template applied to this group (same set as arizuko create --product). On miss, errors with the expected PRODUCT.md path. |
State touched: filesystem (group skeleton), groups, routes, default-task seed.
arizuko group krons add whatsapp:120363042@g.us standup
arizuko group krons add "discord:guild/123/456" eng --product developer
Source: cmd/arizuko/main.go:275 (v0.40.6 added --product)
arizuko group <instance> rm <folder>
Delete the group row by folder via store.DeleteGroup. Does not remove the on-disk group directory or routes pointing at it; clean those up manually if needed.
State touched: groups table.
arizuko group krons rm standup
Source: cmd/arizuko/main.go:313
arizuko group <instance> grant <sub> <pattern>
Authorize sub on a scope. The literal pattern ** writes acl_membership(sub, role:operator) (the operator role's permissions live on the role, not duplicated per user); any other pattern writes an acl(principal=sub, action=admin, scope=pattern, effect=allow) row. Idempotent. See grants reference for syntax.
State touched: acl_membership (for **) or acl table.
arizuko group krons grant google:alice@example.com 'solo/**'
arizuko group krons grant telegram:42 'corp/eng/sre'
arizuko group krons grant google:operator@example.com '**' # operator role
Source: cmd/arizuko/main.go:347
arizuko group <instance> ungrant <sub> <pattern>
Reverse of grant. ** removes the operator-role membership edge; any other pattern deletes the matching acl row.
State touched: acl_membership (for **) or acl table.
arizuko group krons ungrant google:alice@example.com 'solo/**'
Source: cmd/arizuko/main.go:327
arizuko group <instance> grants [<sub>]
List grants. With no sub, lists all grants. With a sub, filters to that subject. Tab-separated SUB | PATTERN | GRANTED_AT.
State touched: read-only.
arizuko group krons grants
arizuko group krons grants google:alice@example.com
Source: cmd/arizuko/main.go:333
Identities
Identities unify multiple subject IDs (google:, telegram:, github:…) under one logical user. Dispatcher at main.go:550.
arizuko identity <instance> list
List all identities and the subs claimed by each. Columns: ID | NAME | CREATED_AT | SUBS (comma-joined).
State touched: read-only.
arizuko identity krons list
Source: cmd/arizuko/main.go:562
arizuko identity <instance> link <sub> [--name NAME] [--id ID]
Bind sub to an identity. With no --id, creates a new identity (display name is --name or, if empty, sub) and adds sub as its first claim. With --id, attaches sub to that existing identity.
| Flag | Type | Default | Effect |
|---|---|---|---|
--name | string | "" | Display name when creating a new identity. Ignored if --id is set. |
--id | string | "" | Existing identity ID to attach sub to; bypasses creation. |
State touched: identities, identity_subs.
arizuko identity krons link google:alice@example.com --name Alice
arizuko identity krons link telegram:42 --id id_a1b2c3
Source: cmd/arizuko/main.go:566
arizuko identity <instance> unlink <sub>
Remove the claim row for sub. Prints "no claim to remove" if there was none.
State touched: identity_subs.
arizuko identity krons unlink telegram:42
Source: cmd/arizuko/main.go:577
Invites
Onboarding tokens consumed by onbod's invite landing. Dispatcher at main.go:473.
arizuko invite <instance> create <target_glob> [--max-uses N] [--expires DURATION]
Mint an invite token whose redemption grants the user the given target_glob pattern. Prints token, target, max-uses, optional expiry.
| Flag | Type | Default | Effect |
|---|---|---|---|
--max-uses | int | 1 | Maximum redemptions. Rejected if < 1. |
--expires | duration | 0 (no expiry) | Time-from-now after which the token is dead. Parsed by time.ParseDuration (24h, 72h30m, …). |
State touched: invites table; issued_by_sub is set to the literal "cli".
arizuko invite krons create 'solo/**' --max-uses 1 --expires 72h
arizuko invite krons create 'corp/eng/**' --max-uses 5
Source: cmd/arizuko/main.go:485
arizuko invite <instance> list [--issued-by SUB]
List invites. Columns: TOKEN | TARGET_GLOB | ISSUED_BY | ISSUED_AT | EXPIRES_AT | USED (where USED is used_count/max_uses).
| Flag | Type | Default | Effect |
|---|---|---|---|
--issued-by | string | "" | Filter to invites issued by a specific subject. Empty = all. |
State touched: read-only.
arizuko invite krons list
arizuko invite krons list --issued-by cli
Source: cmd/arizuko/main.go:512
arizuko invite <instance> revoke <token>
Revoke a token by ID. Future redemption attempts fail.
State touched: invites row marked revoked.
arizuko invite krons revoke inv_abc123
Source: cmd/arizuko/main.go:538
Gates (rate limits)
Per-spec daily limits enforced inside onbod (the admission daemon). Dispatcher at main.go:402.
arizuko gate <instance> list
List gates as GATE | LIMIT/DAY | ENABLED. Prints no gates if empty.
State touched: read-only.
arizuko gate krons list
Source: cmd/arizuko/main.go:414
arizuko gate <instance> add <spec> <N>/day
Upsert a gate at the given daily limit. Limit string accepts an optional /day suffix (stripped); must parse as a positive integer.
State touched: gates table.
arizuko gate krons add solo/inbox 200/day
arizuko gate krons add 'corp/eng/**' 1000
Source: cmd/arizuko/main.go:434
arizuko gate <instance> rm <spec>
Delete a gate row by spec.
State touched: gates table.
arizuko gate krons rm solo/inbox
Source: cmd/arizuko/main.go:447
arizuko gate <instance> enable <spec>
Flip enabled to true on the row.
State touched: gates table.
arizuko gate krons enable solo/inbox
Source: cmd/arizuko/main.go:454
arizuko gate <instance> disable <spec>
Flip enabled to false on the row. The row stays so the spec/limit survives re-enable.
State touched: gates table.
arizuko gate krons disable solo/inbox
Source: cmd/arizuko/main.go:461
Budget (cost caps)
Per-folder and per-user daily spend caps in cents. The pre-spawn gate in gateway/ refuses to spawn when today's spend exceeds the lower of (folder cap, user cap). Caps live on groups.cost_cap_cents_per_day and auth_users.cost_cap_cents_per_day; spend is summed from cost_log. Spec 5/34. Dispatcher at budget.go:18.
arizuko budget <instance> set <folder|user> <name|sub> --daily N
Set a daily cap (in cents) on a folder or user. --daily 0 removes the cap (uncapped). Negative values are rejected.
| Flag | Type | Default | Effect |
|---|---|---|---|
--daily | int | required | Daily cap in cents. 0 = uncapped (cap row removed). |
State touched: groups.cost_cap_cents_per_day (folder scope) or auth_users.cost_cap_cents_per_day (user scope).
arizuko budget krons set folder corp/eng --daily 5000
arizuko budget krons set user google:alice@example.com --daily 1000
arizuko budget krons set folder solo/inbox --daily 0 # uncapped
Source: cmd/arizuko/budget.go:30
arizuko budget <instance> show <folder|user> <name|sub>
Print the cap, today's spend, remaining budget, and a status line (ok, WARN at ≥80%, EXHAUSTED when turns will be refused). Tab-aligned key/value table.
State touched: read-only.
arizuko budget krons show folder corp/eng
arizuko budget krons show user google:alice@example.com
Source: cmd/arizuko/budget.go:43
Network allowlist
Per-folder egress rules consumed by the crackbox proxy. Walks the folder ancestry on resolve. Dispatcher at network.go:12.
arizuko network <instance> allow <folder> <target>
Add an allow rule binding a folder to a hostname (or other target form supported by store.AddNetworkRule). created_by is set to the literal "cli".
State touched: network_rules table.
arizuko network krons allow main api.github.com
arizuko network krons allow corp/eng api.openai.com
Source: cmd/arizuko/network.go:24
arizuko network <instance> deny <folder> <target>
Remove a previously-added allow rule. Naming preserves the operator-mental-model (allow + deny as paired verbs); under the hood it's a row delete via store.RemoveNetworkRule.
State touched: network_rules table.
arizuko network krons deny main api.github.com
Source: cmd/arizuko/network.go:32
arizuko network <instance> list [<folder>]
List rules. Without <folder>, lists all. With a folder, lists that folder's own rows (not inherited ones — use resolve for that). Columns: FOLDER | TARGET | CREATED_AT | CREATED_BY (root rows render as (root)).
State touched: read-only.
arizuko network krons list
arizuko network krons list corp/eng
Source: cmd/arizuko/network.go:40
arizuko network <instance> resolve <folder>
Print the fully resolved allowlist for a folder — walks ancestry, dedupes, includes default seeds (anthropic.com, api.anthropic.com from migration 0037). One target per line. Useful for verifying what crackbox will accept for a given folder.
State touched: read-only.
arizuko network krons resolve corp/eng/sre
Source: cmd/arizuko/network.go:66
Routes
The route table maps inbound messages to group folders. Each row is a seq (priority, lower wins), a match expression over message attributes, and a target folder. arizuko group add writes a route for you; use route to add the catch-all and cross-source rules by hand. Routes share their store with acl (routd.db in the split topology, messages.db in the monolith); writes are audit-free, mirroring the grant path. For bulk or GitOps-style edits, declare routes in a manifest and arizuko apply. Dispatcher at route.go:20.
arizuko route <instance> list
List every route ordered by seq then id. Columns: ID | SEQ | MATCH | TARGET. An empty match renders as * (catch-all). Prints no routes if empty.
State touched: read-only.
arizuko route krons list
Source: cmd/arizuko/route.go:29
arizuko route <instance> add <match> <target> [--seq N]
Add a route binding a match expression to a target folder. match is a space-separated set of key=value predicates (e.g. platform=telegram, verb=mention, chat_jid=hook:*/sentry/*); * or an empty string is the catch-all and is stored as an empty match. Prints the new id.
| Flag | Type | Default | Effect |
|---|---|---|---|
--seq | int | 0 | Match priority; lower wins. Put it before the positionals. |
State touched: routes table (audit-free PutRouteRow).
arizuko route krons add 'platform=telegram' supermarket
arizuko route krons add '*' corp/intake --seq 10
arizuko route krons add 'chat_jid=hook:*/sentry/*' corp/eng/sre --seq -10
Source: cmd/arizuko/route.go:35
arizuko route <instance> rm <id>
Delete a route by id (from route list). Errors with no route <id> if it doesn't exist.
State touched: routes table row delete (audit-free DeleteRouteRow).
arizuko route krons rm 7
Source: cmd/arizuko/route.go:46
Secrets (folder & user)
Folder-scoped and user-scoped secrets backing the secret-broker model (see specs/7/Y-secret-broker.md). Keys must match ^[A-Z][A-Z0-9_]*$ (validated by keyValid at secret.go:132).
secrets table, split by scope_kind (folder or user). The same rows back the REST and MCP secret surface (spec 7/Y). Values are encrypted at rest; list shows keys, never values.arizuko secret <instance> set <folder> KEY --value V
Store a folder-scoped secret. --value is required; empty values rejected. Key is validated against the uppercase ENV-style pattern.
| Flag | Type | Default | Effect |
|---|---|---|---|
--value | string | "" | Secret value. Required, must be non-empty. |
State touched: secrets table, scope_kind = folder.
arizuko secret krons set corp/eng GITHUB_TOKEN --value ghp_xxxxxxxxxxxx
arizuko secret krons set main OPENAI_API_KEY --value sk-xxxxxxxx
Source: cmd/arizuko/secret.go:28
arizuko secret <instance> list <folder>
List keys (not values) for a folder. Columns: KEY | CREATED_AT. Prints no secrets if empty.
State touched: read-only.
arizuko secret krons list corp/eng
Source: cmd/arizuko/secret.go:38
arizuko secret <instance> delete <folder> KEY
Delete one folder-scoped key.
State touched: secrets table row delete.
arizuko secret krons delete corp/eng GITHUB_TOKEN
Source: cmd/arizuko/secret.go:43
arizuko user-secret <instance> set <user_sub> KEY --value V
Operator fallback for setting a user-scoped secret on behalf of a user who hasn't logged in via /dash/me/secrets yet. Same key validation as secret set.
| Flag | Type | Default | Effect |
|---|---|---|---|
--value | string | "" | Secret value. Required, must be non-empty. |
State touched: secrets table, scope_kind = user.
arizuko user-secret krons set google:alice@example.com GITHUB_TOKEN --value ghp_xxx
Source: cmd/arizuko/secret.go:67
arizuko user-secret <instance> list <user_sub>
List keys for one user sub. Columns: KEY | CREATED_AT.
State touched: read-only.
arizuko user-secret krons list google:alice@example.com
Source: cmd/arizuko/secret.go:77
arizuko user-secret <instance> delete <user_sub> KEY
Delete one user-scoped key.
State touched: secrets table row delete.
arizuko user-secret krons delete google:alice@example.com GITHUB_TOKEN
Source: cmd/arizuko/secret.go:82
See also
- reference index
- env vars — what the daemons themselves read
- MCP tools — the in-container surface the agent calls (often pairs with these CLI verbs)
- grants syntax — pattern language used by
group grantandinvite create cmd/arizuko/— source of truth