@reclaimprotocol/agent 0.1.42 → 0.1.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,87 @@
1
+ # AI sessions: the first route for a backend integration
2
+
3
+ An AI session proves a claim about a user's account on a website. You describe
4
+ the claim. An AI agent completes it in a remote browser. You need no provider,
5
+ no capture, and no org keypair: Builder manages a hidden AI app key for each
6
+ org.
7
+
8
+ ## When to use it
9
+
10
+ Use AI sessions first for any claim about a user's account on a site, for
11
+ example "prove the user is a student at example.edu". Prefer them over
12
+ authoring a provider and creating regular sessions. Fall back to the provider
13
+ route only as [Fall back to a provider](#fall-back-to-a-provider) describes.
14
+
15
+ ## Set up
16
+
17
+ 1. Sign in (`get_me`, then `authenticate` on 401; topic `auth`) and pick the
18
+ org with `list_orgs`.
19
+ 2. Call `issue_org_token`. It writes `RECLAIM_ORG_SECRET` to the env file.
20
+ Never print the key.
21
+ 3. Add at least one callback subscription with `create_callback_subscription`.
22
+ For local development, call `proxy_callback_events({ port, path })` as
23
+ topic `integration` describes. Without a subscription, creating a session
24
+ returns 409.
25
+
26
+ ## Try it first
27
+
28
+ 1. Call `create_ai_verification_session`:
29
+ - `prompt`: the claim in plain words.
30
+ - `dataPoints`: `{ name, description, isOptional }` items. Include exactly
31
+ one required identifier. Other fields are optional. `isOptional` defaults
32
+ to `false`. Names match `^[A-Za-z_][A-Za-z0-9_]{0,63}$`. Describe each
33
+ one. Never invent values.
34
+ - `loginUrls`: the portal URLs, when the developer knows them.
35
+ - Omit `verificationClientUrl`. Only the portals verification client
36
+ supports AI sessions today, and it is the default. Don't pass another
37
+ client.
38
+ - Leave `isEmailVerificationAllowed` `false`. The email option isn't
39
+ working yet.
40
+ 2. Call `wait_for_ai_session`. Put the session's `verificationUrl` in the same
41
+ message as your question to the developer, and end your turn. Then wait
42
+ until the session is terminal.
43
+ 3. Inspect the outcome with `get_verification_session`,
44
+ `list_verification_events`, `list_verification_deliveries`, and
45
+ `read_callback_events`.
46
+
47
+ ## Write the backend code
48
+
49
+ Keep every secret on the server.
50
+
51
+ 1. Create the session server-side: `POST /verifications/ai-sessions` with the
52
+ org token. Use `reclaim.api('CreateAiVerificationSession', …)` from
53
+ `@reclaimprotocol/client`, or `fetch`.
54
+ 2. Return only `verificationUrl` to the frontend. The frontend opens it in an
55
+ iframe or a new tab.
56
+ 3. Receive the result on the callback endpoint. Verify it with
57
+ `reclaim.results.receive(body, { reclaimSessionId })` (client 0.1.44 or
58
+ later accepts results that have no provider). Topic `integration` has the
59
+ full route, including idempotent storage and `503` for retryable errors.
60
+ 4. Read the values from the verified proofs' `extractedParameters`. Every
61
+ required data point is present.
62
+ 5. Handle the three outcomes:
63
+ - `verification_success`: use the verified data.
64
+ - `verification_rejected`: read `reasonCode`. `missing-data-points` means a
65
+ required data point is missing. `context-mismatch` means the context
66
+ differs from the session's.
67
+ - `verification_error`: record the failure and offer a retry.
68
+
69
+ ## Verifying results
70
+
71
+ Builder checks regular sessions against provider recipes. AI-session proofs
72
+ come from Popcorn. Builder verifies them with the ai-sdk `verifyProofs`, then
73
+ checks the required data points and the context pin. AI results omit
74
+ `provider_id` and `resolved_version`. Verify both kinds with
75
+ `reclaim.results.receive` from `@reclaimprotocol/client` 0.1.44 or later.
76
+ Older clients reject AI results.
77
+
78
+ ## Fall back to a provider
79
+
80
+ Switch to the provider route (`start_integration` with route `provider`:
81
+ capture, provider, regular sessions) when:
82
+
83
+ - Lookup fails: 404 (no login page) or 422 (not verifiable).
84
+ - The session is rejected after one adjusted retry.
85
+ - The user can't finish it, or it errors or expires repeatedly.
86
+ - `503` persists.
87
+ - The developer prefers a deterministic provider.
@@ -6,8 +6,8 @@ Provider-authoring and verification tools for the Builder backend.
6
6
 
7
7
  ## Routing
8
8
 
9
- - "Add Reclaim to my app" or similar: call `start_integration` first and follow its plan. Don't ask what they want to do with the result.
10
- - A claim they describe (for example, "prove the user is over 18 on example.com"): build a new org-private provider for exactly that claim. Use an existing provider only when they name one or ask to reuse one (topic `discover`).
9
+ - "Add Reclaim to my app" or similar: call `start_integration` first (it defaults to AI sessions) and follow its plan. Don't ask what they want to do with the result.
10
+ - A claim about a user's account on a site (for example, "prove the user is a student at example.edu"): use AI sessions first (topic `ai-sessions`). Author a provider only as the fallback, or when they name or ask to reuse one (topic `discover`).
11
11
  - Intent unclear: ask one short question.
12
12
 
13
13
  ## Authoring rules
@@ -48,5 +48,5 @@ Treat every ID, version, URL, and value as opaque: copy it from the latest tool
48
48
  `how_it_works({})` lists topics. Fetch only the one for your next step:
49
49
 
50
50
  - `overview`: authoring checklist; `prove`, `publish`, `browser`: the details behind each step.
51
- - `integration`: app integration, trying a session without an app, existing `@reclaimprotocol/js-sdk` projects.
51
+ - `ai-sessions`: the first route for proving a claim; `integration`: app integration, trying a session without an app, existing `@reclaimprotocol/js-sdk` projects.
52
52
  - `auth`: sign-in (`get_me`, then `authenticate` on 401) and backend mode.
@@ -5,7 +5,7 @@
5
5
  - The field, per backend
6
6
  - Which mechanism to pick, and when to use any of them at all
7
7
  - When a site won't load, or won't let the user sign in — ask which clients
8
- ship it, bisect, then the remedies
8
+ ship it, bisect, then the remedies (including the in-app Hawkeye hook mode)
9
9
  - The document-replay flag, and why the two backends invert its polarity
10
10
  - Recognizing live interception on a provider you didn't author
11
11
  - Related topics
@@ -169,6 +169,41 @@ the page differently: old-devtools supports `HAWKEYE`, `MSWJS`, `XHOOK`, and
169
169
  `CDP`; Builder supports `HAWKEYE`, `MSWJS`, and `CDP`. `CDP` operates below the
170
170
  page's JavaScript but is not supported by every in-page client.
171
171
 
172
+ ### In-app SDK: change how Hawkeye hooks `fetch`
173
+
174
+ Under `HAWKEYE`, the InApp SDK can wrap the page's `fetch` three ways, and a
175
+ site can break under one and work under another. Suspect this when the provider
176
+ works in Portals or Builder but the in-app page stalls: for example, a bot-check
177
+ or "one moment" screen that never clears, a sign-in form that never appears, or
178
+ the site's own scripts failing on requests they normally make. Try it before
179
+ removing interception, because it keeps the interceptor working.
180
+
181
+ Set the mode on the provider version, keeping `interceptorType: "HAWKEYE"`:
182
+
183
+ ```json
184
+ "clientOptions": { "inapp": { "interceptorOptions": {
185
+ "interceptorType": "HAWKEYE",
186
+ "interceptorSettings": "{\"interceptionMethod\":\"GETTER_SETTER\"}"
187
+ } } }
188
+ ```
189
+
190
+ `interceptorSettings` is a JSON object **string**. `interceptionMethod` is one
191
+ of:
192
+
193
+ - `PROXY` (default): wraps `fetch` in a `Proxy`, so `fetch.toString()` still
194
+ looks native.
195
+ - `GETTER_SETTER`: rebuilds each call as `new Request(input, init)`, and keeps
196
+ wrapping if the page reassigns `window.fetch`. Try this first.
197
+ - `DIRECT_REPLACEMENT`: the same wrapper, assigned once.
198
+
199
+ `GETTER_SETTER` and `DIRECT_REPLACEMENT` make `fetch.toString()` non-native. Some
200
+ anti-bot vendors check for that, so confirm with a real in-app verification;
201
+ authoring never exercises the in-app client. Optional `disableFormIntercept`
202
+ (default `true`) and `delayFormSubmitForFetch` (default `false`) go in the same
203
+ object. Keys you leave out keep the SDK's defaults, and other interceptor types
204
+ ignore `interceptorSettings`. If no mode works, go back to the bisect steps
205
+ above.
206
+
172
207
  ⚠️ **The direct-claim remedy needs a client that consumes `window.Reclaim`.**
173
208
  The InApp SDK, browser extension, portals, and Builder's built-in client do. The
174
209
  built-in client uses the page-supplied request to generate the proof;
@@ -0,0 +1,58 @@
1
+ # Plan: let users prove "{{goal}}" in this app with a Builder AI session
2
+
3
+ Follow this plan end to end. Mark each step done as you go. Do not ask the developer whether to integrate: integrating into this codebase is the goal.
4
+
5
+ An AI session needs no provider. The user prompt and data points tell Builder what to prove, and Builder finds the site and the login page. Only the portals verification client supports AI sessions today, so omit `verificationClientUrl` (portals is the default). Start with the steps that need the developer (sign in, try a session), and write app code while you wait.
6
+
7
+ **Asking the developer.** When you need an answer or an action, end your turn with the question. Don't use background or asynchronous question tools: the developer may never see them. Put every link they need in that same message. Ask each question once.
8
+
9
+ ## 1. Sign in and pick the organization
10
+
11
+ - [ ] Call `reclaim_authenticate` if you are not signed in. Give the developer the returned `signInUrl` to approve in their browser (end your turn first if `browserOpened` is false), then call `wait_for_sign_in`.
12
+ <!-- if:orgId -->
13
+ - [ ] Use organization `{{orgId}}` for every call below.
14
+ <!-- endif -->
15
+ <!-- ifnot:orgId -->
16
+ - [ ] Call `list_orgs`. Use the only organization, or ask the developer which one when there are several.
17
+ <!-- endif -->
18
+
19
+ ## 2. Get an org token
20
+
21
+ - [ ] If `RECLAIM_ORG_SECRET` is not in the server env file, call `issue_org_token` with the organization, this project's absolute path, and the server env file. It writes the key to that file and never returns it. Never print or commit the key, and confirm the env file is in `.gitignore`.
22
+
23
+ ## 3. Make sure results have a destination
24
+
25
+ - [ ] Call `list_callback_subscriptions`. If the organization has none, call `create_callback_subscription` for the session-ending events: `verification_success`, `verification_rejected`, `verification_error`, `verification_cancelled`, and `session_expired`.
26
+ - [ ] For local development, start the app's backend and call `proxy_callback_events({ port, path })` with the callback route's port and path. It forwards the org's verification events to that route on localhost, with no public URL. The proxy works only while this coding agent's MCP server runs.
27
+ - [ ] For production, ask the developer for the public callback URL, and call `create_org_callback_subscription` with it. If they have no deployed URL yet, tell them: "When you deploy, ask me to run `create_org_callback_subscription` with your public callback URL, or results will not reach the app."
28
+
29
+ ## 4. Read the guide
30
+
31
+ - [ ] Call `how_it_works({ topic: "ai-sessions" })` and follow it for request fields, session states, and error codes. Don't repeat its detail here.
32
+
33
+ ## 5. Try a session
34
+
35
+ - [ ] Call `create_ai_verification_session` with:
36
+ - `prompt`: a sentence for "{{goal}}", written as the claim to prove.
37
+ - `dataPoints`: the values the claim needs. Mark one identifier required. Mark the others optional. Add no profile or identity extras.
38
+ - `loginUrls`: the site's sign-in URLs, when you know them.
39
+ - [ ] Call `wait_for_ai_session` with the returned session ID, until the lookup is ready.
40
+ - [ ] Share the returned `verificationUrl` with the developer, in the same message as the ask: "Open this link, sign in to the site, and tell me when you are done." End your turn.
41
+ - [ ] After they reply, call `wait_for_ai_session` until the session reaches a terminal status. Use `read_callback_events({ sessionId })` to see the delivered result.
42
+ - [ ] The hosted verification page streams the target site as an image, so text or DOM checks of that page come back empty. Check progress with `wait_for_ai_session`, `list_verification_events`, and `get_verification_session`, not by reading the page.
43
+
44
+ ## 6. Write the backend integration
45
+
46
+ Write this while you wait on the developer. Don't let it delay a step that needs them.
47
+
48
+ - [ ] Detect the app's framework and package manager from the repository, and use them. Read `how_it_works({ topic: "integration" })`.
49
+ - [ ] Add a backend route that calls `POST /verifications/ai-sessions` server-side, with the same prompt, data points, and login URLs as step 5, and returns `verificationUrl`. Never call it from the browser: it needs the org key.
50
+ - [ ] Add a callback route that verifies each result with `reclaim.results.receive` from `@reclaimprotocol/client` version 0.1.44 or later, then stores only the requested data points. Store every failure on the verification session record and log it server-side. Respond `error.retryable ? 503 : 200`. A result that failed verification gets 2xx, because retrying can't fix it.
51
+ - [ ] Add a status route the frontend polls, and a frontend Verify button that opens `verificationUrl`. Render every state in "UI states" in `how_it_works({ topic: "integration" })`, including **Try again** on failure.
52
+ - [ ] If the org has a key pair (`get_org_keypair`), pass `orgEthPrivateKey` from `RECLAIM_ORG_ETH_PRIVATE_KEY` to `results.receive`. The developer puts that key in the env file, never in chat.
53
+ - [ ] If a permission check blocks a command, follow "Permission blocks" in the server instructions.
54
+
55
+ ## 7. Fall back to a provider when the session cannot work
56
+
57
+ - [ ] If `wait_for_ai_session` recommends a fallback, adjust the `dataPoints` or `loginUrls` as its result suggests and create one more session.
58
+ - [ ] If the retry also recommends a fallback, call `start_integration` with `route: "provider"` and the same `goal`, and follow the plan it returns. Keep the backend work from step 6: the provider plan reuses the callback route.
@@ -1,5 +1,7 @@
1
1
  # Plan: let users prove "{{goal}}" in this app
2
2
 
3
+ This is the provider route: the fallback when a Builder AI session cannot prove the claim, or the route you chose explicitly.
4
+
3
5
  Follow this plan end to end. Mark each step done as you go. Do not ask the developer whether to integrate: integrating into this codebase is the goal.
4
6
 
5
7
  **Order.** Do the steps that need the developer first: sign in to Builder, attach the browser, capture, and prove the provider (step 2). These need the developer at the browser, and they show early whether a proof is possible on this site. Write app code (step 3) after the proof works, or while you wait on the developer. Never spend a long stretch on app code before the developer has signed in and the browser is attached.
@@ -1,5 +1,8 @@
1
1
  # Integrate a Builder verification client
2
2
 
3
+ For a claim about a user's account on a site, start with topic `ai-sessions`.
4
+ This guide covers the provider route and the shared callback details.
5
+
3
6
  ## Set up an application with the coding agent
4
7
 
5
8
  For "add Reclaim to my app", call `start_integration` first and follow its
@@ -98,6 +101,18 @@ legacy devtools mode), or migrate to the Builder HTTP API?"
98
101
  from `VerificationClient` in the SDK. Do not send an unregistered URL or
99
102
  call a legacy backend for an `api=2` session.
100
103
 
104
+ A session only works in the client it was created for: Builder fixes the
105
+ client at creation, and any other client gets
106
+ `403 x-reclaim-vc-id does not match this session`. For a mobile app using
107
+ the in-app SDK or the add-to-app module, create every session with
108
+ `verificationClientUrl` set to
109
+ `https://build.reclaimprotocol.org/share/inapp-sdk`
110
+ (`VerificationClient.inAppSdk`); the default Portal link won't open there.
111
+ For native iOS or Android apps, follow the
112
+ [iOS SDK README](https://github.com/reclaimprotocol/reclaim-inapp-ios-sdk#readme)
113
+ or the
114
+ [Android SDK README](https://github.com/reclaimprotocol/reclaim-inapp-android-sdk#readme).
115
+
101
116
  The hosted verification page streams the target site as an image, so text
102
117
  and DOM checks of that page come back empty. Check a session's progress
103
118
  with `list_verification_events` and `get_verification_session` instead.
@@ -164,6 +179,60 @@ curl -X POST https://build.reclaimprotocol.org/verifications/sessions \
164
179
  }'
165
180
  ```
166
181
 
182
+ For an in-app SDK or add-to-app host, add the in-app SDK's client URL and pass
183
+ the returned `verificationUrl` to the app's `startVerificationFromUrl`:
184
+
185
+ ```bash
186
+ curl -X POST https://build.reclaimprotocol.org/verifications/sessions \
187
+ -H "authorization: Bearer $RECLAIM_ORG_SECRET" \
188
+ -H "content-type: application/json" \
189
+ -d '{
190
+ "providers": [
191
+ {
192
+ "providerId": "<your-provider-id>"
193
+ }
194
+ ],
195
+ "context": {
196
+ "userId": "abc"
197
+ },
198
+ "verificationClientUrl": "https://build.reclaimprotocol.org/share/inapp-sdk"
199
+ }'
200
+ ```
201
+
202
+ With `@reclaimprotocol/client`:
203
+
204
+ ```js
205
+ import { ReclaimVerification, VerificationClient } from '@reclaimprotocol/client'
206
+
207
+ const reclaim = ReclaimVerification.create({
208
+ orgSecret: process.env.RECLAIM_ORG_SECRET,
209
+ })
210
+
211
+ const session = await reclaim.sessions.create({
212
+ providers: [{ providerId: '<your-provider-id>' }],
213
+ context: { userId: 'abc' },
214
+ // Required for the in-app SDK and add-to-app module. Omitted, Builder
215
+ // selects the Portal, and the app's requests get 403.
216
+ verificationClientUrl: VerificationClient.inAppSdk,
217
+ })
218
+ // Store session.id; hand session.verificationUrl to the app.
219
+ ```
220
+
221
+ The app opens it with `startVerificationFromUrl(verificationUrl)`. If the
222
+ backend returns fields instead of a link, it calls
223
+ `startVerificationFromJson({ "api": "2", "sessionId": session.id })` with the
224
+ same result. Add `"diag": "1"` only when `verificationUrl` contains `diag=1`;
225
+ other keys are ignored.
226
+
227
+ For a native app, read the SDK's README before writing app code. Each README
228
+ has a Builder mode section covering installation, starting from a URL or
229
+ JSON, and handling the result:
230
+
231
+ - iOS (Swift):
232
+ [reclaim-inapp-ios-sdk](https://github.com/reclaimprotocol/reclaim-inapp-ios-sdk#readme)
233
+ - Android (Kotlin/Java):
234
+ [reclaim-inapp-android-sdk](https://github.com/reclaimprotocol/reclaim-inapp-android-sdk#readme)
235
+
167
236
  Receive and verify the result on the callback route. This is the one place the
168
237
  client package is needed:
169
238
 
@@ -1,5 +1,5 @@
1
1
  // AUTO-GENERATED by packages/app/scripts/mcp-tools-gen.ts
2
- // from packages/app/openapi.yaml (spec v0.1.0, source sha256:c3421d6bcf76).
2
+ // from packages/app/openapi.yaml (spec v0.1.0, source sha256:cbe3daf2a1f3).
3
3
  // The hash catches drift the version misses (a spec can change without a
4
4
  // version bump) — do not remove it as "redundant" with the version.
5
5
  // Run `npm run openapi:gen --workspace=packages/app` to regenerate. Do not edit by hand.
@@ -125,6 +125,7 @@ export const MCP_TOOLS = {
125
125
  "revenue",
126
126
  "usage",
127
127
  "goals",
128
+ "ai-session-prompts",
128
129
  "tools",
129
130
  "agents",
130
131
  "funnel"
@@ -505,6 +506,117 @@ export const MCP_TOOLS = {
505
506
  }),
506
507
  annotations: {"openWorldHint":false},
507
508
  },
509
+ "CreateAiVerificationSession": {
510
+ description: "Start an AI verification session from a prompt\n\nStarts an AI verification session from a plain-language prompt and optional dataPoints/loginUrls; returns the session with verificationUrl to share with the user. Needs the org token and at least one callback subscription (409 otherwise). No provider or org keypair needed: Builder manages the AI app key. Poll with get_ai_verification_session or wait_for_ai_session.",
511
+ inputSchema: toZod({
512
+ "type": "object",
513
+ "properties": {
514
+ "params": {
515
+ "type": "object",
516
+ "properties": {
517
+
518
+ }
519
+ },
520
+ "query": {
521
+ "type": "object",
522
+ "properties": {
523
+
524
+ }
525
+ },
526
+ "body": {
527
+ "type": "object",
528
+ "additionalProperties": false,
529
+ "description": "Body for `POST /verifications/ai-sessions`. Send a `prompt`, at least one entry in `dataPoints`, or both.",
530
+ "properties": {
531
+ "prompt": {
532
+ "type": "string",
533
+ "minLength": 0,
534
+ "maxLength": 10000,
535
+ "description": "What to verify, in plain language, such as \"verify I'm a student at Manipal University\". Required unless `dataPoints` has at least one item. Builder rejects a prompt that contains credentials, card numbers, instructions for the AI, or a sensitive claim. The prompt and the data point lines together can't exceed 10,000 characters."
536
+ },
537
+ "dataPoints": {
538
+ "type": "array",
539
+ "maxItems": 32,
540
+ "description": "The values to verify. Required unless you send a `prompt`. Names must be unique, and at least one data point must be required (its `isOptional` is `false` or absent). When you send data points, Builder keeps them and adds only optional data points that the prompt implies. When you send none, Builder chooses the data points from the prompt. Every required data point must appear in the verified proofs. If one is missing, the session ends as `rejected` with `reasonCode` `missing-data-points`.",
541
+ "items": {
542
+ "type": "object",
543
+ "additionalProperties": false,
544
+ "required": [
545
+ "name",
546
+ "description"
547
+ ],
548
+ "properties": {
549
+ "name": {
550
+ "type": "string",
551
+ "maxLength": 64,
552
+ "pattern": "^[A-Za-z_][A-Za-z0-9_]{0,63}$",
553
+ "description": "Name of the value, such as `username`. Starts with a letter or underscore, followed by up to 63 letters, digits, or underscores."
554
+ },
555
+ "description": {
556
+ "type": "string",
557
+ "minLength": 1,
558
+ "maxLength": 300,
559
+ "description": "What the value is and why it proves the claim."
560
+ },
561
+ "isOptional": {
562
+ "type": "boolean",
563
+ "description": "Defaults to `false`. If `true`, the claim can be proven without this value, and the proofs can omit it. If `false` or absent, the data point is required, and a session whose proofs omit it ends as `rejected` with `reasonCode` `missing-data-points`."
564
+ }
565
+ }
566
+ }
567
+ },
568
+ "loginUrls": {
569
+ "type": "array",
570
+ "maxItems": 10,
571
+ "description": "Pages where the user signs in, such as `https://portal.example.edu/login`. Builder shows them first as candidates with source `caller`, and skips the web search. Each URL must use `http` or `https`, can't contain credentials, and must resolve to a public host.",
572
+ "items": {
573
+ "type": "string",
574
+ "format": "uri",
575
+ "maxLength": 2048
576
+ }
577
+ },
578
+ "isEmailVerificationAllowed": {
579
+ "type": "boolean",
580
+ "description": "Defaults to `false`. If `true`, the share page offers the user a choice to verify using email instead of signing in. If you omit it, the page doesn't offer that choice."
581
+ },
582
+ "context": {
583
+ "type": "object",
584
+ "maxProperties": 50,
585
+ "additionalProperties": true,
586
+ "description": "Values you already know, such as `{\"fullName\": \"Asha Rao\"}`. Builder merges them over the values the prompt states and returns the result in `context`. Must not contain `attestationNonce` or `attestationNonceData`; bind those after you create the session. Also must not contain `reclaimSessionId`, `extractedParameters`, or `builderSessionId`. Omit if you have none."
587
+ },
588
+ "verificationClientUrl": {
589
+ "type": "string",
590
+ "description": "Base URL of the registered verification client the user verifies with, as for `POST /verifications/sessions`. Builder charges this client's quota pool. If you omit it, Builder uses the default (`portals`) client.",
591
+ "maxLength": 2000,
592
+ "pattern": "^https?://"
593
+ },
594
+ "geoLocation": {
595
+ "type": "string",
596
+ "description": "ISO 3166-1 alpha-2 country code, such as `IN`. Builder searches the web from this country (Google's `gl` parameter), so portals for that country rank first. If you omit it, the search has no country preference.",
597
+ "minLength": 2,
598
+ "maxLength": 2,
599
+ "pattern": "^[A-Za-z]{2}$"
600
+ }
601
+ }
602
+ },
603
+ "orgToken": {
604
+ "type": "string",
605
+ "pattern": "^rorg_",
606
+ "maxLength": 200,
607
+ "description": "The organization API key (`rorg_…`) this call authenticates with: from `issue_org_token`, or the app's RECLAIM_ORG_SECRET. Defaults to the MCP server's RECLAIM_ORG_SECRET. Never echo it back to the user."
608
+ }
609
+ },
610
+ "required": [
611
+ "params",
612
+ "query",
613
+ "body"
614
+ ],
615
+ "additionalProperties": false
616
+ }),
617
+ orgTokenOnly: true,
618
+ annotations: {"openWorldHint":false},
619
+ },
508
620
  "CreateCallbackSubscription": {
509
621
  description: "Register a callback subscription\n\nRegisters a destination for verification results on the organization\nthe presented `OrgToken` resolves to. At least one subscription must\nexist for the org before you can create a verification session.\nDelivery is scoped by org: terminal results are ECIES-encrypted to the\norg's eth public key when its `canEncryptResult` is enabled (see\n`PUT /orgs/{orgId}/keypair`), else delivered as plaintext.\n\nTo receive results at a URL, send `callbackUrl` and `events`. Builder\nPOSTs each delivery to that URL.\n\nTo read results without a public URL during local development, send\n`deliveryMode: \"pull\"`. Builder keeps the deliveries and you read them\nwith `GET /verifications/callback-events`. A pull subscription is a\n90-second lease: it receives events and satisfies the session-creation\ncheck only while the lease is unexpired. Send the same request about\nevery 30 seconds to renew it, and call\n`POST /verifications/callback-listener/release` when you stop. Production\nneeds a webhook subscription. An org has at most one pull subscription.\nIf it already exists, Builder renews it and returns it with status 200.\nIf the body includes `events`, they replace the subscription's events;\nif it omits them, the existing events are kept.\n",
510
622
  inputSchema: toZod({
@@ -5342,6 +5454,50 @@ export const MCP_TOOLS = {
5342
5454
  }),
5343
5455
  annotations: {"readOnlyHint":true,"openWorldHint":false},
5344
5456
  },
5457
+ "GetAiVerificationSession": {
5458
+ description: "Get what an AI verification session's prompt resolved to\n\nGets what the AI session's lookup found: status resolving|ready|started|failed, candidates (login pages), merged dataPoints, error. Use get_verification_session for the overall outcome.",
5459
+ inputSchema: toZod({
5460
+ "type": "object",
5461
+ "properties": {
5462
+ "params": {
5463
+ "type": "object",
5464
+ "properties": {
5465
+ "sessionId": {
5466
+ "type": "string",
5467
+ "format": "uuid",
5468
+ "description": "Verification session id (UUID v7 when supported). Also echoed in the result payload as `reclaimSessionId`."
5469
+ }
5470
+ },
5471
+ "required": [
5472
+ "sessionId"
5473
+ ],
5474
+ "additionalProperties": false
5475
+ },
5476
+ "query": {
5477
+ "type": "object",
5478
+ "properties": {
5479
+
5480
+ }
5481
+ },
5482
+ "body": {
5483
+ "type": "object"
5484
+ },
5485
+ "orgToken": {
5486
+ "type": "string",
5487
+ "pattern": "^rorg_",
5488
+ "maxLength": 200,
5489
+ "description": "The organization API key (`rorg_…`) this call authenticates with: from `issue_org_token`, or the app's RECLAIM_ORG_SECRET. Defaults to the MCP server's RECLAIM_ORG_SECRET. Never echo it back to the user."
5490
+ }
5491
+ },
5492
+ "required": [
5493
+ "params",
5494
+ "query"
5495
+ ],
5496
+ "additionalProperties": false
5497
+ }),
5498
+ orgTokenOnly: true,
5499
+ annotations: {"readOnlyHint":true,"openWorldHint":false},
5500
+ },
5345
5501
  "GetMe": {
5346
5502
  description: "Get the authenticated user\n\nGets the authenticated caller's own profile: id, email, and name. Requires a signed-in user session, not an OrgToken. Use it to confirm who the current credentials belong to.",
5347
5503
  inputSchema: toZod({
@@ -49,6 +49,7 @@ const SHARED_TOPIC_FILES: Record<string, string> = {
49
49
  /** Detailed topics that exist only in Builder mode. */
50
50
  const BUILDER_TOPIC_FILES: Record<string, string> = {
51
51
  'contributions': 'community-contributions.md',
52
+ 'ai-sessions': 'ai-sessions.md',
52
53
  'integration': 'verification-client-integration.md',
53
54
  }
54
55
 
@@ -78,6 +79,9 @@ const TOPIC_SUMMARIES: Record<string, string> = {
78
79
  + 'providers, and going live.',
79
80
  'discover': 'Reusing existing providers: finding, resolving, copying one '
80
81
  + 'that needs changes, and creating a verification session.',
82
+ 'ai-sessions': 'The first route for a backend integration: prove a claim '
83
+ + 'about a user\'s account with create_ai_verification_session, no '
84
+ + 'provider or capture. Setup, backend code, and when to fall back.',
81
85
  'integration': 'After start_integration: org key and keypair, callback '
82
86
  + '(local proxy_callback_events or deployed webhook), frontend and '
83
87
  + 'backend over the HTTP session API, js-sdk projects, trying a '
@@ -360,7 +360,14 @@ export function createVersionFromCaptureTool(
360
360
  interceptorSettings: {
361
361
  type: 'string',
362
362
  description:
363
- 'Free-form JSON config for the chosen interceptor.',
363
+ 'Free-form JSON config for the chosen interceptor, '
364
+ + 'as a JSON object string. For HAWKEYE in the '
365
+ + 'in-app SDK: {"interceptionMethod": PROXY | '
366
+ + 'GETTER_SETTER | DIRECT_REPLACEMENT}, plus '
367
+ + 'optional disableFormIntercept and '
368
+ + 'delayFormSubmitForFetch. Try GETTER_SETTER when '
369
+ + 'the in-app page stalls but Portals works; see '
370
+ + 'topic interception.',
364
371
  },
365
372
  isDocumentRequestReplayEnabled: {
366
373
  type: 'boolean',
@@ -8,6 +8,7 @@ interface StartIntegrationArgs {
8
8
  userRequest?: string
9
9
  orgId?: string
10
10
  providerIds?: string[]
11
+ route?: 'ai-session' | 'provider'
11
12
  }
12
13
 
13
14
  /**
@@ -22,7 +23,10 @@ export function startIntegrationTool(): RegisteredTool {
22
23
  name: 'start_integration',
23
24
  description:
24
25
  'Returns a step-by-step plan for adding Reclaim verification to the '
25
- + 'current codebase: sign in to Builder, attach the browser, capture, '
26
+ + 'current codebase. Recommends Builder AI sessions first: no '
27
+ + 'provider to build, just a prompt and data points. Use route '
28
+ + '"provider" to fall back to provider authoring, which is what '
29
+ + 'this describes: sign in to Builder, attach the browser, capture, '
26
30
  + 'and prove the provider first, then set up the app (session route, '
27
31
  + 'callback, Verify button, local event proxy) after the proof or '
28
32
  + 'while waiting on the developer, bootstrapping from the '
@@ -60,7 +64,16 @@ export function startIntegrationTool(): RegisteredTool {
60
64
  maxItems: 10,
61
65
  items: { type: 'string' },
62
66
  description:
63
- 'Existing provider IDs to use. Omit to build a new provider.',
67
+ 'Existing provider IDs to use. Implies route "provider".',
68
+ },
69
+ route: {
70
+ type: 'string',
71
+ enum: ['ai-session', 'provider'],
72
+ description:
73
+ '"ai-session" (default when providerIds is empty) plans a '
74
+ + 'Builder AI session. "provider" (default with providerIds) '
75
+ + 'plans provider authoring; use it as the fallback when an '
76
+ + 'AI session cannot prove the claim.',
64
77
  },
65
78
  },
66
79
  },
@@ -80,9 +93,15 @@ export function renderStartIntegration(args: StartIntegrationArgs): string {
80
93
  orgId: args.orgId,
81
94
  providerIds,
82
95
  }
96
+ // An explicit route wins, so 'ai-session' ignores providerIds.
97
+ const route = args.route
98
+ ?? (providerIds ? 'provider' : 'ai-session')
99
+ const file = route === 'ai-session'
100
+ ? 'start-ai-session-integration.md'
101
+ : 'start-integration.md'
83
102
  const template = readFileSync(
84
103
  fileURLToPath(
85
- new URL('../../../../skill/start-integration.md', import.meta.url),
104
+ new URL(`../../../../skill/${file}`, import.meta.url),
86
105
  ),
87
106
  'utf8',
88
107
  )
@@ -2,6 +2,7 @@ import type { RegisteredTool } from '../../server.ts'
2
2
  import { proxyCallbackEventsTool } from './proxy-callback-events.ts'
3
3
  import { readCallbackEventsTool } from './read-callback-events.ts'
4
4
  import { verificationResultTool } from './result.ts'
5
+ import { waitForAiSessionTool } from './wait-for-ai-session.ts'
5
6
 
6
7
  /**
7
8
  * Builder-mode verification tools: higher-level orchestrations over the
@@ -20,5 +21,6 @@ export function buildVerificationTools(): RegisteredTool[] {
20
21
  verificationResultTool(),
21
22
  readCallbackEventsTool(),
22
23
  proxyCallbackEventsTool(),
24
+ waitForAiSessionTool(),
23
25
  ]
24
26
  }