Archetype is a data-centric Entity-Component-System (ECS) simulation engine. World state is stored as columnar DataFrames. Every tick appends new rows to storage without overwriting previous state, which enables time-travel queries, world forking, and replay.

Archetype architecture

Layers

archetype.api / cli          External interface (REST + HTTP client)
       |
archetype.sugar             ArchetypeRuntime, RuntimeWorld (recommended scripts)
       |
archetype.app                Services, RBAC, CommandBroker, WorldRegistry
       |
archetype.core               AsyncWorld, AsyncProcessor, Resources, Storage

The system runs as a single archetype serve process. The CLI is a thin HTTP client.

Runtime Layer

ArchetypeRuntime is the recommended script entry point. It owns the shared service container, gives you lazy world handles, keeps process lifetime separate from world lifetime, and exposes the brokered mutation surface on RuntimeWorld:

from uuid_utils import uuid7

from archetype import ArchetypeRuntime, Component
from archetype.app.auth.models import ActorCtx


class Position(Component):
    x: float = 0.0
    y: float = 0.0

async with ArchetypeRuntime() as runtime:
    world = runtime.world("demo")
    entity_id = await world.spawn(Position(x=0, y=0))
    admin = world.as_actor(ActorCtx(id=uuid7(), roles={"admin"}))
    await admin.update(entity_id, Position(x=1, y=0))
    await world.run(steps=10)

Drop to the service layer only when you need custom command routing, non-script hosting, or lower-level read-path / lifecycle control.

Service Layer

The service layer mediates all access to worlds.

ServiceContainer

Lower-level composition root that instantiates and exposes all service-layer subsystems:

from archetype.app.container import ServiceContainer

container = ServiceContainer()
# container.world_service     -- world lifecycle
# container.command_service   -- command submission
# container.simulation_service -- tick stepping
# container.query_service     -- read path
# container.broker            -- command queue
# container.storage_service   -- storage backends

Command Flow

All mutations from external actors flow through the command pipeline:

  1. CommandService.submit() -- accepts a Command with type, payload, tick, priority
  2. CommandBroker.enqueue() -- validates RBAC via ActorCtx, enforces quotas, queues by priority
  3. SimulationService.step() -- drains due commands, applies them to the world, steps processors
  4. QueryService -- reads world state (current or historical)

RBAC

Every command submission requires an ActorCtx specifying the actor's roles:

Role Permissions
viewer Read-only (query, get state, get world)
player spawn, despawn, update, message, custom
coder add/remove components, update
operator trajectory ingestion and labeling
maintainer spawn, despawn, components, processors, update
admin All commands (wildcard)

Quotas: 500 commands per tick, 200k token budget per day. See Token Costs and Quotas for details.

Tick Lifecycle

Each step() call follows this sequence:

SimulationService.step(world_id, run_config)
  |
  1. drain_and_apply(world_id, tick)
  |    CommandBroker.dequeue_due(world_id, tick)
  |    CommandService.apply(world, cmd) for each command
  |    → spawn/despawn/update mutations queue in world caches
  |
  2. reset_tick_counters()
  |    Clear per-actor command counts for next tick
  |
  3. world.step(run_config)
       |
       a. For each archetype (concurrently via asyncio.gather):
       |    i.   Query previous state from store (or _live cache)
       |    ii.  Materialize spawn/despawn caches into the DataFrame
       |    iii. Execute matching processors in priority order
       |    iv.  Persist result via updater → store
       |    v.   Update _live cache
       |
       b. Increment tick counter
       c. Fire `PostTick` hooks

Commands applied in step 1 produce deferred mutations (spawn/despawn caches). Those mutations materialize in step 3a-ii of the same tick. Cross-archetype communication (messages, spawns targeting different archetypes) takes effect on the next tick.

For full details: Worlds covers the internal tick cycle, Lifecycle Hooks covers typed observability events, Data Flow covers the command pipeline, System Execution covers processor dispatch.

Deep Dives

Core

The simulation engine. No auth awareness, no multi-world management.

  • Archetype -- signatures, naming, schemas, entity-to-table mapping
  • Components -- Pydantic models with Arrow serialization, column prefixing, field types
  • Processors -- DataFrame transforms, resource injection, LLM integration
  • Systems -- subset rule, priority ordering, per-archetype parallelism
  • Worlds -- tick lifecycle, deferred mutations, _live cache, forking
  • Lifecycle Hooks -- typed world events, async/sync handlers, hook failure policy
  • Resources -- type-keyed dependency injection for world-level shared state
  • Stores -- storage backends, append-only model, write-behind cache
  • Querier -- filtered reads by tick, entity, and component projection
  • Updater -- metadata stamping before append
  • Configuration -- RunConfig, WorldConfig, StorageConfig, CacheConfig

App

The service layer. RBAC, command pipeline, multi-world orchestration.

  • Overview -- how core connects through services to the API
  • Services -- ServiceContainer, dependency graph, each service's role
  • Command Broker -- priority queue, RBAC guardrails, audit trail
  • API Layer -- FastAPI routes, dependency injection, CLI
  • Data Flow -- read/write split, command pipeline, RBAC boundary, drain cycle