@visa/cli 4.1.0-rc.99 → 5.0.0-rc.336
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.
- package/README.md +288 -156
- package/dist/cli.js +333 -532
- package/dist/managed-runtime/resolve-and-update.mjs +268 -0
- package/dist/managed-runtime/runtime-readiness.mjs +126 -0
- package/dist/managed-runtime/update-and-restart.mjs +1079 -0
- package/dist/mcp-apps/ucp-checkout.html +280 -0
- package/dist/mcp-server/index.js +234 -387
- package/dist/merchant-ucp-mcp/index.js +7 -0
- package/dist/skills/pair-visa-agent/RUNTIMES.md +56 -26
- package/dist/skills/pair-visa-agent/SKILL.md +325 -322
- package/dist/skills/pair-visa-agent/scripts/__tests__/setup.test.mjs +407 -0
- package/dist/skills/pair-visa-agent/scripts/setup.mjs +310 -30
- package/dist/skills/visa-shopify-checkout/SKILL.md +88 -0
- package/dist/skills/visa-shopify-checkout/references/evidence-and-states.md +43 -0
- package/dist/skills/visa-ucp-shopping/SKILL.md +90 -0
- package/install.ps1 +10 -6
- package/install.sh +7 -2
- package/native/bin/darwin-arm64/visa-runtime-signer +0 -0
- package/native/bin/darwin-x64/visa-runtime-signer +0 -0
- package/native/bin/linux-arm64/visa-runtime-signer +0 -0
- package/native/bin/linux-x64/visa-runtime-signer +0 -0
- package/native/bin/win32-arm64/visa-runtime-signer.exe +0 -0
- package/native/bin/win32-x64/visa-keychain-win.exe +0 -0
- package/native/bin/win32-x64/visa-runtime-signer.exe +0 -0
- package/package.json +23 -31
- package/server.json +3 -3
- package/dist/checkout-engine/adapters/generic.d.ts +0 -23
- package/dist/checkout-engine/adapters/generic.js +0 -216
- package/dist/checkout-engine/adapters/index.d.ts +0 -10
- package/dist/checkout-engine/adapters/index.js +0 -24
- package/dist/checkout-engine/adapters/shopify.d.ts +0 -31
- package/dist/checkout-engine/adapters/shopify.js +0 -423
- package/dist/checkout-engine/adapters/stripe-like.d.ts +0 -10
- package/dist/checkout-engine/adapters/stripe-like.js +0 -21
- package/dist/checkout-engine/amount.d.ts +0 -15
- package/dist/checkout-engine/amount.js +0 -72
- package/dist/checkout-engine/browser-launch.d.ts +0 -46
- package/dist/checkout-engine/browser-launch.js +0 -81
- package/dist/checkout-engine/ceremony.d.ts +0 -64
- package/dist/checkout-engine/ceremony.js +0 -261
- package/dist/checkout-engine/cli-engine.d.ts +0 -227
- package/dist/checkout-engine/cli-engine.js +0 -779
- package/dist/checkout-engine/detect.d.ts +0 -61
- package/dist/checkout-engine/detect.js +0 -398
- package/dist/checkout-engine/evidence.d.ts +0 -25
- package/dist/checkout-engine/evidence.js +0 -104
- package/dist/checkout-engine/executor.d.ts +0 -176
- package/dist/checkout-engine/executor.js +0 -1325
- package/dist/checkout-engine/hosted-approval.d.ts +0 -187
- package/dist/checkout-engine/hosted-approval.js +0 -478
- package/dist/checkout-engine/index.d.ts +0 -6
- package/dist/checkout-engine/index.js +0 -8
- package/dist/checkout-engine/inline-target.d.ts +0 -13
- package/dist/checkout-engine/inline-target.js +0 -37
- package/dist/checkout-engine/instrument.d.ts +0 -61
- package/dist/checkout-engine/instrument.js +0 -87
- package/dist/checkout-engine/live-fill-approval.d.ts +0 -43
- package/dist/checkout-engine/live-fill-approval.js +0 -90
- package/dist/checkout-engine/mandate/card-mandate.d.ts +0 -121
- package/dist/checkout-engine/mandate/card-mandate.js +0 -227
- package/dist/checkout-engine/mandate/mandate-ledger.d.ts +0 -142
- package/dist/checkout-engine/mandate/mandate-ledger.js +0 -338
- package/dist/checkout-engine/mandate.d.ts +0 -25
- package/dist/checkout-engine/mandate.js +0 -100
- package/dist/checkout-engine/outcome.d.ts +0 -30
- package/dist/checkout-engine/outcome.js +0 -225
- package/dist/checkout-engine/owner-only-file.d.ts +0 -19
- package/dist/checkout-engine/owner-only-file.js +0 -41
- package/dist/checkout-engine/package.json +0 -3
- package/dist/checkout-engine/receipt.d.ts +0 -81
- package/dist/checkout-engine/receipt.js +0 -109
- package/dist/checkout-engine/repo-env.d.ts +0 -11
- package/dist/checkout-engine/repo-env.js +0 -23
- package/dist/checkout-engine/trace-handles.d.ts +0 -8
- package/dist/checkout-engine/trace-handles.js +0 -12
- package/dist/checkout-engine/types.d.ts +0 -44
- package/dist/checkout-engine/types.js +0 -2
- package/dist/checkout-engine/vgs-gateway/fetch-credential.d.mts +0 -74
- package/dist/checkout-engine/vgs-gateway/fetch-credential.mjs +0 -248
- package/dist/checkout-engine/vgs-gateway/server-mint-client.d.ts +0 -82
- package/dist/checkout-engine/vgs-gateway/server-mint-client.js +0 -180
- package/dist/checkout-engine/vgs-live-instrument.d.ts +0 -179
- package/dist/checkout-engine/vgs-live-instrument.js +0 -296
- package/dist/checkout-engine/vic-confirmation.d.ts +0 -34
- package/dist/checkout-engine/vic-confirmation.js +0 -39
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pair-visa-agent
|
|
3
|
-
description:
|
|
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, or any Agent Skills runtime.
|
|
3
|
+
description: Set up a Visa CLI v4 agent through the single protected enrollment implementation (MCP `agent_enroll` or `visa connect`), 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
5
|
allowed-tools: Bash(visa:*) Bash(visa-cli:*) Bash(node:*) Bash(npm:*) Bash(npx:*)
|
|
6
6
|
metadata:
|
|
7
7
|
author: visa
|
|
8
8
|
homepage: https://visacli.sh/agents
|
|
9
|
-
version: '0.
|
|
9
|
+
version: '0.8.0'
|
|
10
10
|
# OpenClaw-namespaced extension (agentskills.io keeps `metadata` free-form, so
|
|
11
11
|
# non-standard runtime config lives here — `user-invocable` is not a standard
|
|
12
12
|
# top-level field). OpenClaw auto-installs `install[]` when `requires.bins` are
|
|
@@ -27,35 +27,85 @@ metadata:
|
|
|
27
27
|
- visa-cli
|
|
28
28
|
---
|
|
29
29
|
|
|
30
|
-
#
|
|
30
|
+
# Set up a Visa agent
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
One protected enrollment carries everything: this runtime's identity, the binding to
|
|
33
|
+
**this device**, and the spending limits — behind a **single** owner approval in their
|
|
34
|
+
browser.
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
CLI and universal fallback.
|
|
36
|
+
It has two entrances to the exact same protected enrollment implementation: the same
|
|
37
|
+
native signer, Authority routes, owner browser approval, and limits. Never invent or mix
|
|
38
|
+
in a second ceremony.
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
- **You have the Visa MCP server mounted:** call `agent_enroll` and hand the owner the one
|
|
41
|
+
link and short code it returns. Call it again with `wait: true` once they have the page
|
|
42
|
+
open; it finishes activation only after they approve.
|
|
43
|
+
- **The owner is at a terminal:** they run the command below.
|
|
42
44
|
|
|
43
|
-
|
|
45
|
+
```
|
|
46
|
+
# the human runs this:
|
|
47
|
+
visa connect
|
|
48
|
+
|
|
49
|
+
→ it prints a URL and a short code
|
|
50
|
+
→ the human opens the URL and enters the code at /agent/enroll/protected-agent
|
|
51
|
+
→ the human approves the device and its spending limits (one approval)
|
|
52
|
+
→ the command finishes; `get_status` now reports pairing.paired: true
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The installed CLI selects its own service origins from its release channel. Never ask
|
|
56
|
+
for, guess, or construct a Visa URL.
|
|
57
|
+
|
|
58
|
+
Running the same command again resumes an interrupted enrolment; `--restart` replaces an
|
|
59
|
+
unclaimed request with a fresh code. `--ceiling <usd>` and `--per-transaction <usd>`
|
|
60
|
+
propose limits the owner confirms on the approval page.
|
|
61
|
+
|
|
62
|
+
## The older ceremonies were deleted — do not call them
|
|
44
63
|
|
|
45
|
-
|
|
64
|
+
`setup_start`, `setup_status`, `setup_resume`, `setup_cancel`, `setup_agent`,
|
|
65
|
+
`enroll_agent`, `agent_connect`, `agent_connect_poll`, `agent_connect_cancel`,
|
|
66
|
+
`agent_handoff_claim` and `agent_pairing_cancel` are gone, along with the whole
|
|
67
|
+
`visa setup` and `visa agent` command groups — including the retired
|
|
68
|
+
`agent pair`, `agent create`, `agent verify`, `agent enroll-claim`,
|
|
69
|
+
`agent claim`, `agent pairing-resume`, `agent connect`, `agent handoff-claim`
|
|
70
|
+
and every `agent grant-*` verb.
|
|
46
71
|
|
|
47
|
-
|
|
48
|
-
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
72
|
+
**`visa connect` is the LIVE door and is not on that list.** It is the
|
|
73
|
+
top-level command, not the retired `visa agent connect` subcommand: one is the
|
|
74
|
+
one door, the other is a ceremony that no longer exists.
|
|
75
|
+
|
|
76
|
+
Calling any of them returns one refusal:
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"code": "legacy_door_removed",
|
|
81
|
+
"kind": "caller",
|
|
82
|
+
"fix": "visa connect (shell) or agent_enroll (MCP)"
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
That code means the door no longer exists. **Relay the replacement and stop.** Do not
|
|
87
|
+
retry it, do not try a variant spelling, and do not report it to the human as an outage:
|
|
88
|
+
nothing was signed, paired, or paid.
|
|
89
|
+
|
|
90
|
+
## What "set up" means here
|
|
91
|
+
|
|
92
|
+
Each completed protected enrollment mints a **new** agent: a new server-assigned agent,
|
|
93
|
+
a new device-held Ed25519 identity key, and the wallet limits the owner approved.
|
|
94
|
+
|
|
95
|
+
- The runtime keeps the private Ed25519 key and sends only the public JWK.
|
|
96
|
+
- The limits are the ones the owner actually approved on the page. Nothing you asked for
|
|
97
|
+
is granted until they approve it.
|
|
98
|
+
- An email address, a `.visa` mesh name, and TAP bindings remain separate, later
|
|
99
|
+
configuration. Do not infer them from a finished enrolment.
|
|
100
|
+
|
|
101
|
+
**Where the `agentId` comes from — read this before you quote one.** Do not invent it and
|
|
102
|
+
do not read it out of the command's terminal output, which you often cannot see. Read it
|
|
103
|
+
from `get_status` or `agent_capabilities` once the enrolment finishes. Never substitute a
|
|
104
|
+
correlation id, a confirmation code, or an origin for an `agentId`.
|
|
105
|
+
|
|
106
|
+
**Re-running the command does not repair an agent that already exists** — it creates a
|
|
107
|
+
second one. To fix a capability an existing agent is missing, see "Already set up — do NOT
|
|
108
|
+
enrol again" near the end.
|
|
59
109
|
|
|
60
110
|
## Getting this skill
|
|
61
111
|
|
|
@@ -64,33 +114,39 @@ monorepo is required:
|
|
|
64
114
|
|
|
65
115
|
```sh
|
|
66
116
|
npm install -g @visa/cli@rc
|
|
67
|
-
visa
|
|
117
|
+
visa connect
|
|
68
118
|
```
|
|
69
119
|
|
|
70
|
-
`visa
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
120
|
+
`visa connect` auto-detects the runtime it is running in. It plants this skill into that
|
|
121
|
+
runtime's own skills directory (OpenClaw, Hermes, Claude Code and Codex each read their
|
|
122
|
+
own), mounts the Visa MCP server, signs the owner in, enrols this machine's agent and
|
|
123
|
+
renews its device lease — skipping whatever is already done. Pass a client explicitly
|
|
124
|
+
(`visa connect codex`) when auto-detection is not what you want, and `--restart` to
|
|
125
|
+
replace an edited skill. Reload or restart the agent runtime afterwards so it registers
|
|
126
|
+
the skill.
|
|
74
127
|
|
|
75
128
|
Access remains enforced by the Visa service. Installing the public package or skill does
|
|
76
129
|
not authorize an account to pair.
|
|
77
130
|
|
|
78
|
-
OpenClaw users
|
|
131
|
+
OpenClaw users receive the skill via `visa connect openclaw` (or through the `@visa/visa-cli-openclaw` plugin when running from source).
|
|
79
132
|
|
|
80
133
|
## Getting set up
|
|
81
134
|
|
|
82
135
|
1. **Install the prerelease CLI.** Run `npm install -g @visa/cli@rc`, or run the bundled
|
|
83
136
|
idempotent provisioner `node scripts/setup.mjs`. The `@latest` tag may not yet expose
|
|
84
|
-
the v4
|
|
137
|
+
the v4 setup tools. Installation puts `visa` and `visa-cli` on `PATH` and includes
|
|
85
138
|
`@visa/cli/dist/mcp-server/index.js`.
|
|
86
|
-
2. **
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
139
|
+
2. **Run `visa connect <client>`.** One command: it plants the skill, writes the MCP
|
|
140
|
+
entry, signs the owner in, enrols this machine's agent and renews its device lease.
|
|
141
|
+
- **OpenClaw:** `visa connect openclaw` writes `mcp.servers["visa-cli"]` in
|
|
142
|
+
`~/.openclaw/openclaw.json`. (Installing `@visa/visa-cli-openclaw` from
|
|
143
|
+
source/tarball also auto-mounts the server).
|
|
144
|
+
- **Hermes:** `visa connect hermes` writes the entry under `mcp_servers` in
|
|
145
|
+
`~/.hermes/config.yaml`.
|
|
146
|
+
- **No MCP integration:** everything below still works — connecting is a shell
|
|
147
|
+
command, and `--format json` is available on every command.
|
|
148
|
+
3. **Check what is owed.** `visa status` prints the owner, the agent, its limits, which
|
|
149
|
+
clients are mounted, and one `next:` line when something is blocking.
|
|
94
150
|
|
|
95
151
|
## MCP mounting examples
|
|
96
152
|
|
|
@@ -112,323 +168,267 @@ OpenClaw (`~/.openclaw/openclaw.json`):
|
|
|
112
168
|
}
|
|
113
169
|
```
|
|
114
170
|
|
|
115
|
-
Hermes (`~/.hermes/config.yaml`)
|
|
171
|
+
Hermes (`~/.hermes/config.yaml`). **Hermes passes ONLY this `env:` map to the MCP
|
|
172
|
+
subprocess — it does NOT inherit the gateway environment.** Omitting a required variable
|
|
173
|
+
(an RC access code, the right `HOME`, `PATH`) makes the server exit on every start while
|
|
174
|
+
`agent_capabilities` — which reads on-disk grant state, not live tool registration — can
|
|
175
|
+
still report rails as available. Always set the map explicitly:
|
|
116
176
|
|
|
117
177
|
```yaml
|
|
118
178
|
mcp_servers:
|
|
119
179
|
visa-cli:
|
|
120
180
|
command: node
|
|
121
181
|
args: ['<npm root -g>/@visa/cli/dist/mcp-server/index.js']
|
|
182
|
+
# Hermes does NOT inherit the gateway env. This map is the entire
|
|
183
|
+
# subprocess environment; omit VISA_RC_CODE and the server exits on boot.
|
|
184
|
+
env:
|
|
185
|
+
HOME: /home/<user> # the home that holds this runtime's .visa-cli state
|
|
186
|
+
VISA_RC_CODE: <access code>
|
|
187
|
+
PATH: /usr/local/bin:/usr/bin:/bin
|
|
122
188
|
```
|
|
123
189
|
|
|
190
|
+
Hermes also loads skills **per profile** from `~/.hermes/profiles/<profile>/skills/`, not
|
|
191
|
+
from `~/.hermes/skills/`. `visa connect hermes` resolves this automatically: it targets
|
|
192
|
+
the single profile when exactly one exists (or the one named by `HERMES_PROFILE`), and
|
|
193
|
+
**fails loudly** on a multi-profile box instead of planting into the flat dir nothing
|
|
194
|
+
reads — set `HERMES_PROFILE` to choose.
|
|
195
|
+
|
|
196
|
+
**Hermes sanitizes MCP server names when registering tools.** A server declared
|
|
197
|
+
`visa-cli` in `mcp_servers:` registers its tools as `mcp__visa_cli__<tool>` — with an
|
|
198
|
+
UNDERSCORE, not the declared hyphen. Anything that hardcodes `mcp__visa-cli__<tool>` gets
|
|
199
|
+
`unknown tool` on every call while looking correct in review. Read tool names off the
|
|
200
|
+
live registry; never derive them from the config key.
|
|
201
|
+
|
|
124
202
|
In Hermes, `hermes claw migrate` can also import this skill and MCP configuration from an
|
|
125
203
|
existing OpenClaw installation. See `RUNTIMES.md` for the complete runtime map.
|
|
126
204
|
|
|
127
|
-
##
|
|
205
|
+
## Sign in first — the wallet is owner-bound
|
|
128
206
|
|
|
129
|
-
|
|
207
|
+
The USDC wallet is delegated out of the owner's own wallet, so this runtime needs a live
|
|
208
|
+
owner session. Establish it **before** the enrolment command runs:
|
|
130
209
|
|
|
131
|
-
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
210
|
+
- [ ] Call `agent_login` (MCP, default action `"start"`) or run
|
|
211
|
+
`visa connect --format json` (CLI). The result carries a sign-in `browserUrl`
|
|
212
|
+
and a short 6-character `confirmCode`.
|
|
213
|
+
- [ ] Relay **both** to the human in your reply — the bare URL on its own line, and the
|
|
214
|
+
code. You are very often not in a terminal they can see; the chat message is the
|
|
215
|
+
only place these values reach them.
|
|
216
|
+
- [ ] The human opens the link, signs in (Google or email), and **types the confirmation
|
|
217
|
+
code into the sign-in page** — into the browser, never back to you in chat.
|
|
218
|
+
- [ ] Claim the session: `agent_login {"action":"claim"}` (the CLI command polls on its
|
|
219
|
+
own). Once claimed, the session token is stored locally.
|
|
135
220
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
Present it when the field is present and skip it when it is absent; an older server or CLI
|
|
140
|
-
simply omits it, which is not an error. The activation result includes protocol version
|
|
141
|
-
`2`, `pairingId`, stable `agentId`, the display name, and `identityKeyJkt`.
|
|
221
|
+
`agent_login` establishes the OWNER's session on this device. It creates no agent and
|
|
222
|
+
grants no spending authority — those come from the enrolment command and the approval the
|
|
223
|
+
owner gives in their browser.
|
|
142
224
|
|
|
143
|
-
|
|
225
|
+
If something reports `{"code":"session_required"}` or "Not logged in", that is this
|
|
226
|
+
ordering rule, not a fault: run `agent_login`, drive the sign-in above to a claimed
|
|
227
|
+
session, then continue.
|
|
144
228
|
|
|
145
|
-
|
|
146
|
-
|
|
229
|
+
The account that signs in is the owner the enrolment binds to, and the same account must
|
|
230
|
+
be signed in on the approval page. A different account there fails closed.
|
|
147
231
|
|
|
148
|
-
|
|
149
|
-
visa agent pair --format json
|
|
150
|
-
```
|
|
232
|
+
## Core flow
|
|
151
233
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
runtime needs a live owner session: `agent_login` (MCP) or `visa agent login` (CLI).
|
|
219
|
-
This is a short-lived session established once for the grant — **not** a re-pair, and
|
|
220
|
-
**not** something the owner repeats per payment. If `agent_connect` later returns
|
|
221
|
-
`{"code":"session_required"}`, the session lapsed — run `agent_login` again.
|
|
222
|
-
- [ ] **Initiate the grant from MCP — no shelling, no invented URLs.** Call `agent_connect`
|
|
223
|
-
with the rail and caps: `{"rail":"card","ceiling":"<usd>","perTransaction":"<usd>"}`
|
|
224
|
-
(or `"rail":"wallet"`); omit `agentId` to target the most recently paired agent. It
|
|
225
|
-
returns `{ url, code, attachId, willGrant, expiresAt }`. Present the **bare `url` and
|
|
226
|
-
`code` exactly as returned** — never construct, shorten, or guess a Visa URL, and never
|
|
227
|
-
open it yourself. The crypto approval happens in the owner's browser and cannot run
|
|
228
|
-
inline in chat. (`setup_agent {"rail":"card"|"wallet"}` returns the same next-step map
|
|
229
|
-
if you need it.)
|
|
230
|
-
- [ ] **Owner approves once** on the **v4 agent dashboard** (`app.visacli.sh/agent/enroll`),
|
|
231
|
-
confirming the caps — **card with a passkey, wallet with their sign-in session**. You
|
|
232
|
-
cannot approve on their behalf.
|
|
233
|
-
- [ ] **Poll to activation from MCP.** Call `agent_connect_poll` (`{"attachId":"<from
|
|
234
|
-
agent_connect>"}`; or resume by `agentId`) — one bounded poll per call. It returns
|
|
235
|
-
`{"ok":false,"state":"...","blockedByKind":"awaiting_human_approval"}` while pending;
|
|
236
|
-
call again until `{"ok":true,"state":"grant_activated","caps":...}` (wallet also
|
|
237
|
-
returns `fundAddress`). Activation registers the delegated signer + caps: wallet writes
|
|
238
|
-
the Turnkey credential (`turnkey.json`); card writes the card pointer. It never spends.
|
|
239
|
-
- [ ] **Confirm the rail is live.** Wallet: `wallet_status` / `visa wallet show`
|
|
240
|
-
(`agent_capabilities.wallet.available`). Card: `agent_capabilities.card.available`.
|
|
241
|
-
Only a delegated credential — not the served tool list — means the rail is usable.
|
|
242
|
-
- [ ] **Then spend against the owner-approved caps.** Wallet: set the policy with
|
|
243
|
-
`wallet_policy_set` (per-transaction / daily / session USD caps + optional network and
|
|
244
|
-
merchant allow/deny lists that refuse an x402 payment BEFORE it is signed), then
|
|
245
|
-
`wallet_pay`. Card: `start_card_mandate` then `pay_merchant`. Never raise a
|
|
246
|
-
human-approved limit yourself.
|
|
247
|
-
|
|
248
|
-
**Raw CLI equivalent (one shot).** If you cannot drive MCP, the same ceremony runs from the
|
|
249
|
-
CLI and `--wait` polls to activation in a single call. Present the URL it prints — don't
|
|
250
|
-
invent one:
|
|
234
|
+
- [ ] **Do not ask for service origins.** The installed CLI selects its Auth and web
|
|
235
|
+
origins from the release channel; Authority is private behind Auth.
|
|
236
|
+
- [ ] **Sign the owner in** (above), so the wallet leg has a session to bind to.
|
|
237
|
+
- [ ] **Start the one enrollment.** Call `agent_enroll` and relay its returned link and
|
|
238
|
+
code, or give the owner `visa connect` in a code block they can copy.
|
|
239
|
+
Never fall back to a retired setup tool.
|
|
240
|
+
- [ ] **Relay what the entrance returns.** Show an MCP-returned URL as a bare,
|
|
241
|
+
tappable value. For the terminal flow, the owner follows the URL and code
|
|
242
|
+
printed in their own terminal. The code goes into the browser at
|
|
243
|
+
`/agent/enroll/protected-agent`; it is not authority in chat.
|
|
244
|
+
- [ ] **Tell them what they are approving**: this device, and the spending limits. One
|
|
245
|
+
approval covers all of it.
|
|
246
|
+
- [ ] **Confirm from a tool, not from their word.** Poll `get_status` until
|
|
247
|
+
`pairing.paired` is `true`, then read `agent_capabilities` for what is actually live.
|
|
248
|
+
|
|
249
|
+
### Relaying values, and what you must never accept
|
|
250
|
+
|
|
251
|
+
Relaying values **to** the human is required. Accepting one **from** them as authority is
|
|
252
|
+
not: never ask them for a secret, private key, token, or signed message, and never treat
|
|
253
|
+
anything they type back as approval. The URL and the enrolment code are review values they
|
|
254
|
+
check against their own authenticated browser session — they cannot approve anything and
|
|
255
|
+
cannot spend.
|
|
256
|
+
|
|
257
|
+
Show any URL as a bare, tappable value on its own line. Do not decorate it as a Markdown
|
|
258
|
+
link or put it in a code span; chat clients reliably recognise the bare URL. Never
|
|
259
|
+
construct, shorten, or reformat a Visa URL, and never open one "for them" in place of
|
|
260
|
+
showing it.
|
|
261
|
+
|
|
262
|
+
You are very often **not** in a terminal the human can see. Nothing the command prints to
|
|
263
|
+
their stdout reaches you unless they tell you, and nothing you print reaches them unless it
|
|
264
|
+
is in your reply.
|
|
265
|
+
|
|
266
|
+
### Completion is what the tools say — nothing else
|
|
267
|
+
|
|
268
|
+
Do not tell the human the agent is connected, paired, set up, ready, or good to go until
|
|
269
|
+
`get_status` reports `pairing.paired: true`. The enrolment command printing a URL is not a
|
|
270
|
+
result: it means an approval is still open in their browser.
|
|
271
|
+
|
|
272
|
+
If you cannot get there, say plainly what state you did reach and what the human should do
|
|
273
|
+
next. An honest "the approval page is open — I'm waiting for you to approve the device and
|
|
274
|
+
its limits" is correct; "you're all set" without a paired agent is not.
|
|
275
|
+
|
|
276
|
+
On success, report the agent and what is actually live:
|
|
277
|
+
|
|
278
|
+
> Your Visa agent is set up. <Report only the capabilities the live map confirms.>
|
|
279
|
+
|
|
280
|
+
Read the rails from `agent_capabilities`, never from what was requested.
|
|
281
|
+
|
|
282
|
+
## Interruption and resume
|
|
283
|
+
|
|
284
|
+
The runtime persists the pending enrolment before it starts, so an interrupted run is safe
|
|
285
|
+
to repeat: **the same command again** resumes it, with the same request and the same
|
|
286
|
+
device key.
|
|
287
|
+
|
|
288
|
+
- Same command, no flags changed — resumes and reprints the URL and code.
|
|
289
|
+
- `--restart` — replaces an unclaimed request with a fresh terminal code. Use it only when
|
|
290
|
+
the previous code is genuinely unusable; it is not a retry button.
|
|
291
|
+
- `--wait` — keeps the command polling until the owner has approved, instead of returning
|
|
292
|
+
after printing the link.
|
|
293
|
+
|
|
294
|
+
Do not tell the human to run a second, different enrolment because the first went quiet.
|
|
295
|
+
Two enrolments mean two agents, two identities, and a confused owner. Do not delete or edit
|
|
296
|
+
local pending files to fix a transient failure, and never copy pending state between
|
|
297
|
+
runtimes.
|
|
298
|
+
|
|
299
|
+
## Management commands (an agent that already exists)
|
|
251
300
|
|
|
252
301
|
```
|
|
253
|
-
visa agent
|
|
254
|
-
visa
|
|
302
|
+
visa status --format json # owner, agent, limits, mounts, every readiness gate
|
|
303
|
+
visa limits --format json # what it may spend; with amounts, the owner approves
|
|
304
|
+
visa activity --format json # payments across every rail
|
|
305
|
+
visa disconnect --revoke # drop this machine's spending authority
|
|
255
306
|
```
|
|
256
307
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
308
|
+
`visa status` is the one command that answers "can it spend, and what is missing" — it
|
|
309
|
+
carries the readiness gates the old `spendability` and `preflight` commands each answered
|
|
310
|
+
a fragment of. Pausing, resuming, renaming and revoking an agent are owner actions in the
|
|
311
|
+
Visa Console, not terminal commands.
|
|
312
|
+
|
|
313
|
+
None of these creates an identity. Prefer structured output and parse it; never scrape
|
|
314
|
+
prose.
|
|
315
|
+
|
|
316
|
+
## Already set up — do NOT enrol again
|
|
317
|
+
|
|
318
|
+
If this device already holds an agent, a fresh enrolment is not needed and creates a
|
|
319
|
+
_second, separate_ agent. Do this instead:
|
|
320
|
+
|
|
321
|
+
1. **Tell the user plainly:** "This device is already set up as `<name>`." Read the name
|
|
322
|
+
from `agent_capabilities` or `visa status`. Start another enrolment only if they
|
|
323
|
+
explicitly want a second agent.
|
|
324
|
+
2. **Report status honestly — "set up" is several separate things.** Never imply the agent
|
|
325
|
+
can spend just because it exists. Read it live from tools rather than guessing from
|
|
326
|
+
prose: `agent_capabilities` returns the DERIVED capability map, `get_status` reports
|
|
327
|
+
pairing / account / version, `visa status --format json` answers "can it spend, and
|
|
328
|
+
what is missing", and `agent_login` establishes or confirms the account session.
|
|
329
|
+
- **Identity** — bound to _this user's_ account, on _this device_.
|
|
330
|
+
- **Spending** — the limits the owner approved in the browser. You **cannot** self-grant
|
|
331
|
+
either rail, and never self-mint a wallet with `wallet_init` on mainnet — it throws
|
|
332
|
+
`WalletCredentialRequiredError` until the owner's delegation lands.
|
|
333
|
+
- **Mesh (`.visa` messaging)** — separate; `visa register <name>` joins it.
|
|
334
|
+
- **Trusted (TAP)** — follows spend/provisioning; don't promise it before then.
|
|
335
|
+
3. **Scope everything to the user.** The identity is bound to the account they signed in
|
|
336
|
+
with; the wallet and limits are theirs. Speak in terms of "your agent / your account /
|
|
337
|
+
the limits you approved", never a shared identity.
|
|
260
338
|
|
|
261
|
-
|
|
262
|
-
can actually call: `wallet_discover` (search the public x402 Bazaar), `wallet_probe` (read a
|
|
263
|
-
challenge without paying), `wallet_pay` / `wallet_directory_pay` (pay, policy-enforced),
|
|
264
|
-
`wallet_history` / `wallet_reconcile` (local ledger + resolve `reconciling` holds),
|
|
265
|
-
`wallet_fund` (funding address + faucet), and `wallet_export` (export key material —
|
|
266
|
-
dangerous). All spending is gated by the owner-approved local policy caps.
|
|
339
|
+
## An existing agent is missing a capability
|
|
267
340
|
|
|
268
|
-
|
|
341
|
+
There is no rail-add ceremony any more: `visa agent grant-card` / `grant-wallet` /
|
|
342
|
+
`grant-activate` / `grant-claim` and the `agent_connect` tools were deleted, and calling
|
|
343
|
+
one returns `legacy_door_removed`.
|
|
344
|
+
|
|
345
|
+
What to do instead:
|
|
269
346
|
|
|
270
|
-
- [ ]
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
- [ ]
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
Only a poll result of `activated` means this runtime is paired. Until you have one, do not
|
|
281
|
-
tell the human the agent is connected, paired, enrolled, set up, ready, or good to go, and
|
|
282
|
-
do not move on to spending, mail, or mesh steps that assume an identity.
|
|
283
|
-
|
|
284
|
-
`start` returning successfully is not completion. It returns a stable `agentId` and a
|
|
285
|
-
`requestKeyFingerprint` **before any human has approved anything** — those are review
|
|
286
|
-
values for the browser comparison, not evidence of pairing. Reporting an `agentId` as
|
|
287
|
-
though it were a finished pairing is the most likely way to mislead the human here, because
|
|
288
|
-
the number looks like a result.
|
|
289
|
-
|
|
290
|
-
If you cannot reach `activated`, say plainly what state you did reach and what the human
|
|
291
|
-
should do next. An honest "approved but not yet activated — I'm still polling" is correct;
|
|
292
|
-
"you're all set" without an `activated` result is not.
|
|
293
|
-
|
|
294
|
-
### 1. Start
|
|
295
|
-
|
|
296
|
-
Start once. If there is already a pending pairing, poll it before creating another.
|
|
297
|
-
|
|
298
|
-
The result provides `browserUrl`, stable `agentId`, `requestKeyFingerprint`, and — on newer
|
|
299
|
-
builds — `confirmationCode`. Show the URL as a bare, tappable value on its own line. Do not
|
|
300
|
-
decorate it as a Markdown link or put it in a code span; chat clients reliably recognize the
|
|
301
|
-
bare URL. Show the complete fingerprint without truncation and tell the human to approve
|
|
302
|
-
only when every character matches the browser review page.
|
|
303
|
-
|
|
304
|
-
You are very often **not** in a terminal the human can see. Nothing you print to stdout
|
|
305
|
-
reaches them. Every value the browser asks them to compare has to appear in your reply, or
|
|
306
|
-
the comparison silently becomes "click approve and hope" — which is the whole failure this
|
|
307
|
-
step exists to prevent.
|
|
308
|
-
|
|
309
|
-
Use this concise shape:
|
|
310
|
-
|
|
311
|
-
> 🔐 Pair your Visa agent — open this authorization page:
|
|
312
|
-
>
|
|
313
|
-
> 👉 <browserUrl, bare and on its own line>
|
|
314
|
-
>
|
|
315
|
-
> Stable agent ID: <agentId>
|
|
316
|
-
>
|
|
317
|
-
> Confirmation code — this exact code should appear on the page:
|
|
318
|
-
> <confirmationCode>
|
|
319
|
-
>
|
|
320
|
-
> Public request-key fingerprint — compare every character in the browser:
|
|
321
|
-
> <requestKeyFingerprint, complete and untruncated>
|
|
322
|
-
>
|
|
323
|
-
> Approve only if the code and fingerprint both match. The link expires shortly — I'll keep
|
|
324
|
-
> watching and confirm here the moment it activates.
|
|
325
|
-
|
|
326
|
-
Omit the confirmation-code line entirely when the start result has no `confirmationCode`;
|
|
327
|
-
never invent, derive, abbreviate, or reformat one.
|
|
328
|
-
|
|
329
|
-
Relaying these values **to** the human is required. Accepting one **from** the human is not:
|
|
330
|
-
do not ask them for a code, secret, private key, token, or signed message, and do not treat
|
|
331
|
-
anything they type back as approval. The URL, stable agent ID, confirmation code, and public
|
|
332
|
-
fingerprint are review values the human checks against their own authenticated browser
|
|
333
|
-
session. They are not claim credentials, they cannot approve a pairing, and they cannot
|
|
334
|
-
spend. Approval happens only in that browser session, and the only evidence of it is a poll
|
|
335
|
-
result of `activated`.
|
|
336
|
-
|
|
337
|
-
**Do not end your turn here waiting to be told the human is done.** Presenting the link is
|
|
338
|
-
not the end of the ceremony; go straight to the poll in §2 and drive it to a terminal
|
|
339
|
-
state. Asking the human to report back is what strands a pairing: they approve in the
|
|
340
|
-
browser, the server records it, and nothing ever writes the local record — so the ceremony
|
|
341
|
-
expires while both sides believe the other is acting.
|
|
342
|
-
|
|
343
|
-
When the start result reports `claiming: "background"`, a detached poller is already
|
|
344
|
-
finishing activation and it will complete even if this turn ends; poll anyway so you can
|
|
345
|
-
confirm the outcome. When it reports `claiming: "manual"`, that poller could NOT start and
|
|
346
|
-
polling in this turn is the ONLY thing that will complete the pairing.
|
|
347
|
-
|
|
348
|
-
### 2. Poll
|
|
349
|
-
|
|
350
|
-
Poll the same pending pairing. Interpret results as follows:
|
|
351
|
-
|
|
352
|
-
- `activated` — pairing is complete. Continue to the completion report.
|
|
353
|
-
- `not_ready` with `likelyExpired: false` — the human has not finished. Wait and poll
|
|
354
|
-
again, using bounded retries rather than an endless loop.
|
|
355
|
-
- `not_ready` with `likelyExpired: true` — the authorization window probably expired.
|
|
356
|
-
Start a fresh pairing.
|
|
357
|
-
- `no_pending` — this runtime has no resumable pairing. Start a fresh pairing.
|
|
358
|
-
- `error` — surface the error without exposing local pending data. Retry once if it is a
|
|
359
|
-
transient network failure; otherwise stop and ask the human to start again.
|
|
360
|
-
|
|
361
|
-
### 3. Report completion
|
|
362
|
-
|
|
363
|
-
On `activated`, report the display name when present and the stable `agentId`. You may
|
|
364
|
-
also report `identityKeyJkt` as the current key fingerprint, but label it clearly as a
|
|
365
|
-
rotatable key identifier.
|
|
366
|
-
|
|
367
|
-
Use precise completion language:
|
|
368
|
-
|
|
369
|
-
> Visa agent <displayName> is paired to this runtime. Stable agent ID: <agentId>.
|
|
370
|
-
|
|
371
|
-
Do not claim that activation configured payments, email, tap bindings, or any other
|
|
372
|
-
product capability. Those are separate follow-up configuration flows.
|
|
373
|
-
|
|
374
|
-
## Interruption and replay safety
|
|
375
|
-
|
|
376
|
-
The runtime persists its v2 pending record before sending the signed claim. If a request
|
|
377
|
-
or response is interrupted, the next poll resumes the exact same `pairingId`, `agentId`,
|
|
378
|
-
Ed25519 identity, and claim material. This makes an identical retry safe and avoids
|
|
379
|
-
creating a second identity because a response was lost.
|
|
380
|
-
|
|
381
|
-
The pending record remains until the activated agent record has been written durably.
|
|
382
|
-
Therefore:
|
|
383
|
-
|
|
384
|
-
- Poll before starting over.
|
|
385
|
-
- Do not delete or edit pending files to fix a transient failure.
|
|
386
|
-
- Do not regenerate keys for an existing pairing.
|
|
387
|
-
- Do not copy pending state between runtimes.
|
|
347
|
+
- [ ] **Diagnose first.** `visa status --format json` and `agent_capabilities` say
|
|
348
|
+
exactly what is missing. Do not start anything before you know which of identity,
|
|
349
|
+
wallet delegation, card authority or funding is absent.
|
|
350
|
+
- [ ] **If the device's identity custody is broken**, `visa connect` repairs it in place
|
|
351
|
+
without minting a new agent — it renews the device lease and skips every step that
|
|
352
|
+
is already done.
|
|
353
|
+
- [ ] **If the OWNER never approved that authority**, only they can add it. Say so, name
|
|
354
|
+
what is missing, and stop. Enrolling again mints a NEW agent — it does not upgrade
|
|
355
|
+
this one, and doing it silently leaves the owner with two agents and one funded
|
|
356
|
+
wallet.
|
|
388
357
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
358
|
+
A policy refusal or timeout means **nothing was signed**: report it and stop; do not retry
|
|
359
|
+
with a different command or a reconstructed URL. Never raise a human-approved limit
|
|
360
|
+
yourself.
|
|
361
|
+
|
|
362
|
+
## Spending, once a rail is live
|
|
363
|
+
|
|
364
|
+
Wallet: set the policy with `wallet_policy_set` (per-transaction / daily / session USD
|
|
365
|
+
caps plus optional network and merchant allow/deny lists that refuse an x402 payment
|
|
366
|
+
BEFORE it is signed), then `wallet_pay`. The served wallet tools are `wallet_discover`
|
|
367
|
+
(search the public x402 Bazaar), `wallet_probe` (read a challenge without paying),
|
|
368
|
+
`wallet_pay` / `wallet_directory_pay` (pay, policy-enforced), `wallet_history` /
|
|
369
|
+
`wallet_reconcile` (local ledger + resolve `reconciling` holds), `wallet_fund` (funding
|
|
370
|
+
address + faucet), and `wallet_export` (export key material — dangerous). All spending is
|
|
371
|
+
gated by the owner-approved local policy caps.
|
|
372
|
+
|
|
373
|
+
Card: not available in this build. Visa CLI ships no browser checkout (#8940), so
|
|
374
|
+
`start_card_mandate` returns `card_browser_checkout_removed` and creates no mandate, and
|
|
375
|
+
every `pay_merchant` action refuses with the same code. Nothing is charged. Do not offer
|
|
376
|
+
card checkout to the user, and do not relay a card approval URL; the wallet rail above is
|
|
377
|
+
the payment path where the merchant supports it. A saved card, grant or tester flag does
|
|
378
|
+
not enable card payment, and another enrollment will not repair it. UCP discovery and
|
|
379
|
+
checkout preparation are not payment execution. A continuable `ucp_checkout_handoff`
|
|
380
|
+
returns safe facts and `not_ready` / `card_browser_checkout_removed`, without a payment
|
|
381
|
+
request or continuation capability URL. Preserve the existing checkout for the owner
|
|
382
|
+
to continue with the merchant; use `ucp_checkout_reconcile` afterward to check completion.
|
|
383
|
+
|
|
384
|
+
On a hosted runtime, **every payment requires the owner's browser
|
|
385
|
+
approval** until the protected no-tap executor lands. Enrollment, a session, or a spending
|
|
386
|
+
grant does not approve a later hosted payment. Relay the hosted approval URL and wait for
|
|
387
|
+
the owner's decision before reporting success or retrying.
|
|
388
|
+
|
|
389
|
+
## Retired mesh integration
|
|
390
|
+
|
|
391
|
+
Subway messaging and `visa register` are retired. Pairing grants no directory or
|
|
392
|
+
messaging authority. Do not attempt mesh registration or improvise another transport.
|
|
393
|
+
|
|
394
|
+
## Optional agent mailbox (separate from setup)
|
|
395
|
+
|
|
396
|
+
Connecting an agent does not provision an email address or inbox. If the agent needs a
|
|
403
397
|
mailbox — e.g. to receive a merchant's account-signup or one-time-code email —
|
|
404
|
-
connect one explicitly, from the
|
|
398
|
+
connect one explicitly, from the connected runtime, with the MCP tool:
|
|
405
399
|
|
|
406
400
|
```
|
|
407
|
-
|
|
401
|
+
agent_mail_connect { "agentId": "<agentId>" }
|
|
408
402
|
```
|
|
409
403
|
|
|
410
|
-
|
|
411
|
-
already-
|
|
404
|
+
There is no terminal command for this. It requires an
|
|
405
|
+
already-connected stable-agent identity on this runtime — it reads the local agent
|
|
412
406
|
record and proves the Ed25519 identity to the service. It issues the stable
|
|
413
407
|
agent mailbox if one does not exist, then stores an inbox-scoped credential in an
|
|
414
408
|
owner-only `0600` runtime file so this runtime can read that one inbox.
|
|
415
409
|
|
|
416
410
|
Be honest about scope. A mailbox grants an email address and the ability to read
|
|
417
411
|
that inbox — nothing more. It is **not** identity, a wallet, spend authority, a
|
|
418
|
-
card, or a `.visa` name, and it never authorizes a payment. Do not claim
|
|
412
|
+
card, or a `.visa` name, and it never authorizes a payment. Do not claim setup
|
|
419
413
|
set up mail. Once connected, the MCP `wallet_mail_status`, `wallet_mail_read`,
|
|
420
414
|
and `wallet_mail_await_otp` tools read the inbox (e.g. to await a sender-checked
|
|
421
415
|
one-time code); without the scoped credential those reads fail closed. Keep the
|
|
422
416
|
org-wide AgentMail key off the runtime — provisioning happens only through
|
|
423
417
|
`mail-connect` under operator control.
|
|
424
418
|
|
|
425
|
-
## Optional checkout profile (separate from
|
|
419
|
+
## Optional checkout profile (separate from setup)
|
|
420
|
+
|
|
421
|
+
Do not collect a checkout profile to repair `pay_merchant`: card payment is unavailable
|
|
422
|
+
even with a profile, card authority and `checkout_agent_access`. Existing
|
|
423
|
+
`~/.visa-mcp/contact.json` files use the format below; preserve them with mode `0600`.
|
|
424
|
+
Never infer or invent identity or address data.
|
|
426
425
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
426
|
+
Create and inspect this profile through the `checkout_profile` MCP tool whenever the
|
|
427
|
+
payment flow runs through MCP. Do not shell `visa status` as a substitute unless the
|
|
428
|
+
shell has the exact same `HOME` and `VISA_CLI_HOME` as the MCP subprocess. A profile
|
|
429
|
+
found under another root is owner PII, not a migration candidate: never scan, copy, or
|
|
430
|
+
auto-adopt it. If the roots drifted, keep the root holding the paired identity and have the
|
|
431
|
+
owner save the profile again through `checkout_profile` in that runtime.
|
|
432
432
|
|
|
433
433
|
```jsonc
|
|
434
434
|
{
|
|
@@ -451,18 +451,21 @@ mailbox, key proof, recovery factor, or permission to spend.
|
|
|
451
451
|
|
|
452
452
|
## Security rules
|
|
453
453
|
|
|
454
|
-
- Never read, print, log, paste, or transmit the private Ed25519 JWK or local claim
|
|
455
|
-
|
|
456
|
-
|
|
454
|
+
- Never read, print, log, paste, or transmit the private Ed25519 JWK or any local claim
|
|
455
|
+
token.
|
|
456
|
+
- Never read or echo local pending files. Present only the URL returned by the tool.
|
|
457
457
|
- Never treat `identityKeyJkt` as the stable identity. Use `agentId` for references and
|
|
458
458
|
persistence.
|
|
459
|
-
- Never fetch the
|
|
460
|
-
|
|
461
|
-
- Never invent a secondary
|
|
462
|
-
|
|
459
|
+
- Never fetch or submit the review URL on the human's behalf. They review and approve it
|
|
460
|
+
in their own browser.
|
|
461
|
+
- Never invent a secondary path when a call fails. Preserve the local state, surface the
|
|
462
|
+
error, and resume through the same protected entrance: call `agent_enroll` again, or
|
|
463
|
+
repeat the same `visa connect` command.
|
|
464
|
+
- Never call a retired door to "check whether it still works". `legacy_door_removed` is a
|
|
465
|
+
final answer, not a transient failure.
|
|
463
466
|
|
|
464
467
|
## Further docs
|
|
465
468
|
|
|
466
469
|
- `RUNTIMES.md` — OpenClaw, Hermes, and raw CLI setup.
|
|
467
|
-
- `docs/agents/ARCHITECTURE.md` — where
|
|
470
|
+
- `docs/agents/ARCHITECTURE.md` — where enrolment sits in the v4 request paths.
|
|
468
471
|
- `visacli.sh/agents` — product-facing agent documentation.
|