Archetype runs as a single archetype serve process. The API layer is a FastAPI application over the service layer, and the CLI is a thin HTTP client.
External API operations should enter through iCommandService so authorization, audit emission, and info-class downgrades are consistent with the runtime.
Application Factory¶
create_app() builds the FastAPI app with routers for worlds, commands, simulation, and queries:
@asynccontextmanager
async def lifespan(app: FastAPI):
container = get_container()
try:
yield
finally:
await container.shutdown()
set_container(None)
All worlds live in the server event loop. CLI invocations and remote clients talk to that process over HTTP.
Dependency Injection¶
deps.py owns a module-level ServiceContainer and exposes service getters for FastAPI Depends().
Routes that expose user-visible operations should inject:
CommandServicefor reads, writes, lifecycle, and simulation control.ActorCtxfrom auth middleware.
Lower-level services may still be injected for internal/admin diagnostics, but they are not the normal public boundary.
@router.post("/worlds/{world_id}/run")
async def run_world(
world_id: str,
cs: CommandService = Depends(get_command_service),
ctx: ActorCtx = Depends(get_actor_ctx),
):
return await cs.run(ctx, UUID(world_id), RunConfig(num_steps=10))
Default Actor Context¶
Until real multi-tenant auth is wired, get_actor_ctx() returns a default admin actor:
ActorCtx(id=uuid7(), roles={"admin"})
That mirrors the script runtime default. API servers with real auth should map authenticated principals into ActorCtx explicitly. See Command Gate.
Route Structure¶
Routes are thin translators: validate payloads, call iCommandService, return response models.
Worlds¶
| Endpoint | Method | What it does |
|---|---|---|
/worlds |
POST | Create world through the gate |
/worlds |
GET | List managed worlds / world info |
/worlds/{id} |
GET | Get WorldInfo |
/worlds/{id} |
DELETE | Destroy the live world; persisted data remains |
/worlds/{id}/fork |
POST | Fork a world through the gate |
Lifecycle operations are direct gate calls, not global lifecycle commands submitted through the broker.
Commands¶
| Endpoint | Method | What it does |
|---|---|---|
/worlds/{id}/commands |
POST | Tick-deferred submit through iCommandService.submit |
/worlds/{id}/commands/batch |
POST | Tick-deferred batch submit |
/worlds/{id}/commands |
GET | Audit-backed command history |
Broker pending state is an implementation detail. User-facing history is
audit-backed through /worlds/{id}/history and /worlds/{id}/commands.
Simulation¶
| Endpoint | Method | What it does |
|---|---|---|
/worlds/{id}/step |
POST | Execute one tick |
/worlds/{id}/run |
POST | Execute N ticks |
/worlds/{id}/episode |
POST | Run until termination or cap on this world |
/worlds/{id}/rollout |
POST | Fork N episodes and aggregate |
/worlds/{id}/processors |
GET | List processor info |
See Execution Hierarchy.
Query¶
| Endpoint | Method | What it does |
|---|---|---|
/worlds/{id}/state |
GET | Query world state through the gate |
/worlds/{id}/entities/{eid} |
GET | Query one entity projection |
/worlds/{id}/components |
GET | Query component projections |
/worlds/{id}/history |
GET | Audit history through get_audit_history |
Reads are authorized at iCommandService; iQueryService remains the internal read implementation.
See the REST API Reference for generated schemas.
Route Pattern¶
Example create_world route:
@router.post("", response_model=WorldResponse)
async def create_world(
req: CreateWorldRequest,
cs: CommandService = Depends(get_command_service),
ctx: ActorCtx = Depends(get_actor_ctx),
):
info = await cs.create_world(
ctx,
WorldConfig(name=req.name),
StorageConfig(uri=req.storage_uri) if req.storage_uri else None,
)
return WorldResponse(
world_id=str(info.world_id),
name=info.name,
tick=info.tick,
)
The route does not construct a lifecycle command or bypass the gate.
CLI¶
The CLI (archetype command) is a thin HTTP client.
archetype serve Starts uvicorn with the FastAPI app
archetype world create POST /worlds
archetype world list GET /worlds
archetype world inspect GET /worlds/{id}
archetype world fork POST /worlds/{id}/fork
archetype world destroy DELETE /worlds/{id}
archetype entity spawn POST /worlds/{id}/entities
archetype step POST /worlds/{id}/step
archetype run POST /worlds/{id}/run
archetype episode POST /worlds/{id}/episode
archetype rollout POST /worlds/{id}/rollout
archetype query GET /worlds/{id}/state
archetype history GET /worlds/{id}/history
archetype processors list GET /worlds/{id}/processors
archetype hooks list GET /worlds/{id}/hooks
archetype resources list GET /worlds/{id}/resources
The server URL defaults to http://localhost:8000 and can be overridden with
ARCHETYPE_URL or per command with --url. HTTP commands accept the developer
auth shortcut --role / -r and the bearer-token option --token.
Source Reference¶
- App factory:
src/archetype/api/app.py - Dependency injection:
src/archetype/api/deps.py - Request/response models:
src/archetype/api/models.py - Routes:
src/archetype/api/routes/ - CLI:
src/archetype/cli/main.py