<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Granda | Ideas &amp; Code</title><link>https://granda.org/en/</link><description>Recent content on Granda | Ideas &amp; Code</description><generator>Hugo</generator><language>en</language><lastBuildDate>Fri, 13 Mar 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://granda.org/en/index.xml" rel="self" type="application/rss+xml"/><item><title>Your Parked Tesla Is a Data Center</title><link>https://granda.org/en/2026/03/13/your-parked-tesla-is-a-data-center/</link><pubDate>Fri, 13 Mar 2026 00:00:00 +0000</pubDate><guid>https://granda.org/en/2026/03/13/your-parked-tesla-is-a-data-center/</guid><description>&lt;p&gt;Your car is parked 95% of the time. Inside it sits a chip capable of 300-500 trillion operations per second, connected to cooling, power conversion, and a cellular radio. It does nothing.&lt;/p&gt;
&lt;p&gt;Tesla and xAI want to change that. On March 11, Elon Musk &lt;a href="https://www.cnbc.com/2026/03/11/musk-unveils-joint-tesla-xai-project-macrohard.html"&gt;unveiled &amp;ldquo;Macrohard&amp;rdquo;&lt;/a&gt; — internally called Digital Optimus — a joint project that turns parked Teslas into personal AI agents. Not chatbots. Agents that watch your screen, control your mouse and keyboard, and do actual work.&lt;/p&gt;</description></item><item><title>Visual QA as a CI Pipeline Stage</title><link>https://granda.org/en/2026/02/06/visual-qa-as-a-ci-pipeline-stage/</link><pubDate>Fri, 06 Feb 2026 00:00:00 +0000</pubDate><guid>https://granda.org/en/2026/02/06/visual-qa-as-a-ci-pipeline-stage/</guid><description>&lt;p&gt;I merged a PR last month. The code review looked good. Tests passed. Then I opened the site on my phone and the sidebar was completely broken.&lt;/p&gt;
&lt;p&gt;The fix was trivial—a missing media query. The bug was obvious once you actually looked at the mobile view. Nobody did.&lt;/p&gt;
&lt;p&gt;So I added a pipeline stage that looks.&lt;/p&gt;
&lt;p&gt;I open a GitHub issue that says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Implement the Manual Entry option for adding clients. When clicked, opens a wide slide-over drawer with a form to create a new client.&lt;/p&gt;</description></item><item><title>Who Is Agent Trace For?</title><link>https://granda.org/en/2026/01/30/who-is-agent-trace-for/</link><pubDate>Fri, 30 Jan 2026 00:00:00 +0000</pubDate><guid>https://granda.org/en/2026/01/30/who-is-agent-trace-for/</guid><description>&lt;p&gt;Cursor released &lt;a href="https://github.com/cursor/agent-trace"&gt;Agent Trace&lt;/a&gt;, an open spec for tracking which code in a repo was written by an LLM. It records the model, the tool, the conversation, and the exact line ranges — all appended to a JSONL file in your project.&lt;/p&gt;
&lt;p&gt;The pitch: &amp;ldquo;As agents write more code, it&amp;rsquo;s important to understand what came from AI versus humans.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;I spent time reading the spec and the reference implementation. The engineering is solid — clean schema, thoughtful extensibility, good partner list (Amp, Amplitude, Cloudflare, Cognition, Google, Vercel). But I kept circling back to one question: what do you &lt;em&gt;do&lt;/em&gt; with this data?&lt;/p&gt;</description></item><item><title>Rich Links for Lazy Developers</title><link>https://granda.org/en/2026/01/10/rich-links-for-lazy-developers/</link><pubDate>Sat, 10 Jan 2026 00:00:00 +0000</pubDate><guid>https://granda.org/en/2026/01/10/rich-links-for-lazy-developers/</guid><description>&lt;p&gt;When I share a blog link on Twitter or Slack, it shows up as plain text. No preview image. Just a URL like &lt;a href="https://granda.org/en/2026/01/02/claude-code-on-the-go/"&gt;granda.org/en/2026/01/02/claude-code-on-the-go/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I needed Open Graph images. The standard approach: manually create a 1200x630 image for each post. That&amp;rsquo;s tedious. I asked Claude to automate it.&lt;/p&gt;
&lt;div class="desktop-only"&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-mermaid" data-lang="mermaid"&gt;flowchart LR
 Push[git push] --&amp;gt; GHA[GitHub Actions]
 GHA --&amp;gt; Hugo[Hugo Server]
 GHA --&amp;gt; PW[Playwright]
 PW --&amp;gt;|screenshot| Hugo
 PW --&amp;gt; IMG[OG Image]
 IMG --&amp;gt; Commit[git commit]
 Commit --&amp;gt; Deploy[Deploy]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="mobile-only"&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-mermaid" data-lang="mermaid"&gt;flowchart TB
 Push[git push] --&amp;gt; GHA[GitHub Actions]
 GHA --&amp;gt; Hugo[Hugo Server]
 GHA --&amp;gt; PW[Playwright]
 PW --&amp;gt;|screenshot| Hugo
 PW --&amp;gt; IMG[OG Image]
 IMG --&amp;gt; Commit[git commit]
 Commit --&amp;gt; Deploy[Deploy]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="the-setup"&gt;The Setup&lt;/h2&gt;
&lt;p&gt;I told Claude the problem: posts need social preview images, but I don&amp;rsquo;t want to create them manually. Screenshot the article content, save it as an OG image, update the frontmatter automatically.&lt;/p&gt;</description></item><item><title>Unsubscribe</title><link>https://granda.org/en/unsubscribe/</link><pubDate>Sat, 10 Jan 2026 00:00:00 +0000</pubDate><guid>https://granda.org/en/unsubscribe/</guid><description>&lt;p id="unsubscribe-message"&gt;Processing...&lt;/p&gt;
&lt;script&gt;
(function() {
 const params = new URLSearchParams(window.location.search);
 const msg = document.getElementById('unsubscribe-message');

 if (params.get('success') === 'true') {
 msg.textContent = 'You have been unsubscribed from the newsletter.';
 } else if (params.get('error') === 'missing') {
 msg.textContent = 'Error: No unsubscribe token provided.';
 } else if (params.get('error') === 'invalid') {
 msg.textContent = 'Error: Invalid unsubscribe link.';
 } else {
 msg.textContent = 'Error: Unknown error occurred.';
 }
})();
&lt;/script&gt;</description></item><item><title>My QA Engineer is an LLM</title><link>https://granda.org/en/2026/01/09/my-qa-engineer-is-an-llm/</link><pubDate>Fri, 09 Jan 2026 00:00:00 +0000</pubDate><guid>https://granda.org/en/2026/01/09/my-qa-engineer-is-an-llm/</guid><description>&lt;p&gt;Claude can click buttons.&lt;/p&gt;
&lt;p&gt;That sounds trivial, but it changes how I build UIs. With Playwright MCP, Claude doesn&amp;rsquo;t just write code—it opens a browser, navigates to localhost, and verifies that things actually work. It catches bugs I&amp;rsquo;d miss in code review.&lt;/p&gt;
&lt;h2 id="the-setup"&gt;The Setup&lt;/h2&gt;
&lt;p&gt;Playwright MCP gives Claude browser automation. I run it with headless Chromium:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;mcpServers&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;playwright&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;npx&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;args&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;@anthropic-ai/mcp-server-playwright&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;--headless&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now Claude can navigate, click, type, and screenshot. It sees what users see.&lt;/p&gt;</description></item><item><title>Rolling My Own Newsletter with Claude</title><link>https://granda.org/en/2026/01/07/rolling-my-own-newsletter-with-claude/</link><pubDate>Wed, 07 Jan 2026 00:00:00 +0000</pubDate><guid>https://granda.org/en/2026/01/07/rolling-my-own-newsletter-with-claude/</guid><description>&lt;p&gt;Day two of the Hacker News traffic spike. Forty thousand visitors, no way to reach them again. I needed a newsletter signup.&lt;/p&gt;
&lt;p&gt;I looked at Buttondown, Beehiiv, Substack, ConvertKit. All overkill. I just needed to collect emails. I didn&amp;rsquo;t need campaigns, analytics, or subscriber management. And I wanted to own my data.&lt;/p&gt;
&lt;p&gt;So I asked Claude to build it.&lt;/p&gt;
&lt;div class="desktop-only"&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-mermaid" data-lang="mermaid"&gt;flowchart LR
 User([User]) --&amp;gt; Form[Newsletter Form]
 Form --&amp;gt;|POST /api/subscribe| Worker[Cloudflare Worker]
 Worker --&amp;gt; KV[(Cloudflare KV)]
 KV -.-&amp;gt;|Daily sync| GHA[GitHub Actions]
 GHA -.-&amp;gt; Repo[(subscribers.jsonl)]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="mobile-only"&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-mermaid" data-lang="mermaid"&gt;flowchart TB
 User([User]) --&amp;gt; Form[Newsletter Form]
 Form --&amp;gt;|POST /api/subscribe| Worker[Cloudflare Worker]
 Worker --&amp;gt; KV[(Cloudflare KV)]
 KV -.-&amp;gt;|Daily sync| GHA[GitHub Actions]
 GHA -.-&amp;gt; Repo[(subscribers.jsonl)]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="the-setup"&gt;The Setup&lt;/h2&gt;
&lt;p&gt;I gave Claude a Cloudflare API token via environment variable and described what I wanted: a form that collects emails and stores them somewhere I control.&lt;/p&gt;</description></item><item><title>Claude Code On-The-Go</title><link>https://granda.org/en/2026/01/02/claude-code-on-the-go/</link><pubDate>Fri, 02 Jan 2026 00:00:00 +0000</pubDate><guid>https://granda.org/en/2026/01/02/claude-code-on-the-go/</guid><description>&lt;p&gt;I run six Claude Code agents in parallel from my phone. No laptop, no desktop—just Termius on iOS and a cloud VM.&lt;/p&gt;
&lt;h2 id="the-setup"&gt;The Setup&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-mermaid" data-lang="mermaid"&gt;flowchart LR
 A[Phone] --&amp;gt;|Termius + mosh| B[Tailscale VPN]
 B --&amp;gt; C[Vultr VM]
 C --&amp;gt; D[Claude Code]
 D --&amp;gt;|PreToolUse hook| E[Poke webhook]
 E --&amp;gt;|Push notification| A
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The loop is: kick off a task, pocket the phone, get notified when Claude needs input. Async development from anywhere.&lt;/p&gt;
&lt;h2 id="infrastructure"&gt;Infrastructure&lt;/h2&gt;
&lt;p&gt;A Vultr VM in Silicon Valley:&lt;/p&gt;</description></item><item><title>Letting the AI Do It</title><link>https://granda.org/en/2025/12/28/letting-the-ai-do-it/</link><pubDate>Sun, 28 Dec 2025 00:00:00 +0000</pubDate><guid>https://granda.org/en/2025/12/28/letting-the-ai-do-it/</guid><description>&lt;p&gt;I needed a dev server: VM with SSH access and dev tools installed. I described what I wanted to Claude Code and let it handle the setup.&lt;/p&gt;
&lt;h2 id="the-prompt"&gt;The Prompt&lt;/h2&gt;
&lt;p&gt;I asked for a Vultr VM with 8 cores and 32GB of RAM, accessible only through Tailscale, with persistent sessions that survive network drops.&lt;/p&gt;
&lt;h2 id="what-claude-code-built"&gt;What Claude Code Built&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;1. Provisioned the VM via Vultr API&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It created an 8-core/32GB Ubuntu instance, waited for the IP, then SSH&amp;rsquo;d in as root.&lt;/p&gt;</description></item><item><title>Automatic Blog Translations With Claude and GitHub Actions</title><link>https://granda.org/en/2025/12/23/automatic-blog-translations-with-claude-and-github-actions/</link><pubDate>Tue, 23 Dec 2025 00:00:00 +0000</pubDate><guid>https://granda.org/en/2025/12/23/automatic-blog-translations-with-claude-and-github-actions/</guid><description>&lt;p&gt;Every post I write gets translated automatically. Claude handles the translation, commits the results to main, and the translated versions deploy alongside the original.&lt;/p&gt;
&lt;h2 id="the-flow"&gt;The Flow&lt;/h2&gt;
&lt;p&gt;The translation workflow runs in GitHub Actions when English content is merged to main:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;push&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="l"&gt;main]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;content/**/*.en.md&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-mermaid" data-lang="mermaid"&gt;flowchart LR
 B[Merge to main] --&amp;gt; C[Translations generated]
 C --&amp;gt; D[Committed to main]
 D --&amp;gt; E[Production deploy with all languages]
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="the-prompt"&gt;The Prompt&lt;/h2&gt;
&lt;p&gt;The workflow uses &lt;a href="https://github.com/anthropics/claude-code-action"&gt;claude-code-action&lt;/a&gt;:&lt;/p&gt;</description></item><item><title>About</title><link>https://granda.org/en/about/</link><pubDate>Mon, 22 Dec 2025 00:00:00 +0000</pubDate><guid>https://granda.org/en/about/</guid><description>&lt;h2 id="abstract"&gt;Abstract&lt;/h2&gt;
&lt;p&gt;This document provides background information about the author of this blog.&lt;/p&gt;
&lt;h2 id="1-background"&gt;1. Background&lt;/h2&gt;
&lt;p&gt;Software engineer with 15 years of experience, 10 spent working in the field.
Areas of focus include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Distributed systems&lt;/li&gt;
&lt;li&gt;Backend development and infrastructure&lt;/li&gt;
&lt;li&gt;Full-stack and end-to-end product development&lt;/li&gt;
&lt;li&gt;User interface design&lt;/li&gt;
&lt;li&gt;Building secure and reliable systems&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="2-contact"&gt;2. Contact&lt;/h2&gt;
&lt;p&gt;Always happy to connect with others in the industry:
&lt;a href="https://x.com/mtt"&gt;@mtt&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Authorship</title><link>https://granda.org/en/authorship/</link><pubDate>Mon, 22 Dec 2025 00:00:00 +0000</pubDate><guid>https://granda.org/en/authorship/</guid><description>&lt;h2 id="abstract"&gt;Abstract&lt;/h2&gt;
&lt;p&gt;This document describes the authorship methodology employed by this blog.&lt;/p&gt;
&lt;h2 id="1-introduction"&gt;1. Introduction&lt;/h2&gt;
&lt;p&gt;This blog is largely generated with the assistance of Large Language Models
(LLMs). The author provides direction, editing, and quality control; the
machine provides initial drafts and translations.&lt;/p&gt;
&lt;h2 id="2-rationale"&gt;2. Rationale&lt;/h2&gt;
&lt;p&gt;The author believes in transparency regarding AI-assisted content creation.
Rather than obscuring the tools used, this disclosure aims to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set appropriate expectations for readers&lt;/li&gt;
&lt;li&gt;Contribute to honest norms around AI content&lt;/li&gt;
&lt;li&gt;Acknowledge the collaborative nature of modern writing&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="3-what-this-means"&gt;3. What This Means&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ideas&lt;/strong&gt;: Human-originated&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Structure&lt;/strong&gt;: Collaborative&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prose&lt;/strong&gt;: Primarily AI-generated, human-reviewed&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Translations&lt;/strong&gt;: Entirely AI-generated (not human-reviewed)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="4-quality-assurance"&gt;4. Quality Assurance&lt;/h2&gt;
&lt;p&gt;English content undergoes human review before publication. Translations are
generated automatically and may contain errors or awkward phrasing. The author
takes responsibility for the final published English content.&lt;/p&gt;</description></item><item><title>Hello World</title><link>https://granda.org/en/2025/12/20/hello-world/</link><pubDate>Sat, 20 Dec 2025 00:00:00 +0000</pubDate><guid>https://granda.org/en/2025/12/20/hello-world/</guid><description>&lt;p&gt;Welcome to my blog! This is my first post.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll be sharing ideas, notes, and things I find interesting here.&lt;/p&gt;</description></item></channel></rss>