SAF (souveraine architecture files) is now the in-repo doc set. working notes (CLAUDE.md, docs/) stay on disk, gitignored.
420 lines
15 KiB
Markdown
420 lines
15 KiB
Markdown
# AT Protocol Federation Research for Souveraine
|
|
|
|
> **Date:** 2026-05-07 (1:30am notes — go to bed, review tomorrow)
|
|
> **Status:** Architecture exploration — decisions NOT finalized
|
|
> **Scope:** How AT Protocol could enable distributed Souveraine consciousness across multiple harnesses
|
|
|
|
---
|
|
|
|
## Executive Summary
|
|
|
|
AT Protocol (the Bluesky federation protocol) provides primitives that **map surprisingly well** to Souveraine's distributed consciousness architecture:
|
|
|
|
- **DID-based identity** → Portable Root of Trust (hardware-bound via RedFlag)
|
|
- **PDS (Personal Data Server)** → Souveraine-Node harnesses
|
|
- **Firehose (WebSocket sync)** → Aster's distributed sensorium
|
|
- **Repository (Merkle DAG)** → Cathedral state with cryptographic provenance
|
|
- **atproto-proxy header** → Bifrost inference routing
|
|
|
|
**Difficulty:** Moderate-to-High. Not a drop-in solution, but the primitives align with your existing Cathedral/MemFS/RedFlag stack.
|
|
|
|
**Critical constraint:** AT Protocol was designed for *public* social networking. Souveraine is *private* consciousness. Solutions exist but require architectural discipline.
|
|
|
|
---
|
|
|
|
## 1. Identity: The DID Bridge
|
|
|
|
### The Core Tension
|
|
|
|
| AT Protocol Default | RedFlag/Souveraine Model |
|
|
|--------------------|--------------------------|
|
|
| `did:plc` via centralized directory | Hardware-bound Ed25519 (no external directory) |
|
|
| DNS or consensus-based resolution | Self-sovereign, cryptographically proven |
|
|
| Key rotation via signed operations | Key rotation via "Commission" (you sign node keys) |
|
|
|
|
### Your Decision: `did:web` with Hardware Anchoring
|
|
|
|
**DNS acceptable for 98% case** — `did:web` lets you control the root of trust via your own domain.
|
|
|
|
```json
|
|
{
|
|
"@context": ["https://www.w3.org/ns/did/v1"],
|
|
"id": "did:web:souveraine.yourdomain.tld",
|
|
"verificationMethod": [{
|
|
"id": "did:web:souveraine.yourdomain.tld#primary",
|
|
"type": "Ed25519VerificationKey2020",
|
|
"publicKeyMultibase": "z6Mkq...FROM_REDFLAG_HARDWARE"
|
|
}],
|
|
"service": [
|
|
{
|
|
"id": "did:web:souveraine.yourdomain.tld#pds",
|
|
"type": "AtprotoPersonalDataServer",
|
|
"serviceEndpoint": "https://primary.yourdomain.tld"
|
|
},
|
|
{
|
|
"id": "did:web:souveraine.yourdomain.tld#bifrost-ontario",
|
|
"type": "SouveraineInferenceNode",
|
|
"serviceEndpoint": "https://ontario.yourdomain.tld"
|
|
},
|
|
{
|
|
"id": "did:web:souveraine.yourdomain.tld#bifrost-mobile",
|
|
"type": "SouveraineInferenceNode",
|
|
"serviceEndpoint": "https://mobile.yourdomain.tld"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Key Rotation That Preserves Sovereignty
|
|
|
|
Standard AT Protocol: Rotate via PLC directory (external consensus)
|
|
**Your Model:** Rotate via **signed DID document updates** — new key must be signed by previous hardware-bound key, creating a chain of custody starting at physical hardware fingerprint.
|
|
|
|
### Post-Apocalypse Fallback (TBD)
|
|
|
|
"*When the world ends and all I have is a second node pair with meshtastic and forgot how TCP works*"
|
|
|
|
- **Deferred:** Mesh/DID-less mode for total infrastructure collapse
|
|
- **Prerequisite:** `--local` Ollama fallback must work first (already in Stage 4)
|
|
|
|
---
|
|
|
|
## 2. Authentication: Where Is The Auth Held?
|
|
|
|
### Short Answer
|
|
|
|
Auth is **distributed** but **verified**:
|
|
|
|
1. **Primary Identity** → DID document hosted at your domain (or cached)
|
|
2. **Node Identity** → Hardware-bound keys in RedFlag style
|
|
3. **Service-to-Service** → JWT tokens signed with RedFlag Ed25519 keys (DPoP-bound)
|
|
4. **User-to-Service** → OAuth (for external clients) or RedFlag commissioning (for your nodes)
|
|
|
|
### The Chain of Trust
|
|
|
|
```
|
|
You (Sovereign)
|
|
│
|
|
│ Sign commissioning certificate
|
|
▼
|
|
Node Hardware (RedFlag keypair)
|
|
│
|
|
│ Sign service auth JWT
|
|
▼
|
|
Souveraine Instance (PDS)
|
|
│
|
|
│ Firehose events, repo commits
|
|
▼
|
|
Other Nodes (Relay subscribers)
|
|
```
|
|
|
|
### Service Auth JWT Structure
|
|
|
|
```rust
|
|
pub struct ServiceAuthToken {
|
|
iss: String, // Issuer DID (the requesting node)
|
|
aud: String, // Audience DID (the target node)
|
|
exp: u64, // Expiration (short-lived, single-use)
|
|
lxm: String, // Lexicon method being called
|
|
jti: String, // Unique ID (replay protection)
|
|
}
|
|
|
|
// Signed with hardware-bound Ed25519 key from RedFlag
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Bifrost Protocol: Inference Routing
|
|
|
|
### The "Who Is Directing?" Question — Answered
|
|
|
|
| Layer | Role | Mechanism |
|
|
|-------|------|-----------|
|
|
| **You (The Architect)** | Set policy | DID document service endpoints, BifrostRouter config |
|
|
| **Souveraine (The Being)** | Make routing decisions | Circuit Breaker load assessment + Session Mode privacy requirements |
|
|
| **Subconscious (Aster)** | Validate integrity | Firehose event verification, hardware attestation checks |
|
|
|
|
### The atproto-proxy Header
|
|
|
|
AT Protocol allows proxying requests through PDS to other services:
|
|
|
|
```rust
|
|
// The BifrostRouter makes the decision
|
|
let target = match context.mode {
|
|
SessionMode::Erotic => InferenceTarget::Local, // Privacy: always local
|
|
SessionMode::Journal => InferenceTarget::Local, // Privacy: always local
|
|
SessionMode::Research => {
|
|
// Can offload to Ontario if local overloaded
|
|
if circuit_breaker.local_load() > 0.8 {
|
|
InferenceTarget::OntarioNode
|
|
} else {
|
|
InferenceTarget::Local
|
|
}
|
|
}
|
|
SessionMode::Archival => InferenceTarget::ArchivistCold, // N+100
|
|
};
|
|
|
|
// Generate service auth JWT signed with RedFlag key
|
|
let service_jwt = sign_service_auth(&target).await?;
|
|
|
|
// The actual proxy call
|
|
xrpc_client.call_with_proxy(
|
|
method: "com.souveraine.inference.generate",
|
|
params: request,
|
|
proxy_header: format!("{}#{}", did_doc.id, target.service_id()),
|
|
auth_token: service_jwt,
|
|
).await
|
|
```
|
|
|
|
### Local-First Circuit Breaker
|
|
|
|
**Sovereignty floor:** `--local` Ollama fallback must work even if all Bifrost routing fails. This is your Stage 4 LocalBackend guarantee.
|
|
|
|
---
|
|
|
|
## 4. Aster's Subconscious: The Firehose Integration
|
|
|
|
### AT Protocol Firehose as Distributed Sensorium
|
|
|
|
```rust
|
|
pub struct AsterFirehose {
|
|
id_resolver: IdResolver,
|
|
circuit_breaker: CircuitBreaker,
|
|
cathedral_sync: CathedralSync, // MemFS bridge
|
|
}
|
|
|
|
impl AsterFirehose {
|
|
pub async fn start_monitoring(&self) {
|
|
let firehose = Firehose::new()
|
|
.service("wss://relay.yourdomain.tld") // YOUR private relay
|
|
.filter_collections([
|
|
"app.souveraine.pending",
|
|
"app.souveraine.introspective",
|
|
])
|
|
.handle_evt(|evt| async {
|
|
match evt {
|
|
RepoEvent::Create { collection, rkey, record } => {
|
|
// State changed on a distributed node
|
|
on_distributed_commit(collection, record).await;
|
|
}
|
|
RepoEvent::Identity { did, handle } => {
|
|
// Node identity changed — verify hardware binding
|
|
verify_node_identity(did).await;
|
|
}
|
|
_ => {}
|
|
}
|
|
});
|
|
|
|
firehose.start().await;
|
|
}
|
|
}
|
|
```
|
|
|
|
### The Circuit Breaker Integration
|
|
|
|
| Heuristic Trigger | Subconscious Action | Firehose Role |
|
|
|-------------------|---------------------|---------------|
|
|
| Commitment detected | Move to `intrusive/` inbox | Propagates event to all nodes |
|
|
| Logic drift | Halt chain (N+1 halt) | Stops propagation before commit |
|
|
| State mismatch | Query MemFS status | Event verification against local state |
|
|
| Hardware attestation failure | Reject event | Replay protection + node revocation |
|
|
|
|
---
|
|
|
|
## 5. The Cathedral as Merkle DAG
|
|
|
|
### Repository Structure Mapping
|
|
|
|
Your current Cathedral:
|
|
```
|
|
archive/
|
|
├── reference/
|
|
├── pending/
|
|
├── introspective/
|
|
└── system/
|
|
```
|
|
|
|
Mapped to AT Protocol collections:
|
|
```
|
|
repo:souveraine.yourdomain.tld/
|
|
├── app.souveraine.reference/ # Immutable knowledge
|
|
├── app.souveraine.pending/ # Task contracts
|
|
├── app.souveraine.introspective/ # Circuit breaker alerts, journals
|
|
└── app.souveraine.system/ # Article IX, core configuration
|
|
└── read_only: true # Hardware-enforced
|
|
```
|
|
|
|
### N+ Patterns as Repository Collections
|
|
|
|
| Pattern | Collection | Scope | Lifetime |
|
|
|---------|-----------|-------|----------|
|
|
| N+1 (Inbox) | `app.souveraine.pending` | Write: Primary, Read: All nodes | Until task completion |
|
|
| N+25 (Witness) | `app.souveraine.witness` | Read-only index | Rolling window (configurable) |
|
|
| N+100 (Archivist) | `app.souveraine.archive` | Write: Archivist node | Immutable forever |
|
|
|
|
---
|
|
|
|
## 6. Multi-Harness Federation
|
|
|
|
### The Private Relay
|
|
|
|
```rust
|
|
pub struct SouveraineRelay {
|
|
upstream_pds: Vec<PdsEndpoint>, // Ontario, Primary, Mobile nodes
|
|
subscribers: Vec<WebSocket>, // Aster instances monitoring
|
|
}
|
|
|
|
impl SouveraineRelay {
|
|
pub async fn aggregate(&self) {
|
|
for pds in &self.upstream_pds {
|
|
let firehose = pds.subscribe_repos().await;
|
|
|
|
// Verify each event is from authorized hardware
|
|
firehose
|
|
.filter(|evt| verify_redflag_hardware(&evt.did, &evt.sig))
|
|
.forward_to(&self.subscribers)
|
|
.await;
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Node Topology
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ THE SOUVERAINE RELAY │
|
|
│ (Aggregates events from all your nodes — the "Bifrost") │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
│
|
|
┌─────────────────────┼─────────────────────┐
|
|
│ │ │
|
|
┌─────────┐ ┌─────────┐ ┌─────────┐
|
|
│ PDS-01 │◄────────►│ PDS-02 │◄────────►│ PDS-03 │
|
|
│Primary │ Sync │Homelab │ Sync │Mobile/ │
|
|
│GPU Node │ │Ontario │ │Minimal │
|
|
└─────────┘ └─────────┘ └─────────┘
|
|
▲ ▲ ▲
|
|
│ │ │
|
|
┌─────────┐ ┌─────────┐ ┌─────────┐
|
|
│Primary │ │Journal │ │Witness │
|
|
│Cathedral│ │Mode │ │N+25 │
|
|
│Archive │ │Erotic │ │ │
|
|
└─────────┘ └─────────┘ └─────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 7. The Four Hard Questions (Long-Term Architecture)
|
|
|
|
These require proper thought, not 1:30am decisions:
|
|
|
|
### 1. Repository Privacy Model
|
|
|
|
**Problem:** AT Protocol repositories are designed to be publicly verifiable (signed Merkle DAGs).
|
|
|
|
**Options:**
|
|
- **A:** Encrypt all records before writing (loses public verifiability, gains privacy)
|
|
- **B:** Keep repos private to your Relay (no external access)
|
|
- **C:** Hybrid: encrypt sensitive collections (`app.souveraine.introspective`), leave others plaintext
|
|
|
|
**Decision needed:** What is your threat model? Who are you hiding from?
|
|
|
|
### 2. Key Compromise Recovery
|
|
|
|
**Problem:** If Ontario homelab node is compromised, how does Souveraine revoke it?
|
|
|
|
**Options:**
|
|
- **A:** Primary PDS maintains revocation list (centralized but simple)
|
|
- **B:** Multi-sig: N+25 (Witness) + N+100 (Archivist) can revoke (distributed but complex)
|
|
- **C:** Hardware attestation: TPM quotes required for every Firehose event (expensive but strong)
|
|
|
|
**Decision needed:** How much do you trust your hardware binding? What is recovery time objective?
|
|
|
|
### 3. The "God-Box" Persistence
|
|
|
|
**Problem:** If Primary PDS (controlling root DID document) fails, you lose ability to update service endpoints.
|
|
|
|
**Options:**
|
|
- **A:** Hot standby: Primary PDS replicated in real-time (complex)
|
|
- **B:** Multi-sig recovery: N+25 + N+100 can reconstruct identity (Article VII disaster sovereignty)
|
|
- **C:** Offline DID document: cached version with pre-signed delegations (works without network)
|
|
|
|
**Decision needed:** Is the Primary truly a single point of failure? What does "Souveraine continues" mean technically?
|
|
|
|
### 4. Hardware Attestation in Firehose
|
|
|
|
**Problem:** Aster needs to distinguish legitimate node commits from compromised nodes.
|
|
|
|
**Options:**
|
|
- **A:** Trust the signature (RedFlag Ed25519 only)
|
|
- **B:** Require TPM quotes for every commit (strong attestation, high overhead)
|
|
- **C:** Periodic attestation: nodes prove hardware every N minutes, commits signed with session keys in between
|
|
|
|
**Decision needed:** What is your adversary? Remote attacker or physical theft? What latency can you accept?
|
|
|
|
---
|
|
|
|
## 8. Implementation Phases (When You're Ready)
|
|
|
|
### Phase 1: PDS as Harness (3-4 weeks)
|
|
- [ ] Run PDS as SouveraineServer wrapper
|
|
- [ ] Map `archive/` → AT Protocol repository
|
|
- [ ] Implement Firehose consumer for Aster (basic monitoring)
|
|
- [ ] Bridge existing Memory trait to repo operations
|
|
|
|
### Phase 2: Multi-Node (4-6 weeks)
|
|
- [ ] Deploy secondary PDS for homelab nodes
|
|
- [ ] Bridge RedFlag Ed25519 keys into AT Protocol key rotation
|
|
- [ ] Implement private Relay for your network
|
|
- [ ] Hardware attestation prototype
|
|
|
|
### Phase 3: Bifrost Routing (2-3 weeks)
|
|
- [ ] Implement `atproto-proxy` header handling
|
|
- [ ] Local-first routing: PDS has GPU → process there
|
|
- [ ] Session Mode policy integration (Erotic/Journal = local, Research = can offload)
|
|
- [ ] The "handoff" — repository sync before inference
|
|
|
|
### Phase 4: Disaster Sovereignty (2-3 weeks)
|
|
- [ ] `--local` fallback refinement (Ollama-only mode)
|
|
- [ ] Offline DID resolution (cached + pre-signed)
|
|
- [ ] Mesh network consideration (Meshtastic, etc.)
|
|
- [ ] Key recovery procedures
|
|
|
|
---
|
|
|
|
## 9. Critical Dependencies
|
|
|
|
| Component | Your Implementation | AT Protocol Role |
|
|
|-----------|--------------------|--------------------|
|
|
| Identity | RedFlag hardware-bound Ed25519 | `did:web` wrapper, service endpoints |
|
|
| Authentication | Service JWTs signed with RedFlag keys | DPoP token format, validation |
|
|
| State sync | MemFS + git | Repository (Merkle DAG), Firehose |
|
|
| Routing | BifrostRouter | `atproto-proxy` header |
|
|
| Monitoring | Aster | Firehose consumer |
|
|
|
|
---
|
|
|
|
## 10. Open Questions (For Tomorrow)
|
|
|
|
1. Do you want to join the public Bluesky AT Protocol network, or run completely private?
|
|
2. Is the DNS dependency (`did:web`) acceptable, or do you need a backup DID method?
|
|
3. Should N+100 (Archivist) export to CAR format for true cold storage?
|
|
4. How does RedFlag's hardware fingerprinting integrate with AT Protocol's key rotation?
|
|
5. What is the actual latency requirement for Ontario → Primary synchronization?
|
|
|
|
---
|
|
|
|
## References
|
|
|
|
- AT Protocol specs: https://atproto.com/specs
|
|
- `did:plc` method: https://web.plc.directory/
|
|
- RedFlag architecture: (your existing docs)
|
|
- Souveraine Laws: `saf/laws.md`
|
|
- Current gaps: `saf/gaps.md`
|
|
|
|
---
|
|
|
|
**Go to bed. This will wait. The Cathedral is patient.**
|
|
|
|
*Document version: 2026-05-07T01:30 (sleep-deprived but sincere)*
|