
Radar da Virada: A Telegram Bot for an Election Monitor
What I built as a volunteer for a monitor of Brazil's 2026 election: a Telegram bot, a security fix for AI-agent Markdown, an SEO audit, and what each one became.
From October 9 to 16, 2026, the last stretch before Brazil's presidential runoff, I wrote code for someone else's project. Part of it still runs on the live site. Part of it shipped and worked, and was switched off anyway.
What is Radar da Virada?
A monitor of what people were talking about during the runoff. Every hour it reads public pages and feeds from X, Google, TikTok, Kwai and YouTube, from both sides, and turns them into a page made for phones: trending topics, words that suddenly spiked, themes backed by registered polls, and cards ready to forward on WhatsApp.
The stack is small on purpose. Plain HTML, CSS and JavaScript with no framework and no build step, a Python pipeline of numbered scripts running hourly on GitHub Actions, and Cloudflare Pages Functions with KV for caching and D1 for aggregate visit counts. It reads only public sources, so there are no logins and no paid APIs. A stack like that is easy to read and easy to break, since no build step or framework stands between a mistake and the page people open on their phones.
The site was already live when I joined, so everything I added had to land without breaking what was there.
What did I build?
The first piece was a Telegram bot for "Temas que viram voto" (roughly, "issues that turn into votes"), the section with poll-backed themes. It posts when a new theme appears or when a theme's poll changes, whether that's the number, the polling firm, the date or the link, and it reuses the ready-made text the site offers for WhatsApp, so the channel and the page always say the same thing. It ran outside the site, inside the hourly GitHub Actions workflow, reading only the public JSON with read-only permissions. What it had already announced went into a state file written atomically, so a run that died halfway couldn't post the same poll twice. On its first run it recorded a baseline and posted nothing, which kept a new channel from getting every theme at once. The token never appeared in a log. It came with its own tests and a setup README, and I ran it against a real channel before opening the pull request.
Then a security fix. The homepage serves Markdown to AI agents that ask for it with Accept: text/markdown, and a review found that the Markdown response went out without the site's security headers. I added them and changed the negotiation so HTML wins whenever a client accepts both formats with equal weight. This site does the same thing through a Netlify edge function and copies its headers for the same reason: a Markdown response looks fine in any test that only checks the body.
The SEO audit was mostly subtraction. An automated tool produced a long list. I checked each finding against the code and the live site, dropped the false positives and ranked the rest by return, with 14 days left before the vote, and each finding that survived became an issue someone could pick up. The check also showed that the live site was ahead of the code in version control, so fixing anything from the repository could have deployed over changes already in production. I opened an issue to sync the two before anyone touched the SEO fixes.
I also wrote two rules for who and what gets shown. Only verified accounts, press accounts or accounts with 100,000 followers or more appear by name, and ordinary profiles show up without an @, a link or an image. Every poll the site cites shows its TSE registration and the record behind it, including in the text people forward. In a family WhatsApp group, a poll without a registration number is a rumor with a percentage attached.
To finish, I wrote the project's AGENTS.md: one branch per issue, pull requests in Portuguese, and what to test before opening one. The same file guides volunteers and coding agents. I did most of this work with Claude Code, so writing the rules for agents meant writing them for myself, which I describe in Claude Code workflow tips.
Beyond those, I built a read-only open data API over the monitor's data and an MCP server on top of it, so an AI assistant could ask Radar what was trending instead of scraping the page.
Both worked.
Is any of it still running?
The Markdown fix is live: ask the homepage for text/markdown today and the response comes back with the full set of security headers. The naming rule and the TSE registration on every poll are on the live site as well.
The bot shipped and worked, and the maintainer later decided not to keep it running. The API and the MCP server went the same way. The maintainer chose to keep operating the project alone, for security, and kept some of my implementations in it.
Why that was a reasonable call
During an election, a solo maintainer runs a target. Every integration I added came with something to watch: a bot token, a workflow with its own permissions, an API that someone has to keep up. Fewer moving parts and fewer people with access is a defensible security posture, and it's what I'd tell a client with a single person running production.
If I did it again, I'd ask earlier what the maintainer was willing to operate, before building past it. Two weeks before a vote is a bad moment to propose more infrastructure, however well it's tested.
In the same weeks I worked on the SEO and privacy of Tech Contra Bolsonaro, and at the end of the month I built Voto Livre.
Code written for someone else's project is a proposal. The maintainer decides what runs.