About this template
Your AI reports that churn improved to 4.2% this month. Where did 4.2% come from?
If it takes more than one click to answer that, you can't take it into a pricing decision.
Fork it and see
Paste a read-only Stripe key and type:
/pulse
This week's read lands in Slack: MRR, what churned, who gave notice, whose card is failing, and what to do first. Every figure traces to a specific API call.
Now try to break it. Edit the draft to claim retention hit 118%, and post again:
UNGROUNDED: these figures are not in the facts bundle:
line 12: 118%
It refuses to send. That refusal is the product.
Three mechanisms, not three promises
The model does no arithmetic. Five read-only Stripe calls come back, and every rate, total and delta is computed in Python. The agent reads the result and narrates it. Arithmetic done in prose is where a grounded report quietly stops being one.
A checker reads the draft. It pulls every figure out of the pulse and blocks the Slack post if one isn't in the retrieved data, naming the number and its line. The posting script runs that check itself, so you can't skip it by forgetting.
It can't write to Stripe. Hand it a full secret key and it refuses before the first call. Restricted, read-only keys only.
Gaps count as findings. Anything it can't retrieve is reported under "Not available", and the gate blocks the post if the draft leaves a known hole out.
What you get in the fork
/pulseand/pulse-preflight, ready to run.- An at-risk list built from a rule, not a vibe: notice given, or payment failing. Each one is matched to your PostHog data by email to answer one question. Are they still using the product? That's the difference between fixing an invoice and picking up the phone.
- Churn read from Stripe's event log, not subscription rows. The
createddate on a canceled subscription is when it started, so filtering subscriptions by date reports the wrong week. It's an easy detail to miss, and it fails quietly. - A weekly cadence that re-arms itself after a restart, so it doesn't stop firing in January and get noticed in March.
- A fallback that posts plain numbers when the model is unreachable. A week of silence is worse.
Check it before you trust it
python3 ~/.claude/skills/revenue-pulse/bin/selftest.py
Twelve checks, offline, before you hand it a single credential. It tries to slip a fabricated figure past the gate and confirms the gate stops it. It hands the collector a writable Stripe key and confirms it refuses. It confirms the refusal doesn't echo your key into a log.
Ten more checks cover the template itself, and they were re-run on a fresh fork rather than the machine it was built on. All ten passed there too — which is the only version of that test that means anything to you.
The 30-day guarantee covers your money. The self-test covers your trust, and it costs one command.
Setting it up
Your own Claude Code login, a restricted Stripe key, a Slack bot token and the channel id. PostHog is optional. Without it, engagement is reported as missing rather than guessed. Run /pulse-preflight. It makes a real read-only call to each service and names the one that's wrong. Every credential stays on your VM and is never part of the template.
Who this is for
- You bill on Stripe and you already work in Claude Code.
- Someone asks you every Monday how revenue is doing, and you'd rather answer first.
- You've caught an AI quoting a number you couldn't source, and it made you trust the rest less.
- You want the churn read where the work happens, not in a dashboard you'll open twice.
Not for you if you want dunning emails or subscription edits. That needs a write key, and this refuses one. Also not if you want churn prediction. This reports what happened, with receipts. It doesn't forecast.
Fork it, run the self-test, paste a read-only key, type /pulse. About ten minutes, most of it spent in the Stripe dashboard making the restricted key. Do it today and Monday's pulse posts itself.
Inspired by the Stripe Pulse agent on atomeve.dev. Built native to Claude Code — not on atom, eve or flue.