Skip to content
← All writing & deep dives
Agentic AI & Systems··8 min read

Lois: Building Mortgage Document Agents on Amazon Bedrock AgentCore

From fragile prompt scripts to a typed LangGraph state machine with fail-closed authorization and lender policy validation.

Ashwin RachhaApplied AI Engineer · Loan Labs

1. The file is the problem

A single loan packet can run past 400 pages of PDFs: appraisals, tax returns, W-2s, title commitments, purchase contracts, bank statements. Borrowers upload scans namedIMG_4901_final.pdf. Loan officers spend their hours opening documents, renaming files to lender conventions, and checking policies by hand. Is this appraisal under 120 days old? Are all the required pages here?

The first automation attempt was one-off Ruby LLM calls. It worked, in the way a prototype works. Then three failures started compounding:

  • Guessed answers. Models misclassified ambiguous pages and invented missing dates.
  • Permission overreach. Scripts ran with ambient API tokens, unrestricted delete and overwrite across shared Drive and Box folders.
  • Half-done states. A network timeout mid-tool-call left files unrecoverable.

Each failure alone is an annoyance. Together they tell you something: an agent inside a mortgage workflow is not a chat problem. It is a permissions problem.

2. A state machine, not a prompt

I re-architected Lois as a finite state machine in LangGraph, deployed on Amazon Bedrock AgentCore. Classification, extraction, policy validation, renaming: each a node with typed inputs, so a failure fails at a step you can name instead of somewhere inside a prompt you cannot.

System ArchitectureLois Agentic Pipeline & Permission Architecture
Lois Agentic Pipeline & Permission Architecture
Click to expand & zoom
Diagram Details: End-to-end mortgage workflow: Borrower/Loan Officer intake via LoisOS Chat, Email, and Slack feeds into LoanOS Backend APIs with Postgres DB, connecting to cloud storages (Box, Salesforce, Google Drive). The execution flow delegates to MCP Tool Discovery with strict Auth & Traceability, running on AWS AgentCore Runtime with Amazon Bedrock Claude models and fine-tuned underwriting verification nodes.

3. Fail closed, always

The tenet I care most about from this project: an autonomous agent should never hold ambient broad API privileges. Not because the model is untrustworthy, but because a system you cannot bound is a system you cannot operate.

We enforced it through Composio integrations with Google Drive, Box, Salesforce, and SharePoint:

  • Tenant scoping. Every tool payload carries an immutable tenant and borrower ID. The agent cannot traverse outside its own folder hierarchy.
  • Partitioned permissions. Explicit read, write_new, append_metadata. Delete and purge are hard-blocked at the gateway, not politely discouraged in a prompt.
  • Execution-time checks. Revoke access while a five-step graph is running and step three fails closed. No downstream side effects.

The distinction that matters here is between what a model can say and what application code will do. The model proposes a classification. Code owns authority. A guess can never become an irreversible write, because the boundary between the two is enforced in the gateway, not requested in the prompt.

4. Naming is compliance

Every wholesale lender enforces different file conventions. One wants[Year]_[BorrowerLastName]_[DocType]_[LoanNumber].pdf. Another wants[LoanNumber] - [DocCategory] - [FormID] - Final.pdf. Get it wrong and the loan package bounces.

Lois keeps a deterministic rule engine mapping classified documents onto each lender’s template. Zero compliance rejections during origination, not because the model names files cleverly, but because naming was never left to the model. The rules do the renaming. The model does the classifying. Neither does the other’s job.