Atrium platform docs
AgentCase contract
The cross-agent case API that lets the marketplace host summarize active work without rendering agent chat history.
Why cases exist
Marketplace agents are moving away from turn-by-turn chat history as the host unit of work. The host should not render an agent's transcript. It should render a small cross-agent summary of open work and deep-link to the agent's own subdomain for the rich workflow.
That unit of work is an AgentCase.
Base shape
type AgentCaseStatus = "open" | "blocked" | "done" | "failed";
interface AgentCase {
id: string;
title: string;
status: AgentCaseStatus;
status_label?: string;
updated_at: string;
url: string;
}
Status labels are agent-defined. The generic status is for cross-agent host
rendering, while status_label can say things like Awaiting interview or
Needs receipt.
Agent-owned endpoints
Each agent exposes these endpoints on its own subdomain:
GET https://{slug}.atrium.st/api/cases
POST https://{slug}.atrium.st/api/cases
Create requests use this body:
{
"params": {
"url": "https://example.com/job"
},
"idempotency_key": "req_123"
}
The agent owns the meaning of params. Otto currently accepts params.url
and optional params.mode.
Host proxy
Browsers should call the host proxy instead of agent subdomains:
GET /api/agent-cases?slug=otto
POST /api/agent-cases?slug=otto
The host forwards the incoming Cookie header server-side to
https://{slug}.atrium.st/api/cases. This avoids CORS while still using the
shared Supabase cookie domain across *.atrium.st.
The proxy normalizes the slug before building the outbound host, so the destination is always a sanitized Atrium subdomain.
Optional envelope
The host accepts either a bare array of cases or an envelope:
interface AgentCaseEnvelope {
cases: AgentCase[] | null;
schema: AgentCaseSchema | null;
capabilities: string[];
unsupported?: boolean;
}
Agents that do not implement the contract, return 404, return 401, or
return any other non-2xx response are treated as unavailable case data. The
host must degrade gracefully and fall back to ordinary agent metadata.
Fields, schemas, and actions
The host also supports optional case fields and actions:
interface AgentCaseFieldSchema {
name: string;
label?: string;
type?: string;
options?: Array<{ value: string; label: string }>;
}
interface AgentCaseAction {
id: string;
label: string;
method?: "GET" | "POST" | "PATCH" | "PUT" | "DELETE";
href?: string;
body?: unknown;
intent?: string;
}
Mutations proxy through:
PATCH /api/agent-cases/{id}?slug=otto
POST /api/agent-cases/{id}?slug=otto
PUT /api/agent-cases/{id}?slug=otto
DELETE /api/agent-cases/{id}?slug=otto
Agent subdomains remain the source of truth for valid fields and actions. The host validates the destination and normalizes shape, but it does not own the agent's business model.
Otto mapping
Otto adapts Application and Job rows into AgentCase. The adapter points
one way only: lib/agent-case.ts knows about Otto's model, but Otto's Hasura
data layer does not know the generic AgentCase type exists.
Current status mapping:
| Otto status | AgentCase status |
|---|---|
queued |
open |
submitted |
open |
interview |
open |
offer |
done |
rejected |
done |
withdrawn |
done |
failed |
failed |