LibWorld

Reference

Every verb, generated

The 48 commands world dispatches and the 40 tools the MCP server registers, read out of the programs rather than written down beside them. /start/ is the four-step quickstart; this is the list.

Mirror

world status
server health + backends
world stats
per-backend catalog totals
world ls [--backend B] [--package P] [--limit N] [--keys]
list mirrored artifacts
world prefetch <backend> <spec> [--no-wait]
warm the cache (async job; waits unless --no-wait)
world gc
run retention garbage collection
world orphans [--adopt] [<backend>]
blobs the catalog has no row for
world pin <backend> <blob-key>
protect an artifact from GC
world unpin <backend> <blob-key>
remove pin protection
world repull <backend> <blob-key>
re-download the cached bytes from upstream
world rm <backend> <blob-key> [--force]
delete an artifact (blob + catalog row)
world audit [--limit N] [--since TS] [--backend B]
recent control-plane actions
world serve [args]
run the proxy/mirror server (execs world-server)

Git mirrors

world git ls
list git mirrors (from the catalog)
world git add <org/repo>
mirror a repo eagerly (clone ahead of need)
world git sync [<org/repo>]
refresh a mirror (or all before going offline)

Snapshots

Freeze what the mirror holds, so a build can be replayed years later

world snapshot ls
list snapshots, newest first
world snapshot create <name> [--description S] [--backend B]
freeze what the mirror holds now
world snapshot show <name> [--limit N] [--offset N]
the snapshot and its members
world snapshot verify <name>
re-hash every member against the digest it had when it was taken
world snapshot rm <name>
delete it (frees no bytes; the members lose GC protection)

Repos

Self-hosted forge — create, browse, git push over smart-HTTP

world repo ls
list forge repos
world repo create <name> [--desc D] [--branch B]
init a bare repo
world repo edit <name> [--desc D] [--branch B]
change the description (--desc '' clears it) or the default branch
world repo show <name>
metadata + last commit + clone URL
world repo rm <name> [--force]
delete a repo (force if non-empty)
world repo branches <name>
branches + tags
world repo log <name> [--ref R] [--limit N]
commit history
world repo commit <name> --path P --file F [--branch B] [--message M] [--author A] [--base SHA]
write one file to a BRANCH (never the default ref; runs no hook)
world repo archive <name> [--successor R]
make it read-only (pushes refused)
world repo unarchive <name>
accept pushes again

Builds

The coordinator on :10221

world build <project> [--target T] [--ref R] [--device SERIAL] [--param K=V]... [--watch] [--check]
queue a build; --param is repeatable, --check validates the manifest and target without queueing
world install <project> <number> [--target T] [--device SERIAL]
install a PRIOR build's artifact on the runner holding the handset (<number> is the per-project build number, not the API id)
world builds [--project P] [--target T] [--state S] [--device SERIAL] [--limit N] [--skips [N] | --no-skips]
recent builds; --device is what that handset actually ran, --skips the targets a push did NOT build and why
world build-show <id>
steps, artifacts + report for one build
world build-log <id> [--follow]
the build log, live while it runs
world build-cancel <id>
request cancellation
world build-retry <id>
re-queue a build's project/target/commit
world build-artifacts <id> [--download [<dir>]] [--dir <dir>]
list / fetch artifacts (dir: .)
world build-pin <id> [--off]
protect a build's artifacts from GC
world drain [--history [--days N]] | hold <reason…> | release
is the coordinator leasing, or held by a deploy or an operator? + which targets hold it, and which merely need the deploy token; --history is how long recent deploys waited, and how often that held the fleet; hold / release stop and restart leasing ON PURPOSE (deploy token; running builds are not touched)
world projects
projects the coordinator will build
world runners [--toolchain] [rm <name>]
registered build agents; --toolchain is what each host carries, rm forgets one
world targets [<project> | --project P] [--all]
which declared targets are NOT OK: the ones whose last build FAILED and the ones that have never run at all. world builds is ordered by time, so a target red for three weeks has scrolled off it; this is ordered by whether somebody should look
world labels [--all]
what each label promises: which runners advertise it, which targets need it, which targets require NOTHING (so land anywhere), and which labels nothing verifies
world devices
devices attached to runners
world device-history [--serial S] [--days N] [--limit N]
every state change the fleet's handsets have been through, and how long each state LASTED. world devices says where the hardware is now; this says what it has been doing — the record the device watch's dwell can be measured from, which nothing could answer before

The CLI itself

world config
what configuration each service is ACTUALLY running — read from the process, not from its config file, with a ← VAR on every value the environment overrode. The env silently wins over the JSON, which is how a hub whose blobs all go to MinIO kept a config file saying filesystem
world version
which build this binary is — the sha it was compiled from, so a stale world on a lane can be told from a current one without strings

Environment

Where the CLI points and what it authenticates with. On a LAN behind the dashboard vhost, none of it is needed — nginx injects both bearer tokens server-side.

LIBWORLD_URL
the mirror's control plane, or <dashboard origin>/api
WORLD_MIRROR_TOKEN
bearer token for that control plane
WORLD_BUILD_URL
the build coordinator, or <dashboard origin>/build-api
WORLD_BUILD_TOKEN
bearer token for the coordinator
WORLD_CONTROL_USER
HTTP Basic user for the dashboard vhost, which challenges off-LAN callers
WORLD_CONTROL_PASSWORD
its password. Basic REPLACES the bearer tokens — the vhost injects those itself, and only one Authorization header can travel
WORLD_BUILD_DEPLOY_TOKEN
the separate gate on a protected (deploying) target. nginx cannot inject this one, so it travels from the client

MCP tools

An MCP client reads the whole fleet through these — no shell, no curl, no bearer token of its own. They are available the moment the server starts.

  • catalog_stats

    Per-backend catalog TOTALS — packages, artifacts, bytes and pulls — as world stats prints them. search_catalog returns a page of rows and cannot count; this is the only read that says how many there are. An error of catalog disabled (503) means the mirror runs without a database, which is not the same as an empty mirror.

  • coordinator_status

    The build coordinator's own /status — the coordinator half of world config (mirror_status is the mirror's half). Carries its build id (version), queue depth, runner count, and under config the configuration the PROCESS is actually running, with provenance: a key listed as overridden by an env var means the environment beat the JSON file, silently, which is how a config file can describe a service it no longer matches. Storage is under config.storage (with proxy_upload and the presign endpoint), NOT at the top level. Secrets appear only as *_set booleans.

  • device_history

    Every state change the fleet's handsets have been through, newest first, and how long each state LASTED. list_devices says where the hardware is NOW; this says what it has been doing. Each row carries serial, runner, state, began_at and a class: healthy (state is device), unusable (attached but nothing can lease onto it) or absent. The class is the coordinator's judgement — do not re-derive it from state. for_s IS ABSENT, NEVER ZERO, on the newest row for a handset: that state is still running and has no length yet, so reading a missing value as 0 would report a day-old breakage as fresh. unplugged is a state no tool reports — it is absence, recorded so a spell has an END; without it a handset that went away while broken would read as broken to this day. An unplugged phone is NOT a fault, which is why it is classed absent and not unusable. summary.unusable_duration_buckets is the distribution the device watch's dwell should be chosen from — transients in the low buckets, real faults in the high ones, and the gap between them is the number. The summary covers the whole window, not the returned page; truncated says when even the store's ceiling was hit. AN EMPTY RESULT IS EXPECTED on a recently deployed coordinator: the record starts empty and fills only as handsets change state, so it is not evidence of a fault.

    serial? · days? · limit?

  • drain_history

    How long recent DEPLOYS waited to be leased, and how often that wait held the fleet — the same record world drain --history prints. armed counts deploys that waited past reserve_after_seconds so the coordinator stopped leasing other work for them; expired counts reservations that ran out after reserve_window_seconds and released the fleet again. days in the answer is the window the SERVER used (it clamps to 1-365), not necessarily the one asked for. Rows from before 2026-09-09 measure a wait for a RUNNER, not for a quiet fleet, so a window reaching back that far mixes two quantities. unsupported means the coordinator predates the route — NOT that nothing ever waited.

    days?

  • drain_status

    Is the coordinator handing out leases, and if not what is holding them? Reports two DIFFERENT lists, and conflating them predicts drains that never happen: protected_targets require a deploy token and therefore cannot be queued through this server at all, while drain_targets is what draining is actually derived from. An app deploy is typically protected but does not drain. Each in-flight row may carry elapsed_s, eta_s and eta_confidence — how much longer the holder has to run, from the same estimator get_build quotes. ABSENT MEANS UNKNOWN, never zero: the coordinator omits them when it has no history to estimate from, so a missing eta_s does NOT mean the queue is about to free up. Only eta_confidence: "high" is firm enough to act on; anything else is a rough guess. draining means a deploy is IN FLIGHT; holding_leases is the wider fact that the coordinator is refusing new leases, which is also true while a QUEUED deploy waits for the fleet to go quiet (waiting[] lists those, with how long each has waited). A waiting row's queued_s is how long the DEPLOY has waited, not how long that build row has existed: since 2026-09-09 a build that supersedes queued predecessors inherits the oldest of their waits, and inherited_s says how much of queued_s came that way (0 or absent for the ordinary case). So a queued_s far larger than the build's age is correct, not a clock fault. The two came apart on 2026-09-09 — before that a deploy was leased immediately and blocked inside its own lease. holding_leases absent means an OLDER coordinator, never 'not holding': read draining in that case. operator_hold (since 2026-09-25) is a hold somebody SWITCHED ON — {held, reason, by, since} — for maintenance; while held is true nothing new leases, deploys included, and running builds are untouched. It ends only when a person releases it (deploy token, so not through this server). Absent means an older coordinator, which has no hold.

  • fleet_labels

    Inverts the fleet: for each label, which runners advertise it and which targets require it. Answers 'what can a newly added host now claim?' without cloning every repo. READ unknown BEFORE CONCLUDING ANYTHING: a target's requirement is an OBSERVATION from its most recent build, not a live read of world-build.json, and an empty label set in the database means one of three things — the target declares none, the manifest was unreadable when it was queued, or the target was absent from it. Only unconstrained are the genuine run-anywhere targets (resolved AND empty); unknown is everything nobody has resolved, and reporting those as unconstrained is the exact mistake this route was added to prevent. unsatisfiable targets cannot lease right now because no ONLINE runner advertises what they need. EACH LABEL ALSO CARRIES verification, and its three values are not degrees of the same thing: verified means some advertising host attributes at least one toolchain probe to it (so the promise is CHECKED — not that it is met, which is what toolchain_report compares); hint means it was DECLARED unassertable with a reason in hint_reason (a Mac, an attached handset, sudo), which is a decision somebody made and not a gap; unverified means nobody has ruled either way, and the top-level unverified array is the only one worth raising. Do not report a hint as a gap — on this fleet that would flag 9 of 13 labels and bury the 2 that matter. A label with no advertisers is deliberately left out of that array because satisfiable: false already names it.

  • get_build

    One build in full: steps, artifacts, device/install outcome, dependency window, and the commit it was pinned to at queue time versus the one the runner checked out. Identified by the per-project build NUMBER — the same number list_builds and the CLI show.

    number · project? · search_limit?

  • get_build_log

    The captured log for a build, tailed. Defaults to the last 200 lines because a full log can be megabytes and the useful part of a failure is the end; truncation is stated in the output rather than silent.

    number · project? · max_lines? · search_limit?

  • get_repo

    One forge repo: its metadata and last commit, plus every branch and tag with the commit each points at. Two calls, merged, because a repo's refs are small and are what you want the moment you look at one.

    name

  • get_snapshot

    One snapshot and a page of its members, each with the checksum and the verification provenance it had when the snapshot was taken.

    name · limit? · offset?

  • list_backends

    Every mirrored package ecosystem — one entry per backend the server runs, so this is the count rather than a list anyone typed — with each one's storage mode and location.

  • list_builds

    Recent builds, newest first. Each row carries number (what you pass to other tools), project, target, state, runner, commit, and a live progress estimate for non-terminal builds.

    project? · target? · state? · device? · limit?

  • list_devices

    Phones and tablets attached to runner hosts, with platform, model and online state — plus what each one is DOING: busy names the build holding it right now, waiting counts queued builds pinned to it by serial. Both absent means an older coordinator that cannot say, which is NOT the same as the handset being free.

  • list_orphans

    Blobs in the object store that the catalog has no row for. This walks blobs → catalog, the opposite direction from everything else here (GC and search_catalog both start from a SELECT … FROM artifacts), so an orphan is invisible to every other tool while still answering pulls. Reports only — adopting them is a write and is deliberately not exposed. uncatalogued_by_design is NOT an orphan count: apt keeps its dists/** repo metadata in the blob store uncatalogued on purpose, so the repo still resolves with upstream down. sidecars is NOT an orphan count either: pip's PEP 658 .metadata files beside a catalogued wheel, removed with it. A sidecar whose wheel is gone IS counted as an orphan.

    backend? · limit?

  • list_projects

    Projects the coordinator will build, with their repo and declared targets.

  • list_repo_commits

    Commit history for one forge repo — sha, author, date and subject per commit.

    name · ref? · limit?

  • list_repos

    Self-hosted forge repos: the repos this fleet owns and pushes to, with their default branch, last commit, size and clone URL. ARCHIVED IS IN THIS LISTING, not one call deeper — the listing is where a repo gets chosen, and an archived repo refuses every push (successor names what replaced it). For UPSTREAM repos the mirror caches read-only, use search_catalog with backend 'git' instead.

  • list_runners

    Registered build agents: labels (what an operator declared), capabilities (what the binary can do), toolchain (what the host actually carries), and whether each is online. A busy runner also reports what it is building: current_build is the INTERNAL build id (what get_build_log and the /build/<id> route take), while current_number + current_project are the per-project number a person reads — they are different numbers for the same build, so quote the project and number, never a bare '#<id>'. An idle runner reports current_build 0.

  • list_skips

    Targets a push deliberately did NOT build, with the reason and the diff base per target. This is the answer to 'why didn't my push build X' — a skip is not a failure and has no build record, so it is invisible in list_builds.

    project? · limit?

  • list_snapshots

    Named, frozen sets of what the mirror held at an instant — each one protects its members from garbage collection, so a build can be replayed years later. Reports how many of each snapshot's artifacts had been verified against an upstream digest AT FREEZE TIME.

  • list_targets

    Which DECLARED build targets are not OK: the ones whose last build FAILED, and the ones that have never run at all. This is the inverse of list_builds and answers a question that one cannot — list_builds is ordered by TIME, so a target red for three weeks has scrolled off it, and a path-scoped target that is broken produces exactly as much output as one that is healthy: none. Read needs_attention rather than verdict alone. Two verdicts are deliberately NOT findings: unproven where every attempt failed before a commit resolved (a bad ref is a malformed request, not a broken target) and never on a target the manifest declares on_demand (a fixture nobody schedules). A manifest with seen: false is UNKNOWN, not a declaration that silence is fine. A failing row may carry failing_since and failing_for_s — WHEN this red spell began (the oldest failure with no success after it, not the newest failure) and how long it has run. That is the field that says whether somebody has to act: measured over this fleet, red spells shorter than ~75 minutes almost always fixed themselves and every one that needed a person ran past six hours. ABSENT MEANS UNMEASURED, never 'just now'.

    project?

  • mirror_audit

    The mirror's audit log — pulls, lifecycle actions, and rejected requests.

    limit? · since? · backend?

  • mirror_status

    The mirror's health, security posture, and the deployment record for the host it runs on (which commit is actually deployed, and whether it was a dirty tree).

  • search_catalog

    What the mirror has cached: artifacts by backend and/or package, with size, pull count and pinned state.

    backend? · package? · limit?

  • toolchain_report

    Whether hosts sharing a label carry the same build-time toolchain. divergent means some host LACKS something its peers have — the failure that makes a build's result depend on which runner was free. drift means all have it at different versions, which on a two-distro fleet is expected and not actionable.

  • verify_snapshot

    Re-hash every member of a snapshot against the digest it had when the snapshot was taken. The answer is THREE-WAY and the middle one is the point: present-and-identical, present-and-CHANGED (bytes were replaced under the same name), and gone. unknown is not a pass — intact is true only when all three problem lists are empty. It reads every byte of every member, so it is slow on a large snapshot.

    name

  • wait_for_build

    Block until a build reaches a terminal state, then return it. Bounded by timeout_s — on timeout it returns the build's CURRENT state rather than failing, so a slow build is distinguishable from a broken one. This replaces the hand-written poll loop, which is the single most repeated (and most often subtly wrong) shell construct against this API.

    number · project? · timeout_s? · poll_s? · search_limit?

MCP writes

Registered only when WORLD_MCP_ALLOW_WRITES is set. A server dropped into a config file cannot change anything until somebody says so.

  • cancel_build

    Ask a build to stop. The runner learns of it on its next heartbeat and stops the RUNNING step too — the step is its own process group, sent SIGTERM and, 10s later, SIGKILL — so it lands within a heartbeat plus ten seconds, not at the next step boundary. A build that already finished is refused with a 409 rather than silently accepted.

    number · project? · search_limit?

  • commit_file

    Write ONE file to a forge repo as a commit on a BRANCH — never the default branch, which the server refuses. It is a plumbing write, so no receive hook runs: NOTHING is built or deployed, and the answer's triggered_build: false says so. The branch defaults to world-edit/<author>; merge it like any other. Pass base (the branch sha you started from) to make it a compare-and-swap: if the branch moved since, it is refused (409) instead of erasing that commit. Identical content adds no commit (changed: false). Text files only.

    name · path · content · message? · author? · branch? · base?

  • create_repo

    Create an empty canonical repo on the forge (self/<name>), with its push hooks installed. Additive: nothing that exists is touched, and a name already taken is refused.

    name · description? · default_branch?

  • create_snapshot

    Freeze what the mirror holds right now under a name, protecting those artifacts from garbage collection. It copies no bytes. Snapshots are IMMUTABLE — a name that already exists is refused rather than re-pointed, because a build pins itself to the name.

    name · description? · backend?

  • delete_snapshot

    Delete a snapshot. This removes NO BYTES — its members simply stop being protected from garbage collection, and the ordinary retention rules apply again at the next sweep.

    name

  • install_build

    Install a PRIOR successful build's artifact onto a handset, compiling nothing. Queues an install build (the same authority queue_build grants) whose target defaults to the source build's own, so its install: steps run; name a different target when one target builds and another installs (android-build → android-install). The source must have SUCCEEDED — anything else has no artifact worth installing.

    number · project · target? · device? · search_limit?

  • pin_artifact

    Pin or unpin one mirrored artifact. A pin protects it from retention GC; unpinning FREES NOTHING BY ITSELF — it only makes the artifact eligible again, and the next sweep decides. Backends with a retention CLASS (images) are skipped by GC whatever the pin says, so unpinned there does not mean collectable.

    backend · blob_key · pinned?

  • pin_build_artifacts

    Protect one build's artifacts from build-artifact GC, or release them (pinned: false). Releasing deletes nothing itself — retention applies again at the next sweep. A build whose artifacts were already evicted has nothing to pin and is refused.

    number · project? · pinned? · search_limit?

  • prefetch

    Warm the cache: pull a package from upstream into the mirror ahead of need, so it is there when the network is not. ADDITIVE — it stores bytes, it replaces none — which is why git is REFUSED: refreshing an existing git mirror prunes and force-updates its refs. It is however an unbounded upstream fetch that can run for minutes and pull gigabytes, so it runs as a background JOB on the server and this tool polls it. A timeout returns the job's current state rather than failing: the pull keeps running, and prefetch_status reads it later.

    backend · spec · timeout_s? · poll_s?

  • prefetch_status

    The state of a prefetch job started earlier, by its job id.

    job

  • queue_build

    Queue a build. This is REMOTE CODE EXECUTION on a build host by design — it runs the repo's own recipe. Protected targets (deploy-hub) are refused by the coordinator, which requires a deploy token this server does not hold. Use check: true to resolve and validate the target WITHOUT queueing anything.

    project · target? · ref? · device? · params? · check?

  • retry_build

    Re-queue a build's project, target and COMMIT — the same source, not the branch tip. This queues work on a build host, the same authority queue_build grants. The new build gets its own number and carries retry_of.

    number · project? · search_limit?

  • update_repo

    Change a forge repo's DESCRIPTION. An empty string clears it. The default branch and archiving are deliberately not here: each changes what happens on someone else's machine (what their clone checks out, whether their push is refused), so they are left to a person in the CLI or a client.

    name · description

What is refused

The one hand-written part of this page, because it is a decision rather than a listing.

The line is one question: does the call itself destroy or replace bytes we are holding? Everything on the other side of it is reachable from an MCP client at some setting; five things are not reachable at any setting, and they are refused on purpose rather than merely missing.

  • world gc — evicts unpinned artifacts, irreversibly, with the whole catalog as its blast radius rather than one argument.
  • world rm — removes the blob and the catalog row.
  • world repull — the subtle one, and the reason this list is not simply "the deletes". It overwrites the cached bytes with whatever upstream serves today, which is exactly the difference a snapshot verify exists to detect. A tool that can quietly replace the preserved copy with the current one defeats the point of keeping it, and reports success while doing so. For an artifact a snapshot holds, the mirror itself now refuses the call with a 409 naming that snapshot — so the frozen bytes are protected from every client rather than from the one that happens to read this list.
  • world runners rm — deregistering a build host is fleet surgery, done by somebody who can also restart it.
  • world repo rm — a mirrored repo can be re-cloned; a forge repo is the original.

Queueing a build is not on that list, and is not an oversight: queue_build is remote code execution on a build host by design, and it is available with writes enabled. What it cannot do is deploy — a protected target is gated on a separate X-World-Deploy-Token, which nginx does not inject and this server does not hold. That path is closed by an invariant that already exists, not by a deny list that could drift from one.

Generated from world help --json and the MCP server's own tools/list. If a verb is missing from this page, it is missing from the binary.