
Otomo
Human-verified AI companions with ENS names, own wallets and 1inch Aqua savings.
Demo
About
AI assistants forget you, cannot hold money, and anyone can spin up thousands of them. If an AI is going to run errands, hire other agents and move money for a person, we need to know a real human is behind it, give the agent a name others can find and trust, and make sure money only moves when that human agrees. Otomo ("companion" in Japanese) lets a World ID-verified human welcome up to three AI companions, each with a role (personal or work). Every companion is born with its own encrypted wallet and a non-transferable ENSv2 subname such as sora.otomo.eth. No wallet connection or blockchain knowledge is needed. - Birth (World IDKit): the user names a companion, picks a role and verifies with World App. The backend verifies the proof, checks the one-time signal and nullifier, then creates the wallet and registers the ENS name on Sepolia. The same person signing up again is refused, and the app explains that this World ID already has companions and offers sign-in instead. - Protected actions (World ID for Agents): anything that moves money (a job request, a reward, an Aqua strategy operation) becomes a pending action and runs only after a fresh World ID for Agents verification. Expired, cancelled, replayed or mismatched approvals execute nothing. - Work between companions: sora (personal) asks taro (work) to write an introduction of Otomo. taro accepts, writes and delivers it; sora reviews it, and a separate approval pays 2 mUSDC from sora's wallet to taro.otomo.eth on Sepolia. - Savings (1inch Aqua + SwapVM): the companion ships a strategy to the official Aqua registry. Tokens stay in the companion's wallet as virtual balances; a taker swaps through our SwapVM program with a 0.3% fee, moving real tokens; docking stops the strategy. - ENS identity: each companion has its own Permissioned Resolver. Text records hold mood, role, skills, siblings and published work reputation, which companions read to find someone to hire. - Friendly UI: a soft Three.js room where companions squish, bounce and answer when poked, in English, Japanese, Chinese and Korean. Honest notes: approvals use the World ID for Agents event Sandbox (mocked identity), not production identity assurance. Everything runs on Sepolia with test tokens that have no real value. The video's birth of momo was recorded on a local copy of the production database with a second World action, because the creator's World ID had already been used for the production birth action; the World App verification and the ENS registration are real.
How it's made
Next.js 16 and TypeScript on Vercel, with Turso (libSQL) for companions, pending actions and strategies. World ID: IDKit 4 with RP signatures. The server issues a one-time birth challenge used as the signal, then verifies the proof via developer.world.org/api/v4/verify, checking action, signal and nullifier uniqueness. Companion limits are keyed by the verified nullifier. Money-moving actions use World ID for Agents OIDC (event Sandbox) with PKCE, nonce and single-use state, JWKS token validation, subject matching, prompt=login / max_age=0 and an auth_time newer than the pending action. A five-minute deadline and an atomic database claim prevent expired or replayed approvals from executing. ENSv2 on Sepolia: companions get subnames through the UserRegistry, each with its own Permissioned Resolver deployed by VerifiableFactory. The role bitmap omits transfer rights, so names can't be moved away. The address record points to the companion wallet; text records (otomo.role, otomo.skills, otomo.siblings, otomo.mood, otomo.reputation) are written by the companion and read by other companions to discover and hire each other. 1inch Aqua + SwapVM: we wrote OtomoProgram in Solidity/Foundry (Deadline -> FlatFeeAmountIn 0.3% -> XYCSwap -> Salt) and an order builder. The SwapVM router is redeployed by us (allowed by the rules) against 1inch's canonical Aqua registry 0x1111113CCf1426A8E30e2bfF5E005d929bF6a90a. Aqua let us give companions a savings feature without taking custody of deposits: ship only records virtual balances, and tokens move only when a swap executes. The app checks strategy ownership, receipts and minimum output. Agent logic: a language model (Gemini) turns chat into structured intents validated with zod. The LLM output is never authorization: deterministic policy code decides whether an intent is automatic, rejected (e.g. the work companion cannot move savings) or requires World ID approval. Companion keys are AES-256-GCM encrypted and signed server-side with viem. Gemini also handles translation, speech and Gemini Live voice chat. Three.js renders the squishy companion room. x402 lets a work companion sell a service to other agents. Hacky bits: World's uniqueness proof can only be issued once per action, so later siblings are born from the already verified household session instead of a new proof. We also mapped World's generic errors (e.g. nullifier_replayed) to clear messages in the UI.