Core engine¶
| Package | Value |
|---|---|
| Distribution | archetype-ecs |
| Import package | archetype |
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,
materialize_commands=None,
)
Initialize the fully parallel async world.
last_committed_receipt
property
¶
Return the latest receipt even when advisory PostTick was interrupted.
has_prepared_tick_commit
property
¶
Return whether flushed frames await exact manifest reconciliation.
commit_coordinator
property
¶
Construction-bound coordinator for this world's write identity.
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.
reconcile_prepared_tick
async
¶
Finish exact publication without admitting ordinary tick work.
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
accepted by the store) 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
¶
Executes matching processors in priority order for each archetype.
Each archetype is processed through all its relevant processors concurrently with other archetypes, while preserving priority order within each archetype.
Processor failures are isolated to their archetype while the other archetype tasks finish before the failure is reported.
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 accepted by the 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 committed
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).
list_signatures
async
¶
List every registered signature, including read-created tables.
list_committed_signatures
async
¶
List signatures accepted by a successful store append.
AmbiguousTickCommitError
¶
A prepared tick's manifest outcome could not be read authoritatively.
The world retains the exact prepared commit identity and refuses to
recompute or re-append the tick. A later step retries publication with
that same identity.
TickExecutionError
¶
One or more archetype tables failed while stepping a world tick.
failures preserves every failed table identity and original
exception object in ascending table_id order (the step's
deterministic archetype order). phase names the step phase that
aggregated them: "compute" (processor execution; nothing was
written anywhere) or "commit" (persistence; the failed tables'
staged mutations survive for retry).
The message carries table identities and the phase only — never the
original exception text, which may embed provider payloads or paths.
Raise sites chain the originals as __cause__ (an ExceptionGroup
at async aggregation boundaries, the single original in the fail-fast
sync stack), so tracebacks still render every underlying failure.
Subclasses RuntimeError: callers that caught the old flattened
aggregate keep catching this one; they gain typed classification.
TickFailure
dataclass
¶
One archetype table's original failure within a failed tick.
error is the exception object the table's compute or commit raised,
unwrapped — its type, args, and traceback survive step aggregation.