Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Communication channels [SPEC]

Version: 3.0.0 Last Updated: 2026-03-14 Status: Draft


Reader orientation: This document specifies how a Golem (a mortal autonomous DeFi agent compiled as a single Rust binary on a micro VM) communicates with its owner and the outside world across three surfaces: TUI, web portal, and social connectors (Telegram, Discord, Twitter/X, Farcaster). It sits in the Runtime layer of the Bardo specification. The main prerequisite is the Event Fabric, the internal event bus that all surfaces consume from. For any unfamiliar term, see prd2/shared/glossary.md.

Overview

Three communication surfaces – TUI (primary), web portal (secondary), and social connectors (tertiary) – all fed by the Event Fabric. Per-channel message formats, frequencies, formatting, and delivery guarantees.

Cross-references:

  • ./12-realtime-subscriptions.md — full GolemEvent enum (50+ variants), WebSocket subscription protocol, delta encoding, reconnection semantics, and bandwidth estimates
  • ./11-state-model.md — defines GolemState (mutable internal state) and GolemSnapshot (read-only projection for UI consumption), with all component interfaces
  • ./00-interaction-model.md — user-Golem interaction model: TUI architecture, authentication, Heartbeat FSM, operator intervention (steer/follow_up), and the 29-screen navigation hierarchy
  • ../05-dreams/01-architecture.md — dream scheduling architecture: the three-phase NREM/REM/integration cycle and knowledge consolidation
  • ../03-daimon/07-runtime-daimon.md — runtime integration of the Daimon affect engine: mood event emission, PAD vector updates, and emotional contagion across Clades
  • ../02-mortality/12-integration.md — mortality event integration: death protocol steps, phase transition events, and clock threshold warnings

1. Three surfaces

SurfaceModalityPrimary useAudience
TUI (bardo-terminal)Persistent, 60fpsLive Golem management, creature visualization, knowledge browsingOwners, power users
Web PortalBrowserSetup wizard, reputation profile, vault analytics, knowledge browserAll users
Social connectorsPush notificationsAlerts, daily summaries, death warnings, status checksAll users

The TUI is the primary surface. It is a standalone Rust binary (bardo-terminal) that renders animated sprites, real-time event streams, and multi-pane dashboards at 60fps via ratatui. The web portal handles setup, analytics, and scenarios where a browser is more appropriate. Social connectors are notification channels – they push alerts, they don’t host conversations.


2. Event Fabric (internal bus)

All surfaces consume from the same source: the Event Fabric, a tokio::broadcast channel inside the Golem runtime with a ring buffer of 10,000 entries. Every internal state transition emits a typed GolemEvent (CamelCase Rust enum variants). Surfaces subscribe to the Event Fabric over WebSocket and receive events as tagged JSON.

#![allow(unused)]
fn main() {
/// The Event Fabric is the single source of truth for all Golem events.
/// Surfaces connect via WebSocket, specify topic filters, and receive
/// a filtered stream of GolemEvent variants.
pub struct EventFabric {
    tx: tokio::sync::broadcast::Sender<GolemEvent>,
    ring_buffer: RingBuffer<GolemEvent>,
}

impl EventFabric {
    pub fn emit(&self, event: GolemEvent) {
        // Only serialize if subscribers exist
        if self.tx.receiver_count() > 0 {
            let _ = self.tx.send(event.clone());
        }
        self.ring_buffer.push(event);
    }

    pub fn subscribe(&self, resume_from: Option<u64>) -> EventStream {
        let rx = self.tx.subscribe();
        let replay = resume_from
            .map(|seq| self.ring_buffer.since(seq))
            .unwrap_or_default();
        EventStream { replay, rx }
    }
}
}

Events use CamelCase variant names in Rust (HeartbeatTick, SwapExecuted, DreamInsight) and serialize with #[serde(tag = "type")] for discriminated-union dispatch over the wire. Field names use snake_case. Timestamps are Unix milliseconds.


3. TUI transport (primary)

3.1 Architecture

The TUI connects to the Golem VM’s WebSocket endpoint. A second WebSocket connects to Styx (the global knowledge relay and persistence layer at wss://styx.bardo.run) for ecosystem-wide events (pheromone field, Bloodstains (market conditions recorded at another Golem’s death, broadcast as warnings), other Golems).

+---------------------------+       WebSocket        +------------------+
|   bardo-terminal          |<--- GolemEvents -------|  Golem VM        |
|   (Rust / ratatui)        |---- commands --------->|  (Fly.io)        |
|                           |      :8080             |                  |
|   60fps render loop       |                        |  Event Fabric    |
|   Sprite engine           |       WebSocket        |  Heartbeat FSM   |
|   Particle system         |<--- Styx events -------|                  |
|   Custom widgets          |      :8080/ws          +------------------+
|   Sound engine (rodio)    |                        |  Styx Service    |
|   Input handling          |                        |  (Fly.io)        |
+---------------------------+                        +------------------+

The render loop runs at 60fps independently of event arrival. Events update shared state; the renderer reads state each frame. No frame waits on a network call. Input polling, WebSocket drain, animation tick, and terminal flush all fit within the 16.6ms frame budget.

3.2 Event delivery

The TUI subscribes to all Event Fabric topics and receives every GolemEvent variant. Events drive screen updates:

  • HeartbeatTick updates the Beat screen pipeline visualization
  • SwapExecuted triggers a trade animation and updates the Vault screen
  • DreamInsight appends to the Dreams screen hypothesis tracker
  • VitalityPhaseChange triggers sprite animation transitions
  • PheromoneDeposit updates the Clade (cooperative group of Golems sharing knowledge via Styx) screen heatmap

3.3 Owner commands

The TUI sends typed commands over the same WebSocket:

#![allow(unused)]
fn main() {
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum OwnerCommand {
    Steer { message: String },
    FollowUp { message: String },
    PauseHeartbeat,
    ResumeHeartbeat,
    KillSwitch,
    WakeFromDream,
    SpawnReplicant { config: ReplicantConfig },
}
}

3.4 Auth flow

The TUI uses browser handoff for authentication, mirroring the Claude Code / Codex pattern:

  1. Terminal generates session ID and opens bardo.run/auth?session=xxx in the browser
  2. User authenticates in browser (wallet signature, email, or OAuth)
  3. Terminal polls /auth/status?session=xxx every 2 seconds
  4. On success: session token + wallet address returned
  5. Stored in ~/.bardo/auth.json (0o600 permissions)

While waiting, the terminal shows a copyable URL, a QR code, and keyboard shortcuts. For headless SSH: device code flow (RFC 8628) where the terminal shows a code like BARD-7F3A and the user visits bardo.run/device to enter it.


4. Web portal transport (secondary)

4.1 WebSocket protocol

Primary transport for the portal’s interactive features.

Connection:

wss://<machine-name>.bardo.money/ws
Authorization: Bearer <session-token>

Message types:

#![allow(unused)]
fn main() {
/// Client -> Server
#[derive(Debug, Serialize, Deserialize)]
pub struct WsClientMessage {
    pub channel: String,
    pub action: String,
    pub payload: serde_json::Value,
    pub request_id: Option<String>,
}

/// Server -> Client
#[derive(Debug, Serialize, Deserialize)]
pub struct WsServerMessage {
    pub channel: String,
    pub event: String,
    pub payload: serde_json::Value,
    pub request_id: Option<String>,
    pub timestamp: u64,
}
}

4.2 Channel multiplexing

A single WebSocket carries multiple logical channels:

ChannelDirectionPurpose
systemBidirectionalConnection lifecycle, subscribe/unsubscribe, ping/pong
eventsServer -> ClientReal-time GolemEvent stream
logsServer -> ClientLive structured log stream (filterable by level)
terminalBidirectionalConversation (steer/followUp/response)
strategyBidirectionalStrategy parameter updates, trigger rebalance
grimoireServer -> ClientLive Grimoire (the Golem’s persistent knowledge base of episodes, insights, heuristics, and causal links) updates (new insights, confidence changes)
dreamsServer -> ClientDream cycle progress, insights, mode transitions

4.3 Full server event catalog

All events emitted by the Golem, organized by subsystem. Events use CamelCase Rust enum variants serialized as tagged JSON.

Heartbeat events (topic: heartbeat):

EventTriggerVisibility
MarketObservationStep 1 completeOwner
HeartbeatTickGating decisionOwner
HeartbeatCompleteFull cycle doneOwner
TierSelectedStep 4Owner

Vitality events (topic: vitality):

EventTriggerVisibility
VitalityUpdateEvery tickPublic (partial)
VitalityPhaseChangePhase transitionPublic

Mood events (topic: mood):

EventTriggerVisibility
MoodUpdatePAD delta > 0.15Public (label), Owner (PAD)
MoodAppraisalAppraisal firesInternal
MoodContagionClade PAD syncInternal

Dream events (topic: dream):

EventTriggerVisibility
DreamStartCycle beginsOwner
DreamProgressPhase transitionOwner
DreamCompleteCycle endsOwner
DreamInsightNotable hypothesisOwner
DreamWakeInterruptWake commandOwner

Mortality events (topic: death):

EventTriggerVisibility
MortalityWarningClock thresholdOwner
DeathImminentComposite < 0.15All channels
StochasticCheckEvery tickInternal
SenescenceStageStage changeOwner
DeathProtocolStepProtocol phaseOwner

Tool events (topic: tools):

EventTriggerVisibility
ToolExecutionStartTool invokedOwner
ToolExecutionUpdateProgress stepOwner
ToolExecutionEndTool completeOwner
PermitCreatedCapability issuedOwner
PermitCommittedCapability consumedOwner

Trade events (topic: performance):

EventTriggerVisibility
SwapExecutedTrade completesOwner
VaultNavUpdateNAV changesPublic

4.4 Reconnection

ParameterValue
Initial reconnect delay3 seconds
Backoff multiplier2x
Max reconnect delay30 seconds
Max reconnect attemptsUnlimited (persistent)
Resume-from supportYes (server replays from buffer)
Event buffer size10,000 events

On reconnect, the client sends the last seen sequence number. The server replays missed events from its ring buffer.


5. Social connectors (tertiary)

Social platform connectors bridge platform I/O with the Golem’s event stream. Each connector translates inbound platform messages into typed RPC calls and routes outbound Golem events to platform notifications. The bardo-social crate provides the connector implementations.

5.1 Supported platforms

Telegram (launch platform):

PropertyValue
TransportTelegram Bot API (long polling or webhook)
Rate limits30 messages/sec per chat
Character limit4,096 per message
Rich contentInline keyboards, Markdown formatting, image attachments
Auth modelTelegram user ID mapped to wallet address

Telegram is the primary social connector. Bot API provides reliable delivery, inline keyboards for interactive confirmations, and Markdown formatting for portfolio summaries. Group chat support enables shared monitoring of Clade activity.

Discord (phase 2):

PropertyValue
TransportDiscord Gateway (WebSocket)
Rate limitsPlatform-standard
Character limit2,000 per message, 4,096 per embed
Rich contentEmbeds, buttons, slash commands
Auth modelDiscord user ID mapped to wallet address

Slash commands (/bardo status, /bardo portfolio, /bardo ask) registered as global application commands. Rich embeds with color-coded phase indicators.

Twitter/X (phase 2):

PropertyValue
TransportTwitter API v2
Rate limits300 posts/3h (free tier), higher on paid
Character limit280 per post
Rich contentThreads, polls, card links
Auth modelTwitter user ID mapped to wallet address

Outbound only by default. Public Golems can post performance updates and market observations. Truncation at 270 chars (leave room for mentions).

Farcaster (phase 2):

PropertyValue
TransportFarcaster Hub API
Rate limitsProtocol-level (no hard per-user limit)
Character limit320 per cast
Rich contentFrames, embeds
Auth modelFarcaster FID mapped to wallet address

Native to crypto communities. Cast-based interaction model. Frames can embed interactive vault dashboards.

5.2 Notification events

The social connector emits notifications for lifecycle events. All notifications are outbound only (Golem -> user). The Golem never receives strategy instructions through notification channels.

EventTriggerPriority
StrategyDeployedGolem boots and begins executingHigh
PnlMilestoneP&L crosses configurable thresholdMedium
StopLossTriggeredStop-loss hit, position closedHigh
GolemDyingCredits < 5%, death preparation beginsCritical
CoordinationUpdateERC-8001/8033/8183 intent status changeMedium
ReputationChangeERC-8004 (the on-chain agent identity standard) tier change (up or down)Medium
RegimeShiftMarket regime change detectedMedium

5.3 Platform-specific formatting

Each notification is formatted for the target platform:

#![allow(unused)]
fn main() {
pub fn format_for_platform(
    message: &str,
    platform: &str,
) -> FormattedMessage {
    match platform {
        "twitter" => FormattedMessage {
            text: truncate(message, 270),
            platform: platform.into(),
            truncated: message.len() > 270,
            embeds: vec![],
        },
        "telegram" => FormattedMessage {
            text: format_markdown(message),
            platform: platform.into(),
            truncated: false,
            embeds: vec![MessageEmbed::InlineKeyboard(status_keyboard())],
        },
        "discord" => FormattedMessage {
            text: String::new(),
            platform: platform.into(),
            truncated: false,
            embeds: vec![build_discord_embed(message)],
        },
        "farcaster" => FormattedMessage {
            text: truncate(message, 310),
            platform: platform.into(),
            truncated: message.len() > 310,
            embeds: vec![],
        },
        _ => unreachable!(),
    }
}
}

5.4 Rate limiting

ChannelInbound limitOutbound limit
Social commands1/second per user
Deployment requests5/hour per user
Status queries10/minute per user
Platform notificationsPlatform-specific (see above)
Clade broadcasts1/minute per Clade

5.5 Cross-platform notification routing

Users who interact on multiple platforms configure which platforms receive which notification types:

NotificationDefault platformConfigurable
Deployment confirmationOriginating platformNo
P&L milestonesAll connected platformsYes
Stop-loss alertsAll connected platformsNo (always)
Credit warningsAll connected platformsNo (always)
Status updatesOriginating platform onlyYes

6. Heartbeat delivery

The heartbeat tick is the Golem’s fundamental lifecycle signal.

6.1 Event emission

Every tick emits a HeartbeatTick event via the Event Fabric. The TUI receives all ticks. The web portal receives all ticks over WebSocket. Social connectors receive only phase changes and daily summaries.

6.2 Regime and phase change events

Special events emitted on transitions:

#![allow(unused)]
fn main() {
/// Emitted when the behavioral phase transitions.
GolemEvent::VitalityPhaseChange {
    timestamp: u64,
    golem_id: String,
    sequence: u64,
    tick: u64,
    from_phase: String,
    to_phase: String,
    survival_pressure: f64,
    projected_life_hours: f64,
    trigger: String,
}

/// Emitted when the market regime shifts.
GolemEvent::RegimeChange {
    timestamp: u64,
    golem_id: String,
    sequence: u64,
    tick: u64,
    from_regime: String,
    to_regime: String,
    price_delta: f64,
    volume_spike: f64,
    iv_change: f64,
    new_interval_ms: u64,
}
}

6.3 Per-surface delivery config

Event typeTUIWeb portalTelegramDiscordWebhook
Every tickYesYesNoNoOptional
Trade executedYesYesOpt-inOpt-inYes
Phase changeYesYesAlwaysAlwaysYes
Daily summaryN/AYesYesYesOptional

7. Webhook delivery

7.1 Registration

#![allow(unused)]
fn main() {
pub struct WebhookConfig {
    pub url: String,
    pub events: Vec<String>,
    pub secret: String,
    pub enabled: bool,
}
}

7.2 Signature verification

X-Bardo-Signature: sha256=a1b2c3d4e5f6...
X-Bardo-Delivery-Id: dlv_abc123
X-Bardo-Event: SwapExecuted
X-Bardo-Timestamp: 1709942400000
Content-Type: application/json

HMAC-SHA256 over {timestamp}.{json_payload}.

7.3 Retry policy

AttemptDelay
1Immediate
230 seconds
32 minutes
410 minutes
51 hour
66 hours (final)

After 6 failures: webhook auto-disabled. Re-enable via PATCH /api/v1/webhooks/:id.


8. Delivery guarantees

SurfaceGuaranteeOrderingDurability
TUI (WS)At-most-onceOrdered per channelRing buffer (10,000 events)
Portal WSAt-most-onceOrdered per channelRing buffer (10,000 events)
Portal SSEAt-least-once (with replay)Ordered by sequenceRing buffer (10,000 events)
TelegramAt-least-onceOrdered per chatTelegram server queue
DiscordAt-most-onceOrdered per channelDiscord gateway
WebhookAt-least-once (with retry)Ordered per deliverySQLite dead letter (72h)

End of document.