CLI reference
Two programs, both built from this repository. Help text below is the binaries' own output,
captured from a build of dev on 2026-10-03.
ailang-worldd
ailang-worldd — AILANG World local daemon (loopback only)
Usage:
ailang-worldd serve --db <path> [--bind host:port] [--ailang-bin <path>]
[--workspace-root <dir> --tool-ailang-bin <path>]
[--examples-dir <dir>]
ailang-worldd [--addr <url>] health
ailang-worldd [--addr <url>] head
ailang-worldd [--addr <url>] world get <ref>
ailang-worldd [--addr <url>] object get <ref> [--payload]
ailang-worldd [--addr <url>] object find <semanticId> [--after <ref>] [--limit N]
ailang-worldd [--addr <url>] log get <index>
ailang-worldd [--addr <url>] log range --from N [--limit M]
ailang-worldd [--addr <url>] registry get <name>
ailang-worldd [--addr <url>] log tail [--from N] [--follow] [--interval 1s] [--raw]
ailang-worldd [--addr <url>] commit --file <commit.json> [--session <file|token>]
ailang-worldd [--addr <url>] tools list [--session <file|token>] [--json]
ailang-worldd [--addr <url>] call <tool> [--session <file|token>]
[--arg k=v]... [--arg-json k=<json>]... | --json <obj>|@file|-
[--json-out] [--strict]
ailang-worldd [--addr <url>] why <index|head|sha256:<ref>|a2a:<id>|rest:<id>|->
[--result <file>] [--scan N] [--json]
ailang-worldd [--addr <url>] provenance [--since <entry>] [--episode <ep>] [--scan N]
ailang-worldd session mint --db <path> --episode <ep> --grant EFFECT=SCOPE:BUDGET...
[--ttl 3600] [--out <file>]
ailang-worldd session revoke [--db <path>] <credential_id-hash>
<verb> --help prints the help of: tools, call, why, log tail, provenance.
Session credential (tools, call, commit): --session <file> (a file holding
the 64-hex token, mode 0600) or the token itself (warns: visible on argv),
else $WORLD_SESSION. The token is never printed.
Global client flag:
--addr <url> base URL of the daemon (default http://127.0.0.1:7644).
Applies to client verbs only; it is NOT a 'serve' flag.
serve flags:
--db <path> world store database (required)
--bind host:port loopback listen address (default 127.0.0.1:7644);
a non-loopback host is refused — there is no override
--ailang-bin <path> interpreter to archive and pin at startup (optional)
--workspace-root <dir>
episode worktrees live at <dir>/<episode> (made by the
operator with git worktree add before session mint); it
must not contain the store, its archive, its rendered
policies or its tool cache — startup refuses otherwise
--tool-ailang-bin <path>
AILANG binary the workspace tools run (must be
AILANG v0.52.1); archived and hash-verified like
--ailang-bin. The Workspace.*/Ailang.* tools are served
only when both this and --workspace-root are set
--examples-dir <dir> AILANG examples corpus examples-search reads (passed
to the tool as AILANG_EXAMPLES; World never falls back
to a corpus in the binary). Default: ~/.ailang/examples
when it exists, else examples-search refuses "no
examples corpus configured". Must be outside
--workspace-root
Exit codes: 0 ok, 1 usage or client error, 2 fatal startup,
3 integrity refusal (why: a broken link; call --strict: ok:false).
ailang-worldd help prints the same text. tools, call, why, log tail and provenance
print their own help with --help (exit 0, shown below); for the other verbs Go's flag parser
prints a flag list where one is shown.
--addr is refused with session mint and session revoke, as with serve, because they act on
--db directly, not on a running daemon.
Every invocation refuses to start (exit 2) if AILANG_REGISTRY_API_KEY is set in its
environment.
serve
See the flags in the usage text above, and Operating the daemon.
Client verbs
All client verbs send one bounded request (30 s client timeout) to --addr and print the
response body on success. On an HTTP error they print
ailang-worldd: <path> returned HTTP <status> <Class>: <message> to stderr (with
(observedHead=… selectedHead=…) for a conflict) and exit 1.
| Verb | Request |
|---|---|
health | GET /v1/health |
head | GET /v1/head (prints the ref as plain text) |
world get <ref> | GET /v1/worlds/{ref} |
object get <ref> [--payload] | GET /v1/objects/{ref}, with ?payload=true when --payload is given |
object find <semanticId> [--after <ref>] [--limit N] | GET /v1/objects/by-semantic-id/{semanticId} |
log get <index> | GET /v1/log/{index} |
log range --from N [--limit M] | GET /v1/log?from=N&limit=M |
registry get <name> | GET /v1/registry/{name} |
commit --file <commit.json> [--session <file|token>] | POST /v1/commit |
Flags come after the positional argument for object get, object find, and log range.
commit
Usage of ailang-worldd commit:
-file string
commit JSON file
-session string
session credential for the session-gated /v1/commit: a file holding the 64-hex token (preferred) or the token itself; default $WORLD_SESSION
The session is resolved like call's (see Session credential) and sent as
Authorization: Bearer <token>. With neither --session nor WORLD_SESSION the daemon answers
401 SessionAbsent.
Session credential
tools, call and commit resolve the session the same way:
--session <value>, else theWORLD_SESSIONenvironment variable, else an error.- A 64-hex value is the token itself. Given on the command line it works but warns, because other local processes can read a process's arguments.
- Any other value is a file (at most 256 bytes) holding the token, which is how
session mint --out <file>writes it. A file readable by group or other gets a warning (chmod 600it).
The token is only ever sent as the Authorization: Bearer header; no command prints it.
tools list
usage: ailang-worldd [--addr <url>] tools list [--session <file|token>] [--json]
Lists the tools the session may call (MCP tools/list on /mcp/): name,
description and required arguments. --json prints the tools array verbatim.
The session is --session (a file holding the 64-hex token, preferred; or the
token itself, which warns) or $WORLD_SESSION.
ailang-worldd tools list --session ~/.ailang/world/ep1.session
ailang-check Type-check and Z3-verify an AILANG file inside this episode's worktree (policy-tool `ai_check`) and …
required: path
ailang-read Read a file inside this episode's worktree (policy-tool `read`). The path is relative to the worktre…
required: path
…
8 tool(s)
The list follows the session's grants: a session granted only Workspace.Read lists only
ailang-read.
call
usage: ailang-worldd [--addr <url>] call <tool> [--session <file|token>]
[--arg k=v]... [--arg-json k=<json>]... | --json '<obj>'|@file|-
[--json-out] [--strict]
Calls one tool (MCP tools/call on /mcp/). Arguments come from repeated --arg
(a string value) and --arg-json (any JSON value), or from one --json object
(inline, @file, or - for stdin); the two forms do not mix.
Output: the result's fields (long values elided with their byte counts), then
the world block: the plan ref and, per effect, its id, status and record ref.
--json-out prints the committed output bytes exactly (one trailing newline),
so sha256 of stdout minus that newline is the output ref, and the output can
be piped to 'ailang-worldd why -'.
Exit: 0 committed (including a committed refusal, ok:false); 3 with --strict
when the committed result has ok:false; 1 on a tool error, a session denial
or a host failure. A host failure is probed: "no world head" means commit a
genesis first; "a commit landed (entry N)" means do not retry — run why N.
ailang-worldd call ailang-read --session ~/.ailang/world/ep1.session --arg path=data.txt
content: hello from ep1\n
ok: true
policy_digest: 4b7541a98c773068896571d54c5182bc5601b335f2c5e663743c07eda077b121
tool: sha256:e55ff71c710c10395ebf949f6777ef9114bed8bba859e3ba719ed73c6d1b9c7f
output: sha256:a70447b8e8c490f547b021f257ee0c3799857d3d70ec6eaeccfb9a6293ee1572 (416 bytes)
world:
plan sha256:a1f0feb6b661e46646dab346043e8c144bf3d2be7733df0e520506119b2b773f
effect e1 ok sha256:4770647ef5f9b08c8ccb51773631a3460a070d2be9a06cffb609b4eb094df1df
/mcp/ answers in three shapes, and call tells them apart by HTTP status and Content-Type:
| Answer | Meaning | What call does |
|---|---|---|
200 text/event-stream | the JSON-RPC response | prints the result; a JSON-RPC error inside it is a tool error (exit 1) |
200 application/json with -32603 | a host failure, which can follow a commit that did land | reads /v1/head before and after the call: no head → "no world head" (commit a genesis); the head moved → "a commit landed (entry N) — do not retry"; otherwise the message as sent |
401 text/plain | the session was refused | prints the reason and a one-line fix (absent, unknown, malformed or expired) |
why
usage: ailang-worldd [--addr <url>] why <target> [--scan N] [--json]
ailang-worldd [--addr <url>] why --result <file> [--scan N] [--json]
Walks one committed invocation back to its whole provenance chain and checks every link:
the world ref (recomputed and confirmed by GET /v1/worlds/<ref>), the log entry (its hash
recomputed), the invocation record, the input, the plan, each effect record (with its request
and result), and the output, which must equal the world's stateRoot.
| Target | Resolves by |
|---|---|
<index> or head | the log entry directly |
sha256:<ref> | the object's semanticId: a record, input, output, plan, effect record, effect request or result; or a world ref |
a2a:<id> | the record's invocationId |
rest:<id> | its receipt's world |
- or --result <file> | the output of call --json-out: its sha256 is the output ref (the result's world.plan is the fallback) |
Every target except an index or head is found by scanning the log backwards from the head,
one object read per entry, at most --scan N entries (default 500, maximum 5000) within 60
seconds. Past either limit it prints not found in the last N entries and exits 1. An entry
not written by the coordinator (a REST genesis, say) is shown with its object only, with the
reason.
Exit codes: 0 when every link is ✓; 3 when any link is ✗ (the bytes the daemon served do
not match a content address); 1 when the target is not found. --json prints the chain as
JSON. See Provenance for a walked example.
log tail
usage: ailang-worldd [--addr <url>] log tail [--from N] [--follow] [--interval 1s] [--raw]
Prints log entries, one line each: index, short entry hash, writtenBy, and for
a coordinator invocation its episode, skill and effect statuses.
--from N first entry (default: head-19, the last 20 entries)
--follow keep polling for new entries until Ctrl-C; a daemon restart
is retried with backoff (up to 5 s) and the outage is named
--interval D poll interval with --follow (default 1s)
--raw print each entry as its JSON
#1 ef2b3322 coordinator:a2a ep1 ailang-read [Workspace.Read ok]
#2 b7aa36d6 coordinator:a2a ep1 ailang-read [Workspace.Read ok]
#3 c0cd3ae0 coordinator:a2a ep1 ailang-read [no effects]
With --follow the next read starts at the entry after the last one printed, so each entry
is printed exactly once.
provenance
usage: ailang-worldd [--addr <url>] provenance [--since <entry>] [--episode <ep>] [--scan N]
Prints the trailer that a pull request or commit made through World carries:
World-Provenance: store=/Users/you/.ailang/world/world.db episode=ep1 entries=1-4
store is the daemon's database path from /v1/health; entries are the episode's first and
last coordinator entries from --since (default: the last 500 entries) to the head. Without
--episode it prints one trailer per episode in the range. Any entry in the range can be walked
back with ailang-worldd why <entry>. It exits 1 when the range holds no coordinator entry for
the episode.
session mint
Usage of ailang-worldd session mint:
-db string
world store database (required)
-episode string
episode the session binds to (required)
-grant value
EFFECT=SCOPE:BUDGET, repeatable, at least one
-out string
write the credential ONCE to <path> at mode 0600 (default: print to stdout exactly once)
-ttl int
lifetime in whole seconds (default 3600) (default 3600)
Attended: opens /dev/tty and asks Confirm mint for episode … [y/N] there; refuses without
a controlling terminal. The daemon must be stopped (single writer). Each grant's expiry is set to
the session's (now + ttl). With --out it prints
minted session credential for episode <ep>: <n> grant(s), expires epoch <t>, written to <path>;
it always prints credential_id=<hash> to stderr. See
Sessions and episodes.
session revoke
Usage of ailang-worldd session revoke:
-db string
world store database (required)
ailang-worldd session revoke --db <path> <credential_id>
--db must come before the ID, as the command's usage message
(session revoke [--db <path>] <credential_id-hash> (flags before the id)) says; flags after the
ID are not parsed. The ID
is the 64-hex credential_id printed at mint. Not attended; the daemon must be stopped.
world-publish
world-publish — the attended entrypoint for an IRREVERSIBLE public write
world-publish packet [--package-dir D] [--golden G]
world-publish approve --store S [--registry-origin O] --now N --expires E
world-publish publish --store S --registry-origin O --publisher P \
--credential-file C --approval-ref R --now N --expires E (--live | --dry-run)
world-publish reconcile --store S [--registry-origin O] [--probe]
world-publish transitions --store S --manifest M (--ailang-bin B | --interpreter-ref R) [local registry write]
Exit codes: 0 done · 1 failed · 2 usage · 3 STOP (a fence refused; nothing happened)
This usage is printed when the program is run with no verb or an unknown one
(world-publish --help prints unknown verb "--help" followed by it).
Verbs
| Verb | Kind | What it does |
|---|---|---|
packet | Read-only, headless-permitted | Recomputes the world/core ready-packet from --package-dir and compares every field with --golden. STOP fence=packet reason=drift on any difference. |
approve | Attended | Mints a one-shot ApprovalDecisionV1 for the current packet and prints its ref. |
publish | Attended; irreversible with --live | Spends the approval, exactly once. Exactly one of --live or --dry-run. --dry-run runs every fence and sends nothing. |
reconcile | Read-only, headless-permitted | Lists publish intents with no outcome; --probe issues read-only metadata GETs to resolve them. --live is refused. |
transitions | Attended; local registry write | Publishes a descriptor manifest into the store's transition registry. --live is refused. See Transitions manifest. |
Flags
All verbs share one flag set. Each verb uses the subset shown in the usage above. -h on any
verb prints this list (and exits 2):
-ailang-bin string
transitions: interpreter binary to archive now, as the daemon does at startup
-approval-ref world-publish approve
the ApprovalDecisionV1 hashref minted by world-publish approve
-credential-file string
file outside the working tree holding the registry API key
-decided-by string
who is granting the approval
-dry-run
rehearse the publish: every fence, no request
-episode string
durable episode ID (default "attended-publish")
-expires int
logical time the approval expires at
-golden string
the committed ready-packet golden (default "scripts/world_package_ready_packet.golden.json")
-interpreter-ref string
transitions: archived interpreter HashRef pinned into every descriptor
-live
PERFORM THE IRREVERSIBLE PUBLIC WRITE
-manifest string
transitions: descriptor manifest file (JSON array)
-now int
logical time of this act
-package-dir string
the projected package directory (default "packages/world-core")
-probe
reconcile: issue the read-only metadata GETs
-publisher string
path to the pinned released ailang binary
-registry-origin string
the read-only public bucket origin
-requester string
who is requesting the approval
-store string
path to the world database this publish is recorded in
There is deliberately no flag that sets the registry validator origin; it is a compiled constant. A test compares the flag set to a frozen list, so adding a flag fails the build.
STOP lines
A refusal prints STOP fence=<name>[ reason=<reason>] and exits 3. Fence names: mode, ci,
tty, confirmation, store, approval, credential, packet, handler. See
Attended steps.
Build world-publish to a binary for attended use rather than using go run: go run exits 1
for a child that exited 3, which hides the STOP contract.