<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Guilherme Bandeira Rondon on Guilherme Rondon</title><link>https://guirondon.dev/</link><description>Recent content in Guilherme Bandeira Rondon on Guilherme Rondon</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Tue, 27 Oct 2026 18:00:00 -0300</lastBuildDate><atom:link href="https://guirondon.dev/index.xml" rel="self" type="application/rss+xml"/><item><title>Intrusion detection in kube containers: uid invariants and kernel auditing</title><link>https://guirondon.dev/posts/cluster-detection/</link><pubDate>Tue, 27 Oct 2026 18:00:00 -0300</pubDate><guid>https://guirondon.dev/posts/cluster-detection/</guid><description>&lt;p&gt;In the &lt;a href="https://guirondon.dev/posts/cluster-hardening/"&gt;first post&lt;/a&gt;&#10; I made the cluster harder to attack, but nothing there tells me whether an attack happened. If a process escaped a container, I wouldn&amp;rsquo;t know.&lt;/p&gt;&#10;&lt;p&gt;This second post in the series is about &lt;strong&gt;detecting&lt;/strong&gt; that escape, with two tools: a periodic check that relies on a rule left behind by user namespaces, and kernel auditing, which records events the instant they happen. The third post covers the traffic coming in from the internet.&lt;/p&gt;</description></item><item><title>From RBAC to AppArmor: six phases to harden k3s on a Raspberry Pi</title><link>https://guirondon.dev/posts/cluster-hardening/</link><pubDate>Sun, 25 Oct 2026 20:00:00 -0300</pubDate><guid>https://guirondon.dev/posts/cluster-hardening/</guid><description>&lt;p&gt;In the &lt;a href="https://guirondon.dev/posts/gitea-migration/"&gt;post about the migration to Gitea&lt;/a&gt;&#10; I described how I got my projects&amp;rsquo; builds working inside the cluster. To get there, I took a shortcut: the Gitea runner (the program that executes the CI workflows) got far more privileges than it needed.&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;the &lt;strong&gt;containerd socket&lt;/strong&gt;, the file through which you give orders to the program that runs the containers on the node. Whoever can write to it can ask for a container running as root with the Pi&amp;rsquo;s whole disk mounted;&lt;/li&gt;&#10;&lt;li&gt;the directory holding the cluster&amp;rsquo;s images and data;&lt;/li&gt;&#10;&lt;li&gt;the &lt;strong&gt;admin kubeconfig&lt;/strong&gt;, the credential that lets &lt;code&gt;kubectl&lt;/code&gt; do anything: read passwords, create and delete any resource.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;It worked, but any workflow from any repository had access to the whole cluster. All it takes is an &lt;code&gt;npm ci&lt;/code&gt; that installs a compromised dependency: its script runs inside the job and only has to read the kubeconfig sitting right there.&lt;/p&gt;</description></item><item><title>My Site Went Down, and It Was My Neighbours' Fault</title><link>https://guirondon.dev/posts/wifi-channel-outage/</link><pubDate>Thu, 10 Sep 2026 15:00:00 -0300</pubDate><guid>https://guirondon.dev/posts/wifi-channel-outage/</guid><description>&lt;p&gt;This wasn&amp;rsquo;t the first time. A few weeks earlier I&amp;rsquo;d noticed the site down one morning — no SSH, but the TX/RX lights blinking normally. I power-cycled it, everything came back fine, and as a precaution I turned on persistent logging on the homelab. I left it at that and moved on.&lt;/p&gt;&#10;&lt;p&gt;Then, the day before I started writing this post, the Raspberry Pi that hosts this site went down again, out of nowhere. The site returned a 502, SSH hung, and I did what&amp;rsquo;s usually my first attempt at a quick fix: pulled the power, expecting it to come back. It did — but the instability persisted, and after a few minutes I decided to log into the Pi remotely.&lt;/p&gt;</description></item><item><title>Behind Intercept Brasil's donation ask: hypotheses on cache, edge, and origin</title><link>https://guirondon.dev/posts/edge-cache-security/</link><pubDate>Mon, 27 Jul 2026 14:00:00 -0300</pubDate><guid>https://guirondon.dev/posts/edge-cache-security/</guid><description>&lt;!-- POST 1 - Security series (scope of future posts still open) --&gt;&#10;&lt;!-- Focus: edge/origin responsibility split, origin IP exposure, cache poisoning/deception, stale-if-error as resilience. All attack scenarios treated as personal speculation, never as confirmed cause. --&gt;&#10;&lt;p&gt;I came across a sponsored post from Intercept Brasil asking for donations to reinforce the site&amp;rsquo;s security. According to the outlet itself, the story involving the leaked audio between Flávio Bolsonaro and banker Daniel Vorcaro went offline shortly after being published, and now they&amp;rsquo;re asking readers for money so it doesn&amp;rsquo;t happen again.&lt;/p&gt;</description></item><item><title>Split to double: what I learned bringing two solutions to a hackathon</title><link>https://guirondon.dev/posts/hacarthon/</link><pubDate>Sun, 19 Jul 2026 20:00:00 -0300</pubDate><guid>https://guirondon.dev/posts/hacarthon/</guid><description>&lt;p&gt;Three weeks before haCARthon started, I was supposed to have my head buried in excerpts of Brazil&amp;rsquo;s Forest Code, validating queries against geo databases of Brazilian municipalities. Instead, I was on a video call trying to convince my four-person team to split into two.&lt;/p&gt;&#10;&lt;p&gt;It wasn&amp;rsquo;t an impulsive decision. It was the conclusion of an entire month immersed in a challenge I didn&amp;rsquo;t expect to enjoy this much.&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="r15000-was-the-hook-i-was-missing"&gt;&#10; R$15,000 was the hook I was missing&#10;&lt;/h2&gt;&#10;&lt;p&gt;I was never much of a hackathon enthusiast. But this time the hook was direct: my partner, a UX/UI designer, got an email from PanicLobster — the event organizer — announcing that in a month &lt;strong&gt;haCARthon&lt;/strong&gt; would take place, with a R$15,000 prize for each of the five winning teams. The incentive sparked my interest enough to go dig into the proposed challenges.&lt;/p&gt;</description></item><item><title>From raw electoral files to a dimensional model: building a data pipeline for Brazil's 2026 elections</title><link>https://guirondon.dev/posts/etl-n-modeling/</link><pubDate>Fri, 10 Jul 2026 14:00:00 -0300</pubDate><guid>https://guirondon.dev/posts/etl-n-modeling/</guid><description>&lt;p&gt;In 2024, the election coverage I worked on depended on a very expensive third-party system, which went down right on the night of the count and nearly turned the coverage into a total loss. In 2026 the decision was different: instead of buying a ready-made solution, another developer and I built the pipeline in-house in about three months, with six small services and a single daily schedule.&lt;/p&gt;&#10;&lt;p&gt;The &lt;a href="https://guirondon.dev/posts/elections-intro"&gt;first post in this series&lt;/a&gt;&#10; told the story: three encounters with Brazil&amp;rsquo;s electoral data, and the third time the build was mine to lead. This post is that build — what the TSE (Brazil&amp;rsquo;s electoral authority, which runs every election and publishes the data behind it) actually publishes, how that data lands, and how it became a structured model an API could serve.&lt;/p&gt;</description></item><item><title>I gave Claude 12,732 memories. Here's what it noticed.</title><link>https://guirondon.dev/posts/kg-n-inferences/</link><pubDate>Mon, 06 Jul 2026 14:00:00 -0300</pubDate><guid>https://guirondon.dev/posts/kg-n-inferences/</guid><description>&lt;p&gt;I put the memory system together, used it for a couple months, and then stopped to look at what it had actually accumulated.&lt;/p&gt;&#10;&lt;p&gt;The &lt;a href="https://guirondon.dev/posts/mempalace-setup/"&gt;previous post&lt;/a&gt;&#10; describes how the three layers work: &lt;code&gt;CLAUDE.md&lt;/code&gt; for static context, &lt;a href="https://github.com/MemPalace/mempalace" target="_blank" rel="noopener noreferrer"&gt;MemPalace&lt;/a&gt;&#10; for dynamic session memory, a knowledge graph for structured facts. MemPalace is not Claude&amp;rsquo;s built-in memory feature — it&amp;rsquo;s infrastructure I run myself, with memories stored in ChromaDB and SQLite on my machine and integration over MCP (Model Context Protocol), an open standard any compatible client can speak. If I swapped models tomorrow, everything it has accumulated would stay put.&lt;/p&gt;</description></item><item><title>The memory stack under the AI workflow: CLAUDE.md, MemPalace, and a knowledge graph</title><link>https://guirondon.dev/posts/mempalace-setup/</link><pubDate>Sat, 04 Jul 2026 16:00:00 -0300</pubDate><guid>https://guirondon.dev/posts/mempalace-setup/</guid><description>&lt;p&gt;The &lt;a href="https://guirondon.dev/posts/ai-at-work/"&gt;first post in this series&lt;/a&gt;&#10; was about the practice — how I structure prompts, iterate in short cycles, and delegate mechanical work while keeping judgment on my side. This one is about the infrastructure underneath that practice: the three-layer memory system that makes it work across sessions, projects, and weeks.&lt;/p&gt;&#10;&lt;p&gt;None of these layers is technically complex. The value comes from how they fit together.&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="the-problem-with-ai-memory-briefly"&gt;&#10; The problem with AI memory (briefly)&#10;&lt;/h2&gt;&#10;&lt;p&gt;Language models have no persistent memory. Every session starts blank. That&amp;rsquo;s fine for a one-off question, but if you&amp;rsquo;re using AI as a serious development tool, it creates friction: re-explaining project structure, re-establishing conventions, correcting the same behavior you already corrected last week.&lt;/p&gt;</description></item><item><title>Three elections, three encounters with Brazil's electoral data — and the third time, it was mine to lead</title><link>https://guirondon.dev/posts/elections-intro/</link><pubDate>Fri, 03 Jul 2026 10:00:00 -0300</pubDate><guid>https://guirondon.dev/posts/elections-intro/</guid><description>&lt;!-- POST 1 of 3 — Eleições 2026 series --&gt;&#10;&lt;!-- Narrative/intro post. Three acts: 2019-2020, 2024, 2026. Personal and contextual. --&gt;&#10;&lt;!-- No deep technical implementation here — that's posts 2 and 3. --&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;Election night, 2024. The screen we&amp;rsquo;d spent months building to cover vote counting across Brazil goes dark — not our servers, not our code. A third-party .NET system, running on a machine we handed over but never had access to, buckles under the exact load it was bought to handle.&lt;/p&gt;</description></item><item><title>Using AI and soccer match data to build my own commentator</title><link>https://guirondon.dev/posts/ai-commentator/</link><pubDate>Mon, 29 Jun 2026 16:00:00 -0300</pubDate><guid>https://guirondon.dev/posts/ai-commentator/</guid><description>&lt;!-- POST 2 of 3 — Copa 2026 series --&gt;&#10;&lt;!-- Focus: the integration layer. How data moves from the source through LangChain into a published article. --&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;Somewhere in the middle of those code sessions, I had a simpler thought: if I, as a software developer, could make sense of that same stream — typed events, timestamped, player names, statistics attached — why couldn&amp;rsquo;t an LLM?&lt;/p&gt;&#10;&lt;p&gt;It was from that premise that I started this project.&lt;/p&gt;</description></item><item><title>Building for the World Cup: real-time fan narration and automated editorial</title><link>https://guirondon.dev/posts/produtos-copa/</link><pubDate>Wed, 24 Jun 2026 21:30:00 -0300</pubDate><guid>https://guirondon.dev/posts/produtos-copa/</guid><description>&lt;!-- POST 1 of 3 — Copa 2026 series --&gt;&#10;&lt;!-- Focus: what we built and why. The two products, the editorial angle, the World Cup context. --&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;A goal is scored at a World Cup match. Sixty seconds later, a push notification lands on a fan&amp;rsquo;s phone — with the player&amp;rsquo;s name, the minute, and a line of narration. No journalist wrote it. No one pressed send. The system just knew.&lt;/p&gt;</description></item><item><title>The AI workflow nobody shows you: structure, memory, and real trade-offs</title><link>https://guirondon.dev/posts/ai-at-work/</link><pubDate>Mon, 22 Jun 2026 14:00:00 -0300</pubDate><guid>https://guirondon.dev/posts/ai-at-work/</guid><description>&lt;p&gt;There&amp;rsquo;s a difference between using AI and using AI well. The second requires you to think about what you&amp;rsquo;re doing — not just in the prompt you write, but in the structure you build around the tool.&lt;/p&gt;&#10;&lt;p&gt;I&amp;rsquo;ve been developing this practice over the past few months, both at work and in personal projects. What I&amp;rsquo;ve learned isn&amp;rsquo;t about which model is best or which tool has the most features. It&amp;rsquo;s about how to organize context so that AI is consistently useful — not just in the first session, but in the tenth.&lt;/p&gt;</description></item><item><title>From GitLab to Gitea: how my homelab CI/CD went from 3.4 GB to 100 MB</title><link>https://guirondon.dev/posts/gitea-migration/</link><pubDate>Sun, 21 Jun 2026 17:00:00 -0300</pubDate><guid>https://guirondon.dev/posts/gitea-migration/</guid><description>&lt;p&gt;One of my repositories has a commit history that reads like a story in three acts. The first is about personal ambition. The second is about &lt;a href="https://guirondon.dev/posts/homelab-gitea/"&gt;a Raspberry Pi that went silent in the middle of the night&lt;/a&gt;&#10;. The third is about finding the right tool for the right load.&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="act-i-github-actions-with-a-self-hosted-runner"&gt;&#10; Act I: GitHub Actions with a self-hosted runner&#10;&lt;/h2&gt;&#10;&lt;p&gt;The starting point was simple: I wanted CI/CD running on the Pi, builds happening locally, automated deployments. The natural choice was to keep using GitHub Actions — but with a self-hosted runner in the cluster.&lt;/p&gt;</description></item><item><title>Traefik as ingress on k3s: from local routing to public access without cert-manager</title><link>https://guirondon.dev/posts/traefik-k3s/</link><pubDate>Sun, 21 Jun 2026 09:00:00 -0300</pubDate><guid>https://guirondon.dev/posts/traefik-k3s/</guid><description>&lt;p&gt;When I started setting up my homelab on a Raspberry Pi 4B, one of the first questions was: how do I make multiple services running on the cluster each respond on their own domain, without opening a different port for each one?&lt;/p&gt;&#10;&lt;p&gt;I already knew the answer — I remembered working with EKS on AWS in the past, where ingress was a separate component that needed to be installed and configured. On k3s, it comes included, name and all: Traefik.&lt;/p&gt;</description></item><item><title>Gitea on Raspberry Pi: the story of how GitLab took down my homelab</title><link>https://guirondon.dev/posts/homelab-gitea/</link><pubDate>Sat, 20 Jun 2026 09:00:00 -0300</pubDate><guid>https://guirondon.dev/posts/homelab-gitea/</guid><description>&lt;p&gt;It was a Friday night and I was proud of what I had just built. I had just brought up GitLab Community Edition on my Raspberry Pi 4B — a long-held dream of having a complete development environment entirely under my own control. Git, CI/CD, registry, all in a small box sitting on the shelf.&lt;/p&gt;&#10;&lt;p&gt;I went to sleep.&lt;/p&gt;&#10;&lt;p&gt;Saturday morning, I opened the terminal to push something and found&amp;hellip; silence. The Raspberry Pi wasn&amp;rsquo;t responding. SSH timeout. No ping. I walked over to the shelf, looked at the slowly blinking green LED, and understood: GitLab&amp;rsquo;s memory footprint — likely a slow leak compounded by background jobs competing for CPU — had starved every other service on the node until the kernel had no choice but to intervene. The Pi had rebooted, and without enough headroom to bring everything back up, it just sat there.&lt;/p&gt;</description></item><item><title>Who am I?</title><link>https://guirondon.dev/posts/hello-world/</link><pubDate>Fri, 19 Jun 2026 09:00:00 -0300</pubDate><guid>https://guirondon.dev/posts/hello-world/</guid><description>&lt;p&gt;There&amp;rsquo;s a memory I carry with a lot of fondness: sitting on a bench at my technical school, graph paper on the desk, pen in hand — no computer in sight. The teacher had written a snippet of C code on the blackboard and the task was simple: trace the execution. Variable by variable, call stack by call stack, by hand.&lt;/p&gt;&#10;&lt;p&gt;That hooked me instantly — and changed the way I think about everything.&lt;/p&gt;</description></item><item><title>About</title><link>https://guirondon.dev/about/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://guirondon.dev/about/</guid><description>&lt;p&gt;Software engineer who solves problems and simplifies processes. For nearly 10 years I have designed and built backend, data and distributed systems grounded in analysis and fundamentals, to deliver resilience, quality and efficiency. Today I also bring AI into production work.&lt;/p&gt;</description></item><item><title>Let's talk</title><link>https://guirondon.dev/contact/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://guirondon.dev/contact/</guid><description>&lt;p&gt;Opportunities, projects, a question about a post, or just a chat about backend, data and AI.&lt;/p&gt;</description></item></channel></rss>