Overview
A placement-to-bind pipeline for insurance agencies: a quote PDF goes in; AI extracts the policy details; a human verifies every field; e-signature follows; and a bind request goes to the underwriter. Built in 17 days — 813 commits across 243 pull requests — and now live with a pilot agency.
Project Design
Built with Claude Code agents working in parallel worktrees, with monitoring from day one and an automated check suite in the build pipeline that blocks known failure classes from shipping. AI does the extraction and drafting; a human verification step is structurally required before anything binding happens — the system is designed so the AI can never commit an agency to coverage on its own.
Key modules
Extraction
Claude reads the quote PDF and returns structured policy fields plus the anchor text printed beside every signable field.
Anchor resolver
Deterministically matches detected anchor text to the PDF's text layer and computes each field's coordinates.
Form fingerprinting
Keys operator-confirmed placements to a form's number/edition (plus a MinHash for numberless forms) so recurring templates come back pre-placed.
PDF kit
pdf.js text extraction, zoom-independent coordinate math, and pdf-lib assembly of the final bind package.
Bind dispatch
Assembles the bind package and routes the request to the underwriter once a human has verified every field.
Email relay
Fail-closed outbound over M365 Graph / Gmail behind a classified-status gate — unknown outcomes count as failures.
Key features
Form fingerprinting — placement that learns
Signature placement was the agents' biggest friction point, so it got the most attention. Insurance runs on standardized forms — the same ACORD and carrier templates recur constantly — so ReadySetBind treats placement as a learning problem, not a per-document chore. On upload, Claude detects each signable field and returns the verbatim anchor text printed beside it; a deterministic resolver matches that text against the PDF's text layer and computes the field's coordinates. When an agent nudges a field in the drag-and-drop editor, the corrected placement is saved against a fingerprint of the form — its printed form number and edition, plus a MinHash (a compact similarity signature) of the static label text for forms that carry no number. The next time a matching form comes through — confirmed by a similarity check so a genuinely revised edition is never reused blindly — the operator-approved placement is applied automatically and the document arrives pre-placed. One correction pays off on every future document built from that template.
Security & ops decisions
- Every sensitive database function is deny-by-default: execute rights are revoked from public, anonymous, and authenticated roles — and the tests assert all three stay revoked.
- Email failures route through a fail-closed classifier — anything unknown counts as failed — and a CI rule blocks any new email call that skips the classification.
- One audited function is the single source of tenant access for every row-level security policy — the database filters rows per user — with explicit deny-all policies on tables users should never touch.
- Telemetry pseudonymizes user IDs with a vaulted key, session replay is consent-gated, surveys are choice-only, and error reports are scrubbed before they leave the building.
- Every new API route, edge function, or policy change passes a standing authorization-review gate plus a dedicated security-reviewer agent before merge.
Builder notes
- ~35 parallel agent worktrees, with a pre-tool hook that blocks branch switching — one branch, one worktree, one PR per agent.
- 17 days produced 19 edge functions, 81 migrations, ~60k lines of app TypeScript plus ~20k of edge-function code, and 127 test files.
- The telemetry schema is fail-closed: a no-free-string type union means unregistered analytics properties cannot be sent at all.
- Restoring typed database clients surfaced 18 latent type bugs that had accumulated in eight days of untyped operation — the old workaround is now documented as an anti-pattern.
Lessons learned
- The same bug shipped three times past written rules and zero times past an automated check. Structured gates (hooks and hard rules) solved this problem going forward.
- A platform's default permissions are part of your attack surface: my own lockdown left a sensitive operation publicly callable because of a default grant I didn't know existed. Always audit your settings.
- “Works locally” says little about production: one feature failed four stacked ways that only existed on the server, each invisible until the previous one was fixed.
- Don't rebuild rentable infrastructure: the worst bug lived entirely in a custom email layer that shouldn't have existed.
What carried forward
Every third-party wrapper now returns an explicit status the caller must branch on; recurring defects get an automated gate, not a third paragraph of documentation; and access to every sensitive operation is explicitly denied by default and tested for every role.
Posts from this project
Compile-green, deploy-broken
Every test passed and it worked on my laptop. In production, placing PDF signature fields failed four different ways — pdf.js in a serverless runtime — each one invisible until the previous fix.
The email that shipped three times
I let AI agents build my own email plumbing on top of Resend. The same bug — marking undelivered mail as “sent” — shipped three times before a build gate finally stopped it.
The REVOKE that didn't
I locked a sensitive database function, verified the lock, and a Supabase default grant to the anonymous role left it open to the internet for three days.