A permission screen for AI agents. Like your phone's Allow / Deny popup, but for AI: one field at a time, with a receipt.
🔗 Live demo: https://aipassport.vercel.app 🔗 Pitch deck: https://aipassport.vercel.app/pitch
Built for the Egoist AI Passport ideathon. Track: Agents (touches Work). Lane: Build.
Every new AI agent faces a bad trade. It starts from zero and re-asks everything, or it grabs your whole profile and shares it around. Neither one asks per field. Neither one leaves a trace.
Job hunting makes the stakes obvious. You want an agent to apply for you. You do not want it broadcasting your current salary, or telling recruiters where you work right now. One field, in the wrong hands, costs you leverage or your job.
Juno is an AI recruiter. To brief a hiring team it wants four things about you:
| Field | Shared? |
|---|---|
work.skills |
✅ you approve |
work.history |
✅ you approve |
goals.target_role |
✅ you approve |
profile.current_salary |
❌ you deny |
You approve three and deny your salary. Juno gets a scoped answer with three fields, not four. Your salary never leaves your passport. Juno proposes one memory update ("open to remote, not relocation") and you decide. Every read and write becomes a signed receipt you can verify and revoke.
The page shows both sides at once. Left: without a passport, one tap hands your whole profile to eight recruiters with no receipt and no undo. Right: the passport flow, scoped and audited.
The deny is the demo. Approve-all proves nothing. Refusing one field, and watching the answer shrink, is the whole point.
We already solved consent for the things around personal context. Logins got OAuth. Payments got Google's AP2, which proves a human authorized an action when no human is present. Your personal context got nothing.
That is the gap. AI Passport is OAuth for the self: exactly the fields an agent needs, scoped, time-boxed, and receipted.
The demo maps one-to-one to the AI Passport model:
- Context — the fields an app reads, and the memory it proposes to write back.
- Permissions — a per-field approval gate, bound to a stated purpose and a duration.
- Proof — a signed receipt of every read and write, verifiable and revocable.
Presentation over a mocked passport layer that speaks the real request shape:
POST /api/app/request → an app requests read:[fields] + purpose + duration
POST /api/passport/approve → per-field grant, returns scoped context only
POST /api/app/propose-write → the app proposes one memory update
POST /api/passport/confirm-write → you accept or decline the write
GET /api/passport/state → current requests, grants, receipts, memory
POST /api/passport/revoke → flip a grant to revoked, live
POST /api/app/slurp → the villain: grabs everything, no consent, no receipt
State lives in an in-memory store. Grants and receipts carry mock Ed25519/DSSE-style signatures so the flow is real without a live Egoist API. The data model is field-generic; the recruiting case is one seeding of it.
pnpm install
pnpm dev # http://localhost:3000 (demo) · /pitch (deck)
pnpm build # production build- Next.js 15 (App Router) on Vercel
- Mantine 8 for the UI, Fira Sans + Fira Code
- TypeScript, in-memory store, mock-signed grants and receipts
- No Tailwind, no emoji, no gradient — editorial two-tone by design
src/
app/
page.tsx demo: narration band + split-screen
pitch/page.tsx 8-slide keyboard-driven deck
api/ passport + app mock endpoints
components/
WithPanel.tsx the passport side: gate, scoped context, receipt
WithoutPanel.tsx the villain side: the slurp
PremiseBar.tsx header + reset
ui.tsx shared primitives (no icon deps)
lib/
contract.ts the request/grant/receipt types and demo seed
mock.ts, store.ts the in-memory passport engine
The passport layer is a mock. There is no live Egoist API behind this, and the signatures are illustrative, not a real trust root. The point is the interaction: per-field consent, a purpose, a duration, and a receipt you can check.
Concept and product: Egoist Machines / AI Passport. This is an ideathon entry, not affiliated with Egoist.