Quickstart
Run Agent Passport locally and drive the Northbank Sandbox — a fake brokerage with a real API — from allow to deny to live revocation to a 403 block. About five minutes.
The demo bundle starts four things on your machine: the passport service (verify + mandates), the Northbank Sandbox brokerage (guarded by requireKYA), the principal & platform dashboards, and an MCP server + CLI for the agent. Storage is SQLite via Drizzle — no external services.
Prerequisites #
- Node.js 20+ and
npx. - Optional: Claude Code (or any MCP-capable runtime) to drive the agent through the MCP server. A plain CLI path is included if you'd rather not.
Everything is sandboxed: KYC is a stub with the same interface shape as Persona / Stripe Identity, and the sanctions screen is a stub. No real identity data, no real money.
Spin up the stack #
One command boots the passport, the demo brokerage, and both dashboards:
# boot passport + Northbank Sandbox + dashboards
npx @passport/demo up
# → passport http://localhost:4000
# → northbank http://localhost:4100 (guarded by requireKYA)
# → dashboard http://localhost:4200
Leave it running. The next steps use the dashboard for the human parts (KYC, issuing and revoking mandates) and the CLI or MCP server for the agent parts.
Onboard a principal #
Open the dashboard at http://localhost:4200 and create a principal. Run it through the sandbox KYC flow (any test input passes) to reach kyc: verified. Behind the scenes this is a POST /v1/principals plus the vendor callback.
curl -X POST http://localhost:4000/v1/principals \
-H "Authorization: Bearer $PLATFORM_KEY" \
-d '{ "type": "individual", "country": "US" }'
# → { "id": "prn_a1…", "kyc": "pending", "onboarding_url": "…" }
Register an agent & issue a mandate #
Register the agent's public key, then issue a scoped mandate. The demo agent is treasury-bot, and the mandate mirrors the pitch: account.refill up to $1,000 / transaction and $2,500 / week at Northbank.
# generate a keypair & register the public key → agt_…
passport agent init --name treasury-bot --runtime claude-code
# issue the mandate from the dashboard, or:
passport mandate issue \
--agent agt_9f… \
--action account.refill \
--max-per-tx 100000 \ # $1,000.00 (minor units)
--max-per-period 250000 \ # $2,500.00 / week
--period week --currency USD \
--platform plt_northbank
# → mnd_tr7… status: active
In the alpha the passport signs the mandate after the principal authorizes it in the dashboard — the CA model. The documented upgrade is principal-held keys / W3C Verifiable Credentials with identical semantics.
Present a signed assertion #
The agent signs a per-request assertion and calls Northbank. From Claude Code, use the MCP tool passport_present; or use the CLI directly:
# signs { mandate_id, action, amount, currency, platform_id, nonce, ts }
# with the agent key, attaches X-Passport, and calls Northbank
passport present --action account.refill --amount 500
# → ALLOW $500.00 remaining_this_period $2,000.00 vrf_9c1…
In Claude Code the same thing looks like a tool call — see the MCP server guide:
passport_present({ action: "account.refill", amount: 50000, currency: "USD" })
// → { decision: "allow", chain: {…}, verification_id: "vrf_9c1…" }
Walk the demo storyline #
Run these in order to see every decision path. This is the pitch:
passport present --action account.refill --amount 500 # ALLOW · remaining $2,000
passport present --action account.refill --amount 2000 # DENY per_tx_cap
passport present --action account.refill --amount 900 # ALLOW · remaining $1,100
passport present --action account.refill --amount 900 # ALLOW · remaining $200
passport present --action account.refill --amount 900 # DENY period_cap
# now revoke mnd_tr7… in the dashboard (one click), then:
passport present --action account.refill --amount 500 # DENY mandate_revoked (< 2s later)
# and an anonymous caller with no passport:
curl -s -X POST http://localhost:4100/v1/account/refill -d amount=250
# → HTTP 403 "KYA required" { onboarding_url: "…/kya/start" }
Each ALLOW returns the full resolved chain of agency and a JWS receipt. After Northbank executes the refill it can countersign the verification, producing a record signed by both sides.
Teardown #
npx @passport/demo down # stops services, keeps the SQLite audit log
npx @passport/demo reset # wipes local state for a clean run