Skip to content

Architecture overview

How the engine is layered, what happens to a command, and which crate does what.

Canwu is a headless simulation engine: it has no renderer or UI of its own. Your application, whether a game, a research tool, a debug client, or an AI agent, links it as a Rust library. The application changes the world by submitting commands and reads it through snapshots, events, and actor-relative views. Only the engine’s runtime holds the live world, and it changes that state only while settling commands and scheduled work.

Select a layer to see its crates, or switch to Follow a command to step through one command from submission to replay.

  1. Public API boundary · code above this line uses only canwu-api

  2. Engine internals · reached only through canwu-api

Your application

Owns rendering, input, the real-time clock, accounts, and historical content. It depends on canwu-api, registers the plugins it needs, submits commands, and reads the results.

Reference client in this repository

  • canwu-debugDesktop debug client (egui) built on the public API and the reference integrations

Domain plugins

Domain extensions add reusable rules as simulation plugins built on canwu-api. Register only the ones you need, or write your own. Reference content packs supply data, and reference integrations combine the pieces into small worlds you can run and copy.

Domain extensions (published on crates.io)

Reference content packs

Reference integrations (repository only, not published)

Write your own plugin →

canwu-api

The engine crate your application depends on; extension crates build on it too. Its Canwu type creates and advances a run, accepts commands, returns detached snapshots and actor-relative views, and saves, forks, and replays runs. It re-exports the types you need from the crates below.

Main calls

Integrate Canwu →

canwu-sim

Holds the authoritative state. It queues incoming commands, runs scheduled work, and settles due work in boundaries: one all-or-nothing pass at one simulation time, run in 14 fixed phases. If anything fails, the whole boundary rolls back. It also records the evidence and hashes used for saves and replay. Applications reach it only through canwu-api.

Crate

  • canwu-simRuntime, scheduling, settlement, plugins, persistence, hashing, and replay
How a boundary is settled →

Models and mechanisms

Data types that plugins and applications reach through canwu-api: what happened and why, what each actor knows, pending decisions, and route and transport records. The runtime itself uses the event, knowledge, and decision types.

Crates

Events and causality →

Foundation

Typed IDs, deterministic random numbers, schema metadata, and simulation time arithmetic. Every other crate builds on these two.

Crates

  • canwu-coreStable IDs, deterministic random numbers, and schema primitives
  • canwu-timeSimulation time and checked duration arithmetic
Replayable randomness →
  1. Step 1 of 7

    Build a command

    Your client creates a typed command. In the starter example, the reference world wraps a MovementCommand into a command envelope.

    let envelope = order_movement(Issuer::Actor(commander), &command)?;
  2. Step 2 of 7

    Queue it

    enqueue_command puts the request in the ingress queue for its due time and returns a receipt. Resending the identical request returns the same receipt; reusing its ID with different content fails. The world has not changed yet.

    canwu.enqueue_command(due_at, priority, CommandRequest::new(id, revision, envelope))?;
  3. Step 3 of 7

    Advance time

    advance_canonical moves simulation time forward. Each batch of work that falls due is settled in one boundary.

    canwu.advance_canonical(SimDuration::hours(19))?;
  4. Step 4 of 7

    Settle the boundary

    The engine checks the issuer's authority, the revision the command was based on, and its expected time. A rejected command is recorded with its reason. Plugin systems then run in 14 fixed phases and propose changes, which commit together or roll back together.

    The 14 phases →
  5. Step 5 of 7

    Record what happened

    Committed changes produce events that carry their cause and audience. Characters' knowledge and reports are updated, and the replay journal gains one more boundary.

  6. Step 6 of 7

    Read it back

    A player or agent reads through viewer_for_actor and sees only what that actor knows. Trusted host tools can also list events() and ask explain() why something happened.

    let viewer = canwu.viewer_for_actor(actor)?;
    Reading state safely →
  7. Step 7 of 7

    Save and replay

    snapshot_json saves the run, and replay_journal returns its recorded inputs. replay_from_journal rebuilds the run from those inputs; equal checkpoint hashes show the replay is exact.

    let replayed = Canwu::replay_from_journal(&[&plugin], &canwu.replay_journal())?;
    assert_eq!(replayed.checkpoint_hash(), canwu.checkpoint_hash());
    Save, replay, and fork →
Each layer uses only its own layer and the layers below it. Select a layer to see its crates, or switch to Follow a command and use the arrows.
  • Your application depends on canwu-api and registers the plugins it needs.
  • Domain plugins are optional crates built on canwu-api. First-party extensions get the same access as a plugin you write yourself, so you can replace any of them.
  • canwu-api is the supported public API. It re-exports the types you need from the crates below it.
  • canwu-sim is the private runtime behind canwu-api. It owns the live state, the ingress queue, scheduling, settlement, persistence, and replay.
  • Models and mechanisms (canwu-event, canwu-knowledge, canwu-decision, canwu-routing, canwu-transport) define shared data types; canwu-api re-exports them.
  • Foundation (canwu-core, canwu-time) provides IDs, deterministic random numbers, and simulation time.

This graph shows the direct dependencies declared in each crate’s Cargo.toml: A → B means A depends on B, and external and dev dependencies are left out. It opens at 250%; zoom between 50% and 600% with the buttons or the mouse wheel inside the graph, and drag to pan.

Direct dependencies between all Canwu workspace crates; arrows point from each crate to the crates it depends on. View dependency graph source.
View dependency graph source
flowchart TB
  subgraph Tools["Tools"]
      Debug["canwu-debug"]
  end

  subgraph Extensions["Extensions"]
      Correspondence["canwu-correspondence"]
      Information["canwu-information"]
      Society["canwu-society"]
      Culture["canwu-culture"]
      Law["canwu-law"]
      Technology["canwu-technology"]
      History["canwu-history-research"]
      Fiscal["canwu-fiscal"]
      Resource["canwu-resource"]
      Production["canwu-production"]
      Military["canwu-military"]
      Movement["canwu-movement"]
  end

  subgraph Examples["Examples"]
      MingFiscal["canwu-ming-fiscal"]
      EconomyContent["canwu-economy-reference-content"]
      MingReference["canwu-ming-fiscal-reference"]
      ForceSupply["canwu-force-supply-reference"]
      EconomyReference["canwu-economy-reference"]
      ReferenceWorld["canwu-reference-world"]
      MilitaryContent["canwu-military-reference-content"]
      MilitaryReference["canwu-military-reference"]
  end

  subgraph PublicApi["Public API"]
      Api["canwu-api"]
  end

  subgraph RuntimeMechanisms["Runtime and mechanisms"]
      Sim["canwu-sim"]
      Transport["canwu-transport"]
      Routing["canwu-routing"]
  end

  subgraph Models["Models"]
      Decision["canwu-decision"]
      Event["canwu-event"]
      Knowledge["canwu-knowledge"]
  end

  subgraph Foundation["Foundation"]
      Core["canwu-core"]
      Time["canwu-time"]
  end

  Debug --> Api
  Debug --> MingReference
  Correspondence --> Api
  Correspondence --> Information
  Information --> Api
  Society --> Api
  Culture --> Society
  Culture --> Api
  Law --> Api
  Technology --> Api
  History --> Api
  History --> Technology
  Fiscal --> Api
  Resource --> Api
  Production --> Api
  Production --> Resource
  Production --> Technology
  Military --> Api
  Movement --> Api
  MingFiscal --> Api
  MingFiscal --> Fiscal
  EconomyContent --> Api
  EconomyContent --> Production
  EconomyContent --> Resource
  EconomyContent --> Technology
  MingReference --> Api
  MingReference --> Fiscal
  MingReference --> MingFiscal
  MingReference --> ReferenceWorld
  ForceSupply --> Api
  ForceSupply --> EconomyContent
  ForceSupply --> Resource
  EconomyReference --> Api
  EconomyReference --> EconomyContent
  EconomyReference --> ForceSupply
  EconomyReference --> Production
  EconomyReference --> ReferenceWorld
  EconomyReference --> Resource
  EconomyReference --> Technology
  ReferenceWorld --> Api
  MilitaryContent --> Api
  MilitaryContent --> Military
  MilitaryReference --> Api
  MilitaryReference --> Military
  MilitaryReference --> MilitaryContent
  MilitaryReference --> ReferenceWorld
  Debug --> ReferenceWorld

  Api --> Core
  Api --> Decision
  Api --> Event
  Api --> Knowledge
  Api --> Routing
  Api --> Sim
  Api --> Time
  Api --> Transport

  Sim --> Core
  Sim --> Decision
  Sim --> Event
  Sim --> Knowledge
  Sim --> Time

  Transport --> Core
  Transport --> Routing
  Transport --> Time

  Routing --> Core
  Routing --> Time

  Decision --> Core
  Decision --> Time
  Event --> Core
  Event --> Time
  Knowledge --> Core
  Knowledge --> Time
  1. State changes through commands. Clients submit commands; plugins submit proposals from their boundary systems. The runtime validates both and commits them at a boundary.
  2. Every run is reproducible. Time, scheduled work, system order, and random draws follow fixed rules, so a replay of the journal produces the same checkpoint hash.
  3. Knowledge belongs to characters. The runtime keeps the true state apart from what each character knows. Players and agents read through actor-relative views.
  4. History is recorded with its causes. Every event keeps its cause, audience, and correlation ID, so you can ask the engine why something happened.

The engine keeps period-specific rules out of its core. They live above canwu-api, in four forms:

Kind What it provides Example
Domain extension Reusable mechanics as simulation plugins canwu-resource, canwu-movement
Reference content pack Versioned data for an extension, with sources canwu-ming-fiscal
Reference integration A small runnable world that combines extensions and content canwu-economy-reference
Starter kit A runnable example you copy and modify the starter example in canwu-reference-world
From the Canwu engine to extensions, content, integrations, and your application. View diagram source.
View diagram source
flowchart TB
  Engine["canwu-api + canwu-sim"] --> Domain["Domain extensions"]
  Domain --> Pack["Reference content packs"]
  Domain --> Integration["Reference integrations"]
  Pack --> Integration
  Integration --> Starter["Starter kits"]
  Starter -. "copy and modify" .-> App["Your game or research tool"]
  Domain -. "register directly" .-> App
  Pack -. "reuse directly" .-> App

A few examples show how ownership is split:

  • Movement. canwu-transport holds plain records: orders, runs, itinerary changes, handoffs, bookings, and capacity pools. canwu-movement is the plugin that runs them: it admits movement orders, settles each leg when it falls due, allocates capacity pools, and publishes movement reports to the characters who should receive them. Incidents, hazards, and hostility stay in your own systems, together with the random draws that decide them.
  • Correspondence. canwu-correspondence owns letters from demand to delivery: address lookup, routes, carriers, disasters, and interception. It builds on canwu-information, which owns documents, copies, and interpretation.
  • Economy. canwu-resource owns conserved quantities and their fulfillment. canwu-production consumes resources and technology evidence to run facilities and work orders. canwu-economy-reference combines both with transport and military supply in a seasonal grain loop. Its scarcity and price-pressure numbers are read-only projections, and it reports a price only when a trade, quote, official rate, or contract supplies one.

For the owner of every cross-plugin contract (transition manifests, access grants, delegated carriers, and so on), see model ownership.

Crate Responsibility
canwu-core Typed IDs, deterministic random numbers, and schema metadata
canwu-time Simulation time and checked duration arithmetic
canwu-event Event envelopes with cause, audience, and structured fields
canwu-knowledge What each actor knows, with source, confidence, and age
canwu-decision Decision tickets, controllers, deterministic evaluation, and the policy SDK
canwu-routing Route planning where travel times change over time
canwu-transport Records for transport runs, itinerary changes, handoffs, bookings, and capacity pools
canwu-sim Private runtime: state, scheduling, plugins, settlement, persistence, hashing, and replay
canwu-api Public API: commands, domain records, views, snapshots, evidence, and replay
Crate Responsibility
canwu-resource Resource accounts with protected floors, demand, reservation, allocation, transfer, consumption, loss, access grants, and fulfillment
canwu-production Processes, production sites, facilities, capacity, work orders, work in progress, projects, and output
canwu-movement Movement orders, leg settlement, capacity-pool allocation, and movement reports, built on canwu-transport records
canwu-military Forces, operations, combat, occupation, and pending effects that other domains settle and acknowledge; replace it if your game needs different combat rules
canwu-society Social diffusion between population groups
canwu-culture Culture authoring and compilation, plus a culture lifecycle that runs on canwu-society
canwu-law Legal authoring, institutional procedures (including weighted, unit-block, and consultation stages), versioned law, and applicability; experimental
canwu-technology Technology built from evidence: capability, implementation, adoption, and diffusion
canwu-fiscal Fiscal procedures, regional adoption, assessment, execution receipts, and per-holder knowledge reports
canwu-information Documents, copies, access, release, interpretation, and authenticity findings
canwu-correspondence Addressed letters: demand, address lookup, routes, carriers, disasters, and interception
canwu-history-research Optional research assessment plugins for technology runs
Crate Responsibility
canwu-ming-fiscal Source-cited fiscal content from the early Ming to the Southern Ming, with coverage declarations
canwu-economy-reference-content Economy model cards, citations, and coverage declarations, with explicit unknown and not-applicable states
canwu-military-reference-content Versioned synthetic military rulesets for the military extension

Reference integrations and tools (repository only)

Section titled “Reference integrations and tools (repository only)”
Crate Responsibility Also depends on
canwu-reference-world A small example world (armies, people, territories, letters), its movement plugin, projection, routing adapter, and the starter example only canwu-api
canwu-ming-fiscal-reference Runnable Hongwu, Wanli, and Hongguang fiscal scenarios canwu-fiscal, canwu-ming-fiscal, canwu-reference-world
canwu-force-supply-reference Military supply as a replaceable resource consumer, with a requisition saga canwu-resource, canwu-economy-reference-content
canwu-economy-reference A runnable grain loop combining resources, production, transport, force supply, scarcity, and price evidence canwu-resource, canwu-production, canwu-technology, canwu-economy-reference-content, canwu-force-supply-reference, canwu-reference-world
canwu-military-reference The military extension and its synthetic content running in the reference world canwu-military, canwu-military-reference-content, canwu-reference-world
canwu-debug Desktop debug client built on the public API and the reference integrations canwu-reference-world, canwu-ming-fiscal-reference

Domain systems supply the concrete rules for knowledge, decisions, resources, war, taxes, and more, and each one has its own design page. The domain systems page lists all eight and the crates that provide them.

  • Settlement: the 14 phases of a boundary, allocation, commit, and rollback
  • Events: causes, audiences, and explanations
  • Randomness: how random draws stay replayable
  • Guides: integrating, reading, saving, and extending
  • Get started: runnable examples