wai: one operation catalogue (noun.verb) for every door, wai ops, the agent rules on every command, and the wai-* service binaries #506
Loading…
Reference in a new issue
No description provided.
Delete branch "wai/ops-catalogue"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
WAI toolchain v1: one catalogue of
noun.verboperations, the same name through every door, the agent rules on every command, and CI that fails on drift.On today's main
#505, #508 and #507 have landed, and so have the fleet (#518) and wai-quantum 0.7.0 (#521).
origin/main(25d38c48) is merged into this branch, with no rebase and no force push, so main is an ancestor of the head and this diff against main is this PR's own. Where the branch carried an earlier copy of #507, main's final version is the one kept, routed through the catalogue; there is one envelope and agent-rules module (wai_cli/dx/envelope.rs).How each conflict was resolved
wai-rs/src/bin/wai_cli/dx/mod.rsVERBS(implementations by operation id) kept; main'sVerb/Run::Checks/Run::Statustable anddispatch, which the door replaces, not taken. The fleet's module is declared, and its four operations are implementations by id (next commit).wai-rs/src/bin/wai_cli/dx/verify.rs*.wai-fleet.jsonread and recomputed), with this branch'sOpErrorand its usage from the catalogue.wai-rs/src/bin/wai_cli/dx/envelope.rswai-rs/src/bin/wai_cli/dx/breaking/rust_api.rs,dx/conform/adapter.rswai-rs/src/bin/wai_cli/dx/conform/mod.rs,tests/cli_conform.rsout.rs, reports underdata.wai-rs/tests/cli_breaking.rsdata.wai-rs/Cargo.tomlquickstartwith main'sfleet; both test targets,cli_opsandcli_fleet.wai-rs/src/lib.rsstrict_jsongated onfleettoo, as main has it;cataloguein place ofops..github/workflows/wai-conformance.ymlfleetfeature and test in the verifier and per-feature steps); this branch's step text forwai mcpkept.wai/CHANGELOG.mdWorkflow steps against both merge parents: 0 problems (
wfsteps.py 0abd2ae46 3363058002 270be911a 25d38c480); every workflow parses.What is in it
The catalogue (
wai/wai-rs/src/catalogue.rs,wai::catalogue). One Rust table holds every operation the toolchain offers that works today: id, summary, CLI spelling and aliases, usage, placement, input and output JSON Schemas (each input carries the flag or position that gives it; a service operation's schemas point into its OpenAPI document), stream, effect, route, toolset, stability, since/deprecated, receipt, the build features it needs, whetherwai mcpserves it, and when it waits for confirmation (Op::confirms: never, a file the command line did not name, any file that exists, the target it names or a file, always; by its effect unless its entry says).wai ops exportwrites it aswai/catalogue/ops.json(formatwai.ops/1), with each operation's name in every door and the agent flags (agent_flags).Naming rules, enforced (library tests that also break each rule in a copy of the table and require it refused): lowercase
noun.verb; a singular noun; a verb from N3's closed list; no near-synonym (get,describe,infoareshow;init,new,keygenarecreate); one CLI form per operation and none a prefix of another; a routed operation placed on a service and every service operation routed; every operation reachable by some door; a change to a target, or a destructive one, waits for--yes, and a read never does.The fleet's operations (#518) are in the catalogue as the others are:
enrolment.create,enrolment.list,report.create,report.export, placed on the client against a fleet service, with their effect, toolset, schemas, receipt and the feature they need (fleetfor the two that sign or verify; the other two need none).wai enrolment|reportrun through the door, and the fleet's command module now keeps the agent rules ofdx/envelope.rsinstead of a copy of its own: the envelope with--json; every file throughout.rs, and in a dry run every request the service would be sent named in the plan (out::would_send) and none sent;--yesbefore the service is changed or a file replaced.wai verify's entry names the conformance results and fleet bundles it reads.wai ops:list,search "<task>"(offline, ranked over ids, command lines, aliases and summaries with stems and a few synonyms, at most five),show <id>(alsowai ops schema),export [--out F | --check F].The CLI through the catalogue (
wai_cli/door.rs). A command line resolves through the catalogue alone: its spelling today (wai inspect,wai hello,wai mcp) or its id's words (wai envelope inspect). The implementation is found by id (door::IMPLS, anddx::VERBSfor the developer path).wai --help,wai <cmd> --helpand every usage error are written from the catalogue. Every command keeps its spelling.The agent rules on every command, in one module: #507's
wai_cli/dx/envelope.rs, extended, withwai_cli/out.rsfor writes.--json: one envelope on stdout,{"wai": "envelope/1", "op", "ok", "data" | "error": {code, message, hint, retryable}, "exit"}; exit 1 carrieserrorand the report indata; exit 4 addsproposedandconfirm; a dry run addsdry_runandplan. Logs stay on stderr. A command that prints text runs again as a child ofwaifor its envelope, so its text is unchanged.--dry-runon every operation whose effect is notreads: every file a command writes goes throughout.rs, which records instead of writing;wai dev,wai http originandwai mcpsay what they would start and start nothing.--yes. An operation waits as its entry says (replacing a file the command line did not name; forwai conform,wai setup-agentandwai report export, any file that exists; forwai enrolment create, the fleet service or a file; forwai report create, always): at a terminal a prompt, otherwise exit 4 with the proposal and the exact confirming command, which names--yes.--no-inputnever asks.--confirm, whichwai conform,wai setup-agentand the fleet took, is its deprecated spelling: it still works and does the same, andwai --help(written fromcatalogue::AGENT_FLAGS), every confirming operation's help and its usage line, and the export say it is deprecated.wai conformnow confirms through the same module.Reconciled with #507 in that one module: exit 3 (authentication or permission) is added; the envelope keeps #507's
waimember; a command's report moves underdata, as every other command's does; and JSON is printed only with--json(#507 also chose it whenever stdout is not a terminal; that would change every piped command's output, so it is not done).wai breaking --jsonandwai conform --jsonare unchanged otherwise, and--textstill forces text.Doors held to the catalogue (
.github/workflows/wai-catalogue.yml):wai ops export --check);tests/cli_ops.rsholds help, the exit codes, the envelope,--dry-runand--yesacross the operations, in the archive's build, with every command-line feature that needs no system library, and with Create's;wai mcp's tool table both ways (every tool is an operation the catalogue sayswai mcpserves, in that toolset, namednoun_verb; every such operation is a tool; a tool of MCP alone takes the catalogue's input) inmcp/tools.rs's tests;operationIdis the catalogue's id at the catalogue's route, and every routed operation is described (joule-moq-room/tests/openapi_contract.rs);scripts/check-wai-ops-doors.py(standard library only, with a selftest): MCP tool names, the services'operationIds, the C header, and the Swift and Kotlin sinks. In the C header and the sinks a name is an operation's when its noun is a catalogue noun and its verb an N3 verb; it must then be in the catalogue, and a near-synonym is refused. Other names are library API and reported as such.Service binaries renamed (crates keep their names):
joule-moq-relaybuildswai-relay,joule-moq-roomwai-room,joule-moq-ingestwai-ingest.wai devandwai mcp's dev tools, the quickstart archive, the release and examples workflows, the browser and interop test scripts, the package manifests, the example host script, and the crates' READMEs and example configurations name them so. Wire and record identifiers (joule-moq-relay/session-summary/2,joule-moq-ingest/session/1), theJOULE_MOQ_*_LOGvariables and the conformance corpora keep the crates' names. The messaging service is the room service (wai-roomwith[messaging]), so there is no separate binary. Production keeps running the old names until switched (a private deploy note covers it).Templates are Apache-2.0: every example carries
LICENSE(=wai/LICENSE) and a README line;wai create, from a template or from--from app.oui, writes it from one copy in the binary.Telemetry: none. The
waibinary's only network code is what a person names (wai http receipts,wai http bench, an HTTPwai conformadapter) and loopback (wai dev,wai mcp's bridge). Help, the README and the catalogue's README say: "waisends nothing off your machine unless you name a remote service."The catalogue
toolchain.testwai helloproject.createwai createdev.startwai devdev_startreceipt.verifywai verifyreceipt_verifyenvelope.inspectwai inspectenvelope_inspectenvelope.wrapwai wrapenvelope_wrapenvelope.unwrapwai unwrapmedia.encodewai encodemedia.decodewai decodemedia.generatewai generatescore.buildwai score buildscore.decodewai score renderencoder.listwai encodersencoder.verifywai encode-record verifyregistry.listwai capabilitiesregistry_listregistry.exportwai registry exportprior.listwai prior-setstage.encodewai stage refinestage.decodewai stage applystage.buildwai stage basestage.inspectwai stage inspectstage.wrapwai stage packstage.unwrapwai stage explodehttp.exportwai http publishhttp.inspectwai http codecshttp.startwai http originhls.buildwai http hlsdash.buildwai http mpdplaylist.lockwai http seal-playlistplaylist.verifywai http check-playlistcorpus.generatewai http vectorshttp.loadwai http benchreceipt.fetchwai http receiptscompat.checkwai breakingconformance.runwai conformconformance_runconformance.listwai conformance listconformance_listenrolment.createwai enrolment createenrolment.listwai enrolment listreport.createwai report createreport.exportwai report exportmcp.startwai mcpagent.setupwai setup-agentapp.guidewai app guideapp_guideapp.checkwai app checkapp_checkapp.exportwai app exportapp_exportapp.streamapp_streamregistry.showregistry_showdocs.searchdocs_searchdev.stopdev_stoproom.joinroom_joinroom.leaveroom_leavesession.showsession_showops.listwai ops listops.searchwai ops searchops.showwai ops show(alsowai ops schema)ops.exportwai ops exportThe room service's operations, each placed on
wai-roomat its route (service),preview, toolsetcoreordev;room.grantis also an MCP tool (room_grant):service.show,service.check,room.show,room.grant,admission.show,mls.tail,mls.import,mls.update,performance.list,performance.show,schedule.create,handover.create,window.create,fidelity.create,time.show,source.fetch,watch.setup,watch.tail,watch.show,watch.join,watch.update,control.grant,remote.show,remote.verify,conversation.show,conversation.setup,conversation.join,conversation.tail,conversation.import,conversation.update,message.create,acknowledgement.create,conversation.leave,member.delete,call.setup,call.create,call.invite,inbox.show,answer.create,call.show.Names settled
wai helloistoolchain.test;wai mcpismcp.start; the room session MCP tool issession_show;wai ops schemaisops.show(alias kept);wai score renderisscore.decode.wai stage refine|apply|base|pack|explodearestage.encode|decode|build|wrap|unwrap;wai http publish|codecs|origin|bench|receipts|vectorsarehttp.export|inspect|start|load,receipt.fetch,corpus.generate;wai http hls|mpdarehls.build,dash.build;wai http seal-playlist|check-playlistareplaylist.lock|verify;wai encode-record verifyisencoder.verify;wai encodersencoder.list;wai prior-setprior.list.package_build, which carries a file in an envelope aswai wrapdoes, isenvelope_wrap;package.buildstays free for real packaging when it has a door.watch.setup,conversation.setup,call.setup(they werewatchchallenge.create,conversationchallenge.create,callchallenge.create). Posting a KeyPackage staysmls.import/conversation.import: import is on the list, and the service takes in a member's key material.wai app exportisapp.export, the same writer aswai create <dir> --from app.oui.Changed behaviour (each in the CHANGELOG)
--jsonoutput ofwai create --list,wai dev --check,wai generate,wai score build|render,wai stage apply,wai breaking,wai conformandwai setup-agentis now the envelope'sdata. In-repo readers are updated (the CLI tests,wai/quickstart/build.sh).wai breakingandwai conformprint text when piped, unless--json.wai wrap/wai encodewithout-oover an existingout.wai, andwai helloover an earlier run, exit 4 off a terminal until--yes.wai devwhose stack does not come up exits 6.wai-relay,wai-room,wai-ingest. Nothing main gained since names an old binary: the release workflow's Windows list and the examples workflow buildwai-relay,wai-roomandwai-remote-host; #518's text namesjoule-moq-relayonly in the wire identifierjoule-moq-relay/session-summary/2, which keeps it.--json(they printed it whenever standard output was not a terminal), as every command does; a dry run's members are the envelope'sdry_runandplan(they weredata.dry_runanddata.proposed); a confirming command names--yes.--confirmis deprecated;--yesis the flag.wai breakinggives them:wai::opsgives way towai::catalogue(five Rust items), and the room service's three challenges take theoperationIds N3 gives them (three OpenAPI items).wai breaking --against mainreports these eight, all acknowledged, and nothing else.Checks
Every Rust build and test ran on the Framework box (Linux x86_64) through
rb; none on a workstation. Light scripts ran locally.cargo test --locked --no-default-features --lib cataloguecargo test --locked --no-default-features --features quickstart --bin wai --test cli_ops --test cli_dx --test cli_fleet --test floorcargo test --locked --no-default-features --features quickstart,score,key_discovery --bin wai --test cli_breaking --test cli_conform(wai-breaking.yml's runner)cargo test --locked --no-default-features --features mcp --bin wai --test cli_mcp --test cli_setup_agentcargo test --locked --no-default-features --features app --bin wai --test cli_appcargo test --locked --no-default-features --features quickstart,generate,score,staged,video_int,audio_int,splat_int --test cli_ops; the same withquickstart,appcargo test --no-default-features --features fleet,conform_result --test fleet --test conform_result$WAI_FEATURES(withfleetandconform_result)--bins, and--lib catalogueunder itcargo check --no-default-features --testswith no feature,fleet,conform_result,key_discovery,mcp,app,quickstartcargo clippyon--bin waiand the three CLI tests, withquickstart, the full command-line features andfleetwai ops export --check ../catalogue/ops.json; the export from a bare build and fromquickstart,appwai breaking --against main --text --allwai conformover the claim, JWP, signer and conform-result verifiers and the reference packager, thenwai verify(wai-breaking.yml's steps)joule-moq-room:openapi_contract,mcp_dev_room;wai-fleetbuildcargo metadata --locked --offlinein wai-rs, joule-code-rs, joule-moq-room, joule-moq-remote, wai-fleet, wai-pack, wai-appcheck-wai-ops-doors.pyand its selftestcheck-tests-in-ci.py,check-workflow-concurrency.sh,check-spec-refs.py,check-wai-section-refs.py,check-no-vanity-metrics.sh,test-public-text-checks.sh,check-comparative-prose.sh,check-orphan-sources.py, every workflow's YAMLFalsifications
Committed first; each mutation an exact one-match edit, restored with
git checkout --and a fresh mtime. Every one was caught. The first three are this round's, on the merged head; the rest were made on the earlier head and their guards are unchanged.enrolment.createremoved)door::tests::every_implementation_names_an_operation_of_the_catalogue;wai ops export --check;cli_fleet--confirmno longer the same as--yes(the door reads--yesalone)cli_ops::confirm_is_the_deprecated_spelling_of_yes;cli_fleet::enrolment_create_signs_writes_and_waits_for_confirmationwai report createchanging the service without--yescli_fleet::report_create_and_export_and_verifyImpl { id: "envelope.frob" })door::tests::every_implementation_names_an_operation_of_the_catalogueprior.listremoved)door::tests::every_operation_with_a_command_line_has_exactly_one_implementationout.rs(wrapwriting directly)cli_ops::every_operation_that_is_not_read_only_writes_nothing_with_dry_runcli_ops::the_exit_codes_say_what_happenedcli_ops::replacing_a_file_the_command_line_did_not_name_waits_for_yesregistry.get)catalogue::tests::every_entry_keeps_the_rulesroom.session)wai ops export --checkenvelope_wrapnamedpackage_buildin the real tool tablemcp/tools.rstests;check-wai-ops-doors.pywai mcpserves, with no toolmcp/tools.rstestsoperationIdwatch.setupnamedwatchchallenge.createopenapi_contract;check-wai-ops-doors.py/inboxes)openapi_contractwai_envelope_decode)check-wai-ops-doors.pymedia.decodeWaiReceipt.check)check-wai-ops-doors.pyWaiEnvelope.describe)check-wai-ops-doors.pyNot done
wai::noun::verb) and JavaScript doors are not checked: neither is organised by operation yet. The C header and the sinks carry no catalogue operation today; the check reports their names as library API.compat_checktool (wai breakingas a tool throughbreaking::run).wai serve <role>, anops_runtool,wai --version --json, a generated CLI reference andllms.txt.conformance.run,envelope.wrap), the MCP tool's input schema is the tool's own; the catalogue's is the CLI's.wai/wai-studio/ops.pending.json) is not retired here, androom.testis not added; that is for whichever of the two lands second.wai-fleet serve) has no OpenAPI document, so its routes are not catalogue operations of their own; the four operations are the client's.wai-quantum's command line and MCP servers are a separate binary with their own tool lists; the door check readswai mcp's alone.🤖 Generated with Claude Code
The two verbs join the one table, dx::VERBS, beside hello, create, dev and verify; wai.rs keeps no second command table. A verb ends either as a check (0 held, 1 did not, 2 usage) or with an exit status of the toolchain's table, which setup-agent uses. wai mcp (agent.mcp): each tool is an operation of the catalogue, named by it with `_` for the dot, and nothing else names it. The tools come in toolsets, chosen with --toolset (core when none is named): - core: envelope_inspect, registry_list, registry_show, receipt_verify, package_build, conformance_list, conformance_run, docs_search; - dev: dev_start, dev_stop, room_grant, room_join, room_leave, room_session, on the target local alone (a target named must be it). receipt_verify takes the four kinds the verify tools took one each (delivery, claim, room_session, audit_bundle), by `kind` or read from the arguments, and answers with the kind beside the verifier's verdict. tools/list gives each tool's operation and toolset in its _meta. The development room's program is found as wai dev finds it: beside wai, then on PATH. envelope_inspect counts what this build decodes as wai inspect does, the floor included. wai setup-agent (agent.setup): AGENTS.md always; a CLAUDE.md only where the project has one, which gains an import of AGENTS.md. --toolset registers the server with those toolsets. Off a terminal it answers in the toolchain's JSON envelope (envelope/1: op, ok, error {code, message, hint, retryable}, result, and on exit 4 the proposed changes and the confirming command), with the table's exit statuses: 2 usage, 3 permission, 4 confirmation required, 5 not found, 7 another I/O error. wai::ops holds the rule operation names keep: noun.verb, lowercase letters, the verb from a closed list, and the few names the catalogue gives as they are (room.session among them). The quickstart's wai holds `mcp`, so the server setup-agent registers is in the archive's binary. Co-Authored-By: Claude Opus 5.5 <[email protected]>wai app check's envelope as envelope/1 lays it out