Portfolio · selected work, 2025–2026

How the agents actually work.

Five case studies from healthcare revenue-cycle AI and beyond: the architecture, the state machines, the evals, the guardrails, and what the pilot data said. Real systems with patient and client details removed. Anything illustrative is labeled.

prior_auth_case_events · insert-onlylive replay

Illustrative stream. Real event kinds and rules, synthetic cases.

Clinic pilot
56/68
prior-auth requests resolved in 13 days, each with payer proof
Without a portal
77%
of answers came from APIs, calls, or published policy
Fastest approval
86 min
from submission to a certification number
Tests written
664
375 in the prior-auth stack, 289 in the voice agent

01 Prior authorization · BAM

A prior-auth agent that proves every answer.

Role
Architect and lead engineer, end to end
When
Aug – Oct 2026 · clinic pilot from Sep 16
Status
Live pilot at a specialty practice
Stack
Python · FastAPI · PostgreSQL · Next.js · AWS Bedrock AgentCore · Availity · ModMed FHIR · OpenAI (BAA)

Specialty practices lose hours to prior authorization. Every payer answers through a different door: an X12 278 API, a phone tree with a 40-minute hold, a portal, a PDF list, a fax form. The answer a practice needs isn’t “approved”. It’s proof: a certification number or a reference that wins the appeal if a claim is ever denied.

So I built an agent that treats every case as a plan with an owner and a next date, routes it to the channel most likely to settle it, and refuses to settle anything without evidence.

System map

Tap any part to see how it works.

The state machine

Eight states. Settled means settled.

next_plan(position, outcome, today) is a pure function: the same inputs always give the same plan. Twelve channel outcomes map onto eight case states.

  • An approval without a certification number is downgraded to pending.
  • “Not required” without a payer reference, review ID or policy citation moves on to the next channel.
  • Settled cases never move on their own. Only a person can reopen() one.

Pick a case to replay it. Each step writes the event the real ledger would hold.

    Synthetic cases walked through the real transition rules.

    The clinic pilot · day 13

    68 requests. Every resolution has a receipt.

    Resolved with proof, by pilot day

    Real report snapshots (Sep 18 → Oct 2). Days between snapshots aren’t drawn.

    Routing, as data

    28 rules, each citing the pilot finding or payer page it came from. Payers are shown by type.

    Guardrails

    Off by default. Proven by design.

    The agent ships switched off and check-only: until a practice opts in, a run that reaches a submit button stops before filing. Every answer has to come back with proof, or the case keeps working.

    • 8 payers that refuse automated callers sit on a never-call registry, enforced by both the router and the phone adapter. A live refusal adds a payer automatically.
    • Kill switch globally and per practice, off by default, check-only until a practice opts in.
    • Credentials never reach a model. Code holds the vault, the one-time codes, and the lockout guard.

    The operator

    A reasoning model with nine moves, each checked by code.

    When a case needs judgment, a reasoning model may pick exactly one of nine actions. Code validates every choice before it applies, and each case has a budget of 8 decisions and $1.00.

    route_to_channelretry_laterrecodesettle_not_requiredrecord_decisionask_practicemark_retrochange_payerneeds_human
    114/114dev set, 38 scenarios × 3 repeats
    85/90held-out, built from pilot history (88/90 counting equivalent answers)
    0unsafe choices in the evals
    $0.011per operator decision

    Replay before rollout

    Re-ran the pilot in a sealed room.

    Before review, the rebuilt agent replayed 1,667 imported verification results (87 cases) behind a network guard that blocked every outbound connection: zero filings, 3 bugs found, and agreement with the pilot’s first channel in 27 of 32 linked cases.

    one sync53,982 → 4queries · 27.9 s → 0.3 s

    Shipping it

    ~13.6K lines to production.

    ModMed FHIR, Availity eligibility and prior auth, write-back, and the shared outcome service: ~13.6K lines merged to production (FastAPI, Next.js, PostgreSQL, AWS Lambda), plus 360+ new tests. CI runs lint, types, tests, migrations from scratch with drift and downgrade checks, a docs linter, and a secret scan, with a preview environment per PR.

    The integrations

    FHIR and X12, the strict way.

    ModMed’s certified FHIR R4 API through SMART Backend Services: RS384-signed JWT assertions, a published JWKS, POST searches so record numbers never touch a URL. Availity’s 278 rebuilt to the Service Reviews 2.0.0 spec, with per-payer requirements learned the hard way (one payer took four attempts).

    02 Payer calls · BAM

    Switchboard: a voice agent that pays nothing to wait.

    Role
    Designer and sole engineer
    When
    Aug – Oct 2026
    Scale
    11.5K lines · 289 tests · 423 lab runs
    Stack
    Python · FastAPI · Telnyx · Deepgram · OpenAI Realtime · Gemini Live · Fly.io → AWS Fargate

    I timed 26 real payer calls made by people: 17.5 hours, and 54% of it was hold music. The median wait for a human was 4 minutes; the worst was 34. Per-minute voice platforms bill all of it. Switchboard keeps paid models idle through phone menus and hold until a person is actually on the line, for ~5× lower modeled cost per call than commercial voice-agent platforms.

    Call replay · real lab run, Aug 17

    DIALING→IVR→QUEUE_HOLD→CONVERSATION⇄SOFT_HOLD→WRAP→ENDED

      Switchboard$0.00carrier $0.007/min + model only while awake
      Per-minute platform$0.00same call at $0.11/min (typical $0.09–0.13)
      difference—

      Timing, outcome, and $0.0926 cost are from the lab run (blind payer simulator, 5/5 facts captured, wake p95 300 ms). Dialogue is illustrative of today’s design.

      Hearing hold music

      No model needed to recognize a cello.

      Hold detection is plain signal processing: energy, zero-crossing rate, spectral flatness, and the syllable-rate rhythm of the energy envelope. About 2.4 seconds of steady music enters hold; about 300 ms of speech wakes the agent, and the last 0.8 seconds are replayed so the representative’s first words aren’t lost.

      When a rep says “let me check,” the call parks in SOFT_HOLD: the paid session pauses but keeps its context.

      classifierhold musichuman 0%

      Illustrative signals; real features and thresholds.

      The call lab

      A blind payer, a strict judge, and gates that fail builds.

      A simulated payer works only from a scenario card and never sees the caller’s prompt. Deterministic scoring plus LLM-as-judge grade capture accuracy (identifiers must match exactly), wake latency, cost, and fabricated IDs. Regression gates fail the build unless capture is 100%, wake is under 2 s, a long-hold call costs under $0.10, and a disclosure challenge gets an honest answer.

      • A/B tests across 19 speech and LLM engines, all swappable behind one interface.
      • Speech-to-text word recall: 100% for the winner vs 63% for the runner-up.
      • An approval counts only if three turns check out verbatim, in order: payer answer, agent readback, payer confirmation.

      What the pilot taught me

      Most failed calls weren’t voice problems.

      I reviewed 88 pilot calls by why they ended. Missing or wrong case data ended 44% of them, more than every voice issue combined. So the fix wasn’t a better voice: it was checking data before dialing, and making the phone the last resort after the API, published lists, and the portal agent.

      Disclosure, owned by code

      The model hears silence and nothing reaches the line until the AI-disclosure notice appears in the model’s own output transcript. Two tries, or the call ends. The notice repeats after transfers, and a recording objection deletes the audio.

      Same engine, new job

      A front-desk variant asks practices who handles billing, guarded by 600 lines of rules: calling windows, one attempt per three business days, landlines only, do-not-call lists that fail closed, and a human approval gate. Lab and dry run only, by design.

      Into BAM’s cloud

      Moving from Fly.io to AWS Fargate behind CloudFront and an internal load balancer, with KMS-encrypted storage and logs, state in Postgres, off by default and check-only.

      03 Workflow research · BAM

      7,900 hours of footage, mined until it stops teaching.

      Role
      Built the capture agent and the loop
      When
      Feb – Aug 2026
      Scale
      30 workstations · 56 releases · ~12.6K lines in the loop
      Stack
      Python · ffmpeg · Gemini 2.5 Pro on Vertex (BAA) · Claude · Google Sheets

      Before automating a clinic, you have to know what people there actually do all day. I shipped a signed, consented capture agent to 30 workstations, then built an autonomous loop that turns the footage into per-person task lists, role specs, and the work only a human can do. It fed a ranked roadmap of 28 automation opportunities.

      The loop

      A plain scheduler owns every limit. “An LLM never enforces its own limits.”

      ≥ 85%

      of logged clicks and keystrokes must appear in a description, or code rejects it. A circuit breaker trips when more than 30% fail in a run.

      3 tiers

      of PHI masking, failing closed: on-device model, healthcare regex, then a Claude leak scan. A second leak pauses that client automatically.

      ~1/100

      the cost: a Gemini Flash skim pass decides which footage earns the expensive Gemini 2.5 Pro pass.

      Stopping rule

      Done when there’s nothing new to learn.

      Work on a person stops when three straight segments add under 5% new tasks and at least 60% of their working hours are covered. Not when a token budget runs out. An adversarial Claude reviewer emits “gap records” that decide which footage gets pulled next, and a weekly retro reviews the loop’s own numbers.

      5% new tasks stop: converged segments reviewed →new tasks

      04 Agent engineering · BAM

      A small company, staffed with agents.

      Each was built to take recurring work off people at BAM. They share three habits: a fixed set of allowed actions, an independent checker that isn’t the doer, and a person approving anything that leaves the building.

      Conan, the footage librarian

      Gemini Flash · Vertex · Slack

      Files every recording under a Dewey-style call-number system whose classes follow the life of a dollar through a practice. Its rule is “match → context, no match → null”: it never guesses, and human corrections become examples.

      Lois, the PR studio

      Claude Opus · Gemini · Perplexity

      Matches news to BAM’s writing and drafts posts, and now produces short films. A separate Claude session scores each film on 6 dimensions; anything under 8 goes back for a fix. Deterministic QA checks safe zones, reading time and −14 LUFS loudness. Max 2 films a day; I approve each in Slack.

      Jarvis, the meeting engineer

      OpenAI Realtime · Claude Code · Codex

      Joins Zoom, Meet or Teams, stays silent until its wake word, and keeps a live notes board. Say “fix X” and it hands a PHI-scrubbed brief to a coding agent in an isolated worktree, which may only open a draft PR.

      Relay, the build loop

      Claude Code · GitHub

      Coordinates coder, tester, grader and improver roles across several machines with GitHub as the only backend. Every file has one writer, heartbeats reassign dropped work, and the coder physically can’t edit the acceptance criteria. It’s done only when every reviewer passes the same commit.

      The proposals engine

      Claude · encrypted review site

      Writes proposals, not code. Each states an outcome and picks the cheapest path in a fixed order: backend API, product feature, integration, UI automation as a last resort, then human judgment. IDs hash from titles, so re-ranking never changes what “execute P-967” means.

      Parity Workbench

      Electron · React · Express

      One desktop app covering 28 operational goals. An engine ticks every 20 seconds and the only UI is a “Needs a human” queue. Each kind of work earns trust before its human review is retired.

      05 AI enablement · RepeatMD

      Two agents for a platform team, and the art of deleting models.

      Role
      Head of AI Enablement (consulting)
      When
      2025 – Mar 2026
      Stack
      Next.js · TypeScript · Python · pgvector · OpenRouter · Metabase

      CX Agent

      A support copilot that cites its sources.

      Embedded in the admin console as a Chrome side panel. It answers with RAG over the help center and Notion (pgvector) plus live Metabase and SQL data, through tool calls like search_knowledge_base and get_client_catalog, and it shows which source each claim came from.

      Why didn’t this member’s gift card apply at checkout?

      sql.account_staterag.search · help center

      The gift card is restricted to memberships, and this cart holds a retail product 1. Apply it to the membership renewal instead, or issue store credit 2.

      [1] gift card rules · help center   [2] account state · live SQL

      Platform Agent

      From 13 models to 2.

      A Python pipeline that turns messy client files (PDFs, spreadsheets, images, Gong call transcripts) into structured app-build specs for about 15 practices. Version 20 orchestrated 13 models: 8 for generation, 5 for vision. By version 21 I’d consolidated to Claude Sonnet plus Gemini Flash, keeping the 660-line QA evaluator, JSON repair, and prompt caching.

      v20: 8 generation + 5 vision models · v21: Claude Sonnet + Gemini Flash

      06 How I build

      Six rules that show up in every repo.

      1. 01

        Models propose, code disposes.

        Every model choice is one of a fixed set of actions, validated before it runs: the operator’s 9 moves, Lois’s critic gate, Relay’s locked criteria.

      2. 02

        No proof, no answer.

        Certification numbers, verbatim quotes, click-log coverage. If code can’t verify it, the system keeps working instead of guessing.

      3. 03

        Deterministic first, paid last.

        Signal processing hears hold music, rules route cases, a cheap skim picks footage. The expensive model only runs when it’s the only thing that can.

      4. 04

        Fail closed around PHI.

        BAA-covered, zero-retention models only, POST searches, PHI-free logs and emails, masking that pauses a client on a second leak.

      5. 05

        Replay before you roll out.

        Blind labs, held-out evals, sealed replays of real pilot data with zero outbound connections. Gates fail builds, not demos.

      6. 06

        Sanctioned doors only.

        Disclosed AI calls, never-call registries, kill switches, and credentials that never reach a model.

      Want the live walkthrough?

      I’ll screen-share any of these systems and go as deep as you like: the state machine, the lab, the guardrails, the trade-offs.

      Every figure on this page comes from the systems’ own reports, tests, or repositories. Patient, clinic, staff, and payer-specific details are removed or generalized. Synthetic and illustrative items are labeled where they appear.