Marketing Reporting
Marketing at a small company fails quietly: the post that never went up, the week nobody looked at traffic, the month nobody asked what worked. These three routines make the silence loud. A daily reminder of what is due, a Monday pulse with only facts, and a monthly recap where Claude reads the email numbers and proposes what to write next. Humans post the content and pick the ideas; the machine keeps the calendar.
Three cadences, one calendar
The routines never create content and never post it. They read what humans put on the marketing calendar and what the broadcast engine already sent, and report on it at three speeds.
How each step works
Every piece of content is a row on the marketing calendar: a title, a channel (blog, LinkedIn, Facebook or email), a brand, a publish date and a status. Email rows are produced and sent by the broadcast engine; the other three channels are posted by hand. The routines below read this table and the broadcast table; they never write to either.
The digest selects blog, LinkedIn and Facebook rows whose publish date is today or earlier and whose status is not published or skipped, oldest first. Anything dated before today is tagged overdue. If the list is empty the run ends without sending anything.
Otherwise it does two things: emails the founder a list with a link to the calendar and a one-line instruction (mark each one posted once it is live), and posts the same list, capped at ten with a count of the rest, to the Ops Lark channel. The day boundary is UTC, so a post dated today in Ho Chi Minh City appears in the digest that same morning.
The human step is the only one that touches a social platform. The founder publishes the post wherever it goes, then marks the row published (or skipped) on the calendar. That status change is what stops the digest repeating it tomorrow and what makes it count in Monday’s pulse; the routines cannot tell a post went up any other way.
The pulse is a heartbeat, facts only, no model in the loop. It reads the public site’s last seven days from Vercel Web Analytics (page views, visitors, top three pages, top four channels) and the seven days before that for a week-over-week line. Internal traffic behind the login is excluded so the marketing number is not flattered by the team using the admin.
Then what shipped: calendar rows marked published in the window, broken down by channel (email excluded, since it is counted as broadcasts), and every broadcast marked sent in the window with its sent count, open rate and click rate. The post goes to the Marketing Lark channel with a link to the marketing hub. It always posts, even on a quiet week, so a missing Monday post is a real signal rather than a normal one. The window is rolling seven days from the run, not a calendar week.
On the 4th (not the 1st, so every broadcast from the prior month is past the 72-hour settle window the broadcast summary uses) the recap reads every broadcast marked sent in the previous calendar month. For each it gathers sent, delivered, opened, clicked, unsubscribes attributed since approval, and clicks by topic from the utm_content tags. Those become a month total, a per-broadcast line, and a ranked list of topics by unique clickers.
Claude gets that material and returns a two-to-four sentence readout and three to five content suggestions, each with a one-line rationale tied to the numbers. The recap is stored first (keyed on the month, replaced in place on a re-run) so it exists even if delivery fails, then posted to the Marketing Lark channel, then emailed to the founder with a link to past recaps. A month with no sends, or no model available, is a clean skip: nothing stored, nothing posted.
Every exception has an owner
Reporting routines fail in two ways: they say nothing when they should, or they say something wrong. Each row is a real condition, what the routine does, and where a human hears about it. The silent cases are listed so they are deliberate.
| Condition | What happens | Where you hear about it |
|---|---|---|
| Nothing due today | Digest sends nothing at all, no email and no Lark post | Nowhere, by design |
| More than ten posts due | Lark shows the first ten and a count of the rest; the email lists them all | The Lark post |
| An email-channel item on the calendar | Never in the digest; email sends itself through the broadcast engine | The broadcasts page |
| Vercel Analytics slow or down | Pulse posts with a “Traffic: unavailable” line; the rest of the post is unaffected | The Monday post |
| No prior week of traffic | Week-over-week reads “no prior week” instead of a percentage | The Monday post |
| Quiet week, nothing shipped | Pulse still posts, with zero posts and “Emails: none sent” | The Monday post |
| A calendar or broadcast read fails during the pulse | Logged; that section reports zero and the post still goes out | Run log |
| No broadcasts sent last month | Recap skips cleanly: nothing stored, nothing posted, nothing emailed | Run log, as skipped |
| Claude unavailable for the recap | Same clean skip; the recap has no fallback without the readout | Run log, as skipped |
| Recap run twice for the same month | The stored row is replaced in place; Lark and email go out again | A second Lark post and email |
| Recap stored but the Lark post or email fails | The row is already saved; email failure is reported in the run result, Lark failure is logged only | The recaps page; run log |
| A Lark webhook is not configured | The message is skipped with a warning; the run still reports success | Run log only |
The seven elements
Every workflow we document has the same anatomy: seven elements, each assigned to a human, a machine, or both. This is the Centaur Map from our workflow design method.
Time, three ways: 09:00 (+07) daily for the digest, Monday 09:30 for the pulse, the 4th of the month at 13:00 for the recap. Nobody asks for a report.
The marketing calendar (title, channel, publish date, status), the broadcast table and its event ledger, and Vercel Web Analytics for the public site. All of it already exists; the routines add no data entry.
The digest and the pulse decide nothing; they read and report. The recap asks Claude for a readout and three to five suggestions, grounded in which topics earned clicks. The founder decides what actually gets written.
The digest goes to the founder by email and to the Ops Lark channel. The pulse and the recap go to the Marketing Lark channel; the recap also emails the founder and is stored for the recaps page.
A list of posts due, a five-line weekly heartbeat, and a stored monthly recap with metrics, readout, suggestions and the model that wrote it.
Lark text messages and transactional email through Resend, each with a link back to the calendar, the marketing hub or the recaps page.
A Monday with no pulse is itself the signal. The recap’s numbers are read against last month’s; whether a suggestion was taken is a human call, visible on next month’s calendar.
The standing rules
- The routines read the calendar and the broadcast table; they never write to either
- The digest is silent when nothing is due; the pulse is never silent
- No AI in the daily or weekly report; a single week is too thin to advise on
- The recap is stored before it is delivered, so a delivery failure loses nothing
- A month with no sends produces no recap, not an empty one
- Every run writes a row to the routine log with what it counted
Why it works
- The digest turns a forgotten post into an overdue line the founder sees every morning until it clears
- The pulse makes the marketing number public inside the company every week, with its trend
- The recap grounds next month’s content in which topics actually pulled clicks, not in taste
- Three cadences mean three different questions get answered without anyone asking