AI doesn't assist the workflow. It drives it. Below is how the system is designed.
Next.js 16
App Router, API Routes, Middleware Auth
Auth Layer
NextAuth JWT, per-route validation, role hierarchy
AI Engine
Claude with tool_use: chat, single-shot, and multi-step runs
Tool Execution
11 tools: search, update, remind, note, query, policy lookup, email, documents
Supabase
Postgres, RLS, Storage, real-time
The AI agent uses tool_use to reason and act in a loop. Each iteration: the AI decides what to do, the system validates and executes the tool, then returns the result for the next reasoning step.
while (iterations < MAX_TOOL_CALLS) {
response = ai.messages.create(tools, messages)
if (no tool_use) return response.text
for (tool in response.tool_use) {
validate(tool.name) // reject hallucinated tools
result = executeTool(tool) // try/catch with error recovery
messages.push(tool_result)
}
}
The chat loop above is one entry point. The same tool surface also drives goal-directed runs, saved procedures, and reach into external systems, with a human in the loop on the decisions that matter.
Multi-step runs
lib/agent-runner.tsGive the agent a goal on a claim. It plans 3–8 steps, executes each through the same validated tool surface, and writes a live trace you can watch. High-stakes steps (settlement, denial) pause for human sign-off instead of auto-applying.
Operating procedures
app/aopsSaved, named procedures: a plain-English goal plus the conditions for when it applies. Run on demand, or fire automatically on matching new claims. Draft / Live / Paused, so a manager rolls one out without surprising the existing book.
External systems
app/portal/carrier-xThe agent reaches beyond its own DB: lookup_policy pulls coverage from a carrier portal; send_email_and_wait emails a claimant and blocks on their reply. Both shaped like real integrations, so swapping in a live adapter is a one-file change.
Email intake
lib/email-intake.tsThe claims@ inbox, triaged by the agent: each inbound email is classified and extracted by the model, then deterministic rules route it (create the claim, attach it to the referenced claim, or park it as an exception with a stated reason). Low confidence never acts alone.
Forward-deployed: an agent operating a legacy carrier portal
The same external-systems idea, taken to the real case: an agent that reads and drives a legacy portal in a browser, no API, with a 4/4 eval scored against the system of record.
JWT Auth
Protected API routes validate the NextAuth token before processing; public demo routes have explicit gates, limits, and budgets
Zod Validation
Request bodies are validated against strict schemas, so malformed input is rejected
Tool Whitelist
The agent can only call 11 predefined tools; hallucinated tool names are rejected
Field Whitelist
Only specific claim fields can be modified, with no arbitrary DB writes
Injection Resistance
Untrusted text (operator goals, public intake) is delimited as data in agent prompts, and instructions inside it are not followed
Spend Cap
Every Claude call is metered to a usage table; a global daily budget returns HTTP 429 before the bill runs away
Human Sign-off
High-stakes agent steps (settlements, denials) pause the run for review instead of auto-applying
Error Recovery
Tool failures return structured errors to the AI so the agent can recover
Audit Trail
Every agent action logged with timestamp, tool name, and outcome
Eval Gate
CI runs the eval suite on every PR that touches an AI path; regressions block the merge
What I'd add before deploying to enterprise customers: