# Archon: keeping financial facts outside the LLM, with Strands Agents

> Source: <https://dev.to/efousekis/archon-keeping-financial-facts-outside-the-llm-with-strands-agents-hah>
> Published: 2026-09-14 14:25:30+00:00

A fluent collection email can still be wrong. If a customer has paid part of an invoice, an agent that repeats the original total can damage a relationship before anyone notices.

Archon is my Agents for Humans project for independent joiners: source-backed books, followed by a human-approved collection email. The interesting engineering problem was deciding which parts should **not** belong to the model.

[Watch the working 4:51 demo](https://youtu.be/gpf1Dt8uYgY) · [Open the application](https://d2ssmv59q16d0b.cloudfront.net/) · [Read the MIT-licensed source](https://github.com/upgradedev/archon-aws-strands)

The walkthrough uses fictional invoice JN4410 for €1,860 and a recorded payment of €600. The remaining balance is €1,260.

There are three different questions here:

Generating prose answers none of those questions by itself. Archon keeps them as separate steps.

The drafting workflow uses Python Strands Agent instances, scoped [@tool](https://dev.to/tool) functions and GraphBuilder. Six readers cover suppliers, sales, payroll, trading, cash and metrics. Their reports converge before a tool-less composer prepares the opening and closing prose.

This fan-in means the required reports have completed. It is not a vote and it does not turn agreement into financial truth. The deterministic ledger selects the eligible balance, checks the amounts and supplies the figures inserted into the final draft.

The composer cannot choose arbitrary tools or dispatch an email. Numeric claims in its free-text output are rejected, and invalid structured output produces no draft. A missing graph result blocks preparation instead of being replaced with plausible text.

The separate incoming-document extraction path uses Amazon Bedrock Converse for bounded text and plain-email input. It should not be confused with the six-reader Strands graph. An opt-in intake webhook can accept documents from a configured producer, but cannot draft or send on its own.

A generic approved flag is not enough when the evidence can change.

Archon's approval binds the recipient, exact message, balance, fingerprint and workspace revision, with an expiry. If new evidence changes the decision, the old approval is no longer a shortcut to sending.

The user can inspect linked sources next to the message. The approval control is deliberately part of that workspace, rather than a disconnected confirmation screen. That is a user-experience decision as well as an authorization boundary.

*Deployed service boundaries. The API role cannot call Bedrock or SES directly.*

The React and TypeScript frontend is hosted in private Amazon S3 behind CloudFront. API Gateway invokes a Lambda API, while a separate worker performs the Bedrock and SES operations. The API role cannot directly call those providers.

Workspace, job and outbox state use S3 persistence with conditional writes. A stale browser update must not silently overwrite newer state. Provider work is bounded by a scoped grant; uncertain dispatch outcomes are retained for reconciliation rather than blindly retried.

The deployed storage here is S3, not Aurora. AgentCore is not part of this deployment either. The [architecture documentation](https://github.com/upgradedev/archon-aws-strands/blob/main/docs/ARCHITECTURE.md) includes both the service layout and the orchestration boundary.

The recorded demo includes live Bedrock drafting, explicit human review and a real controlled Amazon SES request. It then reloads the application and shows the durable receipt.

That establishes provider acceptance and persistence, not proof that the message reached an inbox. It also says nothing about a customer's eventual payment. Sending a reminder does not change an invoice to paid; a recorded receipt is not bank-verified settlement.

These distinctions are easy to lose in a polished demo. They are also what makes its evidence interpretable.

The application has a separate portfolio of 240 fictional records: sales and purchase invoices, both kinds of credits, client receipts and supplier payments. Dashboard metrics drill into the underlying records. Loading that portfolio makes no model calls and sends no email.

The fuller portfolio and the focused collection tutorial are separate saved workspaces. One explains the product's information architecture; the other makes a single approval decision easy to follow.

The data is synthetic. I have not established independent accuracy, time saved or money recovered, and do not present this as a production bank integration or accounting replacement. [Evaluation scope](https://github.com/upgradedev/archon-aws-strands/blob/main/docs/EVALUATION.md) and [prior-work disclosure](https://github.com/upgradedev/archon-aws-strands/blob/main/docs/PRIOR-WORK.md) are explicit in the repository.

The agent does useful work by reading context and proposing language. The ledger owns the money, and the human owns the external action. Keeping those responsibilities visible made Archon easier to explain, inspect and test.

If you are building a workflow with external side effects, which change to the evidence should invalidate an approval in your application?
