Inspiration

We kept hearing the same thing about agentic AI: the magic isn't a clever prompt on a laptop — it's operating and governing agents in production, where work is messy, things fail, and a human has to stay accountable. Mortgage underwriting is the perfect crucible for that. Most loan files are routine, but the long tail is brutal: missing documents, low-confidence OCR, conflicting data, marginal debt ratios, appraisal gaps, and fraud. Rigid RPA snaps on those exceptions; a raw LLM has no business making a regulated credit decision on its own.

That tension — autonomy where it helps, humans where it matters — is exactly the shape of UiPath Maestro Case. So we set out to build a real, exception-heavy underwriting case where coded agents do the reasoning, robots do the mechanical work, and humans hold authority at every credit decision.

What it does

CaseWeaver runs a loan application through a six-stage Maestro Case with two human gates and a table-driven exception lane:

Intake → Document Verification → Income Analysis → Credit & Risk Adjudication → Conditions/Compliance → Human-Approved Decision

  • Five coded agents coordinate the case; each emits an auditable timeline entry.
  • Document Understanding extracts fields; a redigitize retry fixes low-confidence OCR before escalating to a human.
  • Adjudication computes the real underwriting math and applies policy:

$$\text{DTI}_{\text{back}}=\frac{\text{debts}+\text{housing}}{\text{income}}\le 0.43,\qquad \text{LTV}=\frac{\text{loan}}{\min(\text{appraisal},\text{price})}\le 0.97$$

A file landing in the borderline band ($0.43 < \text{DTI} \le 0.46$) isn't auto-declined — it's routed to a human with the agent's full reasoning and any compensating factors (reserves, credit depth, equity).

  • Two human gates: Gate A is underwriter decision-support (borderline files only); Gate B is final authority on every approve/decline.
  • Exceptions are the product: an AML watchlist hit is a hard stop that escalates to compliance; conflicting employer data routes to a human; transient bureau failures retry with backoff.

Four personas demo every path end-to-end — clean_approve, conditional_approve, decline, and fraud_exception — each reaching the correct terminal state.

How we built it

The whole project was built by Claude Code (Claude Opus 4.8) through UiPath for Coding Agents, driven as a small multi-agent "AI project agency" (plan → build → test → security → docs).

The architectural keystone is one seam — a PlatformPort interface:

  • Agents are real LangGraph graphs and never import the UiPath SDK directly.
  • RUNTIME_MODE=local injects a LocalAdapter (deterministic mocks + a SQLite "Action Inbox" + a durable checkpointer).
  • RUNTIME_MODE=uipath injects a UiPathAdapter mapping each capability to the real platform: human gates → interrupt(CreateTask | CreateEscalation) (Action Center), secrets → Orchestrator assets, documents → Document Understanding, LLM → UiPath LLM Gateway.

So the exact same graph runs offline-mocked and on UiPath Automation Cloud. Two more deliberate choices:

  • Decisions are deterministic and policy-driven; the LLM only narrates — reproducible, testable, and safe for a regulated decision (offline by default via a stub).
  • Durable suspend/resume via a SQLite-backed LangGraph checkpointer mirrors Maestro: a case pauses at a gate in one process and resumes in another. An external framework (CrewAI) runs a "Credit Analyst vs Risk Officer" panel for borderline files — inside the governed graph, feature-flagged with a deterministic fallback.

We then validated the cloud path for real: uipath init + uipath pack produce a valid .nupkg without a tenant, with a clean CaseInput/CaseOutput contract.

Challenges we ran into

  • No tenant during the build. This is what forced the dual-mode PlatformPort — and it turned out to be the best decision we made.
  • LangGraph 1.x specifics. We probed the live interrupt/Command API and verified cross-process Pydantic-state persistence through SQLite before building on it, and added a module-scoped msgpack deserialization allowlist to keep it safe and warning-free.
  • The UiPath graph loader imports the entry module by file path (no package context), which broke relative imports — fixed by making the orchestrator use absolute imports while siblings stay relative.
  • A 64 KB entry-points schema. Exposing the full internal state made an ugly contract; introducing explicit input_schema/output_schema shrank it to ~29 KB and made the deployed agent's I/O meaningful.
  • Producing the demo video headlessly — Chrome --headless=new hung on file://; classic --headless exits cleanly, which let us render real-data scenes into a narrated MP4.

Accomplishments that we're proud of

  • One codebase, two worlds: the same agents run locally and on UiPath, proven by a packaged .nupkg.
  • Durable, cross-process human-in-the-loop that genuinely survives interruptions — the capability the hackathon asks for.
  • Exception handling as a first-class, auditable feature (seven routes in one policy table, all tested).
  • Production-grade rigor: 72 tests, ~93% coverage, ruff + mypy clean, and a STRIDE security audit with 0 open Critical/High findings.
  • A narrated 3-minute demo where every number on screen is real program output.
  • The whole thing was built by a coding agent, with the git history (every commit co-authored) as the receipt.

What we learned

  • The seam is the product. A clean port between agent logic and platform is what makes "runs on my laptop" and "runs governed in the cloud" the same artifact.
  • Keep the LLM out of the verdict. In regulated work, agents should reason and narrate; the decision belongs to deterministic policy and an accountable human.
  • Probe, don't guess. Inspecting the installed uipath SDK and LangGraph APIs live saved us from a pile of plausible-but-wrong code.
  • Coding agents shine on the unglamorous 80% — adapters, tests, packaging, exception tables, docs — which is exactly the "last mile to production" the platform is about.

What's next for CaseWeaver — Mortgage Underwriting Agents

  • Go live on UiPath Labs: publish the coded agent, wire the Maestro Case canvas from case_definition.yaml, and connect Action Center gates.
  • Real connectors: swap the mocked bureau/AML services for API Workflows and run Document Understanding on actual PDFs.
  • Escalation memory: feed resolved gate outcomes back so the agents learn from underwriter decisions over time.
  • Broaden the case templates to adjacent exception-heavy domains — disputes, KYC remediation, claims — reusing the same governed, human-in-the-loop pattern.

Built With

  • anthropic
  • claude
  • claude-code
  • crewai
  • css
  • document-understanding
  • fastapi
  • ffmpeg
  • html
  • jinja
  • langchain
  • langgraph
  • maestro-case
  • mypy
  • pillow
  • pydantic
  • pytest
  • python
  • ruff
  • sqlite
  • typer
  • uipath
  • uipath-action-center
  • uipath-automation-cloud
  • uipath-cli
  • uipath-coded-agents
  • uipath-langchain
  • uipath-llm-gateway
  • uipath-maestro
  • uipath-orchestrator
  • uv
Share this project:

Updates