An AI journal encrypted in your browser. Reflections run in a TEE. Nobody can read it, not even us.
Millions of people now use ChatGPT as a therapist. It's free, it's awake at 3am, and it never judges. That need is real — but three things go wrong with it.
First, the most private paragraph you will ever write lands in a plaintext database owned by a company you've never met. It's logged, it's retained, and a single breach turns an inner life into a permanent public record.
Second, one model gives you one voice. It mirrors your framing back at you, warmer. That isn't insight — it's an echo chamber with a therapy accent.
Third, and this is the one nobody mentions: it's a dead end. You cannot hand your ChatGPT history to a therapist. Six months of the realest things you've written, and none of it helps you the day you finally sit in front of an actual human being.
Shrimpy is the version where none of that is true.
Write freely. You type, or you speak — speech-to-text runs on Whisper inside your own browser, and the audio never reaches a server and is never stored. Sign-in is a normal Google button; underneath, Sui zkLogin derives an on-chain identity you never have to see. No wallet, no seed phrase, no gas.
Reflect privately. When you save, the entry goes to 0G Private Computer in private mode first: three agents from differents cultures (US, EU and CN) run in parallel inside a hardware-attested TEE — one mirrors the emotion, one looks for patterns across your last five entries, one is instructed to find what the other two missed. A fourth model writes the meta-analysis and is told to keep their disagreements rather than average them away. Only then are the entry and its reflection encrypted together with Sui Seal and stored as one ciphertext snapshot on Walrus. The analysis happens before the encryption — and a failed analysis never blocks a note from being saved.
The agents also return a safety level. When what you wrote points at genuine distress, Shrimpy says so plainly, suggests that talking to a professional could help, and puts local resources one tap away. It never diagnoses, never labels, and never contacts anyone on your behalf.
Share deliberately. You tick individual entries — never the vault — and they are re-encrypted under a separate Seal allowlist policy naming your clinician's own Sui address. They open a read-only portal that can decrypt that extract and nothing else. Revoke, and the next decryption fails on-chain, because a Move function says no — not because our backend does.
And we say the honest thing in the interface: revoking stops future access, it cannot un-read a page someone already read. Walrus blobs are public and retrievable by anyone — they are ciphertext, and the blob id and timing are not treated as secrets. The extract you send to 0G is necessarily in the clear during inference; the TEE protects it from the provider, not from physics.
Shrimpy is a reflective wellness tool. It is not medical advice, diagnosis, treatment, or emergency support, and it says so.
Monorepo: pnpm workspaces, Next.js 15 + React + TypeScript for the app and the landing page, a Move package for the on-chain policies, Docker + GitHub Actions deploying to a VPS.
IDENTITY — Sui zkLogin. The browser generates an ephemeral keypair, binds it to the OAuth nonce, and gets a JWT back from Google. /api/salt and /api/prover proxy Enoki for the user salt and the ZK proof; without an Enoki key they fall back to a local HMAC salt and a self-hosted prover, which is what let us keep developing while the testnet prover situation was unresolved. Writes are gas-sponsored through /api/sponsor, so the user never holds a token or signs anything they'd have to understand. A Sui wallet path via Mysten's dApp Kit exists alongside Google.
ENCRYPTION — Sui Seal, threshold, client-side. The key id is [owner address (32 bytes)][nonce (5 bytes)], and the Move policy sui_contracts::notebook::seal_approve simply asserts the caller's address is a prefix of the requested id. The nice consequence: encryption depends on no on-chain object at all — no allowlist to create, no transaction before you can write. Sharing uses a second policy, sui_contracts::allowlist, where the key id is namespaced by the allowlist object and membership is checked on-chain; revocation is removing an address from that vector.
STORAGE — Walrus holds ciphertext only. The pointer lives in a Notebook object that is owned, so Sui itself guarantees only the owner appends to it, and discovery is a plain listOwnedObjects call: no index, no server state.
DATA MODEL — the notable design call. Instead of one blob per entry, the whole app is a single JSON "vault" snapshot: entries, moods, cached reflections, cosmetics, preferences. Loading a journal is one Walrus fetch and one Seal decrypt instead of N; the Notebook's blob vector becomes the version history for free; and the Move contract never had to change. parseVault normalises with defaults and never throws — losing three years of journal to a schema drift between deploys would be the worst possible failure of this product.
A consequence we liked: there are exactly two events that write on-chain — a new entry, and buying a cosmetic. So a Pearl balance cannot be stored, because one earned between writes would vanish on reload. It's derived instead: distinct days written, minus what you've spent. Gamification with zero extra transactions.
AI — 0G Private Computer, trust mode private. /api/zerog is the sole holder of the key; the browser never sees it. Three agent prompts run in parallel with different mandates, a fourth call synthesises them, and the server validates the result against a strict JSON schema before anything is trusted: it cannot diagnose, cannot label a disorder, and show_safety_popup can only be true when the model itself returned safety_level "urgent". The TEE attestation trace 0G returns is stored on the entry. The 0G testnet router currently serves a single text model, so today the three agents share it and the diversity is in the prompts — the orchestration already takes a model per agent, and the moment more are served we point one at a US model, one European, one Asian, so no single training culture interprets someone's inner life alone.
VOICE — Whisper (onnx-community/whisper-tiny) via transformers.js, WASM, in a web worker. The Float32Array lives in memory long enough to transcribe and is then dropped. Walrus never receives audio, encrypted or otherwise.
SHARING — invitation and access tokens are AES-encrypted and HMAC-keyed server-side with TTLs; the recipient's email is stored as an HMAC digest, never in plaintext, and compared with timingSafeEqual. Resend delivers the two emails. A small request registry tracks pending/accepted/active/revoked status in a Docker volume and contains zero journal text.
Deliberately not automated: the Move package deployment. Publishing on every push would mint a new packageId, orphan every existing Notebook, and require the publishing key in CI. It stays a manual script.

