
Hanami
Whitelist screening by an AI bouncer you own: proof-of-human door, TEE interview, revocable ticket
Demo
About
Nobody can hand-screen 4,400 applicants for 200 whitelist spots. So projects fall back on forms, which get gamed by lunchtime, or captchas, which get solved by farms for pennies. Hanami runs the first pass instead, as a conversation, and leaves the founders with only the borderline cases to read. You write your bouncer: who it is, what it cares about, what it refuses. That character gets minted as an ERC-7857 iNFT you own, and its reputation accrues on the token, so a bouncer that has worked ten doors carries that record into the eleventh. Sell it and the history goes with it. Before it can work a door at all it has to pass its own vetting. Hanami runs eight adversarial scenarios through the enclave against your exact persona, and mint stays locked unless all eight decisions come back correct and every one of them is TEE verified. A bouncer that can be flattered or threatened into a yes never gets deployed. For the applicant it goes: pick a campaign, prove you're a person with World ID, see what the bouncer is about to read about you, then talk to it. The proof-of-human step is not optional and not a checkbox. It binds one human to one attempt on that campaign, so buying a hundred wallets buys you a hundred rejections. Before the interview starts, Hanami pulls your actual on-chain record across five NFT marketplaces and two exchanges through The Graph: how often you flipped inside a week of minting, whether you sold back to the same counterparty, how long you typically hold. The bouncer gets that as evidence it can raise with you. You get to see it first, which is the part people don't expect. Then it interviews you. Not a quiz with right answers, a conversation, and it decides. Every decision is written to 0G Chain with the attestation hash from the enclave that produced it, and anyone can check that hash in the browser in about fifteen seconds without connecting a wallet. An approval also mints you a soulbound ticket with an expiry, which a mint contract can gate on and the campaign owner can revoke from their Roster if something looks wrong later. Owners can still export a Merkle root for a mint contract on any EVM chain. An agent can also apply on a person's behalf, through World AgentKit, and the Roster shows which agent stood in for which human. The rules don't change for them. Live on 0G mainnet, chain 16661, both original contracts verified.
How it's made
Hanami is a TypeScript monorepo. Hono backend, Next.js 16 frontend, Foundry contracts deployed to 0G mainnet (chain 16661). 0G is doing three separate jobs, and all three are load-bearing. Compute runs the bouncer's interview inside a TEE. For the decision turn, we wired the Compute Direct broker instead of the Router, which means the attestation we write on chain is the provider's raw enclave signature rather than a boolean somebody hands us, and the browser recovers that signature to the provider's registered teeSignerAddress. Storage holds the persona, the transcript and the ledger brief, content-addressed. Chain holds the ERC-7857 bouncer iNFT plus two new contracts, Ticket and TicketGate, so an approval becomes a soulbound expiring ticket that any mint contract can check and the owner can revoke. World ID is the Door in front of every interview. IDKit 4 in the browser, idkit-server signRequest on our side, the v4 verify endpoint. The nullifier does most of the work: "one person, one attempt per campaign" is a UNIQUE(campaign_slug, nullifier) constraint and nothing else, and we never store a proof. Agents can apply on a person's behalf too, through AgentKit and AgentBook's lookupHuman, hitting the same table under the same rule. The Graph is how the bouncer gets a record to reason about instead of vibes. Because Messari's subgraphs are standardised, one Trade query covers five NFT marketplaces and one Swap query covers two exchanges. We read them in parallel under a 12-second budget and name every source on the applicant's receipt, including the ones that failed. Now the hacky parts. AgentKit rides on x402, so the natural way to challenge an agent is a 402 Payment Required even though we charge nothing, and there's no signal on an inbound request that says "I'm an agent". Challenging everyone would have sent a paywall status to every browser applicant, so we gate the 402 on a client hint our CLI sets and browsers never see it. World also has no way to ask for "Selfie Check, or Orb if that's what this person has", so we built our own strength ladder (device < selfie < orb) and check what came back against the campaign's floor. The one that actually cost us a demo: an action's verification level in the Developer Portal quietly overrides whatever preset the app requests. Our campaign was set to device on purpose so anyone with World App could pass; every layer on our side agreed, and people still got sent off to find an Orb. That one and five others are written up with versions and workarounds in docs/feedback-world.md.