Core engine¶
Extension API. Supported engine primitives for custom execution and world lifecycle extensions.
Archetype
¶
Convenience handler for archetype operations
sig_from_components
staticmethod
¶
Generate an archetype signature from a list of component instances. Returns a tuple of component types sorted by name for consistent signatures.
projection_columns
staticmethod
¶
Canonical schema column list for a component projection (spec §165).
Projection is type-level — only the schema matters — so this accepts component types directly. Instances are accepted for back-compat and normalized to their types.
Commit-identity columns are excluded: they are storage metadata the read layer filters on, not part of the user-facing shape — and legacy epoch-0 tables do not have them, so projections must not ask.
add_components
staticmethod
¶
Generate a new archetype signature by adding components to an existing signature.
remove_components
staticmethod
¶
Generate a new archetype signature by removing components from an existing signature.
get_name
staticmethod
¶
Generate a compact, filesystem-safe name for an archetype. We avoid extremely long identifiers by using only a short descriptor and a schema hash. This ensures stable uniqueness without exceeding path limits.
The hash covers the FULL storage schema, commit columns included — schema-is-identity is what turns the commit-identity amendment into new-generation table ids instead of in-place evolution.
get_legacy_name
staticmethod
¶
The v0.2 table id for a signature (base schema without commit columns).
Read-only fallback: stores resolve this name when the current-generation table does not exist, so pre-#273 history stays queryable. Nothing ever writes to a legacy table id.
get_archetype_schema
staticmethod
¶
Get the schema for an archetype from a list of component types. Combines the base archetype schema with prefixed component schemas.
get_legacy_schema
staticmethod
¶
The v0.2 storage schema for a signature (no commit columns).
to_row_dict
staticmethod
¶
Convert entity components to a row dictionary for archetype storage.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entity_id
|
int
|
The unique entity identifier |
required |
tick
|
int
|
The simulation tick |
required |
components
|
list[Component]
|
List of component instances |
required |
world_id
|
str
|
The world identifier |
required |
run_id
|
str
|
The run identifier |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
Dict containing the row data for this entity |
AsyncWorld
¶
AsyncWorld(
*,
world_id,
name,
querier,
updater,
system,
resources,
hooks,
run_id=None,
tick=0,
next_entity_id=1,
entity2sig=None,
spawn_cache=None,
despawn_cache=None,
lineage=None,
commit_coordinator=None,
)
Initialize the fully parallel async world.
active_signatures
property
¶
Get the union of all archetypes that need processing this tick.
step
async
¶
Executes one full, parallel simulation tick.
Tick Lifecycle
- pre_tick hook fires
- For each archetype (parallel): a. Query previous state (tick N-1) b. Materialize mutations (spawn/despawn caches) c. Execute processors (priority order) d. Persist to store
- Increment tick
- post_tick hook fires (tick is now N+1)
Note: Messages enqueued in tick N are dequeued in tick N+1.
materialize_mutations
¶
Apply pending despawns and concat pending spawns onto df, consuming both caches.
Diagnostic/compatibility surface. The step path does NOT use this combined form: it applies despawns before processors, concats spawns after them (initial conditions), and consumes the caches only after the append commits (see _compute_archetype/_commit_archetype).
create_entity
async
¶
Spawn a new entity with an auto-assigned id. Fires OnSpawn.
create_entities
async
¶
Spawn multiple entities in one batch. Fires one OnSpawn per entity.
All spawn rows are appended in a single cache operation per archetype signature, preserving the initial-conditions contract: every entity's first row is its raw spawn values at the materialization tick; processors first apply on the following tick (x_0 is given, x_{t+1} = f(x_t)).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entities
|
list[list[Component]]
|
A list of component lists, one per entity to spawn. |
required |
Returns:
| Type | Description |
|---|---|
list[int]
|
A list of entity IDs in the same order as |
reserve_entity_ids
¶
Reserve n entity IDs without spawning.
The returned IDs are guaranteed never to collide with auto-assigned
ones: they are drawn from the same monotonic counter as
create_entity / create_entities, so interleaved calls produce
disjoint ranges.
Reserved IDs must be materialised via spawn_with_reserved_id
before the next step() that processes their archetype, otherwise
they remain invisible (no spawn_cache row, no entity2sig entry).
Use this when external systems need to reference an entity by ID before the spawn lands on the ledger (e.g. to break a circular dependency between two entities that reference each other).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n
|
int
|
Number of IDs to reserve (must be >= 1). |
required |
Returns:
| Type | Description |
|---|---|
list[int]
|
A sorted list of n reserved entity IDs. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If n is less than 1. |
spawn_with_reserved_id
async
¶
Materialise a previously reserved entity ID.
Registers the entity in entity2sig and spawn_cache exactly as
create_entity would, then fires OnSpawn. The entity will appear
as a raw spawn row at the next materialization tick.
Cancellation contract: if you want to cancel a reserved spawn before
it materialises, call remove_entity(entity_id) — it will find the
pending spawn_cache row and remove it cleanly, matching the semantics
of cancelling a same-tick spawn from create_entity.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entity_id
|
int
|
A previously reserved ID (from |
required |
components
|
list[Component]
|
Initial component values. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If entity_id is already registered (double-spawn guard — prevents silent overwrites of live entities). |
remove_entity
async
¶
Despawn an entity. Cancels a pending same-tick spawn if present,
otherwise queues a despawn row for the current tick. Fires
OnDespawn iff the entity existed.
update_entity
async
¶
Overlay component values on an existing entity without changing its archetype.
The entity keeps its current signature. Only the supplied component fields are overwritten. Used for value mutations (e.g., Position.x += 1) as distinct from add_components which extends the signature.
add_components
async
¶
Attach additional components to an existing entity. Fires
OnComponentAdded iff the signature actually changes.
remove_components
async
¶
Detach components from an existing entity. Fires
OnComponentRemoved iff the signature actually changes.
query_archetype
async
¶
query_archetype(
sig,
run_config_or_ticks=None,
*,
ticks=None,
entity_ids=None,
components=None,
run_id=None,
run_config=None,
)
Facade Method to query an archetype table by signature.
The signature is canonicalized (sorted by class name) before lookup,
so callers may supply types in any order. If the canonical signature
has never been active in this world (not in the live registry AND not
in the store's durable record) an UnknownSignatureError is raised —
a distinct failure from 'the signature exists but has zero rows at
this tick' which returns an empty DataFrame.
Defaults to the world's most recent run_id when not provided. Accepts an optional run_config for instrumentation; ignored by the base querier.
get_components
async
¶
Query all active entities that contain the requested component types.
Passthrough to the querier's query_components method.
execute
async
¶
Execute system processors, passing resources for type-safe dependency injection.
update
async
¶
Update the store with the given archetypes.
When coordinated persistence is active, the update carries the tick's commit identity. Capability is determined before writing so an error cannot cause the same rows to be appended twice.
add_hook
¶
Register a handler for lifecycle events.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event_type
|
type[_HookEventT]
|
Event dataclass to listen for: PreTick, PostTick, OnSpawn, OnDespawn, OnComponentAdded, or OnComponentRemoved. |
required |
fn
|
AsyncHookHandler[_HookEventT]
|
Async callable that accepts the matching event instance. |
required |
mode
|
FireMode
|
"blocking" awaits the handler inline. "spawn" schedules it with asyncio.create_task so the tick does not wait. |
'blocking'
|
Returns:
| Type | Description |
|---|---|
HookHandle
|
HookHandle to pass back to remove_hook when the handler should be |
HookHandle
|
unregistered. |
Example
from archetype.core.hooks import PostTick
async def log_tick(event: PostTick) -> None: print(f"tick {event.tick} done, {len(event.results)} archetypes")
handle = world.add_hook(PostTick, log_tick)
... later ...¶
world.remove_hook(handle)
remove_hook
¶
Unregister a hook by handle.
The operation is idempotent. Passing a handle that was already removed, or a handle minted by another world, is a no-op.
AsyncSystem
¶
Async version of SyncSystem that processes archetypes concurrently.
Key innovation: Each archetype is processed through all its relevant processors concurrently with other archetypes, while maintaining priority-based ordering within each archetype.
This provides the same semantic guarantees as SyncSystem but with per-archetype parallelism.
execute
async
¶
Process a single archetype through all relevant processors.
This is where the concurrency happens - each archetype gets its own task but within each archetype, processors run in priority order (same as sync).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
df
|
DataFrame
|
The DataFrame to process |
required |
sig
|
ArchetypeSignature
|
The archetype signature |
required |
resources
|
Resources | None
|
Type-safe resource container (available as kwarg to processors) |
None
|
debug
|
bool
|
Enable debug logging for processor execution |
False
|
**input_kwargs
|
Additional kwargs passed to processors |
{}
|
AsyncQueryManager
¶
get_archetype
async
¶
Get all archetypes that contain all of the specified component types for provided world_id and run_id.
query_archetype
async
¶
query_archetype(
sig,
world_id,
ticks=None,
entity_ids=None,
components=None,
run_id=None,
commit_tokens=None,
**kwargs,
)
Query active entities for the provided archetype signature.
The signature is canonicalized (sorted by class name) before table resolution, so callers may supply types in any order and will always find the same table.
Raises UnknownSignatureError when the canonical signature has never
been registered in the durable store — distinct from 'the signature
exists but has zero rows at this tick', which returns an empty DataFrame.
_world_validated=True may be passed by the world's query_archetype
facade after it has already verified the sig against live and store sigs.
When set, the querier skips its own redundant check so that sigs that are
live (in spawn cache) but not yet committed do not cause a false positive.
query_components
async
¶
query_components(
components,
world_id,
run_id,
*,
ticks=None,
entity_ids=None,
commit_tokens=None,
)
Query all entities that contain the requested component types.
Discovers matching archetype signatures, queries each, projects to the requested component columns, and unions the results.
If a requested component type does not exist in ANY registered
archetype, a KeyError is raised naming the missing component so
callers can detect the ManipProprio-vs-ManipAction style confusion
(querying a component that belongs to a different archetype).