-
-
Auto-generated invoice PDF, stamped "pending human approval" — nothing ships until a person says yes
-
EventBridge → Orchestrator Lambda (Strands + Bedrock) → DynamoDB → API Lambda → Next.js on Vercel. Human approval gates all external actions
-
Gmail sent: the dunning email sent to the client after the human/freelancer clicked Approve
-
Command Center: live payment status across 5 client accounts, updated by the agent every 15 minutes
-
Pending Approvals: agent-drafted dunning email (day 14 escalation) and invoice proposal, gated behind human sign-off
-
Gmail inbox: the dunning email delivered to the client after the human clicked Approve
-
Activity Log: full audit trail showing the agent's reasoning for every action it took
Inspiration
Fifty-five percent of all B2B invoices in the US are paid late. For a freelancer or small agency, that means you're simultaneously the project manager, the accountant, the bill collector, and the diplomat who has to ask for money without burning the relationship.
CashflowGuardian started from a simple frustration: the moment you finish a milestone, you have to remember to invoice. The moment an invoice goes 3 days overdue, you have to remember to follow up. The moment it goes 14 days, you have to decide whether to escalate or let it slide. That's not a job you signed up for.
The idea: what if an AI agent did the watching, the drafting, and the escalating, but never sent anything without your approval? You get the judgment of a senior accountant without the emotional labor of being "the bad guy."
What it does
CashflowGuardian is a multi-agent AI system that acts as an autonomous cashflow guardian for freelancers and small agencies. It:
- Watches every client's payment status on a 15-minute schedule
- Invoices automatically the moment a milestone is marked complete it generates a PDF invoice with correct amount and due date.
- Chases late payments with escalating, tone-appropriate dunning emails ;friendly at day 3, firm at day 7, final notice at day 14.
- Detects scope creep by flagging milestones that exceed the original SOW.
- Gates every external action behind a human approval nothing is sent until you explicitly approve, edit, or reject it.
The system uses AWS Bedrock (Claude 3.5 Sonnet) via the Strands Agents SDK for multi-agent orchestration, DynamoDB for persistent memory, and the Gmail API for email delivery. A Next.js Command Center dashboard provides a real-time view of all clients, pending actions, and the full activity log with agent reasoning.
How I built it
The architecture is a three-layer system deployed on AWS:
- Orchestrator Lambda (EventBridge, every 15 min): runs the Strands multi-agent pipeline. The Orchestrator agent delegates to specialist agents (Invoice Agent, Dunning Agent, Scope Sentinel) as tools. Each agent reads client state from DynamoDB, applies business rules, and writes proposed actions back to the PendingActions table.
- API Lambda (HTTP API via API Gateway): serves the REST endpoints consumed by the Next.js frontend. Routes: /clients, /actions/pending, /activity-log, /run-scheduled-check, /clients/{id}/milestone-complete, /actions/{id}/resolve.
- Frontend (Next.js 14, deployed on Vercel): single-page Command Center with three panels: Clients, Pending Approvals, and Activity Log.
Infrastructure is defined in a SAM template (template.yaml) — one ./deploy.sh command creates the DynamoDB tables, both Lambdas, the IAM role (least-privilege), the EventBridge schedule, and the HTTP API. The Gmail OAuth flow is a one-time local consent that bakes a refresh token into the Lambda package.
Challenges I ran into
- SAM Globals limitation: The original template placed IAM Policies under Globals.Function, which SAM doesn't support. Had to restructure to attach policies per-function, which also enabled least-privilege scoping (API Lambda gets no Bedrock access).
- Dependency version conflict: The staging script copies packages directly from the local venv into the Lambda zip. A mismatched pydantic_core version (2.46.5 vs required 2.46.4) caused a SystemError at Lambda init. Fixed by ensuring the venv had the exact compatible version.
- OAuth in a headless environment: The Gmail consent flow requires a browser, which Lambda doesn't have. Solved by running the consent flow once locally, then bundling the resulting token.json (containing a long-lived refresh token) into the Lambda package. The gmail_tool module silently refreshes the access token on each invocation.
- Vercel framework detection: Vercel auto-detected the repo as Python (due to .py files at root). Had to explicitly set the root directory to frontend/ and confirm the Next.js preset.
What I learned
The Strands Agents SDK's "agents-as-tools" pattern is genuinely powerful, you get multi-agent orchestration (specialist agents called by an orchestrator) without building a custom inter-agent protocol. The orchestrator decides which specialist to call and when, which maps naturally to business logic.
DynamoDB as agent memory is underrated. The agents don't just process data, they remember state across invocations (which invoices are open, which escalation tier a client is at, what was already proposed). This is what makes the system feel like it has continuity rather than being a stateless function.
The human-in-the-loop gate isn't just a safety feature, it's the product. The value isn't "AI sends emails." The value is "AI does the thinking and drafting, and you make the judgment call." That's the part clients will actually pay for.
What's next for CashflowGuardian
- GitHub webhook for automatic milestone detection (replace manual "mark complete" with commit/PR merge triggers)
- Multi-currency support for freelancers working across borders
- Stripe integration for automated payment collection (not just chasing)
- Client-facing portal where clients can see their invoices and pay online
- Slack/Teams notifications for the approval gate (approve from your phone without opening the dashboard)
Log in or sign up for Devpost to join the conversation.