Sk. Azraf SamiBackend & Applied AI Engineer

The standup writes itself, for nothing.

2026

Standup Bot

Turns Bitbucket commits and Jira activity into a daily standup digest on Telegram, running on Cloudflare Workers and D1 at zero cost.

Private · write-up

Running cost
$0/mo

fits entirely inside the Workers and D1 free tiers

Servers to maintain
0

scheduled Workers, no always-on process

The problem

The daily standup question "what did you do yesterday" already has a complete answer sitting in the commit log and the issue tracker. Asking a team to retype it every morning is a small tax paid every day forever.

Architecture

  • Pulls Bitbucket commits and PRs by polling or webhook, and Jira activity alongside, then reconciles both into one per-person digest.
  • Runs on Cloudflare Workers with a scheduled trigger; D1 holds the state needed to know what has already been reported.
  • Posts to Telegram on a schedule, so the digest exists before the meeting rather than being assembled during it.

What I chose, and what I rejected

This is the smallest project here and it earns its place for one reason: it demonstrates knowing when not to spend.

The instinct, and why it is wrong

Something that polls two APIs on a schedule and writes to a third sounds like a small server. A cron entry, a process manager, a database, a host. That is the shape most people reach for, and it is a shape with a permanent tail: a machine to patch, a process to monitor, a certificate to renew, a disk to watch, and a bill that never quite reaches zero even when the thing is idle — which, for a job that runs once a day, is 99.9% of the time.

Scheduled Cloudflare Workers collapse all of that. There is no always-on component, so there is nothing to patch and nothing to monitor for liveness. The scheduled trigger is the cron. And a workload that executes for a few seconds a day sits inside the free tier with room to spare, so the running cost is genuinely zero rather than rounded to it.

The one piece of state that matters

The interesting engineering here is not the API calls. It is knowing what has already been reported.

Polling without that memory fails in two directions and both are visible to the team. Re-report from a fixed window and yesterday’s commits appear in today’s digest, so people stop trusting it. Report only what is newer than the last run and you drop anything that landed during the run, or during a run that failed and retried — the boundary cases are exactly the late-evening commits people most want credit for.

So the bot keeps a watermark: the point in each source’s timeline it has consumed up to. That is the entire schema. D1 is a SQLite database at the edge, which is almost comically oversized for storing a handful of timestamps — and that is the correct amount of database for this problem. Reaching for Postgres here would mean provisioning a server to hold six rows.

The subtle part is that commits and issue activity do not share a clock or an ordering guarantee. A commit’s author date is client-supplied and can be older than commits already ingested, because someone rebased or their laptop clock drifted. So a watermark on author date silently drops work. Keyed on the ingestion-side ordering the API actually guarantees, it does not. This is the sort of thing that looks like a one-line decision and is the difference between a digest people trust and one they stop reading.

Polling or webhooks

Both are supported, and the choice is not obvious.

Webhooks are lower latency and lower waste — nothing runs when nothing happened. They also require a publicly reachable endpoint, a shared secret, signature verification, and an answer to what happens when a delivery fails while your Worker was mid-deploy. The provider retries, so now you need idempotency, which means the watermark has to be correct anyway.

Polling on a schedule is strictly less efficient and strictly more robust: it has no delivery guarantee to depend on, it self-heals after any outage on either side, and its failure mode is a late digest rather than a missing one. For a report that is consumed once a day, latency is worth nothing and robustness is worth everything, so polling is the default and webhooks are the optimisation.

What it is not

It does not summarise, score or editorialise. A standup digest that paraphrases your commits is a digest people have to double-check, which is worse than no digest. It reports what happened, links to it, and stops. The value is in the aggregation and the schedule, not in interpretation — and resisting the urge to add an LLM to something that does not need one is part of the point.