Inspiration

A washing machine fails 22 months after purchase. The receipt is in a drawer, the repair invoice is in an email, and the seller's address is on a website. The question "can I ask the seller to review this?" never gets asked, because nobody keeps the case together.

Around it sit smaller leaks: a free trial that turns into a paid plan in three days, a backup plan that went from 9.99 to 13.99 a month, a receipt missing for a hardware store purchase.

Hestia is for the person in a household who keeps the family paperwork and may have no accountant or lawyer to ask. It matters because each of these problems is small and easy to put off, and the facts needed to act sit in different places. By the time the facts are together, the moment to decide may have passed.

The track brief asks for agents that run quietly and only ping you when there is a real decision to make. Hestia implements the decision-only surface today, with the person holding the pen; automatic triggers wait on bank and mailbox connections that are not built.

What it does

The surface is the household's own case page in the browser, at the live URL, with no account and no login. Today the household starts a review from the Home page. The intended trigger, a review after each imported statement, waits on bank and mailbox connections that are not built. What Hestia aims to replace is the folder of receipts, the spreadsheet of subscriptions and the letter the household never writes.

For Elena Georgiou, who runs Athens Apartment 4B, Hestia does five things:

  1. The records are hers to add. Start here on Home offers three choices: Report a repair, Add an appliance you own, or Paste a receipt or order email. An appliance carries its receipt reference, seller, purchase date, guarantee months and any product page, manual or quick start link she saved, so the Records page becomes a catalogue that can stand in for the drawer of paper manuals. Pasting is the one place a model touches intake: a Strands agent with no tools reads the pasted text, and Hestia stores its proposed records as a draft for her to correct. Only the exact changes she confirms enter the household records.
  2. A Strands agent on Amazon Bedrock reviews the household. It reads her recorded appliances, subscriptions, transactions, utility bills and saved case through four tools, then writes a briefing in three fixed sections: what it checked, the decisions waiting for her, and one suggested next step. It points; it does not decide eligibility.
  3. The notice is written by plain code, not by the model. The notice to the seller (Acropolis Appliance Store, about the Bosch Series 6 Washing Machine and the recorded EUR 185.00 repair) is prepared on the server from the recorded facts by deterministic Python. Elena reads the exact recipient, subject, amount and text, then approves it with a single-use token bound to that exact draft. A repair she reports on an appliance of her own goes through the same flow.
  4. The case stays whole. Reviewing the notice opens the case file, and approving it moves the case to Authorized. The approval is recorded as a simulation (delivery_status SIMULATED); no email is sent. The timeline then holds replies, silence, extra evidence, planning deadlines and attested outcomes, each with who recorded it, when and from which source.
  5. Subscription and receipt decisions sit next to it. The sample free trial (Fitness Stream Pro) ends three days after each private copy opens, so the agent review names it on any day, and she can record a cancellation request. A price change (Cloud Backup Vault, 9.99 to 13.99) has a Review the subscription button that opens the Records page. A receipt is missing for EUR 85.50 at Piraeus DIY Supplies, and she can link a receipt reference. An electricity bill is above its baseline, and she can record a review request. Two overlapping music plans are flagged by the agent's subscription tool and on the Records page. None of these contacts a provider.

How the agents are limited:

  • 3 reviews and 3 text readings per private copy.
  • One shared daily limit of 200 reviews and readings per UTC day, kept in a conditional S3 counter. A review can make several model requests in its tool loop.
  • 700 output tokens and a 20 second timeout.
  • A pattern guard that withholds a briefing if it matches entitlement or deadline phrases such as "entitled to" or "statutory deadline", names a euro amount the tool outputs do not contain, runs over 3200 characters, or never mentions review.

If no model is configured, a limit is reached, the budget cannot be confirmed, or the model call fails or times out, the review runs the four tools deterministically and the page says which of these happened. The tool trace is one click away.

Reading pasted text has no deterministic equivalent, so it fails closed. A missing model, used-up readings, a spent or unconfirmed daily budget or a model failure returns an error, creates no intake draft and points the household at manual entry. An attempted reading may still retain its input hash, audit event and usage accounting; Hestia does not retain the raw pasted text.

How we built it

How Strands Agents are used

Hestia runs two agents built with the Strands Agents SDK, version 1.53.0, pinned in the Lambda bundle. Both call Claude Haiku 4.5 on Amazon Bedrock through the EU inference profile eu.anthropic.claude-haiku-4-5-20251001-v1:0 in eu-west-1, with 700 output tokens and streaming off. Code: https://github.com/upgradedev/hestia-aws/blob/main/src/hestia/agents/household_agent.py. Details: https://github.com/upgradedev/hestia-aws/blob/main/docs/strands-agents.md.

  • The review agent is a strands.Agent over a BedrockModel at temperature 0.2 with four tools. The tools are built for each private copy: plain Python functions over that copy's recorded facts, wrapped with the Strands tool decorator, so each tool's schema comes from its signature and docstring. They are review_repair_evidence(appliance_id), audit_subscriptions(), check_receipts_and_utilities() and read_case_timeline(). The system prompt requires all four tools, forbids entitlement claims, invented deadlines and any amount or date that no tool returned, and leaves the call order and arguments to the agent before it writes the three-section briefing.
  • The trace is visible. Hestia rebuilds the tool calls and their outputs from the agent's messages and reads token usage from result.metrics.accumulated_usage. The page shows both, with the mode, the model id and the Strands version.
  • The reading agent is a second strands.Agent with no tools, at temperature 0.0. It turns pasted receipt or order text into JSON records. A server-side allow-list of record kinds and keys narrows them, and Hestia stores them as a staged draft that the household edits and confirms. Only the confirmed changes enter the household records.
  • Around both agents: the per-copy and daily limits, the 20 second timeout, the briefing guard and the deterministic fallback described above.

AWS and the rest of the build

  • Amazon Bedrock: the writer role may invoke one Claude Haiku 4.5 inference profile and its foundation model; the reader role denies bedrock:*.
  • AWS Lambda behind an Amazon API Gateway HTTP API: a reader function answers the default route, and a writer function answers an explicit list of POST routes in https://github.com/upgradedev/hestia-aws/blob/main/infra/hestia_api_stack.py. Both deny SES and object deletes. Python 3.11, with boto3 1.43.93 bundled.
  • Amazon S3: one JSON document per private copy, created with If-None-Match and updated with If-Match, so a lost race never overwrites a case. The daily model budget uses the same conditional writes.
  • Amazon CloudFront with S3 serves the React 19, TypeScript and Vite web app, with same-origin API routing and no credentials in JavaScript.
  • AWS Secrets Manager holds the session signing key, which CloudFormation resolves into the functions at deploy time.
  • AWS CloudFormation defines both stacks: the API and the web hosting.
  • GitHub Actions: lint, a prose check over README.md, docs/*.md and the video narration, pytest with a coverage threshold, Lambda packaging with pinned SDKs and the rendered CloudFormation template, and Playwright journeys against the real Lambda handler behind a local HTTP server. A manually started web app release goes through GitHub OIDC and is gated on the live backend health. Production acceptance runs against the live URL.
  • Backend release: CI packages the Lambda zip and renders the template as an artifact. scripts/release_backend.py, run by the owner, downloads that artifact from a successful main run, checks SHA256SUMS, uploads it once, prepares a CloudFormation change set, refuses one that removes or replaces resources, executes it only with --execute, and then checks /healthz for the released commit.
  • Deterministic notice: draft_statutory_claim_letter in https://github.com/upgradedev/hestia-aws/blob/main/src/hestia/agents/tools.py writes the review request from recorded facts. It cites Directive (EU) 2019/771 as a general reference only; eligibility needs its own review.
  • Reused from the author's earlier projects: the CloudFront and S3 hosting template (infra/frontend_stack.py) and the video production tooling. Everything else was written for Hestia.

Challenges we ran into

  • Keeping the model from deciding money or law. The review agent writes the briefing and can read recorded amounts and warranty boundaries. The reading agent only proposes intake facts, which count only after the household confirms them, and it never proposes a repair amount. The notice, the approval and every case step are deterministic. The guard had to be strict enough to catch a sentence that promises a refund and loose enough to let "requires review" through.
  • Bounding cost on a public URL with no login. Per-copy and per-day limits are enforced on the server with S3 conditional writes. An unconfirmed budget means no model call.
  • A Lambda that reports its own configuration. /healthz reports the commit, live_model, the model id and the limits. The web app release gate refuses to publish unless that health names the approved backend commit, live_model true with a model id, live_send false, and configured storage and sessions.
  • Sample data that ages. The sample trial used to end on a fixed date, so from the next day the agent review would stop naming it while Home still showed it. In this release the sample trial ends three days after each private copy opens.
  • Saying what is not built, on the page where it would be expected. The About page marks each feature on or off, and names the ones that are not connected: bank feeds, mailbox and retailer sync, Guardrails and AgentCore.

Accomplishments we are proud of

What we learned

We believe the agent earns trust by reading and pointing, not by acting. A three-section briefing with a visible tool trace, and a deterministic notice the person can read in full, turn "the AI wrote a letter" into "I approved this letter".

We have not tested this with independent users. Briefing quality, extraction accuracy, latency and cost are unmeasured, and independent human user acceptance testing is NOT_RUN.

What's next

  • Reaching households where they already look: a bank's transaction feed, a retailer's order history and an insurer's claim portal, each with explicit consent and a visible label for where a fact came from. Reading a pasted order email already works; reading the mailbox it came from does not.
  • Receipt reading from a photo or a PDF through Bedrock vision, staged behind the same review-and-confirm intake as pasted text. Photo OCR is not connected today.
  • A measurement of extraction quality. Today the model's proposals pass a server allow-list and the same field checks as typed records, then the household reviews them; no accuracy figure is claimed.
  • Email delivery through Amazon SES only after a separate consent step, with the approval token and digest carried into the sent record. Today IAM denies SES.

Built With

Share this project:

Updates

Submission history