INTRO
A multi-agent AI system that runs an Etsy print-on-demand storefront from end to end: trend discovery, artwork generation, listing publication, and margin tracking, with a human only stepping in to approve or reject finished listings.
It looks like plain orchestration until you build it. Real money moves through APIs that don't forgive a double charge, every image generation costs money per call, and LLM output drifts in ways that aren't obvious up front. Most of the effort went into the unglamorous parts: idempotency, dedup, rate limits, and margin math that holds up through currency conversion and fee changes.
SECTION
Four agents, one schema, no orchestrator
The agents don't call each other. They read and write a shared Supabase schema, and each owns one stage of the pipeline. Scout writes `trend_briefs`. Design picks up briefs in `pending` status and writes `design_packages`. Listing picks up packages and publishes to Etsy. Ledger watches Etsy receipts and writes `orders` with derived margins. Status transitions on shared rows are the whole API.
There's no central orchestrator, so each agent has its own runtime, deployment cadence, and retry behavior. Scout runs on a nightly cron, since trends don't change minute to minute. Design and Listing poll every 15 minutes, because image generation is slow and expensive. Ledger polls every 30 minutes, because Etsy receipts settle slowly. They scale and fail on their own: when fal.ai had an outage, Design stalled while the others kept working through the existing backlog.

SECTION
Polyglot on purpose
Scout and Design are Python, using `httpx`, `pydantic`, and `structlog`. Listing and Ledger are TypeScript, using `Zod` for schemas and `Bottleneck` for rate-limited Etsy calls. The shared schema is the contract that lets them differ. Each language has its own client library in the monorepo, `packages/shared_py` for the Python agents and `packages/shared` for TypeScript, wrapping Supabase access, Etsy auth refresh, and Slack and email notifications.
Splitting languages earns its keep here: Python's data and AI tooling for the LLM-heavy upstream stages, and TypeScript's type safety and async ergonomics for the money-touching downstream ones. CI typechecks both stacks and runs an end-to-end test that drives a single trend brief through all four agents against fixture data.
SECTION
Idempotency, dedup, and not getting fleeced
Every step that spends or receives money is guarded. The Design agent SHA-256 hashes the final image prompt before calling fal.ai, so an identical prompt reuses the earlier image instead of paying for a duplicate. Scout runs both exact-match and Claude-powered semantic dedup before writing a brief, so near-duplicate trends don't flood the pipeline. Ledger puts a unique constraint on `etsy_order_id`, so polling can run as often as it likes without counting a sale twice.
When something fails, `structlog` emits a structured line, and a Slack webhook fires on any low-margin order so I catch it within minutes. A separate daily cron sends a revenue and margin digest over Slack and email. I can watch the whole loop from my phone, which is the point when the system runs unattended.

SECTION
Margin math that has to stay right
Etsy returns receipts in the buyer's currency. Printify charges in USD. Etsy's fees depend on listing price, payment method, and shipping origin. True margin is `(USD sale − Etsy fees − print cost)`, and getting that right, then keeping it right as Etsy revises its fee structure, is where projects like this quietly leak money.
Ledger normalizes currencies from a daily rate snapshot, computes fees from Etsy's published rules, looks up print costs by SKU, and writes the final margin onto the row. That same row feeds both the daily digest and the low-margin Slack alert, so every dollar figure on the dashboard traces back to one place.
OUTCOME
Live and shipping listings on Etsy. An optional `HUMAN_REVIEW_ENABLED` gate keeps a person in the loop without putting them on the critical path. It's observable from Slack and deploys with a single `railway up`. The system runs unattended, with the database as the only thing the four agents share.
EXHIBITS
Captures
CAPTURE / 01 OF 03

CAPTURE / 02 OF 03

CAPTURE / 03 OF 03

