Self-hosted Reclaim runner#
The runner is an independently operated, credential-bearing component. Web and mobile never receive RECLAIM_APP_ID or RECLAIM_APP_SECRET; they import a package or pair with a short-lived wallet-bound session.
Configuration#
Use RECLAIM_CREDENTIALS_FILE to reference a non-empty, runner-owned, regular
file with mode 0600. Validate the existing secret-manager mount with
seesaw-reclaim-runner check; do not render RECLAIM_APP_SECRET into a
predictable /tmp path or expand it into a shell command. Bind remote
deployments only with HTTPS and a bearer token. Keep the state directory on a
writable volume owned by the runner user; one runner process owns a state
directory at a time.
This repository does not publish a live-proof GHCR image or a Reclaim SDK adapter. Build and pin the runner from a reviewed commit, then mount a reviewed ESM adapter for live zkFetch/official-SDK execution. Publish the adapter source, integrity digest, review record, and image digest through your own release process before advertising live public use. Fixture adapters are for offline certification only; PRW-2 live evidence remains an operator-supplied gate.
Browser origins (CORS + CSP)#
The Reclaim submission page (/{locale}/reclaim/submit) calls the runner directly from the
browser, so both ends must name each other:
| Side | Variable | Meaning |
|---|---|---|
| Runner | RECLAIM_RUNNER_ALLOWED_ORIGINS | Comma-separated browser origins the runner answers. An allowed origin gets Access-Control-Allow-Origin on every response plus a 204 answer to the OPTIONS preflight; anything else gets a bare 403 {"error":"origin not allowed"} with no CORS headers. |
| Web app | NEXT_PUBLIC_RECLAIM_RUNNER_ORIGINS | Comma-separated runner origins added to the page's CSP connect-src. Without this the browser blocks the request before it leaves the tab. |
Both default sensibly for the local gate: the web app allows http://localhost:8787 (the
endpoint the pairing field placeholders) when NODE_ENV is not production, and the runner
accepts any origin when the allowlist is unset outside production.
In production both are fail-closed. With NODE_ENV=production and no
RECLAIM_RUNNER_ALLOWED_ORIGINS, the runner refuses every browser request with
403 {"error":"origin allowlist not configured"} (non-browser callers, which send no
Origin header, keep working). With no NEXT_PUBLIC_RECLAIM_RUNNER_ORIGINS, the web app's
CSP names no runner at all. Plain http:// is accepted on both sides only for loopback
hosts, matching the client-side rule in apps/web/lib/reclaimRunner.ts.
Abuse controls#
Requests are template/version allowlisted, bounded, idempotent, rate-limited, and budgeted by request, wallet, market, day, month, and concurrency. Duplicate requests reuse the ledger entry. Quota blocks are terminal and do not invoke zkFetch.
Lifecycle safety#
Clients review the proof against the active deployment and Reclaim epoch before signing. The V1 planner binds the signed market, program, lifecycle purpose, and epoch snapshot, then prepares the verifier proof buffer and the Seesaw semantic instruction. Seesaw invokes the verifier through CPI; this path does not use an Ed25519 adjacency requirement or a signature-precompile instruction.
The runner supplies proof material; it does not choose the settlement outcome. Follow the Reclaim SDK guide for staged submission, account validation, and the exact trust statement presented to signers.
<!-- src: packages/core/src/reclaimV1Orchestration.ts:336 buildReclaimV1Plan -->