workbooks docs

wbx CLI

The canonical Workbooks command-line tool. One Rust crate, two build targets (native + wasm32-wasip1): the binary is named wbx (crate wb-cli).

The binary is wbx, not wb. The legacy Elixir escript (runtime/host/cli.ex) and the dead npm @work.books/cli are superseded; this crate is canonical. :SRC: cli/Cargo.toml#bin (name = "wbx", line 10) · cli/SPEC.md:6

Two execution classes (see each verb's Where it runs column):

  • LOCAL — kernel ops, assembly, provenance, orchestration; needs no runtime.

  • ENGINE — a thin RCP call into a running runtime (it owns the compilers, wasmtime, the tenant library). Engine verbs fail with exit 3 + a "no runtime — try =wbx deploy local=" hint when none is reachable.

:SRC: cli/src/main.rs:3 · cli/src/mode.rs:67

Global flags & the mode model

flagsets modebehaviour
(none)autostdout is a TTY → Human · piped/redirected → Agent
--agentAgentnever prompts, no ANSI, stable shapes
--jsonJsonAgent + one JSON envelope on stdout

Both flags are global = true (accepted before or after the verb). :SRC: cli/src/main.rs:27 (--agent) · :30 (--json). Detection precedence --json > --agent=/=WBX_AGENT=1 > TTY → Human → Agent: cli/src/mode.rs:23-33.

Json envelope (success): { "ok": true, "verb": "<path>", "data": … }. If the verb already emitted JSON it is embedded structurally, else wrapped as {"text": …}. Error: { "ok": false, "verb", "error": {code, message, hint, retryable} }. :SRC: cli/src/mode.rs#renderok (:92-107) · #rendererr (:110-135).

Verb introspectionwbx help --json (either order) prints the whole verb tree as JSON so agents introspect the surface instead of scraping help. Agent-mode bare wbx also folds the tree into the health payload. :SRC: cli/src/main.rs#verbtree (:212) · main intercept :233 · landing :257-266.

Exit-code map

Stable contract for agent branching.

codemeaningconst
0ok
1everything else(fallthrough)
2usage (clap parse)clap-emitted
3engine unreachableEXIT_ENGINE (mode.rs:35)
4not foundEXIT_NOT_FOUND (mode.rs:36)
5verification failedEXIT_VERIFY (mode.rs:37)
6conflictEXIT_CONFLICT (mode.rs:38)
7auth rejectedEXIT_AUTH (mode.rs:39)

Codes are assigned by a heuristic over the error-chain text (classify) until errors carry typed codes; the contract is the code, not the text. :CAVEAT: classification is text-matching today (e.g. "connection refused" → 3, "404"/"not found" → 4) — a misworded upstream error can misclassify. :SRC: cli/src/mode.rs#classify (:43-63).

Environment variables

Every key resolves WBX_<KEY> first, then legacy WB_<KEY> (both work; docs prefer WBX_*). :SRC: cli/src/util.rs#envvar (:84-88).

vareffectsrc
WBX_AGENT=1force Agent modecli/src/mode.rs:26
WB_ENGINE_URLremote engine base URL (overrides local discovery)cli/src/io.rs:111-118
WB_ENGINE_TOKENbearer for the remote enginecli/src/io.rs:115
WB_DESKTOP_DIRdiscovery dir holding runtime.json (else app-data disco/)cli/src/io.rs:60-64
WB_IMAGEoverride the deploy runtime image (default below)cli/src/deploy/mod.rs:127
WB_PROVIDERS_DIRwhere wbx deploy resolves provider recipescli/src/deploy/mod.rs:280
WB_TOOLKIT_EXEC=1server-side gate required for wbx toolkit runcli/src/main.rs:169
WB_PUBLIC_BEARER(deploy-managed) control-plane token, generated once on cloud applycli/src/deploy/mod.rs:406

Engine discovery: with no WB_ENGINE_URL, the local engine is located via its discovery file (WB_DESKTOP_DIR/runtime.json → else ~/Library/Application Support/sh.workbooks/disco/runtime.json on macOS, ~/.local/share/sh.workbooks/disco/runtime.json elsewhere). :SRC: cli/src/io.rs#discoverypath (:60-65) · util.rs#appdir (:73-80).

Verbs

Columns: Run = LOCAL or ENGINE · args in fixed, optional in [brackets]. Defaults and flags are exactly as declared in clap. :SRC: cli/src/main.rs#Cmd (:37-132).

Start here (local)

verbargs / flagsdoesRunsrc (main.rs)
wbx (bare)where-am-I landing (doctor + start hints; agents get verb tree)LOCAL:283, :257
wbx initname [=--template= minimal]scaffold a new workbook source (workbook.org + data/)LOCAL:40, :289
wbx dev[=src= .] [=--port=]watch + rebuild + serve a live preview (interactive)LOCAL:42, :290
wbx doctorenv + engine health report (always exits 0; --json for agents)LOCAL:44, :291
wbx statussame landing as bare wbxLOCAL:46, :292
wbx openfileopen a workbook (or any file) in the default browserLOCAL:48, :293
wbx upgradereplace this binary with the latest release (npm → use npm)LOCAL:50, :294
wbx completionsshell (bash| zsh| fish| elvish| powershell)shell completions to stdoutLOCAL:52, :295

Source inspection (local, kernel)

verbargsdoesRunsrc (main.rs)
wbx queryfileorg → headline / structure rowsLOCAL:56, :302
wbx tanglefileorg → WIT-world-shaped build plan (literate)LOCAL:58, :303
wbx lintfilediagnostics over a workbook sourceLOCAL:60, :304

tangle is the org-mode term of art and stays (not renamed to plan). :SRC: cli/TAXONOMY.md:142 (decision LOCKED 2026-06-09).

Workbook lifecycle

verbargs / flagsdoesRunsrc (main.rs)
wbx build[=src= .]compile the source's code components → WASMENGINE:63, :306
wbx bundle[=src= .] [=-o/--out=]assemble org (+ data) → one workbook .wbundleLOCAL:65, :307
wbx unbundlefile [=dest=]workbook → source treeLOCAL:67, :308
wbx runfile [=input…= trailing]execute a workbook's workflow DAG on the engineENGINE:69, :309
wbx publish initscaffold ./publish.orgLOCAL:136, :311
wbx publish validatecoherence-check publish.orgLOCAL:138, :312
wbx publish apply[=workbook= workbook.html]ship the assembled workbook to the configured surfaceLOCAL¹:140, :313

¹ publish is local orchestration — it spawns wrangler=/=git to ship to a surface (CF Pages / gh-pages / host); no runtime, but external tools. :SRC: cli/TAXONOMY.md:136.

build/run delegation rationale: :SRC: cli/TAXONOMY.md:142 (decision 2).

Library (engine-backed)

verbargs / flagsdoesRunsrc (main.rs)
wbx librarylist the tenant's workspaces + membersENGINE:75, :316
wbx checkoutmember dirborrow a library member into a working dirENGINE:77, :317
wbx checkinmember dirpack + sign a member back into the libraryENGINE:79, :318
wbx store[=slug=] [=--list=] [=--build=]archive a workspace to durable storage (--build compiles first)ENGINE:81, :319
wbx fetchkey [=out= ./]restore from durable storageENGINE:88, :320
wbx searchquery [=--semantic= | --literal | =--sql=]cross-workbook search (default: hybrid)ENGINE:90, :321

search mode resolves to semantic / literal / sql if the flag is set, else hybrid. :SRC: cli/src/main.rs:322.

Toolkit (agent extensibility; mixed)

verbargs / flagsdoesRunsrc (main.rs)
wbx toolkit listlist discoverable toolkits (id · status · tagline)ENGINE:146, :327
wbx toolkit showid [=skill=]a toolkit's manifest + skill index (or one skill's recipe)ENGINE:148, :328
wbx toolkit searchq…search toolkits + skillsENGINE:150, :329
wbx toolkit verifyidcheck a toolkit's invocation contract (bin/artifact present)ENGINE:152, :330
wbx toolkit signidsign a toolkit manifest (did:key; required for third-party)LOCAL:154, :331
wbx toolkit buildid [=which=]build a toolkit's declared artifact (in-sandbox compile + register)ENGINE:156, :332
wbx toolkit pushid dirship a toolkit directory onto the engineENGINE:158, :333
wbx toolkit importsource [=--as=] [=--out=]package an existing construct (skill / md / folder) as a toolkitLOCAL:160, :334
wbx toolkit runid task [=args…=]run a toolkit task recipe (gated on WB_TOOLKIT_EXEC=1)ENGINE:169, :336
wbx toolkit audit[=dir= .] [=--fix=]re-run the wasm-compat audit on an imported dir (--fix auto-converts)LOCAL/ENGINE:171, :335

--as override kinds (else detected by shape): claude-skill · markdown · folder. Detected source taxonomy (SKILL.md, single .md, dir, .mcp.json, .cursorrules, AGENTS.md/CLAUDE.md, OpenAPI, package.json bin, pyproject scripts). :SRC: cli/src/main.rs:165 · cli/SPEC.md:185-195.

import pipeline (parse+scaffold → dependency audit → fix-up plan as org TODOs): :SRC: cli/SPEC.md:198-211. verify is the done-test.

Runtime ops (engine-backed)

verbargs / flagsdoesRunsrc (main.rs)
wbx workflow runfile [=input= ""]execute the workflow DAGENGINE:181, :340
wbx workflow planfileshow the schedule/plan without executingENGINE:183, :341
wbx agent runtask… [=--system= "…"] [=--model=]start a long-horizon run (returns an id)ENGINE:189, :344
wbx agent statusidpoll a run's status + resultENGINE:196, :345
wbx workbook listlist deployed workbooksENGINE:201, :348
wbx workbook showidshow a deployed workbook's org sourceENGINE:203, :349
wbx workbook deployid filedeploy an org source under an idENGINE:205, :350
wbx telemetry[=slug=]run index, or one run's summaryENGINE:109, :352
wbx ledgerslugverify a run's signed ledgerENGINE:111, :353

agent run default system prompt: "You are a careful, capable agent." :SRC: cli/src/main.rs:192.

Provenance & federation

verbargs / flagsdoesRunsrc (main.rs)
wbx signfile [=-o/--out=]embed a did:key provenance manifestLOCAL:115, :355
wbx verifyfilecheck an artifact's signature + integrityLOCAL:117, :356
wbx mirrortargetmirror the tenant repo to a git host (url or forge)LOCAL¹:119, :357
wbx federatefederate the tenant repo over Radicle (P2P)ENGINE:121, :358

¹ orchestration: spawns git. :SRC: cli/TAXONOMY.md:136.

Engine (the runtime itself)

verbargs / flagsdoessrc (mod.rs)
wbx deploy init[=preset= local| cloud]scaffold ./deployment.org (TTY picks if omitted):34, :84
wbx deploy validatecoherence check (incl. declared secrets present):36, :85
wbx deploy applyconverge to the declared state:38, :97
wbx deploy statusinspect the live deployment:40, :98
wbx deploy logstail the live deployment's logs:42, :99
wbx deploy downtear it down:44, :100
wbx deploy localshorthand: scaffold local config if absent, then apply:46, :101
wbx deploy doctorengines, recipes, and declared secrets — present/missing:50, :107
wbx deploy secrets setpairs… [=--from-env=]stage KEY=VALUE secrets (0600 under app-dir):62, :225
wbx deploy secrets listlist secret NAMES (never values):66, :251
wbx deploy secrets unsetkeyremove a secret by name:68, :258
wbx deploy secrets pushpush staged secrets to the provider without a deploy:70, :266

Provider model: local uses a container-engine seam (dockerpodmankrunvm, first found wins); any other DEPLOY_TARGET is a recipe at providers/<place>/bootstrap.sh (fly is the bundled one). Adding a provider = dropping a bootstrap.sh, no recompile. :SRC: cli/src/deploy/mod.rs#engine (:359-361) · resolverecipe (:300-303) · header comment :7-12.

Default image: ghcr.io/workbooks-sh/runtime:latest (WB_IMAGE overrides). :SRC: cli/src/deploy/mod.rs:76, :127.

deployment.org keywords: #+DEPLOY_TARGET · #+DEPLOY_APP · #+DEPLOY_REGION (default sjc) · #+DEPLOY_PORT (default 4000) · #+DEPLOY_IMAGE · #+DEPLOY_SECRETS (secret NAMES) · #+DEPLOY_TOOLKITS (id:dir …, pushed after apply). :SRC: cli/src/deploy/mod.rs#Config (:116-145) · apply :384.

Cloud bearer: first cloud apply generates a 256-bit token once, persists it as WB_PUBLIC_BEARER in secrets.env, and never rotates it (rotation would 401 live clients). Call your engine with export WB_ENGINE_TOKEN=<token>. :SRC: cli/src/deploy/mod.rs#ensurecloud_bearer (:406-422).

wbx deploy is the user's tool to run the runtime image for their own use. It is not how the platform publishes the compilers package or the runtime image — do not conflate the three release layers. :SRC: CLAUDE.md "Release / publishing — THREE separate layers" · cli/TAXONOMY.md:122.

Escape hatch & config (local)

verbargs / flagsdoesRunsrc (main.rs)
wbx rtargs… (status| get \pth| post \pth [body])raw RCP escape hatchENGINE:127, :361
wbx varargs… (set| get| list| ref)local variables / secrets (ref-only)LOCAL:131, :363

Not-yet-built: wbx docs *

Planned verbs (per the architecture plan, not present in the binary): wbx docs new · build · drift (keystone CI gate) · lint · untangle · serve · publish, plus wbx schema --json. Verified absent: grep Docs cli/src/main.rs matches nothing.

Legacy: the Elixir escript

See also