Caseyby Dentons

Architecture

How Casey runs in five layers

All five layers live inside one Next.js application. The orchestrator and the LLM sub-agents are real. The data plane is mocked to a single SQLite file shipped with the repo — in production these connect to firm systems.

1

Client (App Router)

Three RSC + Client routes: /, /triage/[jobId], /architecture. EventSource consumes the SSE stream.

/ landing/triage/[jobId]/architecture
2

Route Handlers (Node runtime)

POST /api/triage kicks off orchestrator; GET /stream emits SSE events; GET /[jobId] returns final result.

POST /api/triageGET /api/triage/[id]/streamGET /api/triage/[id]
3

Orchestrator + in-memory jobs

Sequence of generateObject calls. Halts on blocking conflict. Event bus delivers to SSE subscribers.

lib/orchestratorlib/jobs (in-memory bus)
4

Sub-agents (Vercel AI SDK + Anthropic)

Each agent: focused system prompt + Zod schema via generateObject. Model: claude-sonnet-4-6.

ParserConflictsScorerComposerBrief
5

Data plane

Mocked

Read-only SQLite for the demo. In production, these are firm systems: Intapp Conflicts, CRM, experience DB.

Intapp Conflicts (mocked → SQLite)CRM (mocked → SQLite)Experience DB (mocked → SQLite)Firm directory (mocked → SQLite)OCG store (out of scope — pluggable)

Data flow per RFP

  1. 1. User picks a sample or uploads a PDF → POST /api/triage parses the document, mints ajobId, starts the orchestrator in a background promise.
  2. 2. Client navigates to /triage/[jobId] and opens an EventSource on the stream route.
  3. 3. Orchestrator emits stage_N_start / stage_N_done events as each sub-agent completes. UI animates each card in.
  4. 4. On conflicts.overallPosition === 'blocking', the orchestrator emits halted and skips stages 3–5.
  5. 5. On complete, the kickoff brief renders at the bottom of the triage view.