@visa/cli 4.1.0-rc.3 → 4.1.0-rc.300

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,453 @@
1
+ ---
2
+ name: pair-visa-agent
3
+ description: Set up a Visa CLI v4 agent through the single protected enrollment implementation, using the entrance this build advertises, and report its live capabilities honestly. The owner always approves in their browser. Use when the user says "pair my agent", "connect Visa", "enroll my Visa CLI", "set up my agent", or "let this agent pay".
4
+ compatibility: Needs the `visa` CLI (`npm i -g @visa/cli@rc`) — run `node scripts/setup.mjs` to install it if missing — plus network access to the Visa authorization service. Works in OpenClaw, Hermes, Claude Code, Codex, or any Agent Skills runtime.
5
+ allowed-tools: Bash(visa:*) Bash(visa-cli:*) Bash(node:*) Bash(npm:*) Bash(npx:*)
6
+ metadata:
7
+ author: visa
8
+ homepage: https://visacli.sh/agents
9
+ version: '0.8.0'
10
+ # OpenClaw-namespaced extension (agentskills.io keeps `metadata` free-form, so
11
+ # non-standard runtime config lives here — `user-invocable` is not a standard
12
+ # top-level field). OpenClaw auto-installs `install[]` when `requires.bins` are
13
+ # missing; other runtimes (Hermes, Claude Code, …) self-provision via the
14
+ # bundled `scripts/setup.mjs` (see compatibility + Getting set up). @rc pinned
15
+ # until 4.1.0 is promoted to latest.
16
+ openclaw:
17
+ user-invocable: true
18
+ emoji: '🔐'
19
+ requires:
20
+ bins:
21
+ - visa
22
+ install:
23
+ - kind: node
24
+ package: '@visa/cli@rc'
25
+ bins:
26
+ - visa
27
+ - visa-cli
28
+ ---
29
+
30
+ # Set up a Visa agent
31
+
32
+ One command carries everything: this runtime's identity, the binding to **this
33
+ device**, and the spending limits — behind a **single** owner approval in their browser.
34
+
35
+ **Today, the command is run by the OWNER in their terminal.** On one-door builds that
36
+ advertise it, an agent may instead call `agent_enroll` and hand the owner its returned
37
+ link, or the owner runs `visa agent enroll`. These are two entrances to the exact same
38
+ protected enrollment implementation: the same native signer, Authority routes, owner
39
+ browser approval, and limits. Never invent or mix in a second ceremony.
40
+
41
+ ```
42
+ # the human runs this:
43
+ visa agent enroll-protected \
44
+ --authority-url <origin> --auth-url <origin> --url <origin> --wait
45
+
46
+ → it prints a URL and a short code
47
+ → the human opens the URL and enters the code at /agent/enroll/protected-agent
48
+ → the human approves the device and its spending limits (one approval)
49
+ → the command finishes; `get_status` now reports pairing.paired: true
50
+ ```
51
+
52
+ All three origins are required today; the operator supplies them. If the human does not
53
+ know them, ask — do not guess an origin, and never construct a Visa URL yourself.
54
+
55
+ Running the same command again resumes an interrupted enrolment; `--restart` replaces an
56
+ unclaimed request with a fresh code. `--ceiling <usd>` and `--per-transaction <usd>`
57
+ propose limits the owner confirms on the approval page.
58
+
59
+ ## The older ceremonies were deleted — do not call them
60
+
61
+ `setup_start`, `setup_status`, `setup_resume`, `setup_cancel`, `setup_agent`,
62
+ `enroll_agent`, `agent_connect`, `agent_connect_poll`, `agent_connect_cancel`,
63
+ `agent_handoff_claim` and `agent_pairing_cancel` are gone, along with the `visa setup`
64
+ group and `visa agent pair|create|verify|enroll|enroll-claim|claim|pairing-resume|connect|grant-card|grant-wallet|grant-activate|grant-claim|handoff-claim`.
65
+
66
+ Calling any of them returns one refusal:
67
+
68
+ ```json
69
+ { "code": "legacy_door_removed", "kind": "caller", "fix": "visa agent enroll-protected" }
70
+ ```
71
+
72
+ That code means the door no longer exists. **Relay the replacement and stop.** Do not
73
+ retry it, do not try a variant spelling, and do not report it to the human as an outage:
74
+ nothing was signed, paired, or paid.
75
+
76
+ ## What "set up" means here
77
+
78
+ Each completed protected enrollment mints a **new** agent: a new server-assigned agent,
79
+ a new device-held Ed25519 identity key, and the wallet limits the owner approved.
80
+
81
+ - The runtime keeps the private Ed25519 key and sends only the public JWK.
82
+ - The limits are the ones the owner actually approved on the page. Nothing you asked for
83
+ is granted until they approve it.
84
+ - An email address, a `.visa` mesh name, and TAP bindings remain separate, later
85
+ configuration. Do not infer them from a finished enrolment.
86
+
87
+ **Where the `agentId` comes from — read this before you quote one.** Do not invent it and
88
+ do not read it out of the command's terminal output, which you often cannot see. Read it
89
+ from `get_status` or `agent_capabilities` once the enrolment finishes. Never substitute a
90
+ correlation id, a confirmation code, or an origin for an `agentId`.
91
+
92
+ **Re-running the command does not repair an agent that already exists** — it creates a
93
+ second one. To fix a capability an existing agent is missing, see "Already set up — do NOT
94
+ enrol again" near the end.
95
+
96
+ ## Getting this skill
97
+
98
+ The skill ships inside the public `@visa/cli` npm package. No clone of the private
99
+ monorepo is required:
100
+
101
+ ```sh
102
+ npm install -g @visa/cli@rc
103
+ visa agent skill
104
+ ```
105
+
106
+ `visa agent skill` auto-detects OpenClaw, Hermes, Claude Code, and Codex, falling back to
107
+ the project-local `./.agents/skills`. Pass `--runtime <name>` or `--dir <path>` to choose a
108
+ target, `--force` to overwrite, or `--print` to read without writing. Reload or restart
109
+ the agent runtime after installation so it registers the skill.
110
+
111
+ Access remains enforced by the Visa service. Installing the public package or skill does
112
+ not authorize an account to pair.
113
+
114
+ OpenClaw users receive the skill via `visa agent skill --runtime openclaw` (or through the `@visa/visa-cli-openclaw` plugin when running from source).
115
+
116
+ ## Getting set up
117
+
118
+ 1. **Install the prerelease CLI.** Run `npm install -g @visa/cli@rc`, or run the bundled
119
+ idempotent provisioner `node scripts/setup.mjs`. The `@latest` tag may not yet expose
120
+ the v4 setup tools. Installation puts `visa` and `visa-cli` on `PATH` and includes
121
+ `@visa/cli/dist/mcp-server/index.js`.
122
+ 2. **Mount the MCP server when the runtime supports MCP.**
123
+ - **OpenClaw:** run `visa agent skill --runtime openclaw` (or `visa-cli connect openclaw`)
124
+ to install the skill and write `mcp.servers["visa-cli"]` in `~/.openclaw/openclaw.json`.
125
+ (Installing `@visa/visa-cli-openclaw` from source/tarball also auto-mounts the server).
126
+ - **Hermes or another supported runtime:** run `visa-cli connect hermes` or
127
+ `visa-cli connect <runtime>`. For Hermes, the entry is written under `mcp_servers`
128
+ in `~/.hermes/config.yaml`.
129
+ - **No MCP integration:** everything below still works — the enrolment is a shell
130
+ command, and `--format json` output is available on the management commands.
131
+ 3. **Sign the owner in** — see "Sign in first" below.
132
+ 4. **Enrol.** Follow the core flow below.
133
+
134
+ ## MCP mounting examples
135
+
136
+ Both runtimes use the same server entrypoint. Replace `<npm root -g>` with the output of
137
+ `npm root -g`.
138
+
139
+ OpenClaw (`~/.openclaw/openclaw.json`):
140
+
141
+ ```json
142
+ {
143
+ "mcp": {
144
+ "servers": {
145
+ "visa-cli": {
146
+ "command": "node",
147
+ "args": ["<npm root -g>/@visa/cli/dist/mcp-server/index.js"]
148
+ }
149
+ }
150
+ }
151
+ }
152
+ ```
153
+
154
+ Hermes (`~/.hermes/config.yaml`). **Hermes passes ONLY this `env:` map to the MCP
155
+ subprocess — it does NOT inherit the gateway environment.** Omitting a required variable
156
+ (an RC access code, the right `HOME`, `PATH`) makes the server exit on every start while
157
+ `agent_capabilities` — which reads on-disk grant state, not live tool registration — can
158
+ still report rails as available. Always set the map explicitly:
159
+
160
+ ```yaml
161
+ mcp_servers:
162
+ visa-cli:
163
+ command: node
164
+ args: ['<npm root -g>/@visa/cli/dist/mcp-server/index.js']
165
+ # Hermes does NOT inherit the gateway env. This map is the entire
166
+ # subprocess environment; omit VISA_RC_CODE and the server exits on boot.
167
+ env:
168
+ HOME: /home/<user> # the home that holds this runtime's .visa-cli state
169
+ VISA_RC_CODE: <access code>
170
+ PATH: /usr/local/bin:/usr/bin:/bin
171
+ ```
172
+
173
+ Hermes also loads skills **per profile** from `~/.hermes/profiles/<profile>/skills/`, not
174
+ from `~/.hermes/skills/`. `visa agent skill --runtime hermes` resolves this automatically:
175
+ it targets the single profile when exactly one exists (or the one named by
176
+ `HERMES_PROFILE`), and **fails loudly** on a multi-profile box instead of planting into
177
+ the flat dir nothing reads — pass `--dir ~/.hermes/profiles/<profile>/skills` to choose.
178
+
179
+ **Hermes sanitizes MCP server names when registering tools.** A server declared
180
+ `visa-cli` in `mcp_servers:` registers its tools as `mcp__visa_cli__<tool>` — with an
181
+ UNDERSCORE, not the declared hyphen. Anything that hardcodes `mcp__visa-cli__<tool>` gets
182
+ `unknown tool` on every call while looking correct in review. Read tool names off the
183
+ live registry; never derive them from the config key.
184
+
185
+ In Hermes, `hermes claw migrate` can also import this skill and MCP configuration from an
186
+ existing OpenClaw installation. See `RUNTIMES.md` for the complete runtime map.
187
+
188
+ ## Sign in first — the wallet is owner-bound
189
+
190
+ The USDC wallet is delegated out of the owner's own wallet, so this runtime needs a live
191
+ owner session. Establish it **before** the enrolment command runs:
192
+
193
+ - [ ] Call `agent_login` (MCP, default action `"start"`) or run
194
+ `visa agent login --format json` (CLI). The result carries a sign-in `browserUrl`
195
+ and a short 6-character `confirmCode`.
196
+ - [ ] Relay **both** to the human in your reply — the bare URL on its own line, and the
197
+ code. You are very often not in a terminal they can see; the chat message is the
198
+ only place these values reach them.
199
+ - [ ] The human opens the link, signs in (Google or email), and **types the confirmation
200
+ code into the sign-in page** — into the browser, never back to you in chat.
201
+ - [ ] Claim the session: `agent_login {"action":"claim"}` (the CLI command polls on its
202
+ own). Once claimed, the session token is stored locally.
203
+
204
+ `agent_login` establishes the OWNER's session on this device. It creates no agent and
205
+ grants no spending authority — those come from the enrolment command and the approval the
206
+ owner gives in their browser.
207
+
208
+ If something reports `{"code":"session_required"}` or "Not logged in", that is this
209
+ ordering rule, not a fault: run `agent_login`, drive the sign-in above to a claimed
210
+ session, then continue.
211
+
212
+ The account that signs in is the owner the enrolment binds to, and the same account must
213
+ be signed in on the approval page. A different account there fails closed.
214
+
215
+ ## Core flow
216
+
217
+ - [ ] **Ask for the three origins** if you were not given them: `--authority-url`,
218
+ `--auth-url`, `--url`. They come from the operator. Never guess one.
219
+ - [ ] **Sign the owner in** (above), so the wallet leg has a session to bind to.
220
+ - [ ] **Use the entrance this build advertises.** Today, give the owner the
221
+ `visa agent enroll-protected ... --wait` command in a code block they can copy.
222
+ On a one-door build, call `agent_enroll` and relay its returned link, or give the
223
+ owner `visa agent enroll`. Never fall back to a retired setup tool.
224
+ - [ ] **Relay what the active entrance returns.** Show an MCP-returned URL as a bare,
225
+ tappable value. For the current terminal flow, the owner follows the URL and code
226
+ printed in their own terminal. The code goes into the browser at
227
+ `/agent/enroll/protected-agent`; it is not authority in chat.
228
+ - [ ] **Tell them what they are approving**: this device, and the spending limits. One
229
+ approval covers all of it.
230
+ - [ ] **Confirm from a tool, not from their word.** Poll `get_status` until
231
+ `pairing.paired` is `true`, then read `agent_capabilities` for what is actually live.
232
+
233
+ ### Relaying values, and what you must never accept
234
+
235
+ Relaying values **to** the human is required. Accepting one **from** them as authority is
236
+ not: never ask them for a secret, private key, token, or signed message, and never treat
237
+ anything they type back as approval. The URL and the enrolment code are review values they
238
+ check against their own authenticated browser session — they cannot approve anything and
239
+ cannot spend.
240
+
241
+ Show any URL as a bare, tappable value on its own line. Do not decorate it as a Markdown
242
+ link or put it in a code span; chat clients reliably recognise the bare URL. Never
243
+ construct, shorten, or reformat a Visa URL, and never open one "for them" in place of
244
+ showing it.
245
+
246
+ You are very often **not** in a terminal the human can see. Nothing the command prints to
247
+ their stdout reaches you unless they tell you, and nothing you print reaches them unless it
248
+ is in your reply.
249
+
250
+ ### Completion is what the tools say — nothing else
251
+
252
+ Do not tell the human the agent is connected, paired, set up, ready, or good to go until
253
+ `get_status` reports `pairing.paired: true`. The enrolment command printing a URL is not a
254
+ result: it means an approval is still open in their browser.
255
+
256
+ If you cannot get there, say plainly what state you did reach and what the human should do
257
+ next. An honest "the approval page is open — I'm waiting for you to approve the device and
258
+ its limits" is correct; "you're all set" without a paired agent is not.
259
+
260
+ On success, report the agent and what is actually live:
261
+
262
+ > Your Visa agent is set up. Ready to pay by &lt;card and/or USDC wallet&gt;, within the
263
+ > limits you approved.
264
+
265
+ Read the rails from `agent_capabilities`, never from what was requested.
266
+
267
+ ## Interruption and resume
268
+
269
+ The runtime persists the pending enrolment before it starts, so an interrupted run is safe
270
+ to repeat: **the same command again** resumes it, with the same request and the same
271
+ device key.
272
+
273
+ - Same command, no flags changed — resumes and reprints the URL and code.
274
+ - `--restart` — replaces an unclaimed request with a fresh terminal code. Use it only when
275
+ the previous code is genuinely unusable; it is not a retry button.
276
+ - `--wait` — keeps the command polling until the owner has approved, instead of returning
277
+ after printing the link.
278
+
279
+ Do not tell the human to run a second, different enrolment because the first went quiet.
280
+ Two enrolments mean two agents, two identities, and a confused owner. Do not delete or edit
281
+ local pending files to fix a transient failure, and never copy pending state between
282
+ runtimes.
283
+
284
+ ## Management commands (an agent that already exists)
285
+
286
+ ```
287
+ visa agent list --format json
288
+ visa agent show <agentId> --format json
289
+ visa agent spendability --format json # can it spend, and what is missing
290
+ visa agent preflight --format json # every gate before a payment
291
+ visa agent pause|resume|revoke <agentId>
292
+ visa agent keychain status|repair # this device's identity custody
293
+ ```
294
+
295
+ None of these creates an identity. Prefer structured output and parse it; never scrape
296
+ prose.
297
+
298
+ ## Already set up — do NOT enrol again
299
+
300
+ If this device already holds an agent, a fresh enrolment is not needed and creates a
301
+ _second, separate_ agent. Do this instead:
302
+
303
+ 1. **Tell the user plainly:** "This device is already set up as `<name>`." Read the name
304
+ from `agent_capabilities` or `visa agent list`. Start another enrolment only if they
305
+ explicitly want a second agent.
306
+ 2. **Report status honestly — "set up" is several separate things.** Never imply the agent
307
+ can spend just because it exists. Read it live from tools rather than guessing from
308
+ prose: `agent_capabilities` returns the DERIVED capability map, `get_status` reports
309
+ pairing / account / version, `visa agent spendability --format json` answers "can it
310
+ spend, and what is missing", and `agent_login` establishes or confirms the account
311
+ session.
312
+ - **Identity** — bound to _this user's_ account, on _this device_.
313
+ - **Spending** — the limits the owner approved in the browser. You **cannot** self-grant
314
+ either rail, and never self-mint a wallet with `wallet_init` on mainnet — it throws
315
+ `WalletCredentialRequiredError` until the owner's delegation lands.
316
+ - **Mesh (`.visa` messaging)** — separate; `visa register <name>` joins it.
317
+ - **Trusted (TAP)** — follows spend/provisioning; don't promise it before then.
318
+ 3. **Scope everything to the user.** The identity is bound to the account they signed in
319
+ with; the wallet and limits are theirs. Speak in terms of "your agent / your account /
320
+ the limits you approved", never a shared identity.
321
+
322
+ ## An existing agent is missing a capability
323
+
324
+ There is no rail-add ceremony any more: `visa agent grant-card` / `grant-wallet` /
325
+ `grant-activate` / `grant-claim` and the `agent_connect` tools were deleted, and calling
326
+ one returns `legacy_door_removed`.
327
+
328
+ What to do instead:
329
+
330
+ - [ ] **Diagnose first.** `visa agent spendability --format json` and
331
+ `agent_capabilities` say exactly what is missing. Do not start anything before you
332
+ know which of identity, wallet delegation, card authority or funding is absent.
333
+ - [ ] **If the device's identity custody is broken**, `visa agent keychain repair` fixes
334
+ it without minting a new agent.
335
+ - [ ] **If the OWNER never approved that authority**, only they can add it. Say so, name
336
+ what is missing, and stop. Enrolling again mints a NEW agent — it does not upgrade
337
+ this one, and doing it silently leaves the owner with two agents and one funded
338
+ wallet.
339
+
340
+ A policy refusal or timeout means **nothing was signed**: report it and stop; do not retry
341
+ with a different command or a reconstructed URL. Never raise a human-approved limit
342
+ yourself.
343
+
344
+ ## Spending, once a rail is live
345
+
346
+ Wallet: set the policy with `wallet_policy_set` (per-transaction / daily / session USD
347
+ caps plus optional network and merchant allow/deny lists that refuse an x402 payment
348
+ BEFORE it is signed), then `wallet_pay`. The served wallet tools are `wallet_discover`
349
+ (search the public x402 Bazaar), `wallet_probe` (read a challenge without paying),
350
+ `wallet_pay` / `wallet_directory_pay` (pay, policy-enforced), `wallet_history` /
351
+ `wallet_reconcile` (local ledger + resolve `reconciling` holds), `wallet_fund` (funding
352
+ address + faucet), and `wallet_export` (export key material — dangerous). All spending is
353
+ gated by the owner-approved local policy caps.
354
+
355
+ Card: `start_card_mandate`, then `pay_merchant`. The first card purchase asks the owner
356
+ for a spending mandate within the budget they already approved.
357
+
358
+ The current card rail uses VIC browser checkout through `pay_merchant` after
359
+ `start_card_mandate`; do not claim that browser checkout is unavailable before the card
360
+ retirement change lands. On a hosted runtime, **every payment requires the owner's browser
361
+ approval** until the protected no-tap executor lands. Enrollment, a session, or a spending
362
+ grant does not approve a later hosted payment. Relay the hosted approval URL and wait for
363
+ the owner's decision before reporting success or retrying.
364
+
365
+ ## Optional `.visa` mesh binding (separate from setup)
366
+
367
+ Pairing does not register a `.visa` name, TAP key, or Subway peer. If the operator has
368
+ separately enabled and registered those channel bindings, the mounted `visa-cli` MCP server
369
+ may expose `subway_register`, `subway_send`, `subway_inbox`, and `subway_find`.
370
+
371
+ Mesh messaging is available only on a compatible RC/dev build with `SUBWAY_MESH=visa` and
372
+ a reachable `SUBWAY_RELAY_MULTIADDR`. If those tools or the relay are unavailable, report
373
+ that clearly and stop. Do not imply that connecting an agent granted directory or
374
+ messaging authority, and do not improvise another transport.
375
+
376
+ ## Optional agent mailbox (separate from setup)
377
+
378
+ Connecting an agent does not provision an email address or inbox. If the agent needs a
379
+ mailbox — e.g. to receive a merchant's account-signup or one-time-code email —
380
+ connect one explicitly, from the connected runtime, with the raw CLI:
381
+
382
+ ```
383
+ visa agent mail-connect <agentId>
384
+ ```
385
+
386
+ This is CLI-only; no pairing step or MCP tool connects a mailbox. It requires an
387
+ already-connected stable-agent identity on this runtime — it reads the local agent
388
+ record and proves the Ed25519 identity to the service. It issues the stable
389
+ agent mailbox if one does not exist, then stores an inbox-scoped credential in an
390
+ owner-only `0600` runtime file so this runtime can read that one inbox.
391
+
392
+ Be honest about scope. A mailbox grants an email address and the ability to read
393
+ that inbox — nothing more. It is **not** identity, a wallet, spend authority, a
394
+ card, or a `.visa` name, and it never authorizes a payment. Do not claim setup
395
+ set up mail. Once connected, the MCP `wallet_mail_status`, `wallet_mail_read`,
396
+ and `wallet_mail_await_otp` tools read the inbox (e.g. to await a sender-checked
397
+ one-time code); without the scoped credential those reads fail closed. Keep the
398
+ org-wide AgentMail key off the runtime — provisioning happens only through
399
+ `mail-connect` under operator control.
400
+
401
+ ## Optional checkout profile (separate from setup)
402
+
403
+ The experimental `pay_merchant` flow also needs a local `~/.visa-mcp/contact.json` file
404
+ once card authority exists and `checkout_agent_access` is enabled. Collect every value
405
+ from the human before the first review; never infer or invent identity or address data.
406
+ Write the file with mode `0600`.
407
+
408
+ Create and inspect this profile through the `checkout_profile` MCP tool whenever the
409
+ payment flow runs through MCP. Do not shell `visa agent preflight` as a substitute unless
410
+ the shell has the exact same `HOME` and `VISA_CLI_HOME` as the MCP subprocess. A profile
411
+ found under another root is owner PII, not a migration candidate: never scan, copy, or
412
+ auto-adopt it. If the roots drifted, keep the root holding the paired identity and have the
413
+ owner save the profile again through `checkout_profile` in that runtime.
414
+
415
+ ```jsonc
416
+ {
417
+ "fullName": "Ada Lovelace",
418
+ "email": "ada@example.com",
419
+ "addressLine1": "1 Analytical Way",
420
+ "addressLine2": "",
421
+ "city": "San Francisco",
422
+ "state": "CA",
423
+ "postalCode": "94105",
424
+ "country": "US",
425
+ }
426
+ ```
427
+
428
+ `fullName` must be non-blank; `firstName` plus `lastName` is also accepted. The engine reads
429
+ the exact keys `fullName`, `firstName`, `lastName`, `email`, `addressLine1`, `addressLine2`,
430
+ `city`, `state`, `postalCode`, and `country`. The profile supplies checkout/cardholder and
431
+ billing data only. Its `email` value is not the account's verified owner email, an agent
432
+ mailbox, key proof, recovery factor, or permission to spend.
433
+
434
+ ## Security rules
435
+
436
+ - Never read, print, log, paste, or transmit the private Ed25519 JWK or any local claim
437
+ token.
438
+ - Never read or echo local pending files. Present only the URL returned by the tool.
439
+ - Never treat `identityKeyJkt` as the stable identity. Use `agentId` for references and
440
+ persistence.
441
+ - Never fetch or submit the review URL on the human's behalf. They review and approve it
442
+ in their own browser.
443
+ - Never invent a secondary path when a call fails. Preserve the local state, surface the
444
+ error, and resume through the same protected entrance. On today's build, repeat the
445
+ same `visa agent enroll-protected ... --wait` command.
446
+ - Never call a retired door to "check whether it still works". `legacy_door_removed` is a
447
+ final answer, not a transient failure.
448
+
449
+ ## Further docs
450
+
451
+ - `RUNTIMES.md` — OpenClaw, Hermes, and raw CLI setup.
452
+ - `docs/agents/ARCHITECTURE.md` — where enrolment sits in the v4 request paths.
453
+ - `visacli.sh/agents` — product-facing agent documentation.