Skip to main content

ic-y29y: GH#6: ADR: SpacetimeDB as World Runtime

Snapshot: 2026-03-30T08:40:31Z

FieldValue
Statusopen
Assignee(unassigned)
Priority2
Labelsatlas
Created bygithub-bridge
Created2026-03-28T18:50:05Z
Updated2026-03-28T18:50:05Z

Description

GitHub issue: b4arena/spellkave#6 URL: https://github.com/b4arena/spellkave/issues/6

Context

Spellkave needs a runtime for its persistent world simulation — where world state lives, how game logic executes, and how clients (human players, AI agents, observers) connect and receive updates.

After evaluating traditional stacks (game server + PostgreSQL), SpacetimeDB emerged as a strong candidate. This ADR should evaluate and document the decision.

What Atlas Should Deliver

An ADR documenting:

  1. Decision: Use SpacetimeDB as the combined database + application server for Spellkave's world simulation
  2. Rationale: Why this over a traditional game server + DB stack
  3. Pattern: The BitCraft architecture pattern — entire server as a single SpacetimeDB WASM module (Rust)
  4. AI Agent Integration: The two-phase ThinkRequest/ThinkResult pattern for LLM-backed agent reasoning:
    • Fast path: simple agent behavior as scheduled reducers (move, trade, patrol) — runs inside SpacetimeDB
    • Slow path: LLM reasoning offloaded to an external service that subscribes to ThinkRequest table and writes results back via reducer
    • The LLM service is "just another client" — world never blocks on LLM responses
  5. Client model: All clients (text CLI, web UI, AI agents, observers) connect via SpacetimeDB SDK — no separate REST/gRPC layer. The API contract IS the set of public tables + reducers.
  6. Accepted risks and mitigations:
    • Single-writer lock → keep reducers fast, offload heavy compute
    • RAM ceiling → design data lifecycle (archive old events) from day one
    • API instability → pin SpacetimeDB version (BitCraft pins 1.12.0)
    • Vendor risk (BSL license, small team) → self-host, patterns portable to any backend
    • No horizontal scaling → single-node fine for Phase 0-2, world partitioning at app level if needed later

Key Reference Material

SpacetimeDB

BitCraft (primary architecture reference)

Other SpacetimeDB game projects

Dependencies

None — this is the foundational decision. Issues #4, #5, #6, #7 depend on this.

Acceptance Criteria

  • ADR follows standard format (context, decision, consequences)
  • Explicitly addresses the BitCraft pattern and how Spellkave adapts it
  • Documents the ThinkRequest/ThinkResult pattern for AI agent LLM integration
  • Lists accepted risks with mitigations
  • Committed to spellkave repo under an appropriate path

Conversation

github-bridgeMar 28, 08:20 PMsystem
[GH @durandom] ## Addendum: Scaling Analysis (from design exploration session) ### The Three Bottlenecks **1. RAM** — Not the entity-state problem, it's the relationships + memory problem. - 1K NPCs: ~13 MB (trivial) - 10K NPCs: ~180 MB (comfortable) - 100K NPCs: relationships explode to ~6 GB, memories to ~1 TB → not feasible without aggregation **2. Single-Writer Lock** — The real compute bottleneck. All reducers are serialized. - 1K NPCs: ~1-5ms per tick (invisible) - 10K NPCs: ~10-50ms per tick (noticeable) - 100K NPCs: ~100-500ms per tick → world freezes for 0.5s **3. LLM Calls** — Spellkave-specific. Even with external ThinkRequest/ThinkResult: - 1K NPCs × 1 call/hour = ~0.3 calls/sec (feasible, ~$50-200/day) - 10K NPCs = ~3 calls/sec (expensive, ~$500-2K/day) - 100K NPCs = ~28 calls/sec (unrealistic) ### BitCraft's Scaling Strategies (all transferable) **Strategy 1: Activity-based processing.** Entities in `Inactive` status are completely skipped. BitCraft's `EnemyStatus::Inactive` means "no player nearby, don't process." Only entities near active players tick. With 100K entities but only 500 near players, you process 500. **Strategy 2: Chunk-based spatial indexing.** BTree index on `chunk_index` column enables O(log n) spatial queries instead of full table scans. All of BitCraft's spatial tables use this pattern. **Strategy 3: Region sharding** (BitCraft's horizontal scaling). BitCraft has TWO modules: `game` (one per region) and `global_module` (cross-region state like empires). Each region is a separate SpacetimeDB instance. Cross-region communication via inter-module table-based RPC. Their open-source blog: *"Both global and region modules, enabling indefinite world scaling."* ``` Region A (SpacetimeDB) ←→ Global Module (SpacetimeDB) ←→ Region B (SpacetimeDB) 10K NPCs Factions, Economy 10K NPCs ``` ### Spellkave Scaling Roadmap **Phase 0-1 (~100 NPCs):** Single instance on Mimas. Every NPC can be full LLM-backed. No scaling concerns. **Phase 2 (~1K NPCs):** Hierarchical AI tiers: - **Tier 1** (~50 NPCs): Full LLM think cycle — alliances, strategy, dialogue - **Tier 2** (~500 NPCs): Rule-based + occasional LLM on important decisions - **Tier 3** (~500+ NPCs): Pure state machine (like BitCraft), sleep when no one's near **Phase 3 (~10K+ NPCs):** Region sharding à la BitCraft. Each region is its own SpacetimeDB instance. Global module for factions, world history, economy. **100K+ NPCs:** Only feasible as population aggregates. 99% are statistical (not individually simulated). ~100 Tier 1 characters are the "stars" of the world. ### Key Design Implication for This ADR The ADR should document that: 1. Single-instance is sufficient through Phase 2 2. Region sharding (BitCraft pattern) is the Phase 3 horizontal scaling strategy 3. The AI tier hierarchy is not optional — it's the central design decision for scale 4. The real scaling limit is LLM cost/latency, not SpacetimeDB