CRUMB a card from devarno-cloud

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

MethodPathOperationStatus Codes
POST/v1/councilscreateCouncil201, 400, 404, 409
POST/v1/chains/executeexecuteChain200, 400, 404, 409
GET/v1/chains/{id}/historygetChainHistory200, 404
GET/healthhealthCheck200, 503
GET/metricsprometheusMetrics200

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
end

Key validations:

  1. Domain not empty
  2. Sprites list not empty
  3. Gate agents list not empty
  4. All sprite IDs exist in registry
  5. All gate agent IDs exist in registry
  6. Gate agents are a subset of sprites
  7. Exactly one gate agent (DEC-002)
  8. 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
end

Chain 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 20
  • offset: default 0
  • status (optional): filter by completed, failed, or vetoed
  • Sorted by completed_at (or started_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[]), optional chains and rules
  • 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