All work

Morning Ops, in Telegram.

The numbers that decide your day usually live behind a login nobody opens before coffee. So I send them instead. A short recap of yesterday lands on the owner's phone at 6 in the morning, before anyone asks.

Client
Remodeling Concepts (live) + Tee Off For A Cause
Role
Solo build, design to cron
Stack
Bash, host cron, Telegram Bot API
Status
RC live in production
01 · Context

Owners do not open dashboards. The numbers should come to them.

Remodeling Concepts is a home remodeling company with real money moving every day: deals closing, appointments getting set, social posts pulling in leads. All of it was visible if you went and looked. Nobody went and looked at six in the morning.

The owner wanted to start the day already knowing whether yesterday was good. Not by opening a dashboard, then a CRM, then two more tabs. Just knowing.

02 · Problem

A digest only works if it is boring and never wrong.

This sounds trivial right up until you build it. A morning recap has to fire exactly once, at 6 AM local time, every day, forever. It has to pull real numbers and get them right. And when a data source is down, it cannot go silent and it cannot spam. It has to say so and move on.

Get any of that wrong and people stop trusting the number, which is worse than never sending it. The rules I set:

  • Fires once per day, at 6 AM Eastern, all year, daylight saving included.
  • Deterministic. No model in the loop, no "roughly." The number is the number.
  • Degrades gracefully. If the dashboard is unreachable, it sends a plain "couldn't pull this morning, will retry tomorrow" instead of nothing or noise.
  • Readable in two seconds on a lock screen.
03 · What I built

A tiny cron job and a Telegram bot. That is the whole thing.

No app, no new dashboard, no queue. One shell script runs on the VPS that already hosts the company's other automations. It hits a single token-gated endpoint on the marketing dashboard, reads yesterday's totals, formats four lines, and posts them to a Telegram chat through the Bot API.

The interesting part is the 6 AM part. Plain cron cannot say "6 AM Eastern, but shift for daylight saving." So the job wakes up twice each morning, checks the current Eastern hour itself, and only fires when it reads 06. A per-day lock file makes sure it sends exactly once even though it woke up twice. That little dance is what keeps it correct year round without me touching it in spring and fall.

What lands at 6 AM

☀️ RC Daily Recap · Wed, Jun 4 💰 Sales: 3 won · $48,200 📅 Appointments set: 7 ❤️ Social likes: 142

Stack

Bash Host cron Telegram Bot API Token-gated JSON endpoint jq Hostinger VPS

The same idea, a second business

Once it worked for Remodeling Concepts, the format obviously traveled. Tee Off For A Cause is a 1,000-golfer charity event with its own morning question: are registrations and foursomes filling, and how close is the date. Same four-line shape, different numbers. I mocked it up to show the pattern; the Remodeling Concepts version is the one running live.

⛳ TOFAC Daily Recap · Wed, Jun 4 🎫 Registrations: 6 new · $4,150 👥 Foursomes: 38 / 50 filled ⏳ 41 days to tee-off
04 · The screenshots

It shows up where they already are.

Nobody installed anything. It arrives in the same app they already check, which is the whole reason it actually gets read.

Two phone lock screens at 6:00 AM, each showing a Telegram push: an RC daily recap and a TOFAC daily recap
05 · Why it works

Deterministic beats clever. Exactly-once is the hard part.

Keep: no AI. People trust a number that is always the number. The moment a recap says "approximately," it becomes a thing to double check, and then nobody reads it.

Keep: the graceful fallback. The "couldn't pull this morning" message has fired only a couple of times, and both times the owner knew I would already be on it. Silence would have quietly eroded trust in every other morning.

Learned: the timezone-and-lockfile dance is the actual product. The formatting took ten minutes. Making it fire once, at the right local hour, every day, with nobody watching, is the part worth getting right.

Learned: ship it where people already are. Nobody adopts the tool you tell them to go check. They read the one that shows up in the app they are already in.