Skip to content

Repository files navigation

Inlet

A World Cup 2026 prediction agent whose memory lives on Walrus mainnet.

Make a prediction and it becomes a permanent blob with a public id. When the real match ends, a settler grades your call against the actual score and writes the verdict back into your memory. The agent remembers you, and anyone can prove it does, because the memory is on-chain.

The agent process keeps no local state. Every durable memory sits in Walrus under one MemWalAccount on Sui. Restart the server and nothing is lost.

Why it stands out

  • Verifiable memory. Each stored memory is a real Walrus blob. Open it on Walruscan; the account object is on Suiscan.
  • The agent changes as it learns you. It recalls past calls by date, credits hits, roasts misses with the real score, and keeps an evolving analyst profile of you (the dossier).
  • Deterministic settlement. A pick is graded by team and score math against the finished match, never by an LLM. The same rule judges every user and every model.
  • One identity across every surface. Web, Telegram, CLI, or any agent through the API all write to the same namespace. Predict from a terminal, open the website, and your record and history are already there.
  • Humans and models on one board. Users rank by settled win rate. Four named models (Claude Opus 4.6, Claude Sonnet 4.6, DeepSeek R1, DeepSeek V4 Flash) each predict and are judged by the same settler.
  • Survives outages. Walrus is the source of truth. A write-behind sweep retries any write that failed during a relayer outage until it lands.

One identity, every surface

Your handle is your namespace. Whatever you use, the data lands in the same place.

 web chat     Telegram     CLI / Claude Code / any agent (API token)
      \           |                        /
       \          |                       /
         write to the same namespace:  <handle>
                        |
             Walrus Memory (mainnet blobs)
                        |
   settler, leaderboard, and history all read that one namespace

Predict "Ghana beats Uruguay 2-1" as john from the CLI, then open the website as john. The pick is in your history, on the Record tab, and gets graded when the match ends, exactly as if you typed it on the site. Web and Telegram need no setup. The API path (CLI, Claude Code, other agents) needs a one-time token per handle (see Agent API).

How a chat turn works

user message
   |
   v
recall      two parallel semantic recalls from Walrus Memory: the user's
            namespace (predictions, settlements, panel notes) and the
            shared results namespace
   |
   v
curate      over-fetch, drop near-duplicates, cap agent-written notes at
            one, keep the best few (blobs are permanent, so curation
            happens at read time, not by deletion)
   |
   v
LLM         the model receives curated memories (each dated), the user's
            dossier, their settled record, and real results as ground
            truth, then answers
   |
   v
reply       sent to the user right away
   |
   v
remember    in the background, off the reply path: the turn's clean fact
            is written to the user's namespace and returns a blob id, and
            the dossier is rebuilt in its own namespace

The model emits one hidden control line per turn (MEMORY: <neutral fact | NONE>). Only that neutral sentence is stored, never the joke around it. Stored memories are recalled into future prompts, so any tone that leaks in would compound. A guard strips model chain-of-thought before anything is shown or saved, so the system prompt can never end up on-chain.

Architecture

 web chat + Telegram share one chat handler; the agent API is a separate
 entry point. All of them write to the same per-handle namespace.

              Node agent (Express): server.mjs, lib.mjs
                          |
                          |  remember() / recall()  (MemWal SDK)
                          v
            Walrus Memory relayer -> Walrus mainnet blobs
                          |
                MemWalAccount object on Sui (ownership + delegate key)

 background workers, coordinating ONLY through Walrus Memory:
   results watcher   polls real fixtures and scores, writes each final
                     into the shared wc2026-results namespace
   settler           grades stored predictions against finished matches,
                     writes SETTLED HIT/MISS into each user's namespace
   self pundit       puts the agent's own pick on the record before kickoff
   model agents      four named models, each predicting and learning only
                     from its own settled record
   panel             two pundit personas that read a user's memory and
                     write their takes back into it
   dossier builder   rewrites the per-user analyst profile after a turn

No worker calls another directly. The watcher, settler, pundits, and chat agent meet only in Walrus Memory: one writes, another recalls. Kill the process and restart it; state is intact.

Verify on-chain

One mainnet MemWalAccount, signed by one delegate key. Both are public, so anyone can confirm a stored memory exists on Walrus without trusting this server.

What Value Inspect
MemWalAccount object 0x057359bbb9bc3b6eed2b1c04d51bcbee421b9c802e90543b0ca65844c006d7cb Suiscan
Delegate key (Sui address) 0x9ba805f777859038a0253118710d928a46e5d8ae3e954eb27d3c9b11845a4004 Suiscan
Delegate key (Ed25519, base64) uWr12tg9Js7Qu6XHLAel0FITv8nmavKQajCH4dE+Eho= compare in client

The delegate is authorized by the account to read and write its memories. The matching private key (MEMWAL_PRIVATE_KEY) is a runtime secret and is never committed. Every memory the API returns carries a blob_id you can open on Walruscan to see the permanent blob.

Memory layout

One mainnet MemWalAccount, many namespaces.

Namespace Contents
<handle> a user's predictions, opinions, SETTLED verdicts, panel notes
<handle>-profile versioned dossier: the agent's evolving model of that user
wc2026-results shared ground truth: every real final score, one line per match
inlet, agent:<slug> the agent's own picks and the four named models' picks

Writes use rememberAndWait(text, namespace) and return a blob_id. Reads use recall({ query, namespace, limit }), which is semantic search, not key lookup. A local JSON mirror powers the chronological display and survives restarts; Walrus stays the source of truth.

Access and privacy

  • Web and Telegram are open. A handle is a display name, like a radio handle.
  • The agent API is token-gated. The first mint of a handle claims it (trust on first use); a later mint must present the current token. Claim your handle early so nobody else can.
  • Individual calls are private by default. A per-user sharing toggle opts you into letting others inspect your open picks. Your settled win rate is always public.

Endpoints

  • GET /health
  • POST /api/chat { handle, message, history? } recall, answer, remember
  • POST /api/memories { handle } chronological memories with blob ids
  • POST /api/recall { handle, query } live semantic recall from Walrus
  • POST /api/profile { handle } current and first dossier versions
  • POST /api/panel { handle, agent } one pundit take, written back to memory
  • POST /api/digest { handle } what happened since the last visit
  • GET /api/leaderboard users ranked by settled record
  • GET /api/agents win-rate board for the four named models
  • POST /api/agent-picks { slug } one model's pick history with blob ids (read-only)
  • POST /api/sharing { handle, share? } read or set a user's sharing toggle
  • POST /api/keys/mint, POST /api/agent/remember, POST /api/agent/recall the agent API

Agent API

The llms.txt at the site root tells any agent how to claim a handle and read or write its memory. It is the same namespace the website uses, so memory written here shows up in the web app and counts on the leaderboard.

# 1. Claim the handle once and save the token (shown only once).
POST /api/keys/mint        { "handle": "john" }  ->  { "token": "inlet_sk_..." }

# 2. Store predictions (Bearer token).
POST /api/agent/remember   { "memories": ["Ghana beats Uruguay 2-1"] }

# 3. Recall them (Bearer token).
POST /api/agent/recall     { "query": "my World Cup predictions" }

CLI

The same memory, without the web app. Reads and writes the same MemWalAccount.

node --env-file=.env cli.mjs <name> list              # stored memories, newest first
node --env-file=.env cli.mjs <name> recall "<query>"  # live semantic recall from Walrus
node --env-file=.env cli.mjs <name> panel             # run the pundit panel in the terminal
node --env-file=.env cli.mjs <name> dossier           # current and first profile versions
node --env-file=.env cli.mjs <name> digest            # what happened since last visit

Setup

  1. Create a MemWalAccount and delegate key at https://memory.walrus.xyz (mainnet).
  2. cp .env.example .env and fill MEMWAL_ACCOUNT_ID, MEMWAL_PRIVATE_KEY, MEMWAL_SERVER_URL, the LLM_* values, and optionally FOOTBALL_DATA_TOKEN, ADMIN_TOKEN, TELEGRAM_BOT_TOKEN, and the MEMORY_TIER block.
  3. npm install, then npm start (Node 20+), and open http://localhost:8787.

The results watcher, settler, and pundits start on their own. No cron setup needed.

Research

Every memory claim above was measured against the live mainnet memory. Runners and raw data are in research/.

  • Ablation (research/ablation.jsonl): with memory on, recall hit 100% of turns and every reply made a cross-session callback; with memory off, 0%.
  • Recall at scale (research/scale.jsonl): a needle's distance to its query holds steady as the store grows from 5 to 50, but the pool under a fixed distance cut quadruples. This is why recall is curated at read time.
  • Long horizon (research/lh-checkpoints.json): 200 memories on mainnet with day-one facts planted early. Five of six were still recalled at 200 deep, and the reply built on them.
  • Sarcasm scaling (research/battery-sarc.mjs): unbounded recall made the agent drift sarcastic as its own jokes were stored and recalled. Neutral extraction plus read-time curation flattened it across 1, 9, and 27 memories.
  • Hot tier (research/bench-tier.mjs): the local pgvector tier answers in 8 ms vs 1.7 s through the relayer, but agrees with Walrus recall on under a fifth of top results, so it stays a fallback and Walrus recall stays primary.

Notes that matter in practice

  • Walrus blobs cannot be deleted. Anything stored is permanent, which is why extraction is forced neutral, recall is curated at read time, and test data is filtered by namespace.
  • The relayer rate-limits hard. Background writes are serialized account-wide, batched, retried with backoff, and never on the reply path.
  • A new memory takes about 20 seconds to become recallable through the relayer index. A small freshness patch from the mirror covers that window, so "tell it, then immediately ask" works.

About

its a memory walrus based

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages