Noter Example
The noter example (apps/noter) is a note-taking app with zkLogin sign-in, so users authenticate with OAuth instead of managing a wallet. It shows the note-to-memory pattern: free-form writing becomes structured facts that recall can find later.
How it uses Walrus memory
Noter keeps a shared server-side Walrus Memory client and uses analyze to turn note content into discrete facts, which the relayer stores as separate memories, and returns the text of each extracted fact:
export const extractMemories = async (text: string): Promise<string[]> => {
const memwal = getMemWalClient();
const result = await memwal.analyze(text);
return (result.facts ?? []).map((f) => f.text);
};
Because analyze stores each extracted fact as its own memory, later recall returns the specific fact that matches a query instead of a whole note. The user configures the delegate key and account at runtime.
Run it locally
Noter ships without an .env.example, so create apps/noter/.env yourself with the variables the noter README lists:
DATABASE_URLfor PostgreSQL- Google OAuth credentials:
GOOGLE_CLIENT_IDandGOOGLE_CLIENT_SECRET - The zkLogin endpoints
OPENROUTER_API_KEYNEXT_PUBLIC_APP_URL- The Walrus Memory values from the dashboard:
MEMWAL_PRIVATE_KEY,MEMWAL_ACCOUNT_ID, andMEMWAL_SERVER_URL
With the environment configured, create the database tables and start the app from the repo root:
Source: examples/noter.md$ pnpm install
$ pnpm --filter noter db:push
$ pnpm dev:noter
The app runs on localhost:3002.
How does zkLogin sign-in work in Noter?
Noter signs users in through Enoki zkLogin, which runs client-side in app/components/enoki-login-card.tsx and sui-providers.tsx. The Enoki wallet only gives the app a Sui address. To prove control of that address, the client signs a server-issued, single-use challenge with its zkLogin key, and the server verifies the signature against the address. Noter stores each challenge in Redis and removes it at verification, so nobody can replay a captured signature. On success, the app registers or looks up the user by Sui address and creates a session in the wallet_sessions table with walletType = "enoki".
The auth tRPC router (package/feature/auth/api/route.ts) also supports sign-in with a Sui wallet (connectWallet) and manual login with a delegate private key and account ID (connectDelegateKey).