REST API — Council Creation & Chain Execution
iris intermediate 5 min read
ELI5
The council and chain APIs are like a project management system. You create a team (council) with specific members and one designated team lead who can veto bad ideas. Then you run project workflows (chains) through that team. If the team lead says “stop,” the workflow halts immediately and you get a detailed report of what happened.
Technical Deep Dive
Endpoint Summary
| Method | Path | Operation | Status Codes |
|---|---|---|---|
POST | /v1/councils | createCouncil | 201, 400, 404, 409 |
POST | /v1/chains/execute | executeChain | 200, 400, 404, 409 |
GET | /v1/chains/{id}/history | getChainHistory | 200, 404 |
GET | /health | healthCheck | 200, 503 |
GET | /metrics | prometheusMetrics | 200 |
Create Council (POST /v1/councils)
sequenceDiagram participant Client participant Router as councils.py participant SReg as SpriteRegistry participant CReg as CouncilRegistry
Client->>Router: POST /v1/councils Note over Client,Router: {domain, sprites, gate_agents, chains, rules}
Router->>Router: Validate domain not empty alt Domain empty Router-->>Client: 400 end
Router->>Router: Validate sprites not empty Router->>Router: Validate gate_agents not empty
Router->>SReg: Check all sprite IDs exist alt Missing sprites SReg-->>Router: Missing: [uuid1, uuid2] Router-->>Client: 404 {missing_sprites} end
Router->>SReg: Check all gate_agent IDs exist alt Missing gate agents Router-->>Client: 404 end
Router->>Router: gate_agents ⊆ sprites? alt Not subset Router-->>Client: 400 INVALID_GATE_AGENT end
Router->>Router: len(gate_agents) == 1? alt Not exactly one Router-->>Client: 400 INVALID_GATE_AGENT end
Router->>CReg: Check domain uniqueness alt Domain exists CReg-->>Router: Conflict Router-->>Client: 409 COUNCIL_CONFLICT else Unique CReg->>CReg: Convert ChainDefinition → Chain (generate UUIDs) CReg-->>Router: Council Router-->>Client: 201 Council endKey validations:
- Domain not empty
- Sprites list not empty
- Gate agents list not empty
- All sprite IDs exist in registry
- All gate agent IDs exist in registry
- Gate agents are a subset of sprites
- Exactly one gate agent (DEC-002)
- Domain is unique
Execute Chain (POST /v1/chains/execute)
sequenceDiagram participant Client participant Router as chains.py participant CReg as CouncilRegistry participant Executor as ChainExecutor participant HReg as ExecutionHistoryRegistry
Client->>Router: POST /v1/chains/execute Note over Client,Router: {council_id, chain_id, input}
Router->>CReg: get_by_id(council_id) alt Council not found CReg-->>Router: None Router-->>Client: 404 end
Router->>Router: Find chain in council.chains alt Chain not found Router-->>Client: 404 end
Router->>Executor: execute_chain(council_id, chain, input) Executor-->>Router: ChainExecutionResult
Router->>HReg: create(history) HReg-->>Router: execution_id
alt status == "vetoed" Router-->>Client: 409 GATE_VETO {execution_id, gate, reason} else Router-->>Client: 200 ChainExecutionResult endChain Execution Result
{ "execution_id": "uuid", "council_id": "uuid", "chain_id": "uuid", "status": "completed", "started_at": "2026-04-27T10:00:00Z", "completed_at": "2026-04-27T10:00:05Z", "duration_ms": 5000, "steps": [ { "order": 0, "sprite_id": "uuid", "action": "generate_code", "status": "completed", "output": {"code": "def hello(): ..."} } ], "gates": [ { "type": "before", "sprite_id": "uuid", "decision": "allow", "reason": "Task scope approved" } ]}Gate Veto Response (409)
{ "code": "GATE_VETO", "message": "Chain execution was vetoed by gate authority", "details": { "execution_id": "uuid", "gate_sprite_id": "uuid", "gate_type": "before", "reason": "Task scope not authorised" }, "request_id": "req-uuid"}Execution History (GET /v1/chains/{id}/history)
flowchart LR A["GET /v1/chains/{id}/history"] --> B["Query params"] B --> C["limit: 1-100 (default 20)"] B --> D["offset: default 0"] B --> E["status: completed/failed/vetoed (opt)"] C --> F["ExecutionHistoryRegistry"] D --> F E --> F F --> G["Sort by completed_at DESC"] G --> H["Return {executions, total, limit, offset}"]Pagination:
limit: 1–100, default 20offset: default 0status(optional): filter bycompleted,failed, orvetoed- Sorted by
completed_at(orstarted_at) descending — most recent first
Health Check (GET /health)
{ "status": "healthy", "version": "1.0.0", "uptime_seconds": 3600, "checks": { "database": "healthy", "sprite_registry": "healthy", "council_registry": "healthy", "telemetry": "healthy" }, "timestamp": "2026-04-27T12:00:00Z"}Returns 200 when healthy, 503 when any dependency is degraded or unhealthy.
Key Terms
- CouncilCreate → Request model:
domain,sprites(UUID[]),gate_agents(UUID[]), optionalchainsandrules - ChainExecuteRequest → Request model:
council_id,chain_id,input(object) - GATE_VETO → Error code returned as HTTP 409 when a gate vetoes chain execution
- ExecutionHistory → Persisted audit record of every chain execution, indexed by
chain_id - HealthCheck → System status endpoint reporting per-dependency health (database, registries, telemetry)
Q&A
Q: Can I update or delete a council?
A: The current API only implements POST /v1/councils. No GET, PUT, DELETE, or LIST endpoints exist yet. Councils are managed in-memory.
Q: What happens if I execute a chain with a non-existent chain_id?
A: The endpoint searches the council’s chains list. If the chain is not found, it returns 404.
Q: How do I know which gate vetoed?
A: The 409 response includes details.gate_sprite_id, details.gate_type, and details.reason.
Q: Can I filter execution history by date range?
A: Not currently. The history endpoint supports filtering by status and pagination via limit/offset.
Q: What does /metrics return?
A: Prometheus text-format metrics generated by prometheus_client.generate_latest(). Includes counters and histograms for sprite operations, council operations, chain executions, and gate decisions.
Examples
The council/chain API is like a court system:
- POST /v1/councils = Forming a new court (assigning judges, clerks, bailiffs; designating one chief justice with veto power)
- POST /v1/chains/execute = Running a trial (opening statements → evidence presentation → closing arguments → verdict)
- Gate veto = The chief justice declaring a mistrial (halts everything immediately)
- Execution history = The court transcript (complete record of what happened, who spoke, what was decided)
- Health check = The court administrator verifying the building has power, water, and all staff are present
neighbors on the map
- Synchronous Chain Execution Engine (DEC-002) designing chain execution logic
- REST API — Sprite CRUD & Verification integrating with the sprite registry
- MCP Bridge — 4 Tools (Tier 2) integrating IRIS with Claude or other MCP clients