This commit completes Beat 2 of the SequentialThinkingForCHORUS implementation, adding end-to-end age encryption for all MCP communications. ## Deliverables ### 1. Age Encryption/Decryption Package (pkg/seqthink/ageio/) - `crypto.go`: Core encryption/decryption with age - `testkeys.go`: Test key generation and convenience functions - `crypto_test.go`: Comprehensive unit tests (11 tests, all passing) - `golden_test.go`: Golden tests with real MCP payloads (12 tests, all passing) **Features:** - File-based identity and recipient key loading - Streaming encryption/decryption support - Proper error handling for all failure modes - Performance benchmarks showing 400+ MB/s throughput **Test Coverage:** - Round-trip encryption/decryption for various payload sizes - Unicode and emoji support - Large payload handling (100KB+) - Invalid ciphertext rejection - Wrong key detection - Truncated/modified ciphertext detection ### 2. Encrypted Proxy Handlers (pkg/seqthink/proxy/) - `server_encrypted.go`: Encrypted tool call handler - Updated `server.go`: Automatic routing based on encryption config - Content-Type enforcement: `application/age` required when encryption enabled - Metrics tracking for encryption/decryption failures **Flow:** 1. Client sends encrypted request with `Content-Type: application/age` 2. Wrapper decrypts using age identity 3. Wrapper calls MCP server (plaintext on loopback) 4. Wrapper encrypts response 5. Client receives encrypted response with `Content-Type: application/age` ### 3. SSE Streaming with Encryption (pkg/seqthink/proxy/sse.go) - `handleSSEEncrypted()`: Encrypted Server-Sent Events streaming - `handleSSEPlaintext()`: Plaintext SSE for testing - Base64-encoded encrypted frames for SSE transport - `DecryptSSEFrame()`: Client-side frame decryption helper - `ReadSSEStream()`: SSE stream parsing utility **SSE Frame Format (Encrypted):** ``` event: thought data: <base64-encoded age-encrypted JSON> id: 1 ``` ### 4. Configuration-Based Mode Switching The wrapper now operates in two modes based on environment variables: **Encrypted Mode** (AGE_IDENT_PATH and AGE_RECIPS_PATH set): - All requests/responses encrypted with age - Content-Type: application/age enforced - SSE frames base64-encoded and encrypted **Plaintext Mode** (no encryption paths set): - Direct plaintext proxying for development/testing - Standard JSON Content-Type - Plaintext SSE frames ## Testing Results ### Unit Tests ``` PASS: TestEncryptDecryptRoundTrip (all variants) PASS: TestEncryptEmptyData PASS: TestDecryptEmptyData PASS: TestDecryptInvalidCiphertext PASS: TestDecryptWrongKey PASS: TestStreamingEncryptDecrypt PASS: TestConvenienceFunctions ``` ### Golden Tests ``` PASS: TestGoldenEncryptionRoundTrip (7 scenarios) - sequential_thinking_request (283→483 bytes, 70.7% overhead) - sequential_thinking_revision (303→503 bytes, 66.0% overhead) - sequential_thinking_branching (315→515 bytes, 63.5% overhead) - sequential_thinking_final (320→520 bytes, 62.5% overhead) - large_context_payload (3800→4000 bytes, 5.3% overhead) - unicode_payload (264→464 bytes, 75.8% overhead) - special_characters (140→340 bytes, 142.9% overhead) PASS: TestGoldenDecryptionFailures (5 scenarios) ``` ### Performance Benchmarks ``` Encryption: - 1KB: 5.44 MB/s - 10KB: 52.57 MB/s - 100KB: 398.66 MB/s Decryption: - 1KB: 9.22 MB/s - 10KB: 85.41 MB/s - 100KB: 504.46 MB/s ``` ## Security Properties ✅ **Confidentiality**: All payloads encrypted with age (X25519+ChaCha20-Poly1305) ✅ **Authenticity**: age provides AEAD with Poly1305 MAC ✅ **Forward Secrecy**: Each encryption uses fresh ephemeral keys ✅ **Key Management**: File-based identity/recipient keys ✅ **Tampering Detection**: Modified ciphertext rejected ✅ **No Plaintext Leakage**: MCP server only on 127.0.0.1 loopback ## Next Steps (Beat 3) Beat 3 will add KACHING JWT policy enforcement: - JWT token validation (`pkg/seqthink/policy/`) - Scope checking for `sequentialthinking.run` - JWKS fetching and caching - Policy denial metrics 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
CHORUS – Container-First Context Platform (Alpha)
CHORUS is the runtime that ties the CHORUS ecosystem together: libp2p mesh, DHT-backed storage, council/task coordination, and (eventually) SLURP contextual intelligence. The repository you are looking at is the in-progress container-first refactor. Several core systems boot today, but higher-level services (SLURP, SHHH, full HMMM routing) are still landing.
Current Status
| Area | Status | Notes |
|---|---|---|
| libp2p node + PubSub | ✅ Running | internal/runtime/shared.go spins up the mesh, hypercore logging, availability broadcasts. |
| DHT + DecisionPublisher | ✅ Running | Encrypted storage wired through pkg/dht; decisions written via ucxl.DecisionPublisher. |
| Leader Election System | ✅ FULLY FUNCTIONAL | 🎉 MILESTONE: Complete admin election with consensus, discovery protocol, heartbeats, and SLURP activation! |
| SLURP (context intelligence) | 🚧 Stubbed | pkg/slurp/slurp.go contains TODOs for resolver, temporal graphs, intelligence. Leader integration scaffolding exists but uses placeholder IDs/request forwarding. |
| SHHH (secrets sentinel) | 🚧 Sentinel live | pkg/shhh redacts hypercore + PubSub payloads with audit + metrics hooks (policy replay TBD). |
| HMMM routing | 🚧 Partial | PubSub topics join, but capability/role announcements and HMMM router wiring are placeholders (internal/runtime/agent_support.go). |
See docs/progress/CHORUS-WHOOSH-development-plan.md for the detailed build plan and docs/progress/CHORUS-WHOOSH-roadmap.md for sequencing.
Quick Start (Alpha)
The container-first workflows are still evolving; expect frequent changes.
git clone https://gitea.chorus.services/tony/CHORUS.git
cd CHORUS
cp docker/chorus.env.example docker/chorus.env
# adjust env vars (KACHING license, bootstrap peers, etc.)
docker compose -f docker/docker-compose.yml up --build
You’ll get a single agent container with:
- libp2p networking (mDNS + configured bootstrap peers)
- election heartbeat
- DHT storage (AGE-encrypted)
- HTTP API + health endpoints
Missing today: SLURP context resolution, advanced SHHH policy replay, HMMM per-issue routing. Expect log warnings/TODOs for those paths.
🎉 Leader Election System (NEW!)
CHORUS now features a complete, production-ready leader election system:
Core Features
- Consensus-based election with weighted scoring (uptime, capabilities, resources)
- Admin discovery protocol for network-wide leader identification
- Heartbeat system with automatic failover (15-second intervals)
- Concurrent election prevention with randomized delays
- SLURP activation on elected admin nodes
How It Works
- Bootstrap: Nodes start in idle state, no admin known
- Discovery: Nodes send discovery requests to find existing admin
- Election trigger: If no admin found after grace period, trigger election
- Candidacy: Eligible nodes announce themselves with capability scores
- Consensus: Network selects winner based on highest score
- Leadership: Winner starts heartbeats, activates SLURP functionality
- Monitoring: Nodes continuously verify admin health via heartbeats
Debugging
Use these log patterns to monitor election health:
# Monitor WHOAMI messages and leader identification
docker service logs CHORUS_chorus | grep "🤖 WHOAMI\|👑\|📡.*Discovered"
# Track election cycles
docker service logs CHORUS_chorus | grep "🗳️\|📢.*candidacy\|🏆.*winner"
# Watch discovery protocol
docker service logs CHORUS_chorus | grep "📩\|📤\|📥"
Roadmap Highlights
- Security substrate – land SHHH sentinel, finish SLURP leader-only operations, validate COOEE enrolment (see roadmap Phase 1).
- Autonomous teams – coordinate with WHOOSH for deployment telemetry + SLURP context export.
- UCXL + KACHING – hook runtime telemetry into KACHING and enforce UCXL validator.
Track progress via the shared roadmap and weekly burndown dashboards.
Related Projects
- WHOOSH – council/team orchestration
- KACHING – telemetry/licensing
- SLURP – contextual intelligence prototypes
- HMMM – meta-discussion layer
Contributing
This repo is still alpha. Please coordinate via the roadmap tickets before landing changes. Major security/runtime decisions should include a Decision Record with a UCXL address so SLURP/BUBBLE can ingest it later.