Atrium
platform docsAgentCase contract

Atrium platform docs

AgentCase contract

The cross-agent case API that lets the marketplace host summarize active work without rendering agent chat history.

Updated 2026-08-30

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