# CLI `atlibs` is one Rust binary: run and serve modules, fetch published ones, stage them for a site or a server, sign in, and publish. `atlibs help` lists everything; a bad invocation prints that command's usage. Results go to stdout, progress and errors to stderr; a reader that stops early (`atlibs help | head -1`) ends the command quietly, exit 0. ## Install ```bash run=install cargo install --locked --git https://knotless.dev/johnandersen777.bsky.social/atlibs --rev 88b2ba8 atlibs ``` Into `~/.cargo/bin` (`--root `: `/bin`). From a clone: `cargo install --locked --path rust/cli`, or `cargo host` (into `rust/host/target//release/`). ## Refs Every command takes modules by **ref**, resolved the same way everywhere: | ref | example | |---|---| | a published module | `bobvmbuilder.bsky.social/echo`, `did:plc:.../echo`, `at://did:plc:.../com.fedfork.exec.wasm.module/echo` | | pinned | `bobvmbuilder.bsky.social/echo@<32+ hex of its pin>` or `@` | | a name in `atlibs.lock.json` | `echo` (after `atlibs add`) | | a module directory | `examples/rust/hello` (its `module.json`, the `cargo wasm` build above it, `records/.json`) | | a bare example name | `hello`, for `examples/rust/hello` | | a composition | `examples/rust/compose/composition.json`, or a published one | | a wasm and its spec | `module.wasm module.json` | | a staged module | `staged/stage.json compose` | Output and `atlibs.lock.json`'s `ref` show `/`; what identifies a module is its `uri` (by DID), `cid` and `pin`, so a handle that moves breaks nothing. A published composition names its modules by at:// URI. ```text help A is /[@pin|@cid] (or /), an at:// URI, a name in atlibs.lock.json, a module directory or a name under examples/rust, a composition or clientMetadata .json, , or . ``` ## run ```text help run [] ['' | - | @file] [--handler = ...] [--allow-exec] [--params '' | @file] ``` Prints `{ entry, result, error?, events, calls }`; exits 1 when the run failed. `-` reads the input from stdin and `@file` from a file, which keeps secrets out of `ps` and out of error messages. ```bash run atlibs run hello 2>&1 | tail -1 echo '{"n":3}' | atlibs run examples/rust/compose lookup - | jq -c .result ``` ```output hello entries: count {"ack":null,"caller":null,"doubled":6} ``` A composition runs one instance's entry. Its declared handlers come from `--handler`: another module's entry (`wasm:#`), an `https://` URL (`http://` to localhost only), or a command (`exec:`, with `--allow-exec`; JSON in on stdin, out on stdout, an empty environment). ```bash run atlibs run examples/rust/compose/composition.json ui caller '{"nsid":"com.example.compose.confirm","input":{"n":1}}' \ --handler 'confirm=exec:jq -c "{approved: true, n: .input.n}"' --allow-exec | jq -c .result.q ``` ```output {"ok":true,"output":{"approved":true,"n":1}} ``` ## serve ```text help serve [--port 8787] [--host 127.0.0.1] [--origin URL | ATLIBS_ORIGIN] [--oauth-path oauth/] [--handler = ...] [--allow-exec] ``` `GET /` lists the entries (a form page in a browser), `POST /run/` runs one (`/run//` for a composition), `GET /oauth//client-metadata.json` serves the modules' OAuth clients. Sign-in and the request guard: [Server sessions](server/sessions.md). With `--origin` and a session record that declares `app`, it also serves the app's own identity ([App identity](server/app-identity.md)). ```bash run atlibs serve examples/rust/compose/composition.json --handler confirm=wasm:examples/rust/compose#lookup --port 8793 & ``` ```bash run curl -s -X POST localhost:8793/run/ui/caller -H 'content-type: application/json' -d '{"nsid":"com.example.compose.lookup","input":{"n":6}}' | jq .result.q.output.doubled ``` ```output 12 ``` ## add ```text help add /[@pin|@cid] | ... [--dir .] ``` Resolves the handle to a DID (checked both ways), fetches the module record (or a composition), checks the blob against its CID, and writes `atlibs.lock.json` and `modules/.wasm` + `.json`. A module's hook defaults and a composition's modules come too. ```bash run=network atlibs add bobvmbuilder.bsky.social/echo jq -c '.modules.echo | {ref, session, wasm}' atlibs.lock.json ``` ```output {"ref":"bobvmbuilder.bsky.social/echo","session":"echo","wasm":"modules/echo.wasm"} ``` Every read of a vendored module checks its wasm and spec against the lockfile's **pin**: the sha256 of the wasm's sha256 and the record's grant fields (`calls`, `anyRecords`, `hooks`, `implements`, `anyHooks`, `didkey`). A republished record whose calls changed no longer matches. `add` again to update. ## stage ```text help stage [--target spa|server] [--out dist] [--origin https://site/] [--oauth-path oauth/] [--name [--record ]] [--dir .] [ ...] ``` `--target spa` writes a static site's files ([Sign in from a page](browser/oauth.md)); `--target server` writes modules and a `stage.json` with each session's record, for a server to mount ([Node](server/node.md), [Rust](server/rust.md)). No ref: everything in `atlibs.lock.json`. A spa with `--origin` and a session record that declares `app` gets the app identity's static files too ([App identity](server/app-identity.md)). ```bash run atlibs stage --target server --out staged examples/rust/compose examples/rust/statusphere | jq -c '{modules: (.modules | keys), sessions: (.sessions | keys)}' ``` ```output {"modules":["compose","statusphere"],"sessions":["statusphere"]} ``` ## oauth ```text help oauth --origin https://site/ [--oauth-path oauth/] [--name ] [--dir .] [ ...] ``` Prints the client metadata documents an origin serves, by session. ```bash run atlibs oauth --origin https://you.example/ examples/rust/statusphere | jq -r .statusphere.client_id ``` ```output https://you.example/oauth/statusphere/client-metadata.json ``` ## login, logout ```text help login [--scope "atproto transition:generic"] [--no-open] logout ``` Signs in with OAuth through a loopback redirect in your browser (`ATLIBS_BROWSER` opens it; the URL is printed either way). The session is saved per DID in the state dir and refreshed as it expires. ```bash run=account atlibs login you.bsky.social atlibs run examples/rust/statusphere clear_status --as you.bsky.social atlibs logout you.bsky.social ``` | flag (every command) | acts as | |---|---| | `--as ` | the OAuth session `atlibs login` saved | | `--app-password ` with `--password-file ` or `--password-env ` `[--pds ]` | an app password (tests, operator accounts); saved, so later commands may give `--app-password ` alone | | neither | signed out: public reads only | ## new ```text help new ``` ```bash run atlibs new my-module > /dev/null && find my-module -type f | LC_ALL=C sort ``` ```output my-module/.cargo/config.toml my-module/.gitignore my-module/Cargo.toml my-module/modules/my-module/Cargo.toml my-module/modules/my-module/module.json my-module/modules/my-module/src/lib.rs ``` ## publish ```text help publish [ ...] [--dir modules] [--dry-run] [--check-live] [--no-build] [--allow-dirty] [--out records/wasm] publish module ... [--no-build] [--out records/wasm] [--allow-dirty] publish records [ ...] publish tile [--out records/tiles] publish composition [--rkey ] publish delete ... ``` `atlibs publish` builds every module, compares each with what it last published (a cache under `$XDG_CACHE_HOME/atlibs//`, or the live records with `--check-live`), publishes what changed and prints a table: `published`, `unchanged`, `would-publish` (`--dry-run`), `skipped:dirty` (uncommitted sources), `drift` (changed elsewhere), `failed`. The subcommands publish one kind of thing each. Details: [Publish a module](modules/publish.md). ```bash run=account atlibs publish --dry-run --as you.bsky.social ``` ## verify ```text help verify / | ``` Rebuilds a published module from its source records in a container and compares the sha256 with the manifest and the blob: `atlibs publish` built it in that same `rust:` container. The engine is `CONTAINER_ENGINE`, else the first of podman, docker and Apple's `container` (macOS) that answers `info` (`container system status`): a docker CLI whose daemon is stopped is skipped. A build that exits 0 without writing the manifest's artifact is reported as the engine's fault (a docker look-alike whose `run` returns before the command ends). ```bash run=container atlibs verify bobvmbuilder.bsky.social/echo ``` ## compose ```text help compose bindings [--dir .] [ ...] compose check ``` `compose bindings` writes `atlibs.modules.js` and `.d.ts`, the modules a `compose.ts` imports ([Compositions](compositions.md#write-one)): those `atlibs.lock.json` vendors (pinned; `atlibs add` writes them too), `modules/` directories and the ones named. `compose check` runs the hosts' load checks without the wasm: modules from `atlibs.lock.json` or `stage.json` beside it (pins too), module directories (`module.json`) or published refs. Prints the composition as it would run, hook defaults added; exits 1 with the reason it would not load. ```bash run atlibs compose check examples/rust/compose/composition.json | jq -c '[.instances[].name]' jq '.instances[1].input.n = "four"' examples/rust/compose/composition.json > bad.json atlibs compose check bad.json 2>&1 || echo "exit $?" ``` ```output ["ui","lookup","even"] composition: instance lookup: input n must be of type integer exit 1 ``` ## Environment Every variable: [reference/env.md](reference/env.md). Previous: [MCP servers](server/mcp.md) | Next: [Write a module](modules/write.md)