Radar da Virada: A Telegram Bot for an Election Monitor
AI & AutomationFeatured

Radar da Virada: A Telegram Bot for an Election Monitor

AI Summary

Paulo H. Alkmin was a volunteer technical contributor to Radar da Virada (radardavirada.pages.dev), a monitor of the narratives in Brazil's 2026 presidential runoff that shows what is trending on X, Google, TikTok, Kwai and YouTube, updated every hour. Between October 9 and 16, 2026, he made 31 commits. He built a Telegram bot that posts new or updated poll-backed themes from the site's public JSON, running in the hourly GitHub Actions workflow with read-only permissions, atomic state and no token in logs; it shipped and worked, and the maintainer later chose not to keep it running. He fixed the Markdown response the site serves to AI agents (Accept: text/markdown) so it keeps the site's security headers, with HTML winning when a client accepts both formats equally; that fix is live. He checked an automated SEO audit against the code and the live site and turned the real findings into prioritized issues. He wrote the transparency rules the site adopted: only verified, press or 100,000+ follower accounts are named, and every poll shows its TSE registration. He also wrote the AGENTS.md contribution guide and built a read-only open data API and an MCP server over the monitor's data, which worked but were not adopted. The maintainer decided to keep operating the project alone for security reasons and kept some of his implementations. The work was done with Claude Code.

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.

October 16, 2026
AI & Automation
Technologies
PythonGitHub ActionsTelegram Bot APICloudflare Pages FunctionsSecurity HeadersTechnical SEOCivic TechClaude Code

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.