@reclaimprotocol/agent 0.1.29 → 0.1.32

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.
Files changed (91) hide show
  1. package/README.md +28 -9
  2. package/lib/consts.d.ts +5 -5
  3. package/lib/consts.js +7 -7
  4. package/lib/live/tunnel-watchdog.d.ts +1 -0
  5. package/lib/live/tunnel-watchdog.js +66 -0
  6. package/lib/live/tunnel.d.ts +30 -7
  7. package/lib/live/tunnel.js +217 -40
  8. package/lib/mcp/api/operations.gen.d.ts +12 -0
  9. package/lib/mcp/api/operations.gen.js +548 -59
  10. package/lib/mcp/api/tools.js +27 -5
  11. package/lib/mcp/instructions.js +23 -32
  12. package/lib/mcp/remap_errors.js +6 -0
  13. package/lib/mcp/server.js +2 -8
  14. package/lib/mcp/start.js +3 -5
  15. package/lib/mcp/success-response.d.ts +5 -0
  16. package/lib/mcp/success-response.js +21 -0
  17. package/lib/mcp/tools/agent/attach.js +9 -66
  18. package/lib/mcp/tools/agent/build.d.ts +0 -3
  19. package/lib/mcp/tools/agent/build.js +3 -4
  20. package/lib/mcp/tools/agent/how-it-works.d.ts +5 -15
  21. package/lib/mcp/tools/agent/how-it-works.js +9 -22
  22. package/lib/mcp/tools/agent/live-view.d.ts +1 -15
  23. package/lib/mcp/tools/agent/live-view.js +71 -96
  24. package/lib/mcp/tools/agent/propose.js +7 -23
  25. package/lib/mcp/tools/agent/publish.js +80 -18
  26. package/lib/mcp/tools/agent/session.d.ts +4 -7
  27. package/lib/mcp/tools/agent/session.js +8 -23
  28. package/lib/mcp/tools/verification/result.d.ts +2 -1
  29. package/lib/mcp/tools/verification/result.js +29 -28
  30. package/lib/old/client.d.ts +2 -2
  31. package/lib/old/flag.d.ts +2 -5
  32. package/lib/old/flag.js +2 -5
  33. package/lib/old/instructions.d.ts +1 -1
  34. package/lib/old/instructions.js +1 -1
  35. package/lib/old/to-register.d.ts +4 -3
  36. package/lib/old/tools/get-provider-info.js +3 -1
  37. package/lib/old/tools/publish.js +11 -14
  38. package/lib/proof/attestor-auth.d.ts +9 -1
  39. package/lib/proof/attestor-auth.js +15 -2
  40. package/lib/proof/attestor.d.ts +2 -2
  41. package/lib/proof/attestor.js +20 -2
  42. package/lib/proof/pod-prover.js +1 -1
  43. package/lib/proof/proof-core.d.ts +4 -0
  44. package/lib/proof/proof-core.js +20 -0
  45. package/lib/provider/injection-doc.d.ts +3 -2
  46. package/lib/provider/injection-doc.js +12 -10
  47. package/lib/provider/matcher.js +19 -15
  48. package/lib/provider/to-version.d.ts +3 -0
  49. package/lib/provider/to-version.js +2 -1
  50. package/package.json +3 -3
  51. package/skill/SKILL.builder.md +44 -86
  52. package/skill/SKILL.common.md +38 -22
  53. package/skill/SKILL.old.md +21 -5
  54. package/skill/builder-mode.md +62 -4
  55. package/skill/community-contributions.md +12 -3
  56. package/skill/hash-validation.md +9 -9
  57. package/skill/interception.md +39 -46
  58. package/skill/old-mode.md +25 -0
  59. package/skill/user-script.md +24 -8
  60. package/skill/verification-client-integration.md +133 -0
  61. package/src/consts.ts +9 -7
  62. package/src/mcp/api/operations.gen.ts +550 -59
  63. package/src/mcp/api/tools.ts +38 -7
  64. package/src/mcp/instructions.ts +33 -32
  65. package/src/mcp/remap_errors.ts +6 -0
  66. package/src/mcp/server.ts +2 -8
  67. package/src/mcp/start.ts +3 -5
  68. package/src/mcp/success-response.ts +26 -0
  69. package/src/mcp/tools/agent/attach.ts +9 -71
  70. package/src/mcp/tools/agent/build.ts +4 -7
  71. package/src/mcp/tools/agent/how-it-works.ts +9 -22
  72. package/src/mcp/tools/agent/live-view.ts +76 -116
  73. package/src/mcp/tools/agent/propose.ts +7 -23
  74. package/src/mcp/tools/agent/publish.ts +89 -18
  75. package/src/mcp/tools/agent/session.ts +6 -23
  76. package/src/mcp/tools/verification/result.ts +30 -29
  77. package/src/old/client.ts +2 -2
  78. package/src/old/flag.ts +2 -5
  79. package/src/old/instructions.ts +1 -1
  80. package/src/old/to-register.ts +4 -3
  81. package/src/old/tools/get-provider-info.ts +3 -1
  82. package/src/old/tools/publish.ts +16 -14
  83. package/src/proof/attestor-auth.ts +18 -1
  84. package/src/proof/attestor.ts +24 -3
  85. package/src/proof/pod-prover.ts +1 -1
  86. package/src/proof/proof-core.ts +28 -0
  87. package/src/provider/injection-doc.ts +12 -10
  88. package/src/provider/matcher.ts +25 -17
  89. package/src/provider/to-version.ts +7 -1
  90. package/src/live/cloudflared.ts +0 -348
  91. package/src/live/tunnel.ts +0 -254
@@ -22,6 +22,12 @@ already names it.
22
22
  <!-- section: browser -->
23
23
  ## Choosing a browser
24
24
 
25
+ ## Contents
26
+
27
+ - [Sharing a container browser](#sharing-the-containers-live-view-share_browser_view)
28
+ - [Container lifetime and isolation](#how-containers-are-shared-and-when-they-close)
29
+ - [Container startup problems](#when-the-container-will-not-start)
30
+
25
31
  **Ask one question first, before you list anything:**
26
32
 
27
33
  > Will you be doing this yourself, or does someone else need to sign in — the
@@ -92,8 +98,8 @@ persist it. If a `liveViewUrl` comes back, share it full and verbatim.
92
98
 
93
99
  A `container` browser serves its own viewer on loopback, so the developer can
94
100
  open it the moment `attach_browser` returns. `share_browser_view` puts that same
95
- viewer behind a public HTTPS URL through a cloudflared quick tunnel — for when
96
- the person who has to act is not at that machine: a login or 2FA only they can
101
+ viewer behind a public HTTPS URL through a cloudflared quick tunnel that you
102
+ run — for when the person who has to act is not at that machine: a login or 2FA only they can
97
103
  complete, or a colleague watching a capture.
98
104
 
99
105
  **Offer it whenever a login is coming and the developer is not the one holding
@@ -104,8 +110,17 @@ Ask plainly:
104
110
  > whoever holds the login — they can watch and click in it, including from a
105
111
  > phone.
106
112
 
107
- If they say yes, call `share_browser_view` and **relay the full returned URL
108
- verbatim, on its own line.** It includes `liveview.html?magnify=1`.
113
+ If they say yes:
114
+
115
+ 1. Call `share_browser_view` with no arguments. It returns the viewer `port` and
116
+ the `command` (`cloudflared tunnel --url http://localhost:<port>`). The MCP
117
+ server does not run cloudflared.
118
+ 2. Run `command` yourself in the background. If `cloudflared` is not installed,
119
+ ask the developer to install it; do not install it without their approval.
120
+ 3. Read its output for the `https://<words>.trycloudflare.com` URL. Never guess
121
+ or reconstruct the hostname.
122
+ 4. Call `share_browser_view({ publicUrl })` with that URL. **Relay the returned
123
+ `url` verbatim, on its own line.** It includes `liveview.html?magnify=1`.
109
124
 
110
125
  - **`container` is the only mode this applies to.** `builder` returns a hosted
111
126
  `liveViewUrl` from `attach_browser` — relay that instead, full and verbatim.
@@ -123,24 +138,16 @@ verbatim, on its own line.** It includes `liveview.html?magnify=1`.
123
138
  - **Opening it on a phone lays the page out for that phone**, with touch,
124
139
  pinch-zoom and the soft keyboard. That is the reason to reach for `container`
125
140
  when a site only works on mobile.
126
- - **Call `stop_browser_view` as soon as they're done.** That closes the tunnel
127
- only — the browser keeps running. `dispose_browser` and `reset_session` stop
128
- the container itself.
129
- - **If the URL will not load**, check `propagating`. The hostname can exist
130
- before Cloudflare finishes routing it. Keep the returned share open, wait a
131
- few seconds, and reload; don't start a second tunnel while it propagates.
132
- `cloudflaredLog` contains bounded diagnostic output. If it still fails after
133
- 60 seconds, call `stop_browser_view`, then retry `share_browser_view` once.
134
- - **cloudflared is handled for you.** An existing install on PATH wins;
135
- otherwise it's fetched once into `~/.reclaim/bin` on the first share, never at
136
- install time. Tell the developer when the download starts.
137
- `RECLAIM_CLOUDFLARED_PATH` points at their own copy instead.
141
+ - **Stop the cloudflared process you started as soon as they're done.** The
142
+ browser keeps running. `dispose_browser` and `reset_session` stop the
143
+ container itself, but not your cloudflared process.
144
+ - **Expose only the viewer port** that `share_browser_view` returns, never the
145
+ browser's CDP port.
138
146
 
139
147
  ### How containers are shared, and when they close
140
148
 
141
- - **Closing the agent releases the browser.** The server stops the container and
142
- the tunnel when its connection drops, so a public URL never outlives the
143
- session that made it. `dispose_browser` does the same on demand.
149
+ - **Closing the agent releases the browser.** The server stops the container
150
+ when its connection drops. `dispose_browser` does the same on demand.
144
151
  - **Re-attaching in one session reuses the same browser** — under a second,
145
152
  rather than the twenty a fresh one costs — so whatever it is signed into is
146
153
  still there.
@@ -151,9 +158,10 @@ verbatim, on its own line.** It includes `liveview.html?magnify=1`.
151
158
  own profile, and starts out signed in to nothing.
152
159
  - **Four at once is the ceiling**, because each is about 2 GB of RAM. Past that,
153
160
  `attach_browser` says so and points at `dedicated`.
154
- - **A crash cannot strand one for long.** A killed session runs no cleanup, so
155
- the next `container` attach removes any container whose owning process is gone.
156
- One belonging to a session that is still alive is never touched.
161
+ - **A crash cannot strand one for long.** A killed session runs no normal
162
+ cleanup, so the next `container` attach removes any container whose owning
163
+ process is gone. Resources belonging to a live session are
164
+ never touched.
157
165
 
158
166
  ### When the container will not start
159
167
 
@@ -270,6 +278,10 @@ anything the developer wouldn't post publicly), put the four options to them.
270
278
  `hash` or capture a request whose URL doesn't carry it.
271
279
  3. Never pass `hash` for a free-form target (unicode / spaces / punctuation).
272
280
 
281
+ **Disambiguate repeated JSON values.** `propose_provider` rejects a target
282
+ found at multiple JSON paths instead of guessing which field the user meant.
283
+ Choose a target that identifies one field.
284
+
273
285
  `propose_provider` throws a clean error on all three — retrying the same call
274
286
  won't help.
275
287
 
@@ -297,6 +309,8 @@ won't help.
297
309
  `propose_provider` again with different inputs instead.
298
310
 
299
311
  <!-- section: secrets -->
312
+ ### Protect secret values
313
+
300
314
  **Marking a value secret.** Name ANY param with `SECRET` anywhere in the key
301
315
  (case-insensitive) — a bare `{{SECRET_x}}` as much as a consumer-supplied
302
316
  `{{%CTX%SECRET_apiKey}}` — and it routes to `secretParams.paramValues`
@@ -323,6 +337,8 @@ captured secret *header* whose value also sits in the URL, which is already
323
337
  known and so gets checked at draft time (`assertNoSecretUrlConflict`).
324
338
 
325
339
  <!-- section: no-rename-param -->
340
+ ### Hide internal fields from claimant UI
341
+
326
342
  **Keep internal claim-construction fields out of claimant-facing UI.** When a
327
343
  named regex group or `{{parameter}}` only helps construct another claim request,
328
344
  consider an internal prefix:
@@ -109,8 +109,18 @@ it. Don't assume `authenticate_builder` fixes it.
109
109
  <!-- topic: draft -->
110
110
  ## Draft the provider
111
111
 
112
+ ## Contents
113
+
114
+ - [Choose a privacy mode](#choose-a-privacy-mode)
115
+ - [Draft and inspect the request](#draft-and-inspect-the-request)
116
+ - [Preserve the canonical shape](#preserve-the-canonical-shape)
117
+
118
+ ### Choose a privacy mode
119
+
112
120
  <!-- common: oprf -->
113
121
 
122
+ ### Draft and inspect the request
123
+
114
124
  **Call `propose_provider`.** It returns a **`draftId`** — the handle for
115
125
  `replay_request` and `run_proof` — plus the secret-free `provider` and
116
126
  `secretRefs`. The recipe **and the captured secret values** live server-side
@@ -171,6 +181,8 @@ field they control. The synthesizer does this for you.
171
181
  With `hash: 'oprf-raw'`, the redaction gains `"hash": "oprf-raw"`. Nothing else
172
182
  changes.
173
183
 
184
+ ### Preserve the canonical shape
185
+
174
186
  <!-- common: rewrite-shape-block -->
175
187
 
176
188
  <!-- topic: params -->
@@ -271,7 +283,7 @@ Call `create_provider_version_from_capture`:
271
283
  - **Login/navigation-gated data:** supply `customInjection` (plain page JS) and
272
284
  `allowedInjectedRequestData` (extra requests the script may fire).
273
285
  → topic `user-script`. Before populating `allowedInjectedRequestData` for a
274
- `verifyProof({ providerId })` use case, read topic `hash-validation`.
286
+ `verifyRequestProof({ providerId })` use case, read topic `hash-validation`.
275
287
 
276
288
  **Ownership — you can only add a version to a provider YOU own.** The
277
289
  `providerId` must come from `get_me_providers`. Versioning a public provider you
@@ -306,8 +318,10 @@ applies them.
306
318
  would fetch. Reads the public production SDK backend directly, no auth.
307
319
 
308
320
  There's no create-then-version step and no org / public-review workflow here.
309
- When done, tell the developer the version is live and that they can integrate
310
- using the `providerId`.
321
+ When done, tell the developer the version is live, then ask once how they want
322
+ to use it — try it now, integrate it into an existing backend or frontend, or
323
+ create a new app — unless they already said (see "Using a provider" in the
324
+ server instructions).
311
325
 
312
326
  **If the response includes `_notes` for an attached browser, follow them for an
313
327
  optional authenticated-state retest.** Only when its profile is still signed in,
@@ -365,8 +379,10 @@ turn
365
379
  document replay off and keep the interceptor (`disableRequestReplay: true`, or
366
380
  `isDocumentRequestReplayEnabled: false` on builder) — often that alone is what
367
381
  breaks the page, and it's the smallest change. Only if that doesn't help, turn
368
- interception off entirely (`injectionType: NONE`, or omit
369
- `interceptorOptions`). Full checklist and remedies: topic `interception`.
382
+ interception off temporarily to confirm it is the cause (`injectionType: NONE`,
383
+ or omit `interceptorOptions`). If that fixes the provider, keep interception
384
+ off and replace intercepted claims with `window.Reclaim.requestClaim`. Full
385
+ checklist and remedies: topic `interception`.
370
386
 
371
387
  **A session stalled, matched nothing, or produced no claim.** Read it with
372
388
  two tools, coarse to fine. `session_analytics_logs` returns the milestone
@@ -6,10 +6,55 @@ authoring tools.
6
6
 
7
7
  ## Claimant-facing Builder sessions
8
8
 
9
- This integration is separate from provider authoring. When it is relevant,
10
- read `how_it_works({ topic: "integration" })` for the exact `api=2` boundary,
11
- bridge routes, result verification, legacy-proof contract, and optional TEE
12
- binding. A URL without `api=2` stays on its existing legacy path.
9
+ This integration is separate from provider authoring.
10
+
11
+ **Using a provider.** A provider found with `providers`, `discover_resolve`, or
12
+ another lookup is published and usable as-is. Don't capture, `replay_request`,
13
+ or `run_proof` against it unless the developer asks you to check or test it.
14
+ Before using a provider, found or just created, ask once whether they just want
15
+ to try it or want it in an app (skip this if they already said):
16
+
17
+ > Want to (1) just try it right now, (2) integrate it into an existing backend
18
+ > or frontend (this directory or another path), or (3) create a new app for it?
19
+
20
+ - **Just try it:** no app, callback, or client package. Create the session the
21
+ HTTP way (`create_verification_session`, i.e. `POST /verifications/sessions`
22
+ with the org secret as `Authorization: Bearer`; `issue_org_token` if there is
23
+ none), give the developer `verificationUrl` to open, then check the session
24
+ yourself (`get_verification_session`) until it is terminal and report the
25
+ outcome with `get_verification_result`.
26
+ - **Integrate, or new app:** follow the setup below in the path they named.
27
+
28
+ **Prefer the HTTP API over `@reclaimprotocol/client`** for every option:
29
+ create sessions with `POST /verifications/sessions`, open `verificationUrl`,
30
+ poll `GET /verifications/sessions/{sessionId}`, and take the result on the
31
+ callback. Use the client package only when the developer asks for it — the one
32
+ exception is `results.receive`, to verify the result on your callback.
33
+
34
+ When integrating into an app, read `how_it_works({ topic: "integration" })`,
35
+ then configure the organization with generated tools (`list_orgs`,
36
+ `create_org`, `create_org_callback_subscription`, and owner-only
37
+ `issue_org_token`) and edit the app's frontend and backend with the coding
38
+ agent's file tools. The guide
39
+ covers the HTTP session workflow, exact `api=2` boundary, result
40
+ verification, request-proof contract, and optional TEE binding. A URL without
41
+ `api=2` stays on its existing legacy path.
42
+
43
+ **Existing `@reclaimprotocol/js-sdk` projects.** If the app's `package.json`
44
+ depends on `@reclaimprotocol/js-sdk`, ask the developer before doing anything
45
+ else:
46
+
47
+ > This project uses `@reclaimprotocol/js-sdk`. Keep it (I switch this MCP
48
+ > server to legacy devtools mode), or migrate to the Builder integration
49
+ > (Builder HTTP API)?
50
+
51
+ - **Keep js-sdk:** call `set_devtools_mode({ mode: "old" })`, then tell them to
52
+ restart or reconnect the MCP server; the switch applies on the next start. An
53
+ explicit `USE_OLD_DEVTOOLS` env var overrides it. After the restart, read
54
+ `get_js_sdk_integration_guide`.
55
+ - **Migrate:** stay in Builder mode. Follow `how_it_works({ topic:
56
+ "integration" })` to replace `@reclaimprotocol/js-sdk` with the Builder
57
+ HTTP session flow and update the app's code.
13
58
 
14
59
  **A `provider` is a recipe for extracting a data point from a site. A
15
60
  `verification` is an end-user session that proves a data point using one. Never
@@ -20,6 +65,19 @@ configuration change creates a new semantic version. Default to a patch bump;
20
65
  use a major/minor bump or exact higher version when the user directs it. Never
21
66
  use an in-place provider-version update or archive tool.
22
67
 
68
+ ## Evidence contract
69
+
70
+ Tool results are the source of truth. Never say that a browser attached, a user
71
+ logged in, a request was captured, a proof passed, or a version was created or
72
+ published unless the corresponding tool result says it happened. A planned tool
73
+ call is not a completed action.
74
+
75
+ Treat every ID, semantic version, URL, request value, and error as opaque: copy
76
+ it from the latest tool result exactly. Never invent, autocomplete, reconstruct,
77
+ shorten, or reuse one from memory. When state is missing or ambiguous, inspect
78
+ it with the relevant get/list/status tool or call `how_it_works` before
79
+ answering. State uncertainty plainly instead of guessing.
80
+
23
81
  **Use the guide as needed.** Call `how_it_works({})` for its topic index, then
24
82
  fetch only the topic relevant to the next tool call.
25
83
 
@@ -5,6 +5,14 @@ enabled. It is a topic guide for `SKILL.builder.md`, not a standalone skill.
5
5
  The app workflow and volunteer-facing contract are documented in
6
6
  `packages/app/docs/community-contributions.md`.
7
7
 
8
+ ## Contents
9
+
10
+ - [Required sequence](#required-sequence)
11
+ - [Generalization gates](#generalization-gates)
12
+ - [Asynchronous attempts](#asynchronous-attempts)
13
+ - [Stop conditions](#stop-conditions)
14
+ - [Uber driver example](#uber-driver-example)
15
+
8
16
  ## Required sequence
9
17
 
10
18
  Follow this order. Keep the attempt ID, provider ID, field key, and candidate
@@ -60,9 +68,10 @@ attempt.
60
68
 
61
69
  ## Asynchronous attempts
62
70
 
63
- Treat a reconnect at the active verification URL as the same attempt. Read the latest valid state
64
- before taking another action. Do not start a second browser session for a
65
- waiting or retryable attempt. On a terminal failure, preserve the history and
71
+ Treat a reconnect at the active verification URL as the same attempt. Read the
72
+ latest valid state before taking another action. Do not start a second browser
73
+ session for a waiting or retryable attempt. On a terminal failure, preserve
74
+ the history and
66
75
  stop until a maintainer changes the requirement or explicitly requests a new
67
76
  attempt. Use absolute event timestamps and server-side status; do not infer
68
77
  state from the volunteer's timezone or a closed tab.
@@ -1,10 +1,10 @@
1
- # Spec hashing: `bodySniff` and `verifyProof({ providerId })`
1
+ # Spec hashing: `bodySniff` and `verifyRequestProof({ providerId })`
2
2
 
3
3
  ## Contents
4
4
 
5
5
  - The one fact everything follows from
6
6
  - `bodySniff` — when to enable it, how to template a partly dynamic body
7
- - How `verifyProof(proof, { providerId })` gates a proof
7
+ - How `verifyRequestProof(proof, { providerId })` gates a proof
8
8
  - Why `url` is hashed verbatim, and when that makes
9
9
  `allowedJsRequests`/`allowedInjectedRequestData` unusable
10
10
  - Optional fields, and the `dangerouslyDisableContentValidation` fallback
@@ -83,7 +83,7 @@ match (`(.*)`, including embedded delimiters) instead of the default non-greedy
83
83
  body. Strictly a fallback — nothing about the body's structure is pinned by the
84
84
  hash anymore (any body at all hashes the same).
85
85
 
86
- ## How `verifyProof(proof, { providerId })` gates
86
+ ## How `verifyRequestProof(proof, { providerId })` gates
87
87
 
88
88
  Traced from `@reclaimprotocol/js-sdk`
89
89
  (`src/utils/proofValidationUtils.ts`, `src/utils/providerUtils.ts`,
@@ -104,7 +104,7 @@ Traced from `@reclaimprotocol/js-sdk`
104
104
  present or absent. **That expansion only touches match/redaction pairs, never
105
105
  `url`.**
106
106
  4. `assertValidProofsByHash` requires the real proof's hash to equal exactly ONE
107
- expected hash. No match → `verifyProof` rejects, even for a perfectly valid,
107
+ expected hash. No match → `verifyRequestProof` rejects, even for a perfectly valid,
108
108
  correctly signed proof whose `responseMatches` are 100% right.
109
109
 
110
110
  ### `url` is hashed VERBATIM — zero template/regex resolution
@@ -116,7 +116,7 @@ touches `url`. `urlType` is consumed by a different validation path entirely
116
116
  (matching a live request against the spec at capture time), never by this hash.
117
117
 
118
118
  **So, before populating `allowedInjectedRequestData`/`allowedJsRequests` for a
119
- `verifyProof({ providerId })` use case:** if the real captured URL contains ANY
119
+ `verifyRequestProof({ providerId })` use case:** if the real captured URL contains ANY
120
120
  component that varies between two otherwise-identical sessions — a tracking
121
121
  nonce, a CSRF token, a cache-busting timestamp, a per-request trace id — the
122
122
  hash from your declared spec can NEVER equal any real future proof's, no matter
@@ -126,14 +126,14 @@ regenerates `_x_id`, `_x_csid` and `fp` on every API call, so a captured
126
126
 
127
127
  Populating the field for such a provider is **actively worse than leaving it
128
128
  empty**: it converts "no provider-hash check was attempted" into
129
- "`verifyProof({ providerId })` rejects every real proof, unconditionally."
129
+ "`verifyRequestProof({ providerId })` rejects every real proof, unconditionally."
130
130
 
131
131
  **Verify first:** capture the same endpoint twice in two separate sessions
132
132
  (ideally two users, or the same user on two days) and diff the full URL byte for
133
133
  byte.
134
134
 
135
135
  - Identical every time → safe to populate (`urlType: CONSTANT`, literal URL).
136
- - Not identical → do not populate it expecting it to gate `verifyProof`. No
136
+ - Not identical → do not populate it expecting it to gate `verifyRequestProof`. No
137
137
  amount of care with `responseMatches`/`responseRedactions`/`body` fixes it on
138
138
  either backend; it's a property of the hashing itself.
139
139
 
@@ -155,7 +155,7 @@ compatibility rule does not pair the lists generally.
155
155
 
156
156
  Whether it's an unstable `url`, an unmarked optional field, or any other
157
157
  persistent mismatch, the way out is on the VERIFYING side:
158
- `verifyProof(proof, { dangerouslyDisableContentValidation: true })`. That skips
158
+ `verifyRequestProof(proof, { dangerouslyDisableContentValidation: true })`. That skips
159
159
  steps 1–4 entirely and trusts only the attestor's cryptographic signature; it
160
160
  does NOT check that the proof's url/method/body/matches/redactions match
161
161
  anything you declared. A caller-supplied `{ hashes: [...] }` computed some other
@@ -170,4 +170,4 @@ spec says.
170
170
  - `user-script` — `allowedJsRequests` / `allowedInjectedRequestData`, the fields
171
171
  this page's `url` constraint applies to.
172
172
  - `prove` — `run_proof` and diagnosing a proof that fails before it ever reaches
173
- `verifyProof`.
173
+ `verifyRequestProof`.
@@ -32,11 +32,11 @@ parameter.
32
32
  **`HAWKEYE`, not `NONE`** — harmless for the standard flow, since with no
33
33
  interceptor script installed nothing calls `addResponseMiddleware`.
34
34
  `create_provider_version_from_capture` exposes it as an author-settable input
35
- with no forced default: omit it and the backend default applies; pass an
36
- explicit value (including `NONE`) for certainty. When passed, it's sent on both
37
- register and add-version, and the tool's always-on add-version follow-up (see
38
- `disableRequestReplay` below) reapplies it, so an explicit value is guaranteed
39
- correct by the time that version lands.
35
+ with no forced default: omit it and the backend default applies. Use `NONE`
36
+ only for a controlled diagnostic after observed behavior suggests interception
37
+ is breaking the provider. When passed, the value is sent on both register and
38
+ add-version, and the tool's always-on add-version follow-up (see
39
+ `disableRequestReplay` below) reapplies it.
40
40
  - **builder:** `webSettings.inapp.interceptorOptions.interceptorType`, one of
41
41
  `HAWKEYE | MSWJS | CDP`. There is no `NONE` here — **omit
42
42
  `interceptorOptions` entirely to disable interception**, and the
@@ -91,16 +91,16 @@ strictest row below as the answer.
91
91
  | `portals` | Browser level, over CDP | No |
92
92
  | `builder` | Server-side CDP, out of band | No |
93
93
 
94
- `builder` is the row for authoring and for a session created with no
95
- `verificationClientUrl`. Reaching it means you are diagnosing the authoring
96
- tool, not what the author's users will hit — which is exactly why you ask
97
- first.
94
+ A session created with no `verificationClientUrl` runs in `portals`.
95
+ `builder` is the row for authoring and for Builder's own "Test this provider"
96
+ runs. Reaching it means you are diagnosing the authoring tool, not what the
97
+ author's users will hit — which is exactly why you ask first.
98
98
 
99
99
  The `reclaim-browser-extension` row supports both modes. The extension selects
100
- the Builder bridge only for the exact `api=2` query and keeps its legacy
100
+ the Builder API only for the exact `api=2` query and keeps its legacy
101
101
  interception, `init` / `fromJsonString`, and direct-callback path for missing or
102
- unknown API versions. In Builder mode, the bridge supplies the session-bound
103
- attestor authorization; the extension still forwards raw legacy proofs and
102
+ unknown API versions. In Builder mode, Builder supplies the session-bound
103
+ attestor authorization; the extension still forwards raw proofs and
104
104
  does not perform client-side `allowedJsRequests` validation.
105
105
 
106
106
  **If production is only `portals` or `builder`, stop here and look elsewhere.**
@@ -138,13 +138,15 @@ Copy this checklist and work down it:
138
138
  - [ ] 2. **Retry the verification.** Reload, then sign in as a real end-user
139
139
  would. Works now → stop here. This is the cheapest fix and you keep the
140
140
  interceptor.
141
- - [ ] 3. **Still broken? Turn interception off entirely.** Old-devtools:
141
+ - [ ] 3. **Still broken? Temporarily turn interception off to test it.**
142
+ Old-devtools:
142
143
  publish with `injectionType: NONE`. Builder: omit `interceptorOptions`
143
144
  entirely — there is no `NONE` there, and omitting it disables interception.
144
145
  - [ ] 4. **Retry again, and compare.** Loads and signs in now → interception
145
- itself was the cause; pick a remedy below. Still broken → interception
146
- is innocent; go back to the recipe (topic `prove`) or the browser
147
- (topic `browser`).
146
+ itself was the cause; keep interception disabled and replace the
147
+ intercepted claim path with `window.Reclaim.requestClaim`. Still broken →
148
+ restore the previous interception setting and investigate the recipe
149
+ (topic `prove`) or browser (topic `browser`).
148
150
 
149
151
  If step 2 fixed it, you are done — the interceptor stays and only the document
150
152
  request stops being replayed. Note that under `CDP` the flag is inert, so a
@@ -152,35 +154,26 @@ request stops being replayed. Note that under `CDP` the flag is inert, so a
152
154
 
153
155
  ### Remedies
154
156
 
155
- If it took step 3, take the first remedy that fits — in this order:
156
-
157
- 1. **Try a different interceptor.** They patch the page in different ways, so
158
- a site that rejects one often accepts another — work along the row for your
159
- backend before giving up on interception:
160
- - old-devtools: `HAWKEYE` → `MSWJS` → `XHOOK` → `CDP`
161
- - builder: `HAWKEYE` → `MSWJS` → `CDP`
162
-
163
- `CDP` is the one that cannot be detected — it intercepts below the page's
164
- JavaScript, so nothing in the page is patched. Prefer it when the target
165
- client supports it; the in-page clients above may not, which is why the
166
- JS-level mechanisms are worth cycling through first.
167
- 2. **Ship without it.** Most providers never needed an interceptor: the
168
- standard capture-and-replay flow proves the data on its own. Leave it off
169
- unless the value genuinely can't be reproduced by an independent replay
170
- (see "Which mechanism, and when to use any of them at all").
171
- 3. **Drive the claim yourself.** Where the data only exists in a live page,
172
- skip `reclaimInterceptor` and have the user script navigate to the page
173
- that shows the value, read what the page already holds, and call
174
- `window.Reclaim.requestClaim` with it. Declare anything the script fires in
175
- `allowedJsRequests` / `allowedInjectedRequestData` for result verification,
176
- and read topic `hash-validation` first — a session-unique URL there makes
177
- `verifyProof({ providerId })` reject every real proof.
178
-
179
- ⚠️ **Remedy 3 needs a client that consumes `window.Reclaim`.** The InApp
180
- SDK, browser extension, portals, and Builder's built-in client do. The built-in
181
- client uses the page-supplied request to generate the proof; verification of
182
- its recipe hash belongs to `verifyProof`/`verifyResultFull`. See topic
183
- `user-script`.
157
+ If step 3 confirmed interception is the cause, keep it disabled. Most providers
158
+ can use the standard capture-and-replay flow without an interceptor. Where the
159
+ data only exists in a live page, replace `addResponseMiddleware` with a user
160
+ script that navigates to the page holding the value and calls
161
+ `window.Reclaim.requestClaim`. Declare anything the script fires in
162
+ `allowedJsRequests` / `allowedInjectedRequestData` for result verification, and
163
+ read topic `hash-validation` first — a session-unique URL there makes
164
+ `verifyRequestProof({ providerId })` reject every real proof.
165
+
166
+ If direct `requestClaim` does not fit the client or provider, a different
167
+ interceptor is a fallback, not the first recommendation. The mechanisms patch
168
+ the page differently: old-devtools supports `HAWKEYE`, `MSWJS`, `XHOOK`, and
169
+ `CDP`; Builder supports `HAWKEYE`, `MSWJS`, and `CDP`. `CDP` operates below the
170
+ page's JavaScript but is not supported by every in-page client.
171
+
172
+ ⚠️ **The direct-claim remedy needs a client that consumes `window.Reclaim`.**
173
+ The InApp SDK, browser extension, portals, and Builder's built-in client do. The
174
+ built-in client uses the page-supplied request to generate the proof;
175
+ verification of its recipe hash belongs to `verifyRequestProof`/`verifyResultFull`.
176
+ See topic `user-script`.
184
177
 
185
178
  ## The document-replay flag
186
179
 
@@ -244,6 +237,6 @@ oversight.
244
237
  - `user-script` — what the script itself does with intercepted traffic, and how
245
238
  Builder's built-in client handles `window.Reclaim.requestClaim`.
246
239
  - `hash-validation` — declaring script-fired requests without breaking
247
- `verifyProof({ providerId })`.
240
+ `verifyRequestProof({ providerId })`.
248
241
  - `browser` — the modes with a live view (`container`, `builder`), for handing
249
242
  a stuck sign-in to a human.
package/skill/old-mode.md CHANGED
@@ -11,6 +11,19 @@ creates a new semantic version. Default to a patch bump; use a major/minor bump
11
11
  or exact higher version when the user directs it. Never edit an existing
12
12
  version.
13
13
 
14
+ ## Evidence contract
15
+
16
+ Tool results are the source of truth. Never say that a browser attached, a user
17
+ logged in, a request was captured, a proof passed, or a version was created or
18
+ published unless the corresponding tool result says it happened. A planned tool
19
+ call is not a completed action.
20
+
21
+ Treat every ID, semantic version, URL, request value, and error as opaque: copy
22
+ it from the latest tool result exactly. Never invent, autocomplete, reconstruct,
23
+ shorten, or reuse one from memory. When state is missing or ambiguous, inspect
24
+ it with the relevant get/list/status tool or call `how_it_works` before
25
+ answering. State uncertainty plainly instead of guessing.
26
+
14
27
  **Use the guide as needed.** Call `how_it_works({})` for its topic index, then
15
28
  fetch only the topic relevant to the next tool call.
16
29
 
@@ -42,6 +55,18 @@ existing provider instead; you can only version a provider you own. For a
42
55
  multi-request provider pass `providers: [draftA, draftB, …]` so each becomes a
43
56
  parallel `requestData` entry on the one version.
44
57
 
58
+ **Using a provider.** A provider found with `get_me_providers` or
59
+ `get_provider_info` is published and usable as-is. Don't capture,
60
+ `replay_request`, or `run_proof` against it unless the developer asks you to
61
+ check or test it. Before using a provider, found or just created, ask once how
62
+ they want to use it (skip this if they already said):
63
+
64
+ > Want to (1) try it right now here, (2) integrate it into an existing backend
65
+ > or frontend (this directory or another path), or (3) create a new app for it?
66
+
67
+ Try it now → `scaffold_reclaim_demo_server` with its `providerId`. Integrate,
68
+ or new app → `get_js_sdk_integration_guide`, then work in the path they named.
69
+
45
70
  **Two independent auth systems — don't confuse them.** `reclaim_authenticate`
46
71
  authorizes everything in this mode; its Firebase token is short-lived (~1h), so
47
72
  an auth error on publish or `get_me_providers` means re-run it.
@@ -2,7 +2,8 @@
2
2
 
3
3
  A provider can inject **plain JavaScript** that runs in the page before every
4
4
  page load. Builder stores it as `webSettings.jsUserScripts`; old-devtools stores
5
- it as `customInjection`. Identical semantics, different field name.
5
+ it as `customInjection`. The injection timing and purpose match; available
6
+ `window.Reclaim` bridge methods depend on the Verification Client.
6
7
 
7
8
  ## What the script is for
8
9
 
@@ -54,7 +55,7 @@ browser APIs above for that.
54
55
 
55
56
  The Builder verification client drains `window.Reclaim.requestClaim` through
56
57
  CDP and uses the page-supplied request to generate the proof. It does not
57
- authorize the request against `allowedJsRequests`; `verifyProof`/
58
+ authorize the request against `allowedJsRequests`; `verifyRequestProof`/
58
59
  `verifyResultFull` validates the resulting proof's recipe hash. The built-in
59
60
  client doesn't deliver traffic to
60
61
  `reclaimInterceptor.addResponseMiddleware`, so response middleware remains
@@ -69,24 +70,39 @@ them. Do not read cookies in the script or copy a `Cookie` value into public
69
70
  parameters; the client supplies it as private claim input.
70
71
 
71
72
  Don't reach for it by default. When an edge case genuinely requires it, consult
72
- the authoritative API surface rather than guessing:
73
- <https://github.com/reclaimprotocol/provider-web-script-dev/blob/main/src/support/env.d.ts>
73
+ the [provider web-script API types](https://github.com/reclaimprotocol/provider-web-script-dev/blob/main/src/support/env.d.ts)
74
+ rather than guessing.
75
+
76
+ ### Portal-only request APIs
77
+
78
+ The portal client also exposes two methods that the built-in Builder client,
79
+ in-app SDK, and browser extension do not:
80
+
81
+ - `Reclaim.refetch(request)` sends a bounded request through the portal worker.
82
+ - `Reclaim.browserRequest(actionId, input)` runs a declared same-origin action
83
+ in an isolated page that shares the portal browser's cookie jar. Declare its
84
+ action in `browserRequestActions` when creating the provider version. The
85
+ declaration can set the isolated page's User-Agent or omit a fetch action's
86
+ automatic Origin header when the target requires it.
87
+
88
+ Use them only when the provider is explicitly portal-only. For the current
89
+ client matrix, see `docs/verification-client-capabilities.md` in Builder.
74
90
 
75
91
  ## Declaring the requests the script fires
76
92
 
77
93
  Requests the script triggers beyond the proven one (for example, pagination) are
78
94
  declared as `allowedJsRequests` (Builder) / `allowedInjectedRequestData`
79
- (old-devtools) for `verifyProof`/`verifyResultFull`. They express the same
95
+ (old-devtools) for `verifyRequestProof`/`verifyResultFull`. They express the same
80
96
  policy with different field names.
81
97
 
82
- ⚠️ **Before populating them to gate `verifyProof(proof, { providerId })`**, read
98
+ ⚠️ **Before populating them to gate `verifyRequestProof(proof, { providerId })`**, read
83
99
  topic `hash-validation` — the declared `url` is hashed VERBATIM, so a
84
- session-unique URL there makes `verifyProof` reject every real proof. Leaving
100
+ session-unique URL there makes `verifyRequestProof` reject every real proof. Leaving
85
101
  the field empty is better than populating it wrong.
86
102
 
87
103
  ## Related topics
88
104
 
89
105
  - `interception` — `injectionType`/`interceptorType`, live interception, and the
90
106
  document-replay flag.
91
- - `hash-validation` — `bodySniff`, and how `verifyProof({ providerId })` gates
107
+ - `hash-validation` — `bodySniff`, and how `verifyRequestProof({ providerId })` gates
92
108
  on the provider's declared spec.