From 0d9abbce6bf280f66738dbbfcceab224ab882bfa Mon Sep 17 00:00:00 2001 From: Graham Barber Date: Tue, 11 Nov 2025 17:22:33 +0000 Subject: [PATCH] chore: replace Claude with Letta --- CLAUDE.md | 241 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- .letta/settings.json | 6 ++++++ .letta/settings.local.json | 3 +++ 3 file(s) changed, 9 insertion(s)(+), 241 deletion(s)(-) diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 --- a/CLAUDE.md +++ /dev/null @@ -1,241 +0,0 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with -code in this repository. - -## Commands - -### Testing - -```bash -# Run all tests across the monorepo -deno test --allow-env - -# Run tests for a specific package -deno test packages/crypto/ - -# Run E2E tests (requires CISTERN_HANDLE and CISTERN_APP_PASSWORD environment variables) -deno test --allow-env --allow-net e2e.test.ts -``` - -### Lexicon Code Generation - -```bash -# Generate TypeScript types from JSON lexicon definitions -cd packages/lexicon -deno task generate -``` - -This generates types in `packages/lexicon/src/types/` from the JSON schemas in -`packages/lexicon/lexicons/`. Run this after modifying any `.json` files in the -lexicons directory. - -### Type Checking - -```bash -# Deno executes TypeScript directly - no build step needed -# Check types explicitly with: -deno check -``` - -## Architecture Overview - -Cistern is a **Deno monorepo** implementing a private, encrypted quick-capture -system on AT Protocol. Items are end-to-end encrypted using post-quantum -cryptography and stored temporarily in the user's PDS (Personal Data Server). - -### Monorepo Structure - -Five packages with clear separation of concerns: - -- **`@cistern/crypto`** - Core cryptographic primitives - (encryption/decryption/keys) -- **`@cistern/lexicon`** - AT Protocol schema definitions (pubkey + item - records) -- **`@cistern/shared`** - Authentication utilities and common code -- **`@cistern/producer`** - Creates and encrypts items for storage -- **`@cistern/consumer`** - Retrieves, decrypts, and deletes items - -Internal imports use the `@cistern/*` namespace defined in each package's -`deno.jsonc`. - -### Producer/Consumer Pattern - -**Producer** workflow (packages/producer/mod.ts): - -1. Select a public key from those registered in the user's PDS -2. Encrypt plaintext using the public key -3. Create an `app.cistern.lexicon.item` record with the encrypted payload -4. Upload to PDS - -**Consumer** workflow (packages/consumer/mod.ts): - -1. Generate an X-Wing keypair (post-quantum) -2. Upload public key to PDS as `app.cistern.lexicon.pubkey` record -3. Keep private key locally (never uploaded) -4. Retrieve items via **polling** (`listItems()`) or **streaming** - (`subscribeToItems()`) -5. Decrypt items matching the local keypair -6. Delete items after consumption - -### Encryption Architecture - -**Algorithm**: `x_wing-xchacha20_poly1305-sha3_512` - -The encryption system uses a hybrid approach combining: - -- **X-Wing KEM** (Key Encapsulation Mechanism) - post-quantum hybrid combining - ML-KEM-768 and X25519 -- **XChaCha20-Poly1305** - authenticated encryption cipher -- **SHA3-512** - content integrity verification - -**Encryption flow** (packages/crypto/src/encrypt.ts): - -1. X-Wing encapsulation generates a shared secret from the public key -2. XChaCha20-Poly1305 encrypts the plaintext using the shared secret -3. SHA3-512 hash computed for integrity verification -4. Returns `EncryptedPayload` containing ciphertext, nonce, hash, and metadata - -**Decryption flow** (packages/crypto/src/decrypt.ts): - -1. X-Wing decapsulation recovers the shared secret using the private key -2. XChaCha20-Poly1305 decrypts the content -3. Integrity verification: check content length and SHA3-512 hash match -4. Returns plaintext or throws error if verification fails - -### AT Protocol Integration - -Cistern uses two record types in the user's PDS: - -**`app.cistern.lexicon.pubkey`** -(packages/lexicon/lexicons/app/cistern/lexicon/pubkey.json): - -- Stores public keys with human-readable names -- Referenced by items via AT-URI -- Schema: `{name, algorithm, content, createdAt}` - -**`app.cistern.lexicon.item`** -(packages/lexicon/lexicons/app/cistern/lexicon/item.json): - -- Stores encrypted items temporarily -- Schema: - `{tid, ciphertext, nonce, algorithm, pubkey, payload, contentLength, contentHash}` -- The `pubkey` field is an AT-URI reference to the public key record - -### Real-time Streaming - -The consumer can subscribe to new items via **Jetstream** -(packages/consumer/mod.ts:150-190): - -- Connects to Bluesky's Jetstream WebSocket service -- Filters for `app.cistern.lexicon.item` creates matching user DID -- Decrypts items as they arrive in real-time -- Used for instant delivery (e.g., Obsidian plugin waiting for new memos) - -### Key Management - -**Private keys never leave the consumer's device.** The security model depends -on: - -- Private key stored off-protocol (e.g., in an Obsidian vault) -- Public key stored in PDS as a record -- Items encrypted with public key can only be decrypted by matching private key -- Each keypair can have a human-readable name (e.g., "Work Laptop", "Phone") - -### Dependencies - -**Cryptography** (JSR packages): - -- `@noble/post-quantum` - X-Wing KEM implementation -- `@noble/ciphers` - XChaCha20-Poly1305 -- `@noble/hashes` - SHA3-512 - -**AT Protocol** (npm packages): - -- `@atcute/client` - RPC client for PDS communication -- `@atcute/jetstream` - Real-time event streaming -- `@atcute/lexicons` - Schema validation -- `@atcute/tid` - Timestamp identifiers - -## Key Files and Locations - -### Cryptographic Operations - -- `packages/crypto/src/keys.ts` - Keypair generation (X-Wing) -- `packages/crypto/src/encrypt.ts` - Encryption logic -- `packages/crypto/src/decrypt.ts` - Decryption + integrity verification -- `packages/crypto/src/*.test.ts` - Crypto unit tests - -### Producer Implementation - -- `packages/producer/mod.ts` - Main producer class and encryption workflow - -### Consumer Implementation - -- `packages/consumer/mod.ts` - Keypair management, item retrieval, Jetstream - subscription - -### Authentication - -- `packages/shared/produce-requirements.ts` - DID resolution and session - creation -- Uses Slingshot service for handle → DID resolution -- Creates authenticated RPC client with app password - -### Schema Definitions - -- `packages/lexicon/lexicons/app/cistern/lexicon/*.json` - AT Protocol record - schemas -- `packages/lexicon/src/types/` - Generated TypeScript types (run - `deno task generate` to update) -- `packages/lexicon/lex.config.ts` - Lexicon generator configuration - -## Important Patterns - -### Error Handling in Decryption - -Decryption can fail for multiple reasons (packages/crypto/src/decrypt.ts): - -- Wrong private key (decapsulation fails) -- Corrupted ciphertext (authentication fails) -- Length mismatch (integrity check fails) -- Hash mismatch (integrity check fails) - -Always wrap decrypt calls in try-catch and handle gracefully. - -### Pagination in Consumer - -`listItems()` returns an async generator that handles pagination automatically. -It yields decrypted items and internally manages cursors. Consumers should -iterate with `for await` loops. - -### Resource URIs - -AT Protocol uses AT-URIs to reference records: `at:////` - -The consumer caches the public key's AT-URI with the local keypair to filter -which items it can decrypt. - -## Testing - -### Unit Tests - -Each package contains unit tests following these conventions: -- Test files use `.test.ts` suffix -- Use `@std/expect` for assertions -- Mock external dependencies (RPC clients, credentials) -- Test both success and error paths - -**Test locations:** -- `packages/crypto/src/*.test.ts` - Cryptographic operations -- `packages/consumer/mod.test.ts` - Consumer functionality -- `packages/producer/mod.test.ts` - Producer functionality - -### End-to-End Tests - -`e2e.test.ts` contains integration tests that use real AT Protocol credentials: -- Requires `CISTERN_HANDLE` and `CISTERN_APP_PASSWORD` environment variables -- Tests full workflow: keypair generation, encryption, decryption, deletion -- Uses Deno test steps to segment each phase -- Automatically skipped if environment variables are not set -- Cleans up all test data after execution diff --git a/.letta/settings.json b/.letta/settings.json new file mode 100644 --- /dev/null +++ b/.letta/settings.json @@ -0,0 +1,6 @@ +{ + "localSharedBlockIds": { + "project": "block-19ad1e80-37cd-4413-8f73-e1dddbb89119", + "skills": "block-25b184a7-e851-42d4-bf5a-9422337e7803" + } +} diff --git a/.letta/settings.local.json b/.letta/settings.local.json new file mode 100644 --- /dev/null +++ b/.letta/settings.local.json @@ -0,0 +1,3 @@ +{ + "lastAgent": "agent-2470875d-24da-4bab-8670-293b3cbcf3cf" +} -- tangled.sh