@visa/cli 4.1.0-rc.99 → 5.0.0-rc.335
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 +282 -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 +319 -320
- 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 +122 -0
- package/dist/skills/visa-shopify-checkout/references/evidence-and-states.md +37 -0
- package/dist/skills/visa-ucp-shopping/SKILL.md +86 -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
|
|
63
|
+
|
|
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.
|
|
44
71
|
|
|
45
|
-
|
|
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
|
+
```
|
|
46
85
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
-
|
|
57
|
-
|
|
58
|
-
|
|
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,263 @@ 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
|
|
206
|
+
|
|
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:
|
|
209
|
+
|
|
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.
|
|
128
220
|
|
|
129
|
-
|
|
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.
|
|
130
224
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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.
|
|
228
|
+
|
|
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.
|
|
231
|
+
|
|
232
|
+
## Core flow
|
|
135
233
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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.
|
|
142
248
|
|
|
143
|
-
|
|
249
|
+
### Relaying values, and what you must never accept
|
|
144
250
|
|
|
145
|
-
|
|
146
|
-
|
|
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. Ready to pay by <card and/or USDC wallet>, within the
|
|
279
|
+
> limits you approved.
|
|
280
|
+
|
|
281
|
+
Read the rails from `agent_capabilities`, never from what was requested.
|
|
282
|
+
|
|
283
|
+
## Interruption and resume
|
|
284
|
+
|
|
285
|
+
The runtime persists the pending enrolment before it starts, so an interrupted run is safe
|
|
286
|
+
to repeat: **the same command again** resumes it, with the same request and the same
|
|
287
|
+
device key.
|
|
288
|
+
|
|
289
|
+
- Same command, no flags changed — resumes and reprints the URL and code.
|
|
290
|
+
- `--restart` — replaces an unclaimed request with a fresh terminal code. Use it only when
|
|
291
|
+
the previous code is genuinely unusable; it is not a retry button.
|
|
292
|
+
- `--wait` — keeps the command polling until the owner has approved, instead of returning
|
|
293
|
+
after printing the link.
|
|
294
|
+
|
|
295
|
+
Do not tell the human to run a second, different enrolment because the first went quiet.
|
|
296
|
+
Two enrolments mean two agents, two identities, and a confused owner. Do not delete or edit
|
|
297
|
+
local pending files to fix a transient failure, and never copy pending state between
|
|
298
|
+
runtimes.
|
|
299
|
+
|
|
300
|
+
## Management commands (an agent that already exists)
|
|
147
301
|
|
|
148
302
|
```
|
|
149
|
-
visa
|
|
303
|
+
visa status --format json # owner, agent, limits, mounts, every readiness gate
|
|
304
|
+
visa limits --format json # what it may spend; with amounts, the owner approves
|
|
305
|
+
visa activity --format json # payments across every rail
|
|
306
|
+
visa disconnect --revoke # drop this machine's spending authority
|
|
150
307
|
```
|
|
151
308
|
|
|
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
|
-
- **Identity** — connected (`.visa` name bound to _this user's_ account). ✓ once `already_connected`.
|
|
179
|
-
- **Spending** — a _separate human approval_, and there are two rails, each
|
|
180
|
-
approved on the **v4 agent dashboard** (`app.visacli.sh/agent/enroll`) — not any
|
|
181
|
-
account-settings page (that legacy surface is retired). The Turnkey
|
|
182
|
-
**wallet:x402** rail (stablecoin) is approved with the owner's **sign-in session**
|
|
183
|
-
(the Google/email auth-proxy) — **no passkey**. The **card:vic** rail is approved
|
|
184
|
-
with a **passkey**. You **cannot** self-grant either; there is no
|
|
185
|
-
`visa agent add-rail` command, and never self-mint a wallet with `wallet_init` on
|
|
186
|
-
mainnet — it throws until the owner's delegation lands.
|
|
187
|
-
- **Mesh (`.visa` messaging)** — with `SUBWAY_MESH=visa`, a returning device now
|
|
188
|
-
registers on `pair`; if `meshRegistered` is false, `visa register <name>` joins it.
|
|
309
|
+
`visa status` is the one command that answers "can it spend, and what is missing" — it
|
|
310
|
+
carries the readiness gates the old `spendability` and `preflight` commands each answered
|
|
311
|
+
a fragment of. Pausing, resuming, renaming and revoking an agent are owner actions in the
|
|
312
|
+
Visa Console, not terminal commands.
|
|
313
|
+
|
|
314
|
+
None of these creates an identity. Prefer structured output and parse it; never scrape
|
|
315
|
+
prose.
|
|
316
|
+
|
|
317
|
+
## Already set up — do NOT enrol again
|
|
318
|
+
|
|
319
|
+
If this device already holds an agent, a fresh enrolment is not needed and creates a
|
|
320
|
+
_second, separate_ agent. Do this instead:
|
|
321
|
+
|
|
322
|
+
1. **Tell the user plainly:** "This device is already set up as `<name>`." Read the name
|
|
323
|
+
from `agent_capabilities` or `visa status`. Start another enrolment only if they
|
|
324
|
+
explicitly want a second agent.
|
|
325
|
+
2. **Report status honestly — "set up" is several separate things.** Never imply the agent
|
|
326
|
+
can spend just because it exists. Read it live from tools rather than guessing from
|
|
327
|
+
prose: `agent_capabilities` returns the DERIVED capability map, `get_status` reports
|
|
328
|
+
pairing / account / version, `visa status --format json` answers "can it spend, and
|
|
329
|
+
what is missing", and `agent_login` establishes or confirms the account session.
|
|
330
|
+
- **Identity** — bound to _this user's_ account, on _this device_.
|
|
331
|
+
- **Spending** — the limits the owner approved in the browser. You **cannot** self-grant
|
|
332
|
+
either rail, and never self-mint a wallet with `wallet_init` on mainnet — it throws
|
|
333
|
+
`WalletCredentialRequiredError` until the owner's delegation lands.
|
|
334
|
+
- **Mesh (`.visa` messaging)** — separate; `visa register <name>` joins it.
|
|
189
335
|
- **Trusted (TAP)** — follows spend/provisioning; don't promise it before then.
|
|
190
|
-
3. **Scope everything to the user.** The identity is bound to the account
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
Missing **spend** blocks _checkout mandates_, not a delegated x402 wallet — but that
|
|
195
|
-
wallet must first be acquired by owner approval (below); it is never self-minted.
|
|
196
|
-
|
|
197
|
-
## What you can do once paired — granting spend authority (card or wallet)
|
|
198
|
-
|
|
199
|
-
Pairing binds **identity only**. To let this agent pay, the human owner must **delegate**
|
|
200
|
-
a spend rail — the runtime never self-mints one. There are two rails, and **one** ceremony
|
|
201
|
-
drives both:
|
|
202
|
-
|
|
203
|
-
- **`wallet:x402`** (Turnkey stablecoin) — owner approves with their **sign-in session, no
|
|
204
|
-
passkey**. On mainnet `wallet_init` throws `WalletCredentialRequiredError` until this
|
|
205
|
-
delegation lands, so never call it as a setup step.
|
|
206
|
-
- **`card:vic`** (Visa card checkout) — owner approves with a **passkey**.
|
|
207
|
-
|
|
208
|
-
The contract is identical for both rails, and it is **one command from you, one approval
|
|
209
|
-
from the owner**. You never hand a command, code, or URL back to the human after they
|
|
210
|
-
approve — you poll to completion yourself:
|
|
211
|
-
|
|
212
|
-
1. **You run one command** naming the rail and caps.
|
|
213
|
-
2. **The owner opens the returned link and approves once** (they may adjust the amount).
|
|
214
|
-
3. **You poll to activation** — the owner does nothing further.
|
|
215
|
-
|
|
216
|
-
- [ ] **Pair** the identity (the flow above). Identity only — no rail yet.
|
|
217
|
-
- [ ] **Establish the owner session once.** Grant creation is an account operation, so this
|
|
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:
|
|
336
|
+
3. **Scope everything to the user.** The identity is bound to the account they signed in
|
|
337
|
+
with; the wallet and limits are theirs. Speak in terms of "your agent / your account /
|
|
338
|
+
the limits you approved", never a shared identity.
|
|
251
339
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
visa agent grant-
|
|
255
|
-
|
|
340
|
+
## An existing agent is missing a capability
|
|
341
|
+
|
|
342
|
+
There is no rail-add ceremony any more: `visa agent grant-card` / `grant-wallet` /
|
|
343
|
+
`grant-activate` / `grant-claim` and the `agent_connect` tools were deleted, and calling
|
|
344
|
+
one returns `legacy_door_removed`.
|
|
345
|
+
|
|
346
|
+
What to do instead:
|
|
347
|
+
|
|
348
|
+
- [ ] **Diagnose first.** `visa status --format json` and `agent_capabilities` say
|
|
349
|
+
exactly what is missing. Do not start anything before you know which of identity,
|
|
350
|
+
wallet delegation, card authority or funding is absent.
|
|
351
|
+
- [ ] **If the device's identity custody is broken**, `visa connect` repairs it in place
|
|
352
|
+
without minting a new agent — it renews the device lease and skips every step that
|
|
353
|
+
is already done.
|
|
354
|
+
- [ ] **If the OWNER never approved that authority**, only they can add it. Say so, name
|
|
355
|
+
what is missing, and stop. Enrolling again mints a NEW agent — it does not upgrade
|
|
356
|
+
this one, and doing it silently leaves the owner with two agents and one funded
|
|
357
|
+
wallet.
|
|
256
358
|
|
|
257
|
-
Use the stable `agentId` from pairing or `visa agent list` — never invent or alter the id.
|
|
258
359
|
A policy refusal or timeout means **nothing was signed**: report it and stop; do not retry
|
|
259
|
-
with a different command or a reconstructed URL.
|
|
360
|
+
with a different command or a reconstructed URL. Never raise a human-approved limit
|
|
361
|
+
yourself.
|
|
260
362
|
|
|
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.
|
|
363
|
+
## Spending, once a rail is live
|
|
267
364
|
|
|
268
|
-
|
|
365
|
+
Wallet: set the policy with `wallet_policy_set` (per-transaction / daily / session USD
|
|
366
|
+
caps plus optional network and merchant allow/deny lists that refuse an x402 payment
|
|
367
|
+
BEFORE it is signed), then `wallet_pay`. The served wallet tools are `wallet_discover`
|
|
368
|
+
(search the public x402 Bazaar), `wallet_probe` (read a challenge without paying),
|
|
369
|
+
`wallet_pay` / `wallet_directory_pay` (pay, policy-enforced), `wallet_history` /
|
|
370
|
+
`wallet_reconcile` (local ledger + resolve `reconciling` holds), `wallet_fund` (funding
|
|
371
|
+
address + faucet), and `wallet_export` (export key material — dangerous). All spending is
|
|
372
|
+
gated by the owner-approved local policy caps.
|
|
373
|
+
|
|
374
|
+
Card: not available in this build. Visa CLI ships no browser checkout (#8940), so
|
|
375
|
+
`start_card_mandate` returns `card_browser_checkout_removed` and creates no mandate, and
|
|
376
|
+
every `pay_merchant` action refuses with the same code. Nothing is charged. Do not offer
|
|
377
|
+
card checkout to the user, and do not relay a card approval URL; the wallet rail above is
|
|
378
|
+
the payment path.
|
|
379
|
+
|
|
380
|
+
On a hosted runtime, **every payment requires the owner's browser
|
|
381
|
+
approval** until the protected no-tap executor lands. Enrollment, a session, or a spending
|
|
382
|
+
grant does not approve a later hosted payment. Relay the hosted approval URL and wait for
|
|
383
|
+
the owner's decision before reporting success or retrying.
|
|
269
384
|
|
|
270
|
-
|
|
271
|
-
`visa agent enroll --format json`.
|
|
272
|
-
- [ ] Present the authorization URL, stable agent ID, full public fingerprint, and the
|
|
273
|
-
`confirmationCode` when the start result carries one, to the human.
|
|
274
|
-
- [ ] Poll with `pair_agent_poll`, `enroll_agent` action `claim`, or
|
|
275
|
-
`visa agent enroll-claim --format json`.
|
|
276
|
-
- [ ] Report the stable `agentId` and that the identity is paired on this runtime.
|
|
277
|
-
|
|
278
|
-
### Completion is `activated` — nothing else
|
|
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.
|
|
385
|
+
## Retired mesh integration
|
|
388
386
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
Mesh messaging is available only on a compatible RC/dev build with `SUBWAY_MESH=visa` and
|
|
396
|
-
a reachable `SUBWAY_RELAY_MULTIADDR`. If those tools or the relay are unavailable, report
|
|
397
|
-
that clearly and stop. Do not imply that identity pairing alone granted directory or
|
|
398
|
-
messaging authority, and do not improvise another transport.
|
|
399
|
-
|
|
400
|
-
## Optional agent mailbox (separate from pairing)
|
|
401
|
-
|
|
402
|
-
Pairing does not provision an email address or inbox. If the agent needs a
|
|
387
|
+
Subway messaging and `visa register` are retired. Pairing grants no directory or
|
|
388
|
+
messaging authority. Do not attempt mesh registration or improvise another transport.
|
|
389
|
+
|
|
390
|
+
## Optional agent mailbox (separate from setup)
|
|
391
|
+
|
|
392
|
+
Connecting an agent does not provision an email address or inbox. If the agent needs a
|
|
403
393
|
mailbox — e.g. to receive a merchant's account-signup or one-time-code email —
|
|
404
|
-
connect one explicitly, from the
|
|
394
|
+
connect one explicitly, from the connected runtime, with the MCP tool:
|
|
405
395
|
|
|
406
396
|
```
|
|
407
|
-
|
|
397
|
+
agent_mail_connect { "agentId": "<agentId>" }
|
|
408
398
|
```
|
|
409
399
|
|
|
410
|
-
|
|
411
|
-
already-
|
|
400
|
+
There is no terminal command for this. It requires an
|
|
401
|
+
already-connected stable-agent identity on this runtime — it reads the local agent
|
|
412
402
|
record and proves the Ed25519 identity to the service. It issues the stable
|
|
413
403
|
agent mailbox if one does not exist, then stores an inbox-scoped credential in an
|
|
414
404
|
owner-only `0600` runtime file so this runtime can read that one inbox.
|
|
415
405
|
|
|
416
406
|
Be honest about scope. A mailbox grants an email address and the ability to read
|
|
417
407
|
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
|
|
408
|
+
card, or a `.visa` name, and it never authorizes a payment. Do not claim setup
|
|
419
409
|
set up mail. Once connected, the MCP `wallet_mail_status`, `wallet_mail_read`,
|
|
420
410
|
and `wallet_mail_await_otp` tools read the inbox (e.g. to await a sender-checked
|
|
421
411
|
one-time code); without the scoped credential those reads fail closed. Keep the
|
|
422
412
|
org-wide AgentMail key off the runtime — provisioning happens only through
|
|
423
413
|
`mail-connect` under operator control.
|
|
424
414
|
|
|
425
|
-
## Optional checkout profile (separate from
|
|
415
|
+
## Optional checkout profile (separate from setup)
|
|
416
|
+
|
|
417
|
+
The experimental `pay_merchant` flow also needs a local `~/.visa-mcp/contact.json` file
|
|
418
|
+
once card authority exists and `checkout_agent_access` is enabled. Collect every value
|
|
419
|
+
from the human before the first review; never infer or invent identity or address data.
|
|
420
|
+
Write the file with mode `0600`.
|
|
426
421
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
422
|
+
Create and inspect this profile through the `checkout_profile` MCP tool whenever the
|
|
423
|
+
payment flow runs through MCP. Do not shell `visa status` as a substitute unless the
|
|
424
|
+
shell has the exact same `HOME` and `VISA_CLI_HOME` as the MCP subprocess. A profile
|
|
425
|
+
found under another root is owner PII, not a migration candidate: never scan, copy, or
|
|
426
|
+
auto-adopt it. If the roots drifted, keep the root holding the paired identity and have the
|
|
427
|
+
owner save the profile again through `checkout_profile` in that runtime.
|
|
432
428
|
|
|
433
429
|
```jsonc
|
|
434
430
|
{
|
|
@@ -451,18 +447,21 @@ mailbox, key proof, recovery factor, or permission to spend.
|
|
|
451
447
|
|
|
452
448
|
## Security rules
|
|
453
449
|
|
|
454
|
-
- Never read, print, log, paste, or transmit the private Ed25519 JWK or local claim
|
|
455
|
-
|
|
456
|
-
|
|
450
|
+
- Never read, print, log, paste, or transmit the private Ed25519 JWK or any local claim
|
|
451
|
+
token.
|
|
452
|
+
- Never read or echo local pending files. Present only the URL returned by the tool.
|
|
457
453
|
- Never treat `identityKeyJkt` as the stable identity. Use `agentId` for references and
|
|
458
454
|
persistence.
|
|
459
|
-
- Never fetch the
|
|
460
|
-
|
|
461
|
-
- Never invent a secondary
|
|
462
|
-
|
|
455
|
+
- Never fetch or submit the review URL on the human's behalf. They review and approve it
|
|
456
|
+
in their own browser.
|
|
457
|
+
- Never invent a secondary path when a call fails. Preserve the local state, surface the
|
|
458
|
+
error, and resume through the same protected entrance: call `agent_enroll` again, or
|
|
459
|
+
repeat the same `visa connect` command.
|
|
460
|
+
- Never call a retired door to "check whether it still works". `legacy_door_removed` is a
|
|
461
|
+
final answer, not a transient failure.
|
|
463
462
|
|
|
464
463
|
## Further docs
|
|
465
464
|
|
|
466
465
|
- `RUNTIMES.md` — OpenClaw, Hermes, and raw CLI setup.
|
|
467
|
-
- `docs/agents/ARCHITECTURE.md` — where
|
|
466
|
+
- `docs/agents/ARCHITECTURE.md` — where enrolment sits in the v4 request paths.
|
|
468
467
|
- `visacli.sh/agents` — product-facing agent documentation.
|