Weles/Docs

Reference

Command surface: capabilities, not one verb per site.

Measured 2026-09-09 against weles 0.6.5 built from wisent-ai/weles at 7e933735: 88 leaf invocations across 38 groups, 72 of them with no prose page, and the capabilities that replace 59 of them.

What was measured, and with which command#

Measured 2026-09-09 against weles 0.6.5, built from wisent-ai/weles at 7e93373568f64162da02fa585b4ee0e9892f0f05 (committed 2026-09-09). The measured binary is that revision's own build, weles 0.6.5, sha256 ff7beaa587fa06c46d97398b789201d66be5a70e6144290d8e4ad084948a5245. The measured inputs — package.json, src/cli.ts, src/worker/dispatch.ts, src/worker/deploy/weles-action-allowlist.txt, src/worker/deploy/weles-engagement-declaration.json, src/worker/deploy/weles-observation-declaration.json, src/trajectories — were unmodified in that checkout; the measurement refuses a checkout where they are not, because a count that belongs to no revision cannot be reproduced.

Every number on this page is produced by one command and by nothing else. None of them is copied from another page, from a cached corpus, or from memory.

These numbers belong to that revision, and the product moves on. Every push to this site runs the same measurement against the revision wisent-ai/weles serves, and confronts this page with it: a command, a flag, a count or a group stated here that the product contradicts fails the check, because a page saying something the product does not do is a false page. A newer revision that falsifies nothing fails nothing — it is reported as a staleness reading, because what has changed then is when the measurement was taken and not whether it is true. So the revision above is where these numbers were taken, and every sentence built on them still held at the last push.

Shell
WELES_BIN=<weles>/dist/cli.js npm run docs:surface -- --check

The surface, counted#

88 leaf invocations across 38 groups, on three planes a caller can reach: the CLI answers 15 invocations in 4 groups, the MCP server exposes 9 tools, and the worker action catalog (src/worker/deploy/weles-action-allowlist.txt) admits 64 named actions in 32 groups. The action catalog is the plane the product documents as its own contract — a caller submits an exact origin and an exact action — and it is where the surface actually lives.

2 of the 6 capability families have landed, and they were the two widest. Declared engagement replaced the 22 interaction verbs that were spelled once per site, and reads src/worker/deploy/weles-engagement-declaration.json instead: 46 declared engagements on 7 platforms, each naming its platform, its verb and the reviewed trajectory generic_saved_task replays. Declared observation replaced the 5 benign-activity verbs — browse, dwell, notifications, profile_view, search — and reads src/worker/deploy/weles-observation-declaration.json: 33 declared observations on 8 platforms, each naming in addition the origin it reads, what it must read there and the dwell budget it spends, run by generic_keeper_task. The catalog admits 0 of either now.

0 of the 64 remaining actions resolve to a trajectory file the measured checkout does not carry, because the rows whose trajectory nobody had written went with the verbs they belonged to. The cost that is left is measurable in two places: 72 of the 88 invocations have no prose page, and in the 4 families still to land a new site is another row in the allowlist rather than another declaration.

The largest groups (weles 0.6.5 at 7e933735)
GroupPlaneLeaf invocations
weles_pagemcp7
microsoftaction6
welescli6
genericaction5
weles onboardingcli5
redditaction4
discordaction3
githubaction3
instagramaction3
linkedinaction3
ncbraction3
tiktokaction3

What a declared engagement is, and what it replaced#

src/worker/deploy/weles-action-allowlist.txt is the gate: a build may dispatch exactly the actions it lists, and the worker's own resolver splits each one into a platform and a verb on the first underscore (`src/worker/dispatch.ts`). The platform was already data and the verb was already data, and the reviewed trajectory a run replays was already a declaration with an identity, a session policy, a terminal contract and an evidence identity. What was missing was a capability that consumed them, so src/worker/deploy/weles-engagement-declaration.json now does: one row per engagement, naming its platform, its verb and the reviewed trajectory, read by generic_saved_task under the schema wisent.weles-engagement-declaration.v1.

A caller submits the engagement by name and the target the run acts on. Admission resolves the declaration in the dispatcher, before anything is spawned: an engagement nobody declared is refused there, and a declaration naming a reviewed trajectory the tree does not carry is refused when it is loaded, which the API launcher does before it serves. Both failures used to land at execution — the allowlist admitted the row, the worker spawned the resolved path, and the run discovered the gap after the caller had been told the work was accepted.

What a declared observation is, and what it replaced#

Reading a site is the other half of the same shape, and it was the clearest case of it: most of the actions Declared observation replaced resolved to one shared file, several public invocation names for a single behavior. What told that file apart from itself — which origin to open, how many times to scroll, how long to dwell — was a table inside it, where no caller and no operator could read it, and the dwell column of that table was never applied at all: the loop asked for the default pause and ignored the range beside it. A declaration nothing reads is the defect this fleet already has a rule about; this one was worse, because it looked like configuration.

src/worker/deploy/weles-observation-declaration.json is what a run reads now, under the schema wisent.weles-observation-declaration.v1: 33 rows on 8 platforms, each naming its platform, its verb, the origin it reads, what it must read there, the dwell budget it spends and the reviewed trajectory. generic_keeper_task consumes it. A caller submits the observation by name and the values its origin asks for — a query, a handle, a subreddit — and admission fills them in; a submission that also names the origin or the budget itself is refused, because that is two answers to what the run reads.

The declaration is confronted with what it claims. A row that says it reads search results must carry a query in its origin, and one that says it reads a profile must carry a handle, so a row whose origin could never show what its verb named cannot be declared at all. Four of the replaced actions were exactly that, and they are gone without a declaration rather than carried forward: two discord verbs that both resolved to the direct-message client, an instagram notifications row that opened the home feed with a scroll budget of zero, and a youtube row whose shared trajectory carried neither a youtube origin nor a youtube ban detector.

59 actions are 6 capabilities and 5 primitives#

Counted from the walk, not sorted by hand: every action is assigned to exactly one family by its verb, and an action whose verb is in no family fails the measurement rather than quietly dropping out of the total. The families below sum to 59, and with the 5 primitives to all 64. A family that has landed reads a declaration instead, and the actions column is what the catalog still admits of it.

Capability families (59 of 64 actions)
CapabilityActionsReplacesReads
Declared engagement (landed)022 verbs on 7 platforms, now 46 declared: bookmark, comment, connect, dm, endorse, follow, join_server, join_sub, like, organic_comment, organic_issue_comment, organic_message, organic_reply, post, promote, react, save, star, story_view, upvote, watch_repo, watch_throughgeneric_saved_task — src/worker/deploy/weles-engagement-declaration.json
Declared observation (landed)05 verbs on 8 platforms, now 33 declared: browse, dwell, notifications, profile_view, searchgeneric_keeper_task — src/worker/deploy/weles-observation-declaration.json
Session presence287 verbs on 12 platforms: create_developer_id, health, login, login_search, provision_user_token, register, shadowban_checkgeneric_saved_task on a session-scoped trajectory — the session and fingerprint-profile declaration for one account
Credential lifecycle66 verbs on 1 platforms: adopt_password, entra_adopt_password, entra_reset_password, entra_verify_password, reset_password, verify_passwordthe Skarbiec credential bridge — skarbiec.credential-operation.v3, which already names provider, item, field and operation
Vendor account state172 verbs on 13 platforms: balance, topupgeneric_saved_task on one vendor-account trajectory — the declared vendor account list: provider, Skarbiec item, and the figure to read or move
Declared extraction87 verbs on 6 platforms: analyze_text, apply_correction, key_followup, pangram_audit_new_wniosek, post_message, scrape, verify_correctiongeneric_capture and generic_accessibility_audit — wisent.weles-capture-plan.v1: origin, selector and artifact prefix

The 5 that stay#

A verb is right when it names no vendor, no site and no incident, and takes a declaration as its input. These already do, which is why they are the shape the capabilities land in rather than another thing to remove.

  • generic_accessibility_audit
  • generic_browser_task
  • generic_capture
  • generic_keeper_task
  • generic_saved_task

What has no prose page#

72 of 88 invocations are undocumented. All 15 CLI leaves have a page: the CLI reference documents every one, counting an alternation line as documenting its members. Everything else does not.

  • The 9 MCP tools — weles_browser_close, weles_browser_start, weles_page_click, weles_page_evaluate, weles_page_fill, weles_page_goto, weles_page_new, weles_page_screenshot, weles_page_text — are published by `weles release surface` and named nowhere in this documentation corpus.
  • 63 of the 64 worker actions are named nowhere in it either; the exception is apple_login, which the Apple account workflow page names.
  • The 15 worker HTTP routes are counted separately: a route is not an invocation a caller names, but every one of them is also absent from this corpus.
Undocumented invocations by plane
PlaneLeaf invocationsWith no prose page
CLI150
MCP tools99
Worker actions6463

The removal rule#

A replaced command is deleted in the same change as its replacement. Not in a follow-up, not after a deprecation window: in the same change, together with its allowlist row, its resolver branch, its documentation paragraph and every caller.

The reason is one source of truth. A superseded command left beside its replacement is a second answer to the same question, and it keeps making its promise after the implementation that could honor it is gone. This surface showed the end state of not doing that: the allowlisted actions whose trajectory file was absent were exactly that, promises nobody removed, and there are 0 of them now because they were deleted with the verbs they belonged to rather than left behind. Both landed capabilities went the same way: the rows, the resolver branches, the documentation and the callers moved in the change that replaced them.

The shape the rule is aimed at is measurable, so the measurement reports it: the most shared trajectory file left is src/trajectories/ncbr/apply_correction.mjs, which 2 admitted actions resolve to — ncbr_apply_correction, ncbr_verify_correction. A number larger than one there is a family waiting to be named.

Migration, one capability at a time#

Each capability lands with the declaration it reads, every caller moves to it, and the actions it replaces are removed in the same change. The order follows the cost of being wrong, not the size of the diff.

  1. 1. Declared engagement — landed, 46 declared engagements in src/worker/deploy/weles-engagement-declaration.json and 0 actions left in the catalog: the largest family and the one a caller reaches for daily, so every day it stayed was another caller wired to a verb.
  2. 2. Declared observation — landed, 33 declared observations in src/worker/deploy/weles-observation-declaration.json and 0 actions left in the catalog: the clearest proof that the verbs were not behavior: thirty of them already shared one trajectory file.
  3. 3. Session presence (28 actions), reading the session and fingerprint-profile declaration for one account: it runs before everything else, and a session that cannot be re-established blocks every other capability.
  4. 4. Credential lifecycle (6 actions), reading skarbiec.credential-operation.v3, which already names provider, item, field and operation: the declaration already exists and is owned elsewhere, so this family is a consumer change rather than a new contract.
  5. 5. Vendor account state (17 actions), reading the declared vendor account list: provider, Skarbiec item, and the figure to read or move: read-mostly and low-risk, which is why it is late rather than never.
  6. 6. Declared extraction (8 actions), reading wisent.weles-capture-plan.v1: origin, selector and artifact prefix: each member names one incident, so it is the family whose replacement needs the plan schema to be settled first.

Which side owns the host-placed Weles verbs#

Stado carries nine `stado host weles-*` verbs — weles-recordings-dir, weles-api-runtime, weles-activity, weles-run-diagnostics, weles-image-inspect, weles-capture, weles-capture-status, weles-browser-task and weles-browser-runtime. They are a separate product's surface and are not included in the counts above; the boundary matters because two products both spelling the same operation is the same second-source-of-truth problem, one repository deep.

That nine is read in the Stado repository, at the revision named with it, by the command below. It is not part of this page's measurement and no Stado file is changed by publishing it.

The split follows what each product owns. Placement, host state and release identity are Stado's: weles-api-runtime, weles-browser-runtime and weles-recordings-dir move or read state on a host Stado places Weles on, and stay there. Everything that names a Weles run belongs to Weles: weles-capture and weles-browser-task submit actions this catalog already admits, weles-capture-status and weles-run-diagnostics read a run this product owns, and weles-activity and weles-image-inspect are a report and a fixed submission over the same runs. Those six are the client and the action catalog spelled a second time, one product away, and they belong on the Weles side of the boundary — as calls into this surface, not as verbs of their own.

Shell
git -C stado rev-parse --short=8 HEAD   # 1647e5ba, committed 2026-09-06
grep -c '#\[command(name = "weles-' stado/stado-rs/src/cli/mod.rs   # 9