diff options
| -rw-r--r-- | PLAN.md | 99 |
1 files changed, 99 insertions, 0 deletions
| @@ -0,0 +1,99 @@ | |||
| 1 | # Axon — Implementation Plan | ||
| 2 | |||
| 3 | ## Dependency Philosophy | ||
| 4 | |||
| 5 | 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. | ||
| 6 | |||
| 7 | --- | ||
| 8 | |||
| 9 | ## Phase 1: Core Package | ||
| 10 | |||
| 11 | **Everything depends on this. Do not move to Phase 2 until the signing spec is fully verified.** | ||
| 12 | |||
| 13 | - `Event` struct, `Tag`, kind constants matching the registry in PROTOCOL.md | ||
| 14 | - Canonical signing payload construction — byte-exact per the spec | ||
| 15 | - Tag sorting (`canonical_tags` hash) | ||
| 16 | - Ed25519 sign and verify (`crypto/ed25519`) | ||
| 17 | - X25519 key conversion from Ed25519 keypair (`golang.org/x/crypto/curve25519`) | ||
| 18 | - ChaCha20-Poly1305 encrypt/decrypt for DMs (`golang.org/x/crypto/chacha20poly1305`) | ||
| 19 | - MessagePack encode/decode for events | ||
| 20 | |||
| 21 | **Test vectors — write these before any implementation:** | ||
| 22 | |||
| 23 | Publish a set of known-input → known-output pairs for: | ||
| 24 | - `canonical_tags` hash given a specific tag list | ||
| 25 | - `canonical_payload` bytes given a specific event | ||
| 26 | - Event `id` (SHA256 of payload) | ||
| 27 | - Signature verification | ||
| 28 | |||
| 29 | 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. | ||
| 30 | |||
| 31 | **Go dependencies:** `golang.org/x/crypto` only. | ||
| 32 | |||
| 33 | --- | ||
| 34 | |||
| 35 | ## Phase 2: Relay | ||
| 36 | |||
| 37 | - WebSocket server (stdlib `net/http` + `golang.org/x/net/websocket` or `nhooyr.io/websocket`) | ||
| 38 | - Challenge/Auth handshake on connect | ||
| 39 | - Allowlist: authorized pubkeys in a flat config file or SQLite table | ||
| 40 | - Ingest pipeline: | ||
| 41 | 1. Unmarshal msgpack envelope | ||
| 42 | 2. Verify signature using Phase 1 core | ||
| 43 | 3. Reject duplicates (id PRIMARY KEY) | ||
| 44 | 4. Reject expired job requests (check `expires_at` tag) | ||
| 45 | 5. Reject events exceeding 64KB content limit | ||
| 46 | 6. Write to index + store | ||
| 47 | 7. Fanout to matching subscribers | ||
| 48 | - SQLite storage via `database/sql` + `mattn/go-sqlite3` or `modernc.org/sqlite` (pure Go, no CGo) | ||
| 49 | - Subscription management: filter matching, per-connection subscription map | ||
| 50 | - Ephemeral events (kind 3000–3999): fanout only, skip storage | ||
| 51 | - Error responses with HTTP-borrowed codes | ||
| 52 | - WebSocket keepalive: ping every 30s, close after two missed | ||
| 53 | |||
| 54 | **Go dependencies:** sqlite driver, websocket library. Both should be pure Go where possible. | ||
| 55 | |||
| 56 | --- | ||
| 57 | |||
| 58 | ## Phase 3: Go Client | ||
| 59 | |||
| 60 | - Connect to relay + complete auth handshake | ||
| 61 | - Publish events | ||
| 62 | - Subscribe with filter, receive event stream | ||
| 63 | - Unsubscribe | ||
| 64 | - Reconnect with backoff | ||
| 65 | |||
| 66 | 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. | ||
| 67 | |||
| 68 | **Go dependencies:** none beyond what Phase 1 and Phase 2 already use. | ||
| 69 | |||
| 70 | --- | ||
| 71 | |||
| 72 | ## Phase 4: JS Client | ||
| 73 | |||
| 74 | - Connect + auth (Ed25519 sign the challenge) | ||
| 75 | - Publish events (msgpack encode, Ed25519 sign) | ||
| 76 | - Subscribe / unsubscribe | ||
| 77 | - DM encrypt/decrypt (X25519 ECDH + ChaCha20-Poly1305) | ||
| 78 | - Validate Phase 1 test vectors — JS and Go must agree on every vector before this phase is considered complete | ||
| 79 | |||
| 80 | **JS dependencies:** `@noble/curves` (Ed25519, X25519), `@msgpack/msgpack`. No others. | ||
| 81 | |||
| 82 | --- | ||
| 83 | |||
| 84 | ## Phase 5: Integration | ||
| 85 | |||
| 86 | - End-to-end: publish from JS client, receive in Go client (and vice versa) | ||
| 87 | - Cross-language signature verification: Go signs, JS verifies; JS signs, Go verifies | ||
| 88 | - DM round-trip: encrypt in JS, decrypt in Go | ||
| 89 | - Job protocol flow: request → feedback → result across two separate processes | ||
| 90 | |||
| 91 | At the end of Phase 5 you have a working protocol implementation ready to back an agent system. | ||
| 92 | |||
| 93 | --- | ||
| 94 | |||
| 95 | ## What Comes After | ||
| 96 | |||
| 97 | - Agent discovery via `KindProfile` (kind 0) — capability advertisement | ||
| 98 | - Relay clustering / replication (out of scope for v1) | ||
| 99 | - Retention and event expiry policies | ||
