Kimosabe.AI

Kimosabe.AI — Manual & System Documentation (v1.0-beta)

One document. Two audiences. The first half is for users ("how do I…"). The second half is for operators, contributors, and auditors ("how does it work / how do I run it"). When this graduates to a Docusaurus site, this file becomes the source-of-truth outline — see Docusaurus structure at the bottom.


Part I — User Manual

1. What is Kimosabe.AI?

Kimosabe.AI is a privacy-first, end-to-end encrypted messenger that runs in your browser as an installable app (PWA). It is built for people who want the same security guarantees as Signal, without giving up a phone number, a contact list, or trust in a single vendor's mobile binary.

Tagline: Curate Your Brain.

2. Quick start (60 seconds)

  1. Visit kimosabe.ai.
  2. Tap Create account. Pick an @username, an email, and a password ≥10 chars.
  3. Save your Recovery Key. Copy it into 1Password / write it on paper. This is the only thing that can recover your encrypted history if you forget your password. We cannot see it, reset it, or send you another one.
  4. Tap + New chat, enter a friend's @handle, send your first message.
  5. (Optional) On iOS Safari → Share → Add to Home Screen. Now it's an app.

3. Core concepts

Username (@handle). Your public identity. People find you with this. You can change it later — old links break, your encrypted history doesn't.

Recovery Key. A 24-character one-time code generated at signup. It re-wraps your private key on the server. Used during password recovery and nowhere else. Lose it + lose your password = lose your history. This is not a bug — it's the privacy promise.

Conversation. A 1:1 channel between you and one other handle. Each one has its own AES-GCM-256 key derived via ECDH P-256. Group chats arrive in Phase 2 (MLS, RFC 9420).

Disappearing messages. Per-conversation TTL: off / 1 day / 7 days. A server cron job purges expired ciphertext; your client also clears local copies on next open.

Receipts. Delivery receipts are on by default. Read receipts are opt-in per-account in Settings.

4. Common tasks

Want to… Where
Start a chat Home → + New chat → enter @handle
Send an image In-chat → paperclip icon
Set disappearing messages In-chat → ⋯ → Disappearing messages
Change your password Settings → Security → Change password
Rotate your recovery key Settings → Security → Rotate recovery key
Export your identity Settings → Security → Export identity
Delete your account Settings → Danger zone → Delete account
Recover with key Login → "Forgot password?" → use Recovery Key

5. What Kimosabe protects (and what it doesn't)

Protects: Message content, attachment content, message-key forward secrecy. The server cannot read your conversations even under subpoena.

Does NOT protect (in v1):

  • Metadata. Sender, recipient, and timestamp are visible to the server. (Sealed sender lands in Phase 3.)
  • Compromised device. If your laptop is malware-infected, your private key can be read. We can't fix what we can't see.
  • Group chat. Not in v1 — coming via MLS in Phase 2.
  • Push notifications. Encrypted push lands in Phase 2; for now, notifications only fire when the app is open.

The full, signed threat model lives at /trust.

6. Troubleshooting

"My recovery key didn't work." They are case-insensitive but whitespace-sensitive. Strip spaces. If still failing, the key may be from an older account version — contact support.

"My contact never got my message." Check the lower-left status: Sending (offline outbox), Sent (server has ciphertext), Delivered (recipient device fetched it). If stuck on Sending for >60s, you're offline.

"I uninstalled and reinstalled and I see no history." Expected. Local cache is wiped on reinstall. Sign back in — your wrapped key is on the server, your client will re-decrypt your history on first sync.

"I forgot password AND lost my recovery key." Your account can be deleted (Settings on another logged-in device, or by writing to support). History is gone. This is the price of zero-knowledge.


Part II — System Documentation

7. Architecture at a glance

   ┌──────────────────┐      ciphertext + metadata       ┌──────────────────┐
   │  Browser (PWA)   │  ───────────────────────────▶   │  Lovable Cloud    │
   │                  │                                  │  (Postgres + RLS) │
   │  • ECDH P-256    │  ◀───────────────────────────   │  • Realtime       │
   │  • AES-GCM-256   │       ciphertext envelopes       │  • Storage        │
   │  • Service Worker│                                  │  • Edge Functions │
   └──────────────────┘                                  └──────────────────┘
            │                                                      │
            │       wrapped(privkey)  +  Recovery-key wrap         │
            └─────────────── stored as opaque blob ────────────────┘

The server never holds plaintext message bodies, attachment bytes, or the user's unwrapped private key.

8. Tech stack

  • Frontend: TanStack Start v1 (React 19, Vite 7, SSR), Tailwind v4, shadcn/ui (Radix), Framer Motion.
  • Backend: Lovable Cloud (Supabase under the hood — Postgres + Auth + Realtime + Storage + Edge Functions).
  • Crypto: WebCrypto API only. No third-party crypto libs.
  • Deploy: Cloudflare Workers (via wrangler) for the SSR/Worker runtime.

9. Cryptographic protocol (v1)

  1. Identity. At signup, the browser generates an ECDH P-256 keypair. The public key is published to the user's profile row. The private key is wrapped with two AES-KW keys derived from (a) the user's password and (b) their Recovery Key. Both wrapped blobs are uploaded; neither secret ever leaves the device.
  2. Per-conversation key. When two users first chat, each derives a shared secret via ECDH(self.priv, peer.pub), then HKDF-SHA-256 produces the AES-GCM-256 conversation key.
  3. Message envelope. {nonce, ciphertext, ttl?}. Server stores it; metadata (from, to, created_at) is plaintext (sealed sender is a Phase 3 deliverable).
  4. Recovery. A user supplies their email + Recovery Key to the recover-with-key edge function, which returns the recovery-wrapped private key blob. The browser decrypts it locally and re-wraps with the user's new password before re-uploading. The function never sees the private key in plaintext.

10. Data model (key tables)

  • profiles(user_id, username, public_key, …) — public.
  • wrapped_keys(user_id, password_wrapped, recovery_wrapped) — opaque blobs.
  • conversations(id, member_a, member_b, created_at, ttl_seconds).
  • messages(id, conversation_id, sender_id, ciphertext, nonce, expires_at).
  • attachments(id, message_id, storage_path, ciphertext_metadata).

All tables have RLS enabled. Policies use a has_role security-definer function for any cross-user access. See supabase/ migrations for exact shapes (we don't reproduce them here to avoid drift).

11. Edge functions

Function Purpose JWT?
recover-with-key Returns recovery-wrapped private key blob given email + recovery key. No (zero-knowledge by design)
delete-account Hard-deletes user + all messages + storage objects. Yes
cleanup-expired-messages Cron-driven purge of TTL'd ciphertext. No (cron)

12. Realtime

Postgres changes on messages are streamed via Supabase Realtime. Clients subscribe to their own conversations only (enforced by RLS). The payload is already ciphertext, so Realtime cannot leak content even if mis-routed.

13. PWA & offline

  • public/manifest.webmanifest — installable on iOS/Android.
  • public/sw.js — service worker caches the app shell + last-N-messages per conversation, and queues outbound sends when offline.
  • src/lib/outbox.ts — IndexedDB-backed send queue with retry.

14. Local development

git clone <repo>
bun install
bun run dev          # vite dev with HMR
bun run typecheck    # strict TS
bun run build        # production build (Workers target)

The Lovable Cloud project (uwjesevjsjxlvstyyrbq) is shared between dev and prod. Local dev hits the same Postgres — be careful with migrations.

15. Roadmap pointer

Phase 1 → Phase 6 is documented in ROADMAP.md. Phase 2 (MLS group chat, X3DH + Double Ratchet, sealed sender v1, voice notes, passkeys) is the next major milestone, gated by a 90-day Phase 1 user trial. See STATE.md for current status.

16. Contributing

Read STATE.md, then STANDARDS.md, then the relevant ADR in adr/. All PRs must:

  • pass bun run typecheck (CI enforces)
  • not weaken anything on the "Out of scope (forever)" list in ROADMAP.md
  • if they touch the protocol, ship as an ADR first

17. Security disclosure

See SECURITY.md. TL;DR: please don't dump 0-days on Twitter. Email security@kimosabe.ai with a PGP-signed report; we respond within 72h and credit the finder unless asked otherwise.


Docusaurus structure

When this becomes a docs site, the proposed sidebar is:

docs/
├── intro.md                  ← Part I §1–2 (Quick start)
├── using-kimosabe/
│   ├── concepts.md           ← §3
│   ├── common-tasks.md       ← §4
│   ├── what-it-protects.md   ← §5 (canonical: links to /trust)
│   └── troubleshooting.md    ← §6
├── system/
│   ├── architecture.md       ← §7–8
│   ├── crypto-protocol.md    ← §9
│   ├── data-model.md         ← §10
│   ├── edge-functions.md     ← §11
│   ├── realtime.md           ← §12
│   └── pwa-offline.md        ← §13
├── contributing/
│   ├── local-dev.md          ← §14
│   ├── how-we-decide.md      ← links to adr/
│   └── standards.md          ← links to STANDARDS.md
└── policy/
    ├── roadmap.md            ← ROADMAP.md
    ├── state.md              ← STATE.md
    ├── security.md           ← SECURITY.md
    └── changelog.md          ← CHANGELOG.md

Docusaurus config notes (when we wire it up):

  • themeConfig.colorMode.defaultMode: "dark" — match the brand.
  • Custom CSS pulls --gold and --purple-deep from src/styles.css.
  • algolia search disabled in beta (privacy-first; no third-party search trackers on a docs site that talks about privacy).

Until then, this single file is the manual.