A clerk, not an author.
The only unattended model call turns what I said into structure. Nothing a client reads is written without me in the loop.
Chose extraction over generationWeekly client reports that come with receipts.
I built Receipts to write the weekly status reports my clients actually read. Every claim in a report points to something I logged, so nothing gets inflated and nothing gets lost.
Northwind Dental
Weekly status report
Sep 21 – 27, 2026 · W39
Prepared for Dana Ruiz
Prepared by Jesús Martínez
Executive summary
Delivered. Four improvements to online booking and appointment reminders.
Live. Patients can book online again without the checkout error.
Decided. Reminders move to email, and SMS is retired.
Needed. The new logo files, to finish the email templates.
1. What was delivered
Why I built it
My clients aren’t technical. Every week they need to know what got done, what’s live and what I need from them. Writing that by hand was slow, and my commit history missed the parts they care about most: the call where we changed the plan, the decision that unblocked a launch, the deploy that fixed their checkout.
The pivot
The first version wrote reports straight from GitHub: merged pull requests in, client-friendly prose out. The model filled every gap with confidence. Work looked more finished than it was, and a week with two client meetings and a production deploy, but no commits, came out as a quiet week.
The code was merged. Nothing had been deployed.We shipped the new booking flow to production this week.
The new booking flow is complete and waiting for release.E-31Every claim traces to a ledger entry I can point to.
So I flipped it. The ledger is the product.
Now the model is a clerk, not an author. It turns what I tell it into structured facts, the report is built only from those facts, and before anything ships I check that every sentence traces back to one.
How it works
During the week I text or send voice notes to a Telegram bot, in English or Spanish. GitHub and Linear sync on their own every three hours.
A model turns each message into ledger entries: work, deploy, meeting, decision, blocker. If I say “actually that was staging,” it corrects the entry instead of adding a new one.
At 6:30 pm the bot asks about each client: here’s what synced today, anything to add? One tap if there’s nothing.
On report day, Claude Code drafts the report from the week’s ledger in a session I supervise. The first gate is an evidence map that ties every claim to an entry.
I send a clean PDF in plain language: what was delivered, what is live, the decisions we made, and what I need from you.
How it works, in 30 seconds
Pick a message for the bot and watch it become a ledger entry, then a line in the report draft with the entry behind it. Try the correction after the deploy.
Nothing logged yet. Send the bot a message.
Nothing yet.
Nothing went live this week.
Nothing yet.
Nothing yet.
A simplified explainer on invented data, not the real interface.
Under the hood
The only unattended model call turns what I said into structure. Nothing a client reads is written without me in the loop.
Chose extraction over generationThe report can’t say live, shipped or in production unless a deploy entry in that week names the environment. Staging is said as staging.
Chose a vocabulary rule over trusting the proseEvery call rebuilds its context from the messages and entries tables. No paused workflows, and every scheduled job catches up after a miss.
Chose stateless jobs over long-running workflowsThe rules it follows
The model only turns my words into structured facts. It never writes for the client.
“Actually that was staging” updates the existing entry instead of adding a second one.
“Live” and “shipped” need a deploy entry that names the environment.
Before a report ships, each sentence maps to the ledger. If it can’t, it goes.
No pull requests, branches or tickets. What the client can now do, and what problem is gone.
Reports cover what happened, never what might.
Build log
Python on a VM: pull GitHub activity, ask Claude for a narrative, render a PDF, drop it in Gmail as a draft. It proved the idea and nothing else.
Next.js, background jobs, reports written from git activity. Fast and polished, and wrong in a way that took months to see.
Telegram and voice capture, evening check-ins, supervised report writing. Moved everything onto Neon (database, functions, storage) and deleted the old pipeline and the layers built for tests that were never written.
What I learned
It will fill the gap, and it will sound sure. Give it the facts, or make it ask.
“Live” is a claim. Tie each strong claim to evidence and the whole report becomes trustworthy.
Version 2 got simpler by removing two platforms and an abstraction layer nobody used.
Next for Receipts: Slack and a chat widget as new ways to log, on the same intake path.