
TL;DR
Commercial underwriters drown in PDF submissions. Here is how to build a Claude Agent SDK triage bot with skills, hooks, and a clean audit trail.
A commercial underwriter at a mid-market property and casualty carrier opens around forty submissions a day. Each one arrives as an email with three to fifteen attachments: a broker cover letter, a five-year loss run, a SOV spreadsheet, an ACORD 125, an ACORD 140, sometimes a building inspection report, sometimes a PDF that is just a photo of a fax. The first job is not pricing. The first job is deciding whether the submission is even quotable inside the carrier's appetite.
Most carriers handle this with a junior underwriting assistant who does the same checks every time: is the named insured already a customer, is the SIC or NAICS in our appetite, are the loss runs current, does the SOV total match the cover letter, are any required forms missing. It is a thirty-minute job per submission that nobody enjoys and everybody does badly by 4pm. The agentic wedge is not "automate underwriting." That is regulated and mostly a bad idea. The wedge is "automate the triage memo," with a hard stop before any decision that affects price or binding.
You could build this in n8n or Power Automate. Many carriers tried. The reason it usually fails is that submissions are messy in long-tail ways. Brokers send the SOV embedded as an image inside a PDF. Loss runs come from twelve different carrier formats. The ACORD form has handwritten amendments in the margins. A rigid workflow handles 60% and dies on the rest. A coding agent with file system access, an LLM, and a skill library handles 90% and writes a clean note about the 10% it could not.
The Claude Agent SDK is the right tool because it gives you the same primitives Claude Code uses, programmatically: tool use, skills, hooks, MCP servers, transcript output. You wrap it in a job runner that pulls from a shared mailbox, and you get a triage bot that produces a memo per submission with full audit lineage.
submission-triage/
src/
index.ts # Agent SDK entry point
runner.ts # mailbox poller, queue, retry
types.ts # Submission, Memo, AppetiteRule
skills/
parse-acord/
SKILL.md
scripts/extract.py # uses pdfplumber + a labeled schema
parse-loss-run/
SKILL.md
scripts/normalize.py # carrier-specific adapters
parse-sov/
SKILL.md
scripts/sov_to_csv.py
appetite-check/
SKILL.md
rules.yaml # appetite filters, owned by underwriting
mcp/
policy-admin.ts # read-only PAS lookup
naics-lookup.ts
prompts/
triage-memo.md
hooks/
redact-pii.sh # PreToolUse, scrubs SSNs, EINs from transcripts
no-bind.sh # PostToolUse, blocks any write to PAS
out/
{submission-id}/
memo.md
lineage.jsonl
attachments/
Get the weekly deep dive
Tutorials on Claude Code, AI agents, and dev tools - delivered free every week.
The four skills are the heart of the system. Each is a small SKILL.md plus a script. The agent picks them up automatically and the underwriting team can update rules.yaml without touching code.
parse-acord knows the ACORD 125 and 140 layouts and returns a JSON object with named insured, mailing address, FEIN, SIC, NAICS, requested coverages, and a confidence per field. It does not guess. If a field is unreadable, it returns null and a reason.
parse-loss-run is the messiest one. It has a small registry of carrier templates (Travelers, Hartford, Liberty, CNA, Chubb, the regional ones the carrier sees most) and a fallback prompt for unknown formats. Output is a normalized five-year frequency and severity table.
parse-sov extracts the schedule of values, totals it, and compares to the cover letter number. A mismatch over 5% is flagged.
appetite-check reads rules.yaml, which encodes the carrier's actual appetite: NAICS in/out lists, TIV bands, loss frequency thresholds, geographic exclusions. The output is a clean pass or a list of specific reasons for referral.
The prompt the agent runs per submission is short and constrained:
You are a submission triage assistant. You do not make underwriting decisions. You produce a triage memo using only the skills available. For the submission in
inbox/{id}/, runparse-acord,parse-loss-run,parse-sov, thenappetite-check. Writeout/{id}/memo.mdusing the template inprompts/triage-memo.md. If any skill returns low confidence, say so explicitly. Never write to the policy admin system. Never quote a premium.
The memo template is the artifact that matters. Underwriters review the memo, not the agent. A good memo has: insured snapshot, appetite verdict with cited rules, loss summary, missing-information list, and a recommendation queue (decline, refer to senior, ready to quote).
Two hooks carry the regulatory weight.
redact-pii.sh runs as a PreToolUse hook on every transcript write. It strips SSNs, EINs in non-allowed contexts, and any string that looks like a driver's license. This keeps the agent's transcripts safe to retain for the seven years your state DOI probably requires.
no-bind.sh runs as a PostToolUse hook and rejects any tool call that targets a write endpoint on the policy admin system MCP. The MCP server itself is read-only, but the hook is a second layer. Auditors love a second layer.
A third optional hook ships transcripts to your SIEM in the same JSONL format you already use for human underwriter activity. From a SOC2 perspective the agent becomes just another principal with an audit trail.
Three risks are worth naming.
Bias. If rules.yaml encodes a proxy for a protected class, the agent will faithfully reproduce that bias at scale. Mitigation: have a model-risk reviewer audit rules.yaml the same way they would audit a rating algorithm.
Hallucinated extraction. The agent might confidently report a TIV that is wrong because the SOV had a merged cell. Mitigation: the SOV-vs-cover-letter cross-check, and a hard rule that any TIV above a threshold gets human extraction regardless of confidence.
Drift. Brokers change their templates. Carriers acquire each other and rename their loss-run formats. Mitigation: a weekly job that flags any submission where more than two skills returned low confidence, and routes those to a "improve the skill" backlog.
You can stand up a useful version of this in an afternoon, against your own sample submissions, no PAS integration required.
npm create @anthropic-ai/agent and pick the TypeScript templateinbox/appetite-check/rules.yaml with five real appetite rules from your underwriting guideparse-acord first, using pdfplumber and a single labeled examplesrc/index.tsTwo of the ten will be wrong in interesting ways. Those two are the spec for the next iteration. Show the other eight to an underwriter and watch what they do with the memo. The carriers that win the next decade are not the ones with the biggest underwriting teams. They are the ones whose teams stop reading PDFs and start reading memos.
Technical content at the intersection of AI and development. Building with AI agents, Claude Code, and modern dev tools - then showing you exactly how it works.
Configure model, tools, MCP, skills, memory, and scoping.
Claude CodeFire when subagents spawn and finish.
Claude CodeSpawn subagents to handle complex hook logic.
Claude Code
Claude Code hooks are powerful but discovery and install is a manual JSON-paste exercise. Hookyard is a directory plus C...

A curated directory of 312 Claude Code skills, plus Pro tools for authors who want analytics, version pinning, and a rea...

Manufacturing teams ship ladder logic and ESP32 firmware without code review. Here is a Codex CLI setup with hooks that...

New tutorials, open-source projects, and deep dives on coding agents - delivered weekly.