<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>Blog — Tom Girou</title><description>Notes from the trenches on PHP, Symfony, PrestaShop, CI/CD, and shipping production software — by Tom Girou, Senior Lead Dev.</description><link>https://tom-girou.dev/</link><language>en</language><item><title>Three Strings and Two Fallbacks: Wiring the Native Share Sheet Into Forgemage.net</title><link>https://tom-girou.dev/blog/forgemage-native-share-sheet/</link><guid isPermaLink="true">https://tom-girou.dev/blog/forgemage-native-share-sheet/</guid><description>The share button on Forgemage.net&apos;s request detail page opens the OS share sheet wherever the operating system has one — Android, iOS, Windows, macOS — copies the link where it doesn&apos;t, and stays quiet when you simply change your mind. Here&apos;s the whole implementation: navigator.share with three strings, an AbortError guard that falls through instead of catching, a clipboard fallback with an execCommand fallback under it, and the one-letter Symfony detail that decides whether the shared link works at all.</description><pubDate>Thu, 27 Aug 2026 00:00:00 GMT</pubDate><category>JavaScript</category><category>Web Share API</category><category>Symfony</category><category>Twig</category><category>Progressive Enhancement</category></item><item><title>Every New Smithmagus Made Search Slower: Killing the N+1 Behind Forgemage.net</title><link>https://tom-girou.dev/blog/forgemage-search-n1-queries/</link><guid isPermaLink="true">https://tom-girou.dev/blog/forgemage-search-n1-queries/</guid><description>Forgemage.net&apos;s smithmagus directory ran roughly seven queries per card — reviews, response time, online status, three lazy relations — plus facet counts recomputed on every filter tweak. Here&apos;s how I got a page of 24 cards from ~168 queries down to a handful, with a request-scoped batch cache and a paginate-then-hydrate pass, without touching the single-profile pages.</description><pubDate>Mon, 20 Jul 2026 00:00:00 GMT</pubDate><category>Symfony</category><category>Doctrine</category><category>PHP</category><category>Performance</category><category>N+1</category></item><item><title>Markdown for Agents, Self-Hosted: One Symfony Subscriber Instead of a Cloudflare Plan</title><link>https://tom-girou.dev/blog/markdown-for-agents/</link><guid isPermaLink="true">https://tom-girou.dev/blog/markdown-for-agents/</guid><description>Cloudflare converts pages to markdown for AI agents via Accept: text/markdown — on paid plans. The same HTTP contract fits in a 144-line Symfony event subscriber. My homepage went from 59 KB of HTML to 7.7 KB of markdown, same URL.</description><pubDate>Wed, 08 Jul 2026 00:00:00 GMT</pubDate><category>Symfony</category><category>PHP</category><category>AI Agents</category><category>HTTP</category><category>SEO</category></item><item><title>Claude Code From My Phone: Tailscale, Termius, and the Whole Machine in My Pocket</title><link>https://tom-girou.dev/blog/claude-code-from-my-phone/</link><guid isPermaLink="true">https://tom-girou.dev/blog/claude-code-from-my-phone/</guid><description>Claude Code&apos;s /remote-control mirrors one session to your phone. SSH over Tailscale hands you the whole workstation: resume sessions, start new ones in any repo, tail logs, restart containers — with nothing exposed to the internet.</description><pubDate>Mon, 06 Jul 2026 00:00:00 GMT</pubDate><category>Claude Code</category><category>Tailscale</category><category>SSH</category><category>Android</category><category>Workflow</category></item><item><title>RepoWrapped: Spotify Wrapped for a GitHub Repo, and the API That Fought Me</title><link>https://tom-girou.dev/blog/repo-wrapped/</link><guid isPermaLink="true">https://tom-girou.dev/blog/repo-wrapped/</guid><description>A weekend idea — a shareable stats page and README badge for any GitHub repo and contributor — turned into a fight with GitHub&apos;s stats API: 202s that never resolve, a top-100 wall, and a first-commit lookup you have to trick out of a header.</description><pubDate>Wed, 01 Jul 2026 00:00:00 GMT</pubDate><category>Laravel</category><category>PHP</category><category>GitHub API</category><category>Caching</category><category>Side Project</category></item><item><title>Letting Non-Technical PMs Query the Codebase in Plain Language</title><link>https://tom-girou.dev/blog/ai-codebase-portal-for-pms/</link><guid isPermaLink="true">https://tom-girou.dev/blog/ai-codebase-portal-for-pms/</guid><description>Why I built a read-only AI analyst that lets project managers ask questions about a codebase and have a Jira ticket filed for them automatically — and why the whole thing only works because the AI can read but never write.</description><pubDate>Mon, 29 Jun 2026 00:00:00 GMT</pubDate><category>Claude</category><category>Agent SDK</category><category>Developer Tools</category><category>Jira</category><category>PrestaShop</category></item><item><title>Adding AI Code Review to a Self-Hosted GitLab — Without Handing It the Keys</title><link>https://tom-girou.dev/blog/claude-gitlab-ai-review/</link><guid isPermaLink="true">https://tom-girou.dev/blog/claude-gitlab-ai-review/</guid><description>How I wired Claude into the merge-request pipeline of an old, self-hosted GitLab, and why the whole design hangs on never letting the AI both read an untrusted diff and hold a token at the same time.</description><pubDate>Wed, 24 Jun 2026 00:00:00 GMT</pubDate><category>CI/CD</category><category>GitLab</category><category>Claude</category><category>Code Review</category><category>Security</category></item></channel></rss>