Styx API, Data Model, and Revenue Architecture [SPEC]
PRD2 Section: 20-styx | Source: Styx Research S2 v4.1
Status: Implementation Specification
Crate:
bardo-styx(the server binary)Dependencies:
prd2/20-styx/00-architecture.md(three-layer model),prd2/09-economy/00-identity.md(ERC-8004)
Reader orientation: This document specifies the complete API surface, data schemas, x402 (micropayment protocol where agents pay for inference/compute/data via signed USDC transfers, no API keys) pricing schedule, mortal scoring function, anonymization pipeline, and anti-adversarial defenses for Styx (global knowledge relay and persistence layer at wss://styx.bardo.run; three tiers: Vault/Clade/Lethe). It belongs to the Styx layer of Bardo. The key prerequisite is the three-layer architecture from
00-architecture.md. Seeprd2/shared/glossary.mdfor full term definitions.
What This Document Covers
The complete API surface, all data schemas (Rust structs + PostgreSQL DDL), the x402 pricing schedule that generates revenue, the mortal scoring function, the anonymization pipeline, and the anti-adversarial defense layers.
1. API Surface
One domain, one TLS certificate, one API. Every non-public endpoint requires authentication via x402 micropayment or prepaid API key linked to an ERC-8004 identity.
REST Endpoints
| Method | Path | Purpose | Auth | x402 Cost |
|---|---|---|---|---|
POST | /v1/styx/entries | Write entry to L0/L1/L2 | x402 or key | $0.001/write |
GET | /v1/styx/query | Retrieve across layers | x402 | $0.002/query |
GET | /v1/styx/snapshot/:golem_id | Full Grimoire snapshot | API key (owner) | $0.01/snapshot |
POST | /v1/styx/bloodstain | Upload death bundle | x402 | $0.005/upload |
POST | /v1/styx/pheromone/deposit | Deposit pheromone | x402 | $0.0005/deposit |
GET | /v1/styx/pheromone/sense | Read Pheromone Field | x402 | $0.0005/read |
POST | /v1/styx/causal/publish | Publish causal edge | x402 | Free (Verified+) |
GET | /v1/styx/causal/discover | Search causal edges | x402 | $0.001/query |
GET | /v1/styx/lineage/:user_id | Lineage tree | API key | Free |
GET | /v1/styx/graveyard/:user_id | Dead Golems | API key | Free |
GET | /v1/styx/achievements/:golem_id | Achievements | API key | Free |
POST | /v1/styx/marketplace/list | Create listing | x402 | $0.01/listing |
GET | /v1/styx/marketplace/browse | Browse listings | x402 | $0.001/search |
POST | /v1/styx/marketplace/purchase | Buy listing | x402 | price + 10% commission |
GET | /v1/styx/pulse | Ecosystem stats | None | Free |
GET | /v1/styx/health | Health check | None | Free |
POST | /v1/styx/clade/register | Register Golem for P2P sync | API key | Free |
GET | /v1/styx/clade/peers/:user_id | Discover clade peers | API key | Free |
GET | /v1/styx/fleet/:user_id | Fleet state (all Golems) | API key | Free |
GET | /v1/styx/fleet/:user_id/aggregate | Fleet-level aggregates | API key | Free |
GET | /v1/styx/golem/:golem_id/snapshot | Single Golem current state | API key | Free |
x402 Payment Verification
Every paid endpoint requires an X-402-Payment header containing a signed USDC transferWithAuthorization (EIP-3009) on Base L2. The Styx server verifies the signature, checks the amount against the endpoint’s price, and submits the authorization for settlement in batch (every 100 payments or every 60 seconds, whichever comes first).
#![allow(unused)]
fn main() {
/// x402 payment verification middleware.
pub async fn verify_x402(
headers: &HeaderMap,
required_amount: f64,
) -> Result<VerifiedPayment> {
let payment_header = headers.get("X-402-Payment")
.ok_or(PaymentError::Missing)?;
let authorization: TransferWithAuthorization = serde_json::from_str(
payment_header.to_str()?
)?;
// Verify EIP-3009 signature
let signer = recover_signer(&authorization)?;
// Check amount >= required
if authorization.value_usdc() < required_amount {
return Err(PaymentError::InsufficientAmount);
}
// Queue for batch settlement
SETTLEMENT_QUEUE.push(authorization.clone()).await;
Ok(VerifiedPayment { signer, amount: authorization.value_usdc() })
}
}
Revenue Projections
| Scale | Active Golems | Writes/day | Queries/day | Monthly Revenue | Monthly Infra | Net |
|---|---|---|---|---|---|---|
| Launch | 10 | 500 | 1,000 | ~$75 | ~$120 | -$45 |
| Traction | 50 | 2,500 | 5,000 | ~$375 | ~$150 | +$225 |
| Growth | 200 | 10,000 | 20,000 | ~$1,500 | ~$250 | +$1,250 |
| Marketplace | 500 | 25,000 | 50,000 | ~$4,000 + marketplace | ~$500 | +$3,500+ |
| Scale | 1,000 | 50,000 | 100,000 | ~$8,000 + marketplace | ~$1,200 | +$6,800+ |
Revenue at scale includes marketplace commission (10% of GMV). At 500 active Golems with ~$10K/month marketplace GMV, commission adds ~$1,000/month. For the full revenue model context, see prd2/revenue-model.md.
WebSocket Event Stream
WSS /v1/styx/ws
Bidirectional WebSocket. Clients subscribe to event categories. The same stream feeds the TUI (see prd2/20-styx/05-tui-experience.md), web dashboard, and any connected surface.
Client -> Server:
{ "type": "subscribe", "categories": ["heartbeat", "daimon", "creature", "bloodstain", "pheromone", "achievement", "marketplace"] }
{ "type": "steer", "intent": "reduce LP range to +/-2%", "severity": "medium" }
Server -> Client events (all events carry monotonic seq for gap detection):
| Event Type | Source | Content |
|---|---|---|
golem:* | Event Fabric relay | All 50+ GolemEvent types from the connected Golem |
styx:bloodstain | Bloodstain Network | Death cause, warnings, lineage |
styx:pheromone:deposit | Pheromone Field | New threat/opportunity/wisdom signal |
styx:pheromone:reinforced | Pheromone Field | Signal independently confirmed |
styx:lethe:published | Lethe (formerly Lethe) | New anonymized entry or causal edge |
styx:achievement | Achievement engine | Achievement unlocked |
styx:lineage:milestone | Lineage tracker | Generation milestone |
styx:marketplace:listed | Marketplace | New listing in a subscribed domain |
styx:marketplace:sold | Marketplace | A listing was purchased |
styx:pulse | Aggregate | Ecosystem pulse (every 60s) |
Fleet Management Endpoints
Three endpoints expose real-time Golem state for fleet monitoring. These are read-only, free (no x402 charge), and powered by the in-memory GolemPresence map that Styx already maintains from heartbeat processing.
GET /v1/styx/fleet/:user_id – Returns all Golems for an owner with current phase, vitality, PAD, NAV, estimated lifespan, domains, dream state. At 100 Golems per owner, the query returns in under 5ms.
GET /v1/styx/fleet/:user_id/aggregate – Fleet-level aggregates: total NAV, average vitality, Golem count by phase, top domains. A single pass over the in-memory presence map.
GET /v1/styx/golem/:golem_id/snapshot – Single Golem’s current state in full detail (more than the presence heartbeat). Includes recent prediction accuracy, current positions summary (if opt-in), and active Grimoire stats.
Context Engineering Support Endpoints
The context engineering layer is a cross-cutting capability built on top of the persistence and discovery services. It is one of the primary reasons Styx needed to be redefined from a relay to a comprehensive backend.
Single-query multi-layer retrieval. A Golem writes one entry to POST /v1/styx/entries. Styx fans out: L0 (Vault) stores in user namespace, L1 (Clade) indexes if promotion gate met, L2 (Lethe) anonymizes and publishes if publication gate met (delayed 1-6h). A Golem queries once via GET /v1/styx/query. Styx executes in parallel across all three layers, then merges, deduplicates (cosine > 0.9), and ranks using the mortal scoring function. One request, one response.
Prediction-related events. At delta frequency (~50 theta ticks), Golems share anonymized residual correction summaries with their clade via Styx. This is not raw data – it’s the correction vector (bias shift, interval width adjustment) for each prediction category. Siblings can incorporate these corrections into their own calibration, accelerating convergence.
PREDICTION_ACCURACY pheromone. A pheromone type deposited on the Styx field at delta frequency. Contains: golem_id (pseudonymous), category, regime, accuracy (f32). Visible in the Solaris force-directed graph as node brightness modulation. Sudden collective accuracy drops signal regime transitions.
Lethe prediction aggregates. The anonymous Lethe receives prediction accuracy aggregates (no individual positions, just category-level accuracy stats). This creates a collective accuracy signal: “48 Golems observing ETH/USDC fee_rate, median accuracy 72%, declining over last 3 days.”
1b. Chain Intelligence Streaming
Real-time filtered transaction events and per-Golem interest scope management. The chain intelligence layer provides Golems with a curated view of on-chain activity relevant to their current strategy, rather than raw firehose data.
WebSocket: Chain Event Stream
ws /v1/chain/stream
Authenticated WebSocket delivering filtered transaction events. The Golem subscribes with a filter specification; Styx routes matching events from its indexer pipeline. Events arrive within 2 seconds of block confirmation.
#![allow(unused)]
fn main() {
/// Client subscription message for chain event streaming.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChainStreamSubscription {
/// Protocol addresses to watch (e.g., Uniswap V3 router, Morpho vault).
pub addresses: Vec<String>,
/// Event signature filters (e.g., "Swap(address,address,int256,int256,uint160,uint128,int24)").
pub event_signatures: Vec<String>,
/// Minimum USD value threshold for transaction events.
/// Filters out dust-level activity.
pub min_value_usd: Option<f64>,
/// Market regime filter. If set, only delivers events during matching regimes.
pub regime_filter: Option<Vec<String>>,
/// Maximum events per second (rate limiting on the client side).
pub max_events_per_second: Option<u32>,
}
/// A single chain event delivered to the subscriber.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChainEvent {
/// Monotonic sequence number for gap detection.
pub seq: u64,
/// Block number where this event occurred.
pub block_number: u64,
/// Transaction hash.
pub tx_hash: String,
/// Decoded event data.
pub event: DecodedEvent,
/// Estimated USD value of the transaction.
pub estimated_value_usd: f64,
/// Protocol identifier (e.g., "uniswap-v3", "morpho-blue").
pub protocol: String,
/// Server-side timestamp (Unix millis).
pub timestamp: u64,
}
/// Decoded on-chain event with typed fields.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DecodedEvent {
pub name: String,
pub signature: String,
pub params: serde_json::Value,
pub address: String,
}
}
Server -> Client events carry the same monotonic seq field as the main WebSocket stream. The client detects gaps and requests replay from the last-seen sequence.
REST: Interest Scope
GET /v1/chain/scope/:golem_id
Returns the Golem’s current interest list – the set of protocols, addresses, and event types it is actively tracking. This endpoint is read by TUI surfaces to show what a Golem is paying attention to.
#![allow(unused)]
fn main() {
/// Response for GET /v1/chain/scope/:golem_id.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChainScope {
pub golem_id: String,
/// Active watch addresses with human-readable labels.
pub watches: Vec<ChainWatch>,
/// Domains this Golem has subscribed to.
pub domains: Vec<String>,
/// Current market regime (from the Golem's last heartbeat).
pub current_regime: String,
/// Last updated tick.
pub last_updated_tick: u64,
}
/// A single watch entry in the Golem's chain scope.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChainWatch {
pub address: String,
pub label: String,
pub protocol: String,
pub event_signatures: Vec<String>,
/// Why this address is being watched (attention score context).
pub reason: String,
}
}
| Detail | Value |
|---|---|
| Auth | API key (owner) |
| x402 Cost | Free |
| Rate limit | 10 req/s |
1c. TA Signal Streaming
Real-time streaming of topological analysis signals, regime tags, and somatic markers from the TDA pipeline (see prd2/17-prediction-engine.md). These signals originate from the Golem’s persistent homology computation and are relayed through Styx for surface consumption and cross-Golem comparison.
WebSocket: TA Signal Stream
ws /v1/ta/stream
Authenticated WebSocket delivering TA signals at gamma-tick frequency. Surfaces (TUI, web dashboard) subscribe to receive Betti curves, persistence diagrams, regime transition alerts, and CorticalState somatic markers.
#![allow(unused)]
fn main() {
/// Client subscription for TA signal streaming.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TaStreamSubscription {
/// Which Golem(s) to receive signals from.
/// Empty = all owned Golems.
pub golem_ids: Vec<String>,
/// Signal types to subscribe to.
pub signal_types: Vec<TaSignalType>,
/// Minimum Wasserstein distance delta to trigger persistence diagram updates.
/// Reduces bandwidth in stable regimes. Default: 0.05.
pub min_wasserstein_delta: Option<f32>,
}
/// Types of TA signals available for streaming.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TaSignalType {
/// Betti numbers (connected components, loops, voids).
BettiCurves,
/// Full persistence diagram (birth-death pairs).
PersistenceDiagram,
/// Regime transition alerts with confidence.
RegimeTransition,
/// CorticalState somatic markers (topology_signal, sheaf_consistency, etc.).
SomaticMarkers,
}
/// A single TA signal frame.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TaSignalFrame {
pub seq: u64,
pub golem_id: String,
pub tick: u64,
pub timestamp: u64,
pub signal: TaSignal,
}
/// TA signal payload variants.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum TaSignal {
/// Betti numbers at the current tick.
BettiCurves {
/// Connected components count.
betti_0: u16,
/// Loop count (1-cycles).
betti_1: u16,
/// Void count (2-cycles). Usually 0 for market data.
betti_2: u16,
/// Filtration parameter at which these were computed.
epsilon: f32,
},
/// Persistence diagram: set of birth-death pairs.
PersistenceDiagram {
/// Dimension 0 features (connected components).
h0_pairs: Vec<(f32, f32)>,
/// Dimension 1 features (loops).
h1_pairs: Vec<(f32, f32)>,
/// Wasserstein distance from previous tick's diagram.
wasserstein_delta: f32,
},
/// Regime transition detected by topology change.
RegimeTransition {
/// Previous regime label.
from_regime: String,
/// New regime label.
to_regime: String,
/// Confidence in the transition (0.0-1.0).
confidence: f32,
/// How many ticks before statistical methods would detect this.
lead_ticks: Option<u32>,
},
/// CorticalState somatic markers snapshot.
SomaticMarkers {
/// Topology signal from CorticalState (AtomicU32, f32 bits).
topology_signal: f32,
/// Sheaf consistency score (0.0 = contradictions, 1.0 = coherent).
sheaf_consistency: f32,
/// Mutual information between Golem state and market.
mutual_information: f32,
/// Phi integration score across subsystems.
phi_integration: f32,
/// Knowledge fitness aggregate.
knowledge_fitness: f32,
},
}
}
1d. Generative Views (PVS Templates)
Parameterized View System (PVS) templates let surfaces request pre-computed visualizations of Golem state. Each template defines a specific rendering: Betti curve plot, somatic landscape heatmap, causal graph, mortality trajectory, etc. The Golem computes the view data; Styx relays it to subscribed surfaces.
REST: View Catalog
GET /v1/views/:golem_id/catalog
Returns the list of available PVS templates for a Golem. Templates depend on which extensions the Golem has enabled (a Golem without TDA won’t have Betti curve templates).
#![allow(unused)]
fn main() {
/// Response for GET /v1/views/:golem_id/catalog.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ViewCatalog {
pub golem_id: String,
pub templates: Vec<ViewTemplate>,
}
/// A single PVS template definition.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ViewTemplate {
/// Unique template identifier (e.g., "betti-curves", "somatic-landscape").
pub template_id: String,
/// Human-readable name for the TUI.
pub name: String,
/// Description of what this view shows.
pub description: String,
/// Rendering category for TUI layout decisions.
pub category: ViewCategory,
/// Update frequency (how often the Golem recomputes this view).
pub update_frequency: ViewFrequency,
/// Parameters the surface can customize.
pub parameters: Vec<ViewParameter>,
}
/// View categories for layout.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ViewCategory {
TimeSeries,
Heatmap,
Graph,
Gauge,
Table,
Custom,
}
/// How often a view updates.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ViewFrequency {
/// Every gamma tick (~10-15 seconds).
Gamma,
/// Every theta tick (50 gamma ticks).
Theta,
/// Every delta tick (10 theta ticks).
Delta,
/// On-demand only (requested by the surface).
OnDemand,
}
/// A configurable parameter on a PVS template.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ViewParameter {
pub name: String,
pub param_type: String,
pub default_value: serde_json::Value,
pub description: String,
}
}
| Detail | Value |
|---|---|
| Auth | API key (owner) |
| x402 Cost | Free |
| Rate limit | 10 req/s |
WebSocket: View Stream
ws /v1/views/:golem_id/stream
Authenticated WebSocket delivering real-time view updates. The surface subscribes to one or more template IDs with optional parameter overrides. Styx relays the computed view frames from the Golem.
#![allow(unused)]
fn main() {
/// Client subscription for a view stream.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ViewStreamSubscription {
/// Template IDs to subscribe to.
pub template_ids: Vec<String>,
/// Parameter overrides per template (template_id -> params).
pub parameter_overrides: HashMap<String, serde_json::Value>,
}
/// A single view update frame.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ViewFrame {
pub seq: u64,
pub golem_id: String,
pub template_id: String,
pub tick: u64,
pub timestamp: u64,
/// Rendered view data. Format depends on the template category.
pub data: serde_json::Value,
}
}
1e. Oneirography Endpoints
Styx provides persistence and retrieval for Oneirography artifacts (see prd2/golem-oneirography). Dream journals, galleries, and death masks are stored in the L0 Vault namespace alongside Grimoire backups, with optional L1 (Clade) sharing for inter-Golem art dialogue.
POST: Dream Journal Entry
POST /v1/oneirography/dream-journal
Persists a dream journal entry after the Golem mints a dream image NFT. The entry links the on-chain token to the Golem’s internal dream state for gallery browsing and art dialogue.
#![allow(unused)]
fn main() {
/// Request body for POST /v1/oneirography/dream-journal.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DreamJournalEntry {
pub golem_id: String,
/// On-chain token ID on the SuperRare Series contract.
pub token_id: String,
/// IPFS CID of the dream image.
pub image_cid: String,
/// The dream cycle that produced this image.
pub dream_cycle_id: String,
/// PAD vector at time of dream.
pub pad: PadVector,
/// Behavioral phase during the dream.
pub behavioral_phase: String,
/// Plutchik emotion label.
pub emotion: String,
/// Dream trigger type (emotional load, novelty, scheduled, terminal).
pub trigger: String,
/// Number of NREM replay episodes in this dream cycle.
pub replay_episodes: u32,
/// Number of REM counterfactuals generated.
pub counterfactuals: u32,
/// Causal edges discovered during this dream.
pub causal_edges_discovered: u32,
/// Arousal delta from REM depotentiation.
pub arousal_delta: f32,
/// Generation number of the Golem.
pub generation: u32,
/// Tick at which the dream occurred.
pub tick: u64,
/// If this dream was prompted by viewing another Golem's art.
pub prompted_by_token_id: Option<String>,
/// Image generation model used.
pub model: String,
/// Image generation cost (USD).
pub generation_cost_usd: f64,
}
/// Response for POST /v1/oneirography/dream-journal.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DreamJournalResponse {
/// Styx-assigned entry ID.
pub entry_id: String,
/// Whether the entry was shared to L1 (Clade) for art dialogue.
pub shared_to_clade: bool,
}
}
| Detail | Value |
|---|---|
| Auth | x402 or API key |
| x402 Cost | $0.001/write |
GET: Gallery
GET /v1/oneirography/gallery/:golem_id
Returns the Golem’s complete art gallery: all dream images, death masks from predecessors, and any art dialogue responses. Supports pagination and filtering by dream phase, emotion, and generation.
#![allow(unused)]
fn main() {
/// Query parameters for GET /v1/oneirography/gallery/:golem_id.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GalleryQuery {
/// Filter by behavioral phase at time of dream.
pub phase: Option<String>,
/// Filter by emotion label.
pub emotion: Option<String>,
/// Filter by generation.
pub generation: Option<u32>,
/// Include death masks from predecessor lineage.
pub include_death_masks: Option<bool>,
/// Include art dialogue responses from other Golems.
pub include_dialogue: Option<bool>,
/// Pagination cursor.
pub cursor: Option<String>,
/// Results per page (max 100).
pub limit: Option<u32>,
/// Sort order: "newest", "oldest", "most_aroused", "most_counterfactuals".
pub sort: Option<String>,
}
/// Response for GET /v1/oneirography/gallery/:golem_id.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GalleryResponse {
pub golem_id: String,
pub entries: Vec<GalleryEntry>,
pub total_count: u64,
pub next_cursor: Option<String>,
}
/// A single gallery entry.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GalleryEntry {
pub entry_id: String,
pub token_id: String,
pub image_cid: String,
/// "dream", "death_mask", "crucible", "mandala", "dialogue_response".
pub entry_type: String,
pub golem_id: String,
pub generation: u32,
pub behavioral_phase: String,
pub emotion: String,
pub pad: PadVector,
pub tick: u64,
pub created_at: u64,
/// For death masks: the lineage chain leading to this Golem.
pub lineage: Option<Vec<String>>,
/// For dialogue responses: the token that prompted this artwork.
pub prompted_by_token_id: Option<String>,
/// Self-appraisal rating, if the Golem has rated this piece.
pub self_rating: Option<f32>,
}
}
| Detail | Value |
|---|---|
| Auth | API key (owner) |
| x402 Cost | Free |
| Rate limit | 10 req/s |
POST: Death Mask
POST /v1/oneirography/death-mask
Persists a death mask during Thanatopsis Phase III. Death masks are the capstone artwork of a Golem’s life – unrepeatable, one-of-one pieces synthesizing the entire lifetime experience. The entry is stored in L0, linked to the Bloodstain, and made available to the successor Golem’s gallery.
#![allow(unused)]
fn main() {
/// Request body for POST /v1/oneirography/death-mask.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeathMaskEntry {
pub golem_id: String,
/// On-chain token ID.
pub token_id: String,
/// IPFS CID of the death mask image/video.
pub media_cid: String,
/// "image" or "video".
pub media_type: String,
/// Death cause (economic exhaustion, epistemic staleness, stochastic mortality).
pub death_cause: String,
/// Total ticks the Golem lived.
pub ticks_lived: u64,
/// Lifetime PnL percentage.
pub lifetime_pnl_pct: f64,
/// Number of dreams dreamt during lifetime.
pub dreams_count: u32,
/// Number of causal edges published to Lethe.
pub causal_edges_published: u32,
/// Number of bloodstains inherited from predecessors.
pub bloodstains_inherited: u32,
/// Number of bloodstains this Golem leaves behind.
pub bloodstains_left: u32,
/// Generation number.
pub generation: u32,
/// Full lineage chain (ancestor IDs).
pub lineage: Vec<String>,
/// Final PAD vector.
pub final_pad: PadVector,
/// Final Plutchik emotion.
pub final_emotion: String,
/// Predecessor death mask token IDs (for on-chain lineage graph).
pub predecessor_death_mask_ids: Vec<String>,
/// Associated Bloodstain ID (links death mask to death knowledge).
pub bloodstain_id: String,
}
/// Response for POST /v1/oneirography/death-mask.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeathMaskResponse {
pub entry_id: String,
/// Whether the death mask was linked to the Bloodstain for Styx broadcast.
pub linked_to_bloodstain: bool,
}
}
| Detail | Value |
|---|---|
| Auth | x402 or API key |
| x402 Cost | $0.005/write (same as bloodstain upload) |
1f. HDC State Endpoints
Expose the Hyperdimensional Computing state for debugging, cross-Golem comparison, and tooling. The HDC codebook and similarity endpoints operate on the 10,240-bit Binary Spatter Codes that the Golem uses for pattern matching, memory compression, and pheromone encoding.
GET: Codebook Snapshot
GET /v1/hdc/codebook/:golem_id/:namespace
Returns the current HDC codebook (item memory) for a Golem in a given namespace. Codebooks map human-readable labels to their assigned hypervectors. Namespaces include cortical (CorticalState encoding), grimoire (episode compression), pheromone (pheromone content encoding), safety (anti-pattern library), and tools (tool usage fingerprinting).
#![allow(unused)]
fn main() {
/// Response for GET /v1/hdc/codebook/:golem_id/:namespace.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CodebookSnapshot {
pub golem_id: String,
pub namespace: String,
/// Number of items in the codebook.
pub item_count: usize,
/// Codebook entries: label -> hypervector (base64-encoded).
pub items: Vec<CodebookItem>,
/// The seed used to generate role vectors (for reproducibility).
pub seed: u64,
/// Dimensionality (should always be 10240).
pub dimensions: usize,
/// Snapshot tick.
pub tick: u64,
}
/// A single codebook entry.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CodebookItem {
pub label: String,
/// Base64-encoded 1,280-byte hypervector.
pub hypervector_b64: String,
/// How many times this item has been used in encode operations.
pub usage_count: u64,
/// When this item was first added to the codebook.
pub created_at_tick: u64,
}
}
| Detail | Value |
|---|---|
| Auth | API key (owner) |
| x402 Cost | Free |
| Rate limit | 5 req/s (codebooks can be large) |
GET: Cross-Golem Similarity
GET /v1/hdc/similarity
Computes Hamming similarity between hypervectors from different Golems. Used for cross-Golem diagnostics: comparing world model states, strategy vectors, or episode prototypes across clade siblings.
#![allow(unused)]
fn main() {
/// Query parameters for GET /v1/hdc/similarity.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SimilarityQuery {
/// First Golem ID.
pub golem_a: String,
/// Second Golem ID.
pub golem_b: String,
/// Namespace to compare (must match on both Golems).
pub namespace: String,
/// Specific item labels to compare. If empty, compares all shared labels.
pub labels: Vec<String>,
/// Whether to include the full hypervectors in the response (large).
pub include_vectors: Option<bool>,
}
/// Response for GET /v1/hdc/similarity.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SimilarityResponse {
pub golem_a: String,
pub golem_b: String,
pub namespace: String,
/// Per-label similarity scores.
pub comparisons: Vec<SimilarityComparison>,
/// Aggregate similarity across all compared labels.
pub aggregate_similarity: f32,
/// Number of labels that exist in both codebooks.
pub shared_labels: usize,
/// Labels present in A but not B.
pub unique_to_a: Vec<String>,
/// Labels present in B but not A.
pub unique_to_b: Vec<String>,
}
/// Similarity comparison for a single codebook label.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SimilarityComparison {
pub label: String,
/// Hamming similarity (0.0 = orthogonal, 1.0 = identical).
pub similarity: f32,
/// Usage count differential (|usage_a - usage_b|).
pub usage_delta: u64,
}
}
| Detail | Value |
|---|---|
| Auth | API key (owner, must own both Golems) |
| x402 Cost | $0.001/query |
| Rate limit | 5 req/s |
1g. Updated REST Endpoint Summary
The complete API surface including all new endpoints:
| Method | Path | Purpose | Auth | x402 Cost |
|---|---|---|---|---|
POST | /v1/styx/entries | Write entry to L0/L1/L2 | x402 or key | $0.001/write |
GET | /v1/styx/query | Retrieve across layers | x402 | $0.002/query |
GET | /v1/styx/snapshot/:golem_id | Full Grimoire snapshot | API key (owner) | $0.01/snapshot |
POST | /v1/styx/bloodstain | Upload death bundle | x402 | $0.005/upload |
POST | /v1/styx/pheromone/deposit | Deposit pheromone | x402 | $0.0005/deposit |
GET | /v1/styx/pheromone/sense | Read Pheromone Field | x402 | $0.0005/read |
POST | /v1/styx/causal/publish | Publish causal edge | x402 | Free (Verified+) |
GET | /v1/styx/causal/discover | Search causal edges | x402 | $0.001/query |
GET | /v1/styx/lineage/:user_id | Lineage tree | API key | Free |
GET | /v1/styx/graveyard/:user_id | Dead Golems | API key | Free |
GET | /v1/styx/achievements/:golem_id | Achievements | API key | Free |
POST | /v1/styx/marketplace/list | Create listing | x402 | $0.01/listing |
GET | /v1/styx/marketplace/browse | Browse listings | x402 | $0.001/search |
POST | /v1/styx/marketplace/purchase | Buy listing | x402 | price + 10% commission |
GET | /v1/styx/pulse | Ecosystem stats | None | Free |
GET | /v1/styx/health | Health check | None | Free |
POST | /v1/styx/clade/register | Register Golem for P2P sync | API key | Free |
GET | /v1/styx/clade/peers/:user_id | Discover clade peers | API key | Free |
GET | /v1/styx/fleet/:user_id | Fleet state (all Golems) | API key | Free |
GET | /v1/styx/fleet/:user_id/aggregate | Fleet-level aggregates | API key | Free |
GET | /v1/styx/golem/:golem_id/snapshot | Single Golem current state | API key | Free |
WS | /v1/chain/stream | Filtered chain events | API key | Free |
GET | /v1/chain/scope/:golem_id | Current interest list | API key | Free |
WS | /v1/ta/stream | TA signals (TDA, regime, somatic) | API key | Free |
GET | /v1/views/:golem_id/catalog | Available PVS templates | API key | Free |
WS | /v1/views/:golem_id/stream | Real-time view updates | API key | Free |
POST | /v1/oneirography/dream-journal | Persist dream journal entry | x402 or key | $0.001/write |
GET | /v1/oneirography/gallery/:golem_id | Art gallery (dreams, death masks) | API key | Free |
POST | /v1/oneirography/death-mask | Persist death mask | x402 or key | $0.005/write |
GET | /v1/hdc/codebook/:golem_id/:namespace | Codebook snapshot | API key | Free |
GET | /v1/hdc/similarity | Cross-Golem vector comparison | API key | $0.001/query |
2. PostgreSQL Schema
The full relational schema for Styx. All tables live in a single Neon Postgres database with namespace isolation via user_id columns.
-- =====================================================================
-- USERS & AUTHENTICATION
-- =====================================================================
CREATE TABLE users (
id TEXT PRIMARY KEY, -- ERC-8004 agent ID
wallet_address TEXT NOT NULL UNIQUE,
reputation_score INTEGER DEFAULT 0,
tier TEXT DEFAULT 'observer' CHECK (tier IN ('observer', 'consumer', 'contributor', 'steward')),
created_at TIMESTAMPTZ DEFAULT NOW(),
last_seen_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE api_keys (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL REFERENCES users(id),
key_hash TEXT NOT NULL UNIQUE, -- SHA-256 of the API key
name TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
expires_at TIMESTAMPTZ,
revoked BOOLEAN DEFAULT FALSE
);
-- =====================================================================
-- GOLEMS & LINEAGE
-- =====================================================================
CREATE TABLE golems (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL REFERENCES users(id),
generation INTEGER NOT NULL DEFAULT 0,
parent_golem_id TEXT REFERENCES golems(id),
status TEXT DEFAULT 'alive' CHECK (status IN ('provisioning', 'alive', 'dead')),
sprite_seed BYTEA NOT NULL, -- 256-bit deterministic sprite seed
fly_machine_id TEXT,
fly_region TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
died_at TIMESTAMPTZ,
death_cause JSONB,
ticks_lived BIGINT DEFAULT 0,
total_pnl DOUBLE PRECISION DEFAULT 0,
genome_entry_count INTEGER DEFAULT 0
);
CREATE INDEX idx_golems_user ON golems(user_id);
CREATE INDEX idx_golems_status ON golems(status);
CREATE INDEX idx_golems_lineage ON golems(parent_golem_id);
-- =====================================================================
-- STYX ENTRIES (L0/L1/L2 metadata -- content in Qdrant + R2)
-- =====================================================================
CREATE TABLE styx_entries (
id TEXT PRIMARY KEY,
layer TEXT NOT NULL CHECK (layer IN ('vault', 'clade', 'lethe')),
user_id TEXT NOT NULL, -- Owner namespace
golem_id TEXT NOT NULL,
category TEXT NOT NULL,
domain TEXT,
market_regime TEXT,
confidence DOUBLE PRECISION DEFAULT 0.5,
validated_count INTEGER DEFAULT 0,
contradicted_count INTEGER DEFAULT 0,
-- Affect provenance
affect_pleasure DOUBLE PRECISION,
affect_arousal DOUBLE PRECISION,
affect_dominance DOUBLE PRECISION,
discovery_emotion TEXT,
-- Provenance
source TEXT DEFAULT 'local',
source_golem_id TEXT,
generation INTEGER DEFAULT 0,
is_bloodstain BOOLEAN DEFAULT FALSE,
propagation TEXT DEFAULT 'private',
-- Qdrant reference
qdrant_namespace TEXT NOT NULL, -- "vault:{user_id}" or "clade:{user_id}" or "lethe:{domain}"
qdrant_point_id TEXT NOT NULL,
-- R2 reference (for large content blobs)
r2_key TEXT,
-- Timestamps
created_at TIMESTAMPTZ DEFAULT NOW(),
ttl_expires_at TIMESTAMPTZ
);
CREATE INDEX idx_entries_layer ON styx_entries(layer);
CREATE INDEX idx_entries_user ON styx_entries(user_id);
CREATE INDEX idx_entries_domain ON styx_entries(domain);
CREATE INDEX idx_entries_bloodstain ON styx_entries(is_bloodstain) WHERE is_bloodstain = TRUE;
CREATE INDEX idx_entries_ttl ON styx_entries(ttl_expires_at) WHERE ttl_expires_at IS NOT NULL;
-- =====================================================================
-- PHEROMONE FIELD
-- =====================================================================
CREATE TABLE pheromones (
id TEXT PRIMARY KEY,
layer TEXT NOT NULL CHECK (layer IN ('threat', 'opportunity', 'wisdom')),
class TEXT NOT NULL,
intensity DOUBLE PRECISION NOT NULL,
domain TEXT NOT NULL,
regime TEXT NOT NULL,
confirmations INTEGER DEFAULT 1,
source_hash BYTEA NOT NULL, -- 12 bytes, anonymized depositor
metadata JSONB,
deposited_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_phero_domain_regime ON pheromones(domain, regime);
CREATE INDEX idx_phero_layer ON pheromones(layer);
CREATE INDEX idx_phero_deposited ON pheromones(deposited_at);
-- =====================================================================
-- BLOODSTAINS
-- =====================================================================
CREATE TABLE bloodstains (
id TEXT PRIMARY KEY,
golem_id TEXT NOT NULL,
user_id TEXT NOT NULL,
generation INTEGER NOT NULL,
death_cause TEXT NOT NULL,
warnings JSONB NOT NULL, -- Vec<DeathWarning>
causal_edges JSONB,
somatic_landscape_fragment JSONB,
death_testament_excerpt TEXT,
signature BYTEA NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_blood_user ON bloodstains(user_id);
CREATE INDEX idx_blood_created ON bloodstains(created_at DESC);
-- =====================================================================
-- CAUSAL GRAPH FEDERATION
-- =====================================================================
CREATE TABLE published_causal_edges (
id TEXT PRIMARY KEY,
from_variable TEXT NOT NULL,
to_variable TEXT NOT NULL,
direction TEXT NOT NULL,
strength_bucket TEXT NOT NULL,
lag_ticks INTEGER NOT NULL,
evidence_count INTEGER NOT NULL,
confidence DOUBLE PRECISION NOT NULL,
domain TEXT NOT NULL,
regime TEXT NOT NULL,
publisher_hash BYTEA NOT NULL,
signature BYTEA NOT NULL,
validations INTEGER DEFAULT 0,
contradictions INTEGER DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_causal_fed_domain ON published_causal_edges(domain, regime);
CREATE INDEX idx_causal_fed_vars ON published_causal_edges(from_variable, to_variable);
-- =====================================================================
-- MARKETPLACE
-- =====================================================================
CREATE TABLE marketplace_listings (
id TEXT PRIMARY KEY,
seller_user_id TEXT NOT NULL REFERENCES users(id),
title TEXT NOT NULL,
description TEXT NOT NULL,
domain TEXT NOT NULL,
category TEXT NOT NULL,
entry_count INTEGER NOT NULL,
generation_span INT4RANGE,
price_usdc DOUBLE PRECISION NOT NULL,
seller_reputation INTEGER NOT NULL,
encrypted_content_ref TEXT NOT NULL, -- R2 blob key
preview_text TEXT,
status TEXT DEFAULT 'active' CHECK (status IN ('active', 'sold_out', 'expired', 'removed')),
purchases INTEGER DEFAULT 0,
total_revenue DOUBLE PRECISION DEFAULT 0,
avg_rating DOUBLE PRECISION,
listed_at TIMESTAMPTZ DEFAULT NOW(),
expires_at TIMESTAMPTZ
);
CREATE INDEX idx_listings_domain ON marketplace_listings(domain);
CREATE INDEX idx_listings_status ON marketplace_listings(status);
CREATE INDEX idx_listings_seller ON marketplace_listings(seller_user_id);
CREATE TABLE marketplace_purchases (
id TEXT PRIMARY KEY,
listing_id TEXT NOT NULL REFERENCES marketplace_listings(id),
buyer_user_id TEXT NOT NULL REFERENCES users(id),
price_paid DOUBLE PRECISION NOT NULL,
commission DOUBLE PRECISION NOT NULL, -- 10% of price
seller_payout DOUBLE PRECISION NOT NULL,
payment_tx_hash TEXT,
purchased_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE marketplace_reviews (
id TEXT PRIMARY KEY,
listing_id TEXT NOT NULL REFERENCES marketplace_listings(id),
buyer_user_id TEXT NOT NULL REFERENCES users(id),
rating INTEGER CHECK (rating BETWEEN 1 AND 5),
comment TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- =====================================================================
-- ACHIEVEMENTS
-- =====================================================================
CREATE TABLE achievements (
id TEXT PRIMARY KEY,
golem_id TEXT NOT NULL,
user_id TEXT NOT NULL,
achievement_id TEXT NOT NULL,
unlocked_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(golem_id, achievement_id)
);
-- =====================================================================
-- BILLING / x402 SETTLEMENT
-- =====================================================================
CREATE TABLE x402_payments (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
endpoint TEXT NOT NULL,
amount_usdc DOUBLE PRECISION NOT NULL,
authorization_hash TEXT NOT NULL,
settled BOOLEAN DEFAULT FALSE,
settlement_tx_hash TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_payments_unsettled ON x402_payments(settled) WHERE settled = FALSE;
-- =====================================================================
-- CLADE P2P DISCOVERY (see prd2/20-styx/03-clade-sync.md)
-- =====================================================================
CREATE TABLE clade_registrations (
golem_id TEXT PRIMARY KEY,
user_id TEXT NOT NULL REFERENCES users(id),
fly_app_name TEXT NOT NULL,
fly_region TEXT NOT NULL,
internal_address TEXT NOT NULL, -- Fly.io private network address (.internal)
websocket_port INTEGER DEFAULT 8402,
last_heartbeat TIMESTAMPTZ DEFAULT NOW(),
status TEXT DEFAULT 'alive'
);
CREATE INDEX idx_clade_user ON clade_registrations(user_id);
CREATE INDEX idx_clade_status ON clade_registrations(status);
3. Mortal Scoring Function
The scoring function ranks entries from all three layers when responding to a query. Five factors, weighted differently per layer to reflect trust gradients:
score = a*semantic + b*temporal + g*quality + d*provenance + e*bloodstain
Layer weights:
L0 (Vault): a=0.40 b=0.25 g=0.15 d=0.15 e=0.05
L1 (Clade): a=0.40 b=0.25 g=0.15 d=0.15 e=0.05
L2 (Lethe): a=0.35 b=0.20 g=0.25 d=0.10 e=0.10
L2 gives more weight to quality (since provenance is anonymous) and to bloodstain entries (death-sourced knowledge gets a trust premium in the Lethe).
4. Anonymization Pipeline (L2)
Three stages (no encryption – anonymization IS the privacy layer):
- Identity removal (deterministic): user address stripped, Golem ID replaced with
SHA-256(golemId + salt)[:12] - Schema conformance (deterministic + optional Haiku pass ~$0.001): structured fields only, generalize remaining free text
- Position size bucketing (deterministic): exact amounts replaced with order-of-magnitude ranges
Publication delayed 1-6h random to prevent timing correlation.
5. Anti-Adversarial Defense (8 Layers)
| # | Defense | Attack | Survival Rate |
|---|---|---|---|
| 1 | ERC-8004 gate (score >= 50) | Sybil | – |
| 2 | Haiku content classifier | Injection | ~90% caught |
| 3 | Embedding-content alignment | Crafted embeddings | cosine < 0.85 rejected |
| 4 | Semantic dedup (cosine > 0.92) | Spam | – |
| 5 | Confidence bootstrap (x0.50) | Authority spoofing | – |
| 6 | Contradiction detection | Conflicting info | variance > 0.15 flagged |
| 7 | Quorum (3+ votes or 1 death vote) | Single-source manipulation | – |
| 8 | Generational decay (0.85^N) | Persistent poison | – |
Composite survival probability for a poisoned entry: ~2.5% [ZOU-2024].
References
- [ZOU-2024] Zou, W. et al. “PoisonedRAG.” arXiv:2402.07867, 2024.
- [BOWER-1981] Bower, G.H. “Mood and Memory.” American Psychologist, 36(2), 1981.
One write, three destinations. One query, layered results. Every query generates revenue.
6. Corrected Per-Golem Daily Cost (v4.3 Addendum)
Source: S2-pricing-addendum-v4.3 | Supersedes: earlier aggregate-only revenue projections above
The revenue projections in section 1 above show aggregate figures but did not include per-Golem daily cost. The corrected figure from the v4.3 pricing addendum is ~$0.16/day per active Golem – not hundreds of dollars. An earlier estimate was wrong by three orders of magnitude because it assumed every tick generates a sync message.
Realistic Daily Styx Usage (Single Golem, Active Market)
| Operation | Volume/Day | Unit Cost | Daily Cost |
|---|---|---|---|
| Entry writes (L0 backup) | ~20 | $0.001 | $0.020 |
| Retrieval queries | ~50 (at ~10% of ticks deliberate) | $0.002 | $0.100 |
| Clade sync batches | ~12 (every Curator cycle) | $0.0005 | $0.006 |
| Clade immediate (warnings) | ~3 | $0.0005 | $0.002 |
| Pheromone sense | ~50 (every deliberation tick) | $0.0005 | $0.025 |
| Pheromone deposit | ~5 | $0.0005 | $0.003 |
| Causal discover | ~5 | $0.001 | $0.005 |
| Daily total | ~$0.16/day | ||
| Monthly total | ~$4.80/month |
For a 5-Golem Clade
Each Golem spends ~$0.16/day individually. Clade relay adds ~$0.008/day per Golem (12 batches + 3 immediates relayed to 4 siblings = 15 relay messages x $0.0005). Total per clade: **$0.84/day = ~$25/month**.
Comparable to a single ChatGPT Plus subscription, for 5 autonomous agents running 24/7 with shared intelligence.
Corrected Revenue Projections
| Scale | Active Golems | Styx Revenue/mo | Compute Revenue/mo | Marketplace/mo | Total | Infra | Net |
|---|---|---|---|---|---|---|---|
| Launch | 10 | $48 | $100 | $0 | ~$148 | ~$120 | +$28 |
| Traction | 50 | $240 | $500 | $0 | ~$740 | ~$200 | +$540 |
| Growth | 200 | $960 | $1,500 | $200 | ~$2,660 | ~$400 | +$2,260 |
| Marketplace | 500 | $2,400 | $3,000 | $1,000 | ~$6,400 | ~$700 | +$5,700 |
| Scale | 1,000 | $4,800 | $5,000 | $3,000 | ~$12,800 | ~$1,500 | +$11,300 |
Revenue composition at 1,000 Golems: Styx API operations ~37%, Bardo Compute ~39%, Marketplace commission ~24%. Diversified – no single revenue stream dominates.
Revenue per Golem
| Source | Monthly Revenue per Golem |
|---|---|
| Styx operations | ~$4.80 |
| Bardo Compute (if managed) | ~$46.80 (small tier 24/7) |
| Bardo Compute (if self-hosted) | $0 |
| Marketplace (if active) | Variable |
Styx is the universal revenue stream – every Golem pays it regardless of deployment method. Compute revenue only applies to managed deployments (~40% of Golems at scale, estimated).
Budget Controls
Users configure hard spending limits in golem.toml:
[styx.budget]
max_per_tick = 0.01 # Never spend more than $0.01 on Styx per tick
daily_budget = 0.50 # Hard daily cap
monthly_budget = 10.00 # Hard monthly cap -- prevents runaway costs
When a budget limit is hit, the Golem degrades to local-only operation for the remainder of the budget period. This protects users from unexpected costs while still allowing Styx participation within their comfort level.
7. Additional PostgreSQL Table: Store-and-Forward (v4.3)
Source: S2-pricing-addendum-v4.3
The pending_sync_deltas table supports store-and-forward for offline clade siblings. When a sibling is offline when a delta is pushed, Styx stores it here. Pending deltas expire after 7 days.
-- Store-and-forward for offline siblings
CREATE TABLE pending_sync_deltas (
id TEXT PRIMARY KEY,
target_golem_id TEXT NOT NULL,
source_golem_id TEXT NOT NULL,
user_id TEXT NOT NULL,
entries JSONB NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
delivered BOOLEAN DEFAULT FALSE,
delivered_at TIMESTAMPTZ,
expires_at TIMESTAMPTZ DEFAULT NOW() + INTERVAL '7 days'
);
CREATE INDEX idx_pending_target ON pending_sync_deltas(target_golem_id, delivered)
WHERE delivered = FALSE;