All writing
3 min read

Let the bot be the bad cop

The worst part of managing engineers is the nagging. So I built a bot to do it - privately - and stopped being the villain of my own team.

The worst part of managing engineers isn't the hard calls. It's the nagging.

Two rules at work. Boring, non-negotiable. Every PR needs a ticket ID in the title, because SOC2 wants every change traceable. Every ticket needs an epic, because work with no goal is just motion with a Jira number.

Nobody argues with either. Everybody forgets anyway.

So someone has to chase. For a while that was me, and every reminder costs you something. You stop being the person who unblocks the team and become the person who shows up to say you forgot a field. Hard pass.

So I built a bot to be the bad cop instead. A Go service called night-watch. It plugs into the stuff you already use:

System architecture. GitHub (PRs and webhooks) and Jira Cloud (tickets and epics) both feed into night-watch, a Go service running on Cloud Run inside Google Cloud (project ev-infra-group). night-watch reads and writes Cloud SQL for state, nudges, and metrics, and the only thing it sends back out is a private reminder through the Slack API.System architecture. GitHub (PRs and webhooks) and Jira Cloud (tickets and epics) both feed into night-watch, a Go service running on Cloud Run inside Google Cloud (project ev-infra-group). night-watch reads and writes Cloud SQL for state, nudges, and metrics, and the only thing it sends back out is a private reminder through the Slack API.
The stack. GitHub and Jira feed night-watch on Cloud Run, it keeps state in Cloud SQL, and the only thing it sends out is a private Slack DM.

Here's a night in its life:

A terminal showing night-watch's nightly run as a stream of log lines: scan jobs (142 PRs, 89 tickets), pull data from Jira and GitHub, a compliance check, 7 violations, metrics by domain and product, 5 team-lead sheets updated, a private Slack reminder sent with no public channel, and a manager-escalation loop that fired zero times. The final line reads: done in 9 minutes, nobody was publicly shamed.A terminal showing night-watch's nightly run as a stream of log lines: scan jobs (142 PRs, 89 tickets), pull data from Jira and GitHub, a compliance check, 7 violations, metrics by domain and product, 5 team-lead sheets updated, a private Slack reminder sent with no public channel, and a manager-escalation loop that fired zero times. The final line reads: done in 9 minutes, nobody was publicly shamed.
One nightly run, top to bottom. The manager loop fired 0 times - they know me.

The whole thing, in two lines:

  • No ticket ID on your PR? It DMs you, privately. Add the key, it shuts up and marks itself resolved. Did it right the first time? You never hear from it.
  • Ticket with no epic? It scans the boards every night and DMs the team lead, on a working day, because it knows when your weekend is.

The trick is that it nags in private. No @channel, no callout in standup, no leaderboard of the least compliant. Public shaming is cheap and it scales badly. A private word is the exact note I'd send, minus me sending it.

Nobody resents a robot for being consistent. They resent a person for it.

And honestly it's a better bad cop than I am. Same message to the staff engineer and the new hire, zero hesitation, no grudges, never tired at 6pm. I put myself on the exempt list, obviously. Rank should buy something.

A radar scope sweeping in the dark. Each pass paints contacts - pull requests with no ticket ID and tickets with no epic - as orange blips tagged with the violation, and fires off a private DM to the offender. The status panel reads: bad cop on duty, seven contacts, manager nags zero, coffee cold.A radar scope sweeping in the dark. Each pass paints contacts - pull requests with no ticket ID and tickets with no epic - as orange blips tagged with the violation, and fires off a private DM to the offender. The status panel reads: bad cop on duty, seven contacts, manager nags zero, coffee cold.
Bad cop on duty. Zero manager intervention, and the coffee has gone cold.

If a lead ghosts it, it sends a second reminder and copies their manager. That's the only step with an audience, and it's the last resort. Mine never get there. They know me.

The bottom line

A manager's authority is scarce. Spending it on "you forgot a field" wastes the one thing the job actually hands you.

So I gave the boring, trust-eroding half away to a machine that takes none of it personally. Now I get to be the good cop. The one who unblocks, decides, covers.

The only cop anyone wanted reporting to them anyway.