Watch
1
0
Fork
You've already forked souveraine
0
souveraine/saf/atproto-federation.md
Fimeg 3ff6ffaa7f license: relicense AGPL-3.0; bring SAF docs online; keep CLAUDE.md + docs/ local
SAF (souveraine architecture files) is now the in-repo doc set. working notes
(CLAUDE.md, docs/) stay on disk, gitignored.
2026-06-19 10:17:56 -04:00

15 KiB

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% casedid:web lets you control the root of trust via your own domain.

{
  "@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

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:

// 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

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

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


Go to bed. This will wait. The Cathedral is patient.

Document version: 2026-05-07T01:30 (sleep-deprived but sincere)