Archetype
An opinion about what data engineering should be: composable, declarative, and data-centric.
Archetype is a state machine that uses big-data technology to run itself, built for the AI-native world.
It is built the way game engines are built — entities, components, processors, ticks, save states — because an operation run by agents and humans together is a real-time simulation, and its record deserves engine-grade physics. Archetype is the physics and the history: what happened, in order, forever. What the record means, and what is allowed to happen next, belongs to the layers you build on top of it — Archetype records; your policy decides.
- Composable — two primitives only: components (data) and processors (behavior). Archetypes, worlds, and forks are compositions of them.
- Declarative — you declare shapes and transforms; the engine derives what a data stack normally makes you build by hand: schemas, columnar tables, partitioning, dispatch, queries, history, audit.
- Data-centric — nothing is deleted. State, history, and the engine's own operation are rows in the same store.
class Position(Component): # a component is a schema
x: float = 0.0
y: float = 0.0
class MovementProcessor(AsyncProcessor): # a processor is a transform
components = (Position, Velocity)
async def process(self, df: DataFrame, **kwargs) -> DataFrame:
return df.with_columns(
{"position__x": col("position__x") + col("velocity__dx")}
)
Entities that share an exact component set share an archetype: a canonical signature that is an Arrow schema that is a columnar table. Processors are Daft DataFrame transforms over whole archetypes at once — one pass over the entire matching population, not a loop over objects. That collapse — component set → signature → schema → table → query — is the core of the system. Everything below is consequence.
Big data's founding move was decoupling storage from compute — that is where Iceberg and Daft come from. The decoupling bought scale but severed provenance: the code that produces a table and the knowledge of how to read it became separate artifacts. Archetype keeps the physical decoupling and restores the connection where it belongs, in the declaration: whatever you process — a simulation, a training run, an agent population — the results are managed for you and queryable with the same code that created them. The component that wrote the rows is the schema you filter on; the processor that transformed them is the lineage. Provenance is derivation, not a catalog.
Data is the point
Nothing is deleted. There is no update path and no delete path in the
storage layer; every tick appends rows keyed (world_id, run_id, tick).
The one-off run you were about to throw away — leave it. Deletion is an
inductive bias.
What you get for keeping everything:
- Time travel —
df.where(col("tick") == t)is the world at tickt - Forking — branch any moment of any run; forks read pre-fork history through lineage and diverge from there
- Experiments over runs — runs, results, and trajectories are
components too (
archetype.experiments); comparing branches is a query, which is the statistical, experiment-based mindset an AI-native data engine asks of you - The engine's own operation is data — every gated command lands in an append-only audit table on the same substrate that stores world state: consistent, partitioned, queryable, trainable
- Any altitude is a query — the same ledger renders the whole operation at command level or a single actor's first-person timeline; views are projections over rows, never separate state to reconcile
Built for agents
The intended user of this system is an agent.
Archetype is the harness: the agent supplies the intelligence; the engine supplies the attachment points, the constraints, and the record. And because the record is data, it is a harness the wearer can train on — an agent improving itself from its own ledger.
Everything is arranged so that an agent can build here and a human can trust the result by reviewing code, not by re-running it:
- Code is the source of truth. The contracts live in
docs/guide/specification.mdand the focused spec pages, and each one is pinned by named tests. What the spec says, a test enforces. - The primitives are safe to extend. New capability means a new
Componentor a newProcessor— small, local, reviewable diffs whose behavior is determined by component presence, not by control flow threaded through a framework. - The invariants will not move under you. Append-only stores. Canonical archetype signatures. All mutation through one gate. A tick either commits or it didn't happen — failed persistence raises, a failed processor fails its tick.
- Recursive operation stays governed. Agents running simulations
inside simulations go through the same gate: authorized, audited,
applied at deterministic tick boundaries in
(tick, priority, sequence)order. The audit trail this produces is the raw material for auto-research loops — the engine improving things that run on the engine. - Humans and agents are the same
Actor. Both act through the same gate under capability bindings (viewer/player/operator/admin); a person can drop into a world with exactly one worker's capabilities, and any elevation is explicit and lands in the audit trail.
The design is meant to scale with its user. The more capable the model, the more it can do with two orthogonal primitives — richer components, sharper processors, deeper experiment loops. Frameworks built as scaffolding depreciate as models improve; primitives appreciate.
Quickstart
pip install archetype-ecs
import asyncio
from daft import DataFrame, col
from archetype import ArchetypeRuntime, AsyncProcessor, Component
class Position(Component):
x: float = 0.0
y: float = 0.0
class Velocity(Component):
dx: float = 0.0
dy: float = 0.0
class MovementProcessor(AsyncProcessor):
components = (Position, Velocity)
priority = 10
async def process(self, df: DataFrame, **kwargs) -> DataFrame:
return df.with_columns(
{
"position__x": col("position__x") + col("velocity__dx"),
"position__y": col("position__y") + col("velocity__dy"),
}
)
async def main():
async with ArchetypeRuntime() as runtime:
world = runtime.world("demo", processors=[MovementProcessor()])
await world.spawn(Position(x=0, y=0), Velocity(dx=1, dy=2))
await world.run(steps=3)
df = await world.query(Position) # full append-only history
print(df.to_pylist())
asyncio.run(main())
Fork-and-diff:
fork = await world.fork("counterfactual") # inherits the source's store
await fork.step() # continues from the source's last tick
source_df = await world.query(Position)
fork_df = await fork.query(Position) # pre-fork history + its own branch
For sync scripts, use with ArchetypeRuntime.sync() as runtime: and drop
the awaits. Component columns are prefixed componentname__field
(e.g. position__x). ArchetypeRuntime is the script boundary; drop to
ServiceContainer only for custom command routing or a non-script host.
How it's organized
| Layer | What it is |
|---|---|
src/archetype/core |
The engine: components, archetypes, worlds, the tick loop, append-only stores |
src/archetype/app |
The gate: every operation authorized, audited, and applied at tick boundaries |
src/archetype/runtime |
ArchetypeRuntime — the recommended script boundary |
src/archetype/api + src/archetype/cli |
Reference deployment of the gate over HTTP, plus a thin CLI |
src/archetype/experiments |
Runs, results, trajectories, branch heads — as components |
Status
- the engine — append-only write path, tick loop, time travel, fork lineage — is the most mature part and the most heavily contract-tested
- the auto-research loop runs on the ledger: each experiment is a lab world whose ticks are the loop's iterations, resumable from its own rows
- the FastAPI layer runs developer-mode auth (a default admin
ActorCtx) - a Rust core implementing the same engine semantics is in progress on a separate branch
Examples
uv run python examples/01_world_mutations.py
uv run python examples/02_fork_counterfactual.py
uv run python examples/03_time_travel.py # historical reads + fork-and-diff
uv run python examples/04_messaging.py
uv run python examples/05_llm_agents.py
uv run python examples/06_trajectory_analysis.py
uv run python examples/07_hooks.py
uv run python examples/08_htn_resolution.py
uv run python examples/09_cloud_storage.py
uv run python examples/10_autoresearch.py # save-state optimization on the ledger
examples/05_llm_agents.py and parts of examples/06_trajectory_analysis.py
require OPENAI_API_KEY. Everything else runs credential-free (and does, in CI).
Observability
Quiet by default: your script's stdout is yours. One flag turns the machinery visible, and tracing is vendor-neutral OpenTelemetry — installing archetype pulls no telemetry vendor.
ARCHETYPE_LOG=debug uv run python your_script.py # logs + one-line spans
Every gated call and tick phase (query / materialize / execute / update)
emits OTel spans. Point them anywhere: a host app's provider is respected
as-is; OTEL_EXPORTER_OTLP_ENDPOINT sends to any collector
(pip install archetype-ecs[otlp]); LOGFIRE_TOKEN sends to
Logfire (pip install archetype-ecs[logfire]),
which also unlocks the opt-in per-tick/per-entity hooks:
from archetype.contrib.logfire_observer import logfire_hooks
world = runtime.world("demo", processors=[...], hooks=logfire_hooks())
Development
make test # fast test suite
make check # format + lint
make ci # CI gate
make docs # build docs
Documentation
- Docs site:
https://archetype-docs.pages.dev - Examples index:
examples/README.md - Architecture notes:
LEARNINGS.md - Specifications:
docs/guide/specification.mdand the focused pages it links (runtime, service protocols, command gate, execution hierarchy, world lifecycle, audit log)
License
Apache 2.0 — LICENSE
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file archetype_ecs-0.2.0.tar.gz.
File metadata
- Download URL: archetype_ecs-0.2.0.tar.gz
- Upload date:
- Size: 157.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
625e507b30e9a85051134965ec0b986b40b3923667f1de9c9487ac8bd82f3d78
|
|
| MD5 |
2bc303c0dd4f049b11b55bf2b3a0c19f
|
|
| BLAKE2b-256 |
805afb936a48835b7c3c4b0b30e3b43cd8c970bf5df11db750d8334fa32ccacf
|
Provenance
The following attestation bundles were made for archetype_ecs-0.2.0.tar.gz:
Publisher:
release.yml on VangelisTech/archetype
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
archetype_ecs-0.2.0.tar.gz -
Subject digest:
625e507b30e9a85051134965ec0b986b40b3923667f1de9c9487ac8bd82f3d78 - Sigstore transparency entry: 2169612846
- Sigstore integration time:
-
Permalink:
VangelisTech/archetype@6dd491f21677916667a69e4242a4546cb3fa0976 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/VangelisTech
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6dd491f21677916667a69e4242a4546cb3fa0976 -
Trigger Event:
push
-
Statement type:
File details
Details for the file archetype_ecs-0.2.0-py3-none-any.whl.
File metadata
- Download URL: archetype_ecs-0.2.0-py3-none-any.whl
- Upload date:
- Size: 212.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
459c282900d985dc607a7424ffc9fb916edb538161ff03c37e5143dca319326c
|
|
| MD5 |
f626b04551d851846d477211f067d25e
|
|
| BLAKE2b-256 |
d59c806597d93e0a878bb09e1ec22563404db2b3e2c5980d111f05ac6c93140c
|
Provenance
The following attestation bundles were made for archetype_ecs-0.2.0-py3-none-any.whl:
Publisher:
release.yml on VangelisTech/archetype
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
archetype_ecs-0.2.0-py3-none-any.whl -
Subject digest:
459c282900d985dc607a7424ffc9fb916edb538161ff03c37e5143dca319326c - Sigstore transparency entry: 2169612925
- Sigstore integration time:
-
Permalink:
VangelisTech/archetype@6dd491f21677916667a69e4242a4546cb3fa0976 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/VangelisTech
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6dd491f21677916667a69e4242a4546cb3fa0976 -
Trigger Event:
push
-
Statement type: