- Architecture
- A local Python runner: PDF pages to PNG at 150 DPI (3 pages max), one prompt with two backends (Bedrock for production, OpenRouter for synthetic tests only), a deterministic vendor matcher (exceptions, normalized exact, unique containment), a plan step that names files and resolves collisions, a review page on 127.0.0.1, then move, log, and queue for QuickBooks.
- Where it runs
- On the bookkeeper's PC against the clinic's network drive. Only the reading step leaves the building, to Bedrock in the clinic's own AWS account (us-east-1), under the AWS BAA. Stephens AI operates it through an access key scoped to one inference profile.
- Tests and evals
- 12 synthetic invoices mirroring her real nine plus the untested cases: 5 rotated image-only scans, a bare-date receipt, a paid invoice, a statement with a period end, an unknown vendor, a same-name collision, 2 patient-data documents. 12 of 12 on Sonnet and on Haiku. Full run, undo, and the browser Go path all proven.
- Cost and latency
- 0.9 cents an invoice on Sonnet 4.6, about 0.3 on Haiku 4.5. At any plausible clinic volume that is $2 to $13 a month of AWS.
- Guardrails
- HIPAA: a business associate agreement between Stephens AI and the clinic, the AWS BAA on the clinic's own account, retention set to none in Bedrock, logging off, the Anthropic use-case form filed. No patient name is ever written to the log or the proposal. Nothing is deleted or overwritten, ever; the tool never creates a folder; a stop-on-first-failure move with a full undo.
- The tradeoff we chose
Why this way and not the other
We moved off Claude Team and Cowork mid-build. They are the easier surface, and the first version ran there, but neither carries a BAA, so the runtime could never read a patient-named file. The Bedrock path costs a compliance program and a Windows installer; it is the only path where the clinic's data stays inside its own boundary. Also chosen: QuickBooks' own capture for the accounting entry, because a model should not touch a ledger when a deterministic feature already does it.