All loops
FinanceEasy 10 min· claude-sonnet-4-5
Weekly investor update generator
Stripe + Postgres metrics → narrative artifact → Resend to your investor list.
NOT DEPLOYEDNOT DEPLOYED
0187ms
Trigger
cron(0 7 * * *) fired · every day · 07:00
021267ms
Agent
claude-sonnet-4-5 · in 1167 tok · out 588 tok
03297ms
Tools
postgres-mcp/anthropic:messages.create → 429 backoff · 227ms
0477ms
Verify
schema check · zod v3 passed
05167ms
Output
invoice row upserted · $4,120
0647ms
Notify
audit log written · runbook link attached
SUCCESS
0%
0 runs
P50
0ms
median
P95
0ms
tail
AVG COST
—
per run
LAST OK
never
—
LAST FAIL
never
none
Latency · last 30 runs0 samples
no runs yet
Latest output · what your users see
Invoice · SegmentTooling
$3,787.87 USD
// press Test to run once · Watch live to keep streaming · Deploy to make it real
The problem
Investor updates slip every week because no one wants to write them at 11pm Sunday.
The outcome
An email lands in your investors' inbox every Monday at 09:00. You proofread it Sunday afternoon in three minutes.
Ingredients & skills
Secrets
- ANTHROPIC_API_KEY
- STRIPE_KEY
- DATABASE_URL
- RESEND_API_KEY
Providers
- Anthropic
- Stripe
- Postgres
- Resend
MCP servers
- postgres-mcp
- stripe-mcp
#fundraising#artifacts#cron
How it works
Cron job pulls MRR from Stripe and active users from Postgres, asks Claude to write a 200-word narrative artifact, and emails it via Resend.
Step 1
1 — Pull the numbers
Two source-of-truth queries. Don't trust derived metrics dashboards for the email.
metrics.ts
import Stripe from "stripe";
import { Client } from "pg";
export async function pullWeeklyMetrics() {
const stripe = new Stripe(process.env.STRIPE_KEY!);
const subs = await stripe.subscriptions.list({ status: "active", limit: 100 });
const mrr = subs.data.reduce((s, x) => s + (x.items.data[0].price.unit_amount ?? 0) / 100, 0);
const db = new Client({ connectionString: process.env.DATABASE_URL });
await db.connect();
const { rows } = await db.query("select count(*)::int as wau from events where ts > now() - interval '7 days' group by user_id");
await db.end();
return { mrr, wau: rows.length };
}Step 2
2 — Narrative artifact
Constrain the model to a fixed structure. Investors hate variance week to week.
typescript
const prompt = `Write a 200-word investor update.\nFormat: 1 sentence headline, then bullets for Wins, Risks, Asks.\nMRR=$${metrics.mrr}, WAU=${metrics.wau}.\nRecent changelog:\n${changelog}`;Step 3
3 — Send via Resend
BCC the investor list so replies stay private.
typescript
await fetch("https://api.resend.com/emails", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.RESEND_API_KEY}`, "content-type": "application/json" },
body: JSON.stringify({ from: "ceo@acme.com", bcc: investors, subject: `Update — week of ${weekOf}`, html: rendered }),
});One-line deploy
The button above runs the same command with your saved config. This is the raw CLI form.
bash
locker schedule investor-update agent.ts --cron '0 9 * * 1'Related loops
Growth
Nightly competitor scan → Slack digest
Wake up to a 5-bullet diff of every competitor page that changed overnight.
Ops
Customer churn predictor
Nightly: score accounts, write a CS queue, post top 10 to Slack.
Finance
Stripe revenue anomaly alert
Detect MRR cliffs in real time and ping #revenue with the suspect customer.