# Axon — Implementation Plan ## Dependency Philosophy Minimize external dependencies at every layer. The protocol is designed so that the Go implementation requires nothing beyond the standard library and `golang.org/x/crypto`. The JS implementation requires only `@noble/curves` and `@msgpack/msgpack` — both small, audited, zero-dependency libraries. No frameworks, no ORMs, no generated code. --- ## Phase 1: Core Package **Everything depends on this. Do not move to Phase 2 until the signing spec is fully verified.** - `Event` struct, `Tag`, kind constants matching the registry in PROTOCOL.md - Canonical signing payload construction — byte-exact per the spec - Tag sorting (`canonical_tags` hash) - Ed25519 sign and verify (`crypto/ed25519`) - X25519 key conversion from Ed25519 keypair (`golang.org/x/crypto/curve25519`) - ChaCha20-Poly1305 encrypt/decrypt for DMs (`golang.org/x/crypto/chacha20poly1305`) - MessagePack encode/decode for events **Test vectors — write these before any implementation:** Publish a set of known-input → known-output pairs for: - `canonical_tags` hash given a specific tag list - `canonical_payload` bytes given a specific event - Event `id` (SHA256 of payload) - Signature verification These vectors must be committed to the repo and validated by the JS client in Phase 4. They are the ground truth for cross-implementation correctness. A disagreement on a test vector means the spec is ambiguous — fix the spec before fixing the code. **Go dependencies:** `golang.org/x/crypto` only. --- ## Phase 2: Relay - WebSocket server (stdlib `net/http` + `golang.org/x/net/websocket` or `nhooyr.io/websocket`) - Challenge/Auth handshake on connect - Allowlist: authorized pubkeys in a flat config file or SQLite table - Ingest pipeline: 1. Unmarshal msgpack envelope 2. Verify signature using Phase 1 core 3. Reject duplicates (id PRIMARY KEY) 4. Reject expired job requests (check `expires_at` tag) 5. Reject events exceeding 64KB content limit 6. Write to index + store 7. Fanout to matching subscribers - SQLite storage via `database/sql` + `mattn/go-sqlite3` or `modernc.org/sqlite` (pure Go, no CGo) - Subscription management: filter matching, per-connection subscription map - Ephemeral events (kind 3000–3999): fanout only, skip storage - Error responses with HTTP-borrowed codes - WebSocket keepalive: ping every 30s, close after two missed **Go dependencies:** sqlite driver, websocket library. Both should be pure Go where possible. --- ## Phase 3: Go Client - Connect to relay + complete auth handshake - Publish events - Subscribe with filter, receive event stream - Unsubscribe - Reconnect with backoff The Go client is the primary tool for integration testing the relay. All relay behavior should be exercised via the client before moving to Phase 4. **Go dependencies:** none beyond what Phase 1 and Phase 2 already use. --- ## Phase 4: JS Client - Connect + auth (Ed25519 sign the challenge) - Publish events (msgpack encode, Ed25519 sign) - Subscribe / unsubscribe - DM encrypt/decrypt (X25519 ECDH + ChaCha20-Poly1305) - Validate Phase 1 test vectors — JS and Go must agree on every vector before this phase is considered complete **JS dependencies:** `@noble/curves` (Ed25519, X25519), `@msgpack/msgpack`. No others. --- ## Phase 5: Integration - End-to-end: publish from JS client, receive in Go client (and vice versa) - Cross-language signature verification: Go signs, JS verifies; JS signs, Go verifies - DM round-trip: encrypt in JS, decrypt in Go - Job protocol flow: request → feedback → result across two separate processes At the end of Phase 5 you have a working protocol implementation ready to back an agent system. --- ## What Comes After - Agent discovery via `KindProfile` (kind 0) — capability advertisement - Relay clustering / replication (out of scope for v1) - Retention and event expiry policies