Your first world
This walkthrough follows docs/QUICKSTART.md §1–§5, updated for two changes since that
section was first run: the interpreter pin is now v0.41.0, and POST /v1/commit now requires a
session. It takes about five minutes.
You need the two programs built and PIN set, as in Install:
unset AILANG_REGISTRY_API_KEY
export PIN=$HOME/.pinned-ailang/ailang
go build -o /tmp/ailang-worldd ./cmd/ailang-worldd
1. Start the daemon
/tmp/ailang-worldd serve --db /tmp/world-demo.db --ailang-bin $PIN &
It prints one line when the socket is bound:
ailang-worldd listening on http://127.0.0.1:7644
serve is loopback-only: a non-loopback --bind is refused, with no override.
--ailang-bin archives the interpreter at startup. Its content hash becomes the replay pin that
every log entry carries. The first start also bootstraps the epoch registry for that
interpreter's release.
/tmp/ailang-worldd health
{"status":"ok","daemon_version":"0.1.0","db_path":"/tmp/world-demo.db","interpreter_ref":"sha256:1a67b014…","interpreter_version":"AILANG v0.41.0\nCommit: 24ee108\n…"}
There is no world yet:
/tmp/ailang-worldd head
ailang-worldd: /v1/head returned HTTP 404 NotFound: no world head has been selected yet
Every read is bounded. A store read that has not answered within 10 s returns
503 with class Timeout. A genuine internal failure returns 500 with the fixed body
internal store failure; the cause goes to the daemon's stderr, one line per error. The
terminal running serve is where you read why.
2. Mint a session (attended)
Committing needs a session. Minting opens the store for writing, and the store allows one writer process, so stop the daemon first:
kill %1
Then mint, at a real terminal:
/tmp/ailang-worldd session mint --db /tmp/world-demo.db --episode quickstart \
--grant world.apply=world:10 --out /tmp/qs-session
It asks on the terminal:
Confirm mint for episode quickstart (1 grant(s), expiry +3600s) with a session credential? [y/N]
Answer y. The token is written once to /tmp/qs-session at mode 0600, and the
credential_id (for revocation) goes to stderr. The world.apply=world:10 grant is not needed
to commit, which only needs a valid session. It is the grant the optional
published transition below requires.
session mint opens /dev/tty and refuses without one:
refusing: no controlling terminal (…); minting a session credential requires one human act at a terminal.
That is the fence working. See Attended steps.
3. Commit the genesis world
Restart the daemon:
/tmp/ailang-worldd serve --db /tmp/world-demo.db --ailang-bin $PIN &
A commit is JSON: observedHead (empty for genesis), content-addressed objects (payload in
base64; hash must be sha256:<hex> of the payload bytes, and the store verifies it),
nextWorld, and the log entry with its six-field header. Generate a valid one:
python3 - <<'EOF'
import json, hashlib, base64, os
def sha(b): return "sha256:" + hashlib.sha256(b).hexdigest()
payload = json.dumps({"goal": "hello, World"}).encode()
interp = open(os.environ["PIN"], "rb").read()
eh = sha(b"genesis-entry-1")
c = {"observedHead": "",
"objects": [{"hash": sha(payload), "interfaceHash": sha(b"iface-v1"),
"semanticId": "world/demo/genesis-goal", "provenance": "quickstart",
"payload": base64.b64encode(payload).decode()}],
"nextWorld": {"ref": sha(b"world-1"), "revision": 0,
"stateRoot": sha(b"state-1"), "logHead": eh},
"entry": {"header": {"entryIndex": 0, "semanticsEpoch": 1,
"transitionFn": sha(payload), "interpreter": sha(interp),
"prevEntryHash": sha(b"genesis"), "writtenBy": "quickstart"},
"entryHash": eh, "transitionRef": sha(payload)}}
open("/tmp/genesis.json","w").write(json.dumps(c, indent=2))
EOF
/tmp/ailang-worldd commit --file /tmp/genesis.json --session "$(cat /tmp/qs-session)"
It returns the new head:
{"selectedHead":"sha256:…"}
A commit has 3 s of store work. If it answers 503, read the class:
Timeout: the budget ended before the durable step. Nothing landed; resending the same file is safe.CommitUncertain: it ended after the durable step began. The commit either landed whole or not at all. Do not resend yet. Readlog get 0and compare it with theentryyou sent: equal in every field means it landed; a 404 or a different row means it did not. The current head is not evidence either way.
For an exact answer, add "invocationId": "rest:<your-id>" to the JSON. The daemon then records
the commit's intent first, and curl -s http://127.0.0.1:7644/v1/receipts/rest:<your-id>
answers resolved (with resultRef equal to your nextWorld.ref), not-started or
indeterminate.
4. Read everything back
/tmp/ailang-worldd head
/tmp/ailang-worldd log get 0
/tmp/ailang-worldd world get "$(/tmp/ailang-worldd head)"
Compare log get 0's header.interpreter with health's interpreter_ref: they are
identical. That is the replay pin, live. Object payloads read back with
object get <hash> --payload (base64). Read routes need no session.
5. See the guarantees refuse things
Send the same commit again:
/tmp/ailang-worldd commit --file /tmp/genesis.json --session "$(cat /tmp/qs-session)"
You get HTTP 409 HeadConflict with both observedHead and selectedHead: the structured
conflict a caller re-plans from. A stale writer gets facts, not corruption.
Without the session:
/tmp/ailang-worldd commit --file /tmp/genesis.json
ailang-worldd: /v1/commit returned HTTP 401 SessionAbsent: a session credential is required: no Authorization Bearer header was present
Start a second writer on the same file:
/tmp/ailang-worldd serve --db /tmp/world-demo.db --bind 127.0.0.1:7645
ailang-worldd: daemon startup failed at store-open: another process already holds writer authority for this database (single-writer is enforced, not conventional): …
6. Stop
SIGTERM (Ctrl-C or kill %1) drains with a bound and releases the writer lock. A clean drain
prints nothing.
7. Optional: publish and call a pure transition
docs/QUICKSTART.md §6–§8 publish a one-line echo transition and call it over A2A and MCP.
Those sections are marked "attended — pending first verbatim run" in the runbook. The publish
step is covered in Transitions manifest and the calls in
MCP and A2A. The session you minted above already holds the
world.apply grant the echo transition's access names.
Next: Coding tools, the eight real transitions.