<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Matt Lambert — Software &amp; Cloud Engineering</title>
    <link>https://iammattl.com/blog</link>
    <description>Thoughts on software engineering, cloud infrastructure, AI-assisted development, and building things for the web.</description>
    <language>en-gb</language>
    <lastBuildDate>Mon, 20 Apr 2026 15:50:00 GMT</lastBuildDate>
    <pubDate>Mon, 20 Apr 2026 15:50:00 GMT</pubDate>
    <atom:link href="https://iammattl.com/feed.xml" rel="self" type="application/rss+xml"/>
    <item>
      <title>Hourly Improvements: Two Ways to Keep a Site Moving</title>
      <link>https://iammattl.com/blog/hourly-improvements-two-ways-to-keep-a-site-moving</link>
      <guid isPermaLink="true">https://iammattl.com/blog/hourly-improvements-two-ways-to-keep-a-site-moving</guid>
      <description>Two parallel implementations of the same idea: one small improvement to my site, every hour, forever. A Claude Code scheduled task running locally and a five-agent pipeline on Cloudflare Workers called Vigil. Same rule at the top of both: ONE improvement per run, never batch.</description>
      <pubDate>Mon, 20 Apr 2026 15:50:00 GMT</pubDate>
      <enclosure url="https://iammattl.com/images/blog/hourly-improvements-two-ways-to-keep-a-site-moving/1776701672020.webp?w=600" type="image/webp" length="0"/>
      <content:encoded><![CDATA[<p>Websites rot. Not in dramatic ways. In small ones. A missing <code>rel=&quot;noopener&quot;</code>, a stale <code>lastmod</code>, a cookie banner that covers the footer on first load, a screen reader that gets spammed by a rotating title every 400ms. Each of these is a five-minute fix. None of them are ever urgent enough to schedule.</p>
<p>I wanted a system that picked one of these off every hour, opened a PR, and let me review it with my coffee. Not a big weekly audit. Not a quarterly cleanup. Small, specific, mergeable changes on a loop.</p>
<p>I ended up building two versions of the same idea. One runs locally inside Claude Code. The other runs on Cloudflare Workers whether my laptop is open or not. This post is about both, and about the constraint that shapes them: one improvement per run, never more.</p>
<h2 id="the-one-per-run-rule">The One-Per-Run Rule</h2>
<p>The temptation with any automated improvement system is to batch. Find ten issues, fix them all, open one big PR. It feels more efficient. It isn&#39;t.</p>
<p>Big PRs don&#39;t get merged. They sit. Small PRs do get merged, because there&#39;s nothing to review beyond the single change they make. A PR titled &quot;Stop sidebar typewriter from spamming screen readers every rotation&quot; takes 30 seconds to review. A PR titled &quot;Accessibility, SEO, and performance fixes&quot; takes 30 minutes, which means it waits until I have 30 minutes, which means never.</p>
<p>So both systems have the same hard rule at the top of their prompt: pick the <strong>one</strong> highest-impact improvement, implement it, open a PR. If there&#39;s nothing worth fixing, exit. Don&#39;t manufacture work.</p>
<p>That constraint shapes everything downstream. Triage has to rank issues, not collect them. The fixer has to touch as few files as possible. The reviewer has to reject scope creep as aggressively as it rejects bad fixes. The rule is the thing that keeps the PR list reviewable instead of a backlog of half-finished audits.</p>
<h2 id="the-local-loop-claude-code-scheduled-tasks">The Local Loop: Claude Code Scheduled Tasks</h2>
<p>Claude Code has two ways to run things on a schedule. <code>/loop</code> runs a prompt or slash command on a recurring interval in the current session. <code>/schedule</code> runs a remote agent on a cron. Both hit the same <code>scheduled_tasks.lock</code> file in the project root so you can see what&#39;s running.</p>
<p>For the local version of this I use <code>/loop 1h follow .claude/prompts/hourly-improvement.md exactly</code>. The prompt is checked into the repo so it evolves with the site. Top of the prompt:</p>
<blockquote>
<p>Your job: Assess the live site and codebase, pick the ONE highest-impact improvement, implement it, and open a PR.</p>
</blockquote>
<p>The prompt walks Claude through four steps. Snapshot the live site via Cloudflare&#39;s Browser Rendering API (desktop and mobile, every key page). Review the codebase for what&#39;s behind whatever the screenshots surfaced. Pick one improvement using a ranked priority list (security, broken functionality, SEO, performance, design polish, accessibility, content, code quality). Implement it and open a PR with a structured body: what&#39;s wrong, why it matters, what changed, evidence.</p>
<p>There&#39;s a hard list of rules at the bottom:</p>
<ul>
<li>ONE improvement per run. Never batch.</li>
<li>Verify the issue actually exists before fixing it.</li>
<li>Only edit existing files, never create new pages.</li>
<li>Check recent PRs to avoid duplicating work someone (or the last run) already shipped.</li>
<li>Read the full file before and after editing.</li>
</ul>
<p>The &quot;check recent PRs&quot; rule earns its keep. Without it, the loop will happily open the same fix twice in a row if the first one hasn&#39;t merged yet. With it, every run starts with <code>gh pr list --state open --limit 10</code> and moves on to the next-highest-priority issue if the top one is already in flight.</p>
<p>The prompt also tells Claude to update <code>CLAUDE.md</code> in the same PR if the change touches anything the doc describes. A new npm script, a new Cloudflare binding, a changed pattern. The doc is the onboarding surface for every future run of this loop, so drift compounds badly if you let it.</p>
<p>What makes this work on top of Claude Code specifically, rather than a shell script calling the Anthropic API: Claude Code already has the MCP servers, the Playwright/Browser Rendering access, the GitHub CLI, the repo context, and the instructions in <code>CLAUDE.md</code>. The loop inherits all of it. I didn&#39;t have to plumb auth for GitHub or build a screenshot pipeline. It was already there.</p>
<h2 id="the-remote-loop-vigil-on-cloudflare-workers">The Remote Loop: Vigil on Cloudflare Workers</h2>
<p>The local loop has one weakness. It runs when my laptop is on and Claude Code is open. If I&#39;m on a train or at an event, nothing happens.</p>
<p>So I built a second version that lives entirely on Cloudflare. I called it Vigil. It monitors multiple sites (currently iammattl.com and techpartprices.com), runs the same kind of checks, and opens PRs through the same GitHub API.</p>
<p>The architecture is a five-agent pipeline running on Cloudflare Workers, with Queues between each stage:</p>
<pre><code>detected → triaged → diagnosed → fixed → review_passed → pr_created → deployed
                                   ↑           |
                                   └── review_failed (retry, max 3)
</code></pre>
<p>Each stage is a separate function that picks up messages from its inbound queue, calls Workers AI, updates state in D1, and enqueues the next stage. Cron triggers drive the detection side of the system on different schedules for different check types:</p>
<pre><code class="language-jsonc">&quot;triggers&quot;: {
  &quot;crons&quot;: [
    &quot;*/15 * * * *&quot;,  // Uptime — every 15 mins
    &quot;0 2 * * *&quot;,     // SEO — daily
    &quot;0 3 * * SUN&quot;,   // Broken links — weekly
    &quot;0 4 * * 1&quot;,     // Lighthouse — weekly
    &quot;0 5 * * 1&quot;,     // Security headers — weekly
    &quot;0 6 * * 1,4&quot;,   // SERP tracking — twice weekly
    &quot;0 3 * * 1&quot;,     // Dependency CVEs — weekly
    &quot;0 9 * * 1&quot;      // Weekly digest — Monday
  ]
}
</code></pre>
<p>Detection is dumb. It finds issues. The interesting work happens in the pipeline after.</p>
<p><strong>Triage</strong> classifies each issue by severity, decides whether it&#39;s auto-fixable, and identifies the likely files. Uses a fast, cheap model (Qwen3) via AI Gateway because the job is classification, not writing.</p>
<p><strong>Diagnostician</strong> fetches the real source from GitHub and analyses root cause. Uses a higher-quality model (Gemma 4) because the output needs to be specific enough for the fixer to act on.</p>
<p><strong>Fixer</strong> generates the minimal code change. Same quality-tier model. Outputs a confidence score. If it&#39;s below 0.8 the change doesn&#39;t progress.</p>
<p><strong>Reviewer</strong> is the important one. It looks at the fix without having written it, judges whether the change actually solves the issue, and can reject with feedback that loops back to the Diagnostician for a retry. Three attempts max. Using a different model from the fixer is deliberate. An independent reviewer catches things the fixer rationalised away.</p>
<p><strong>Deployer</strong> creates a branch, commits the change, opens a PR, and notifies Telegram.</p>
<p>Model routing runs through a Cloudflare AI Gateway binding called <code>vigil</code>. The gateway caches identical prompts, logs every request, and enforces per-account rate limits. When a fixer invocation costs more than the budget allowed, I can see it in the gateway dashboard before it shows up on a bill.</p>
<p>Auto-merge exists but is off by default. It&#39;s gated behind explicit env vars:</p>
<pre><code>AUTO_MERGE_ENABLED=true
AUTO_MERGE_MIN_CONFIDENCE=0.95
AUTO_MERGE_MAX_FILES=2
AUTO_MERGE_MAX_LINES=50
</code></pre>
<p>A fix needs all three constraints to pass before it merges itself. Anything larger still waits for me. That&#39;s the same one-per-run discipline, applied to merge time instead of PR creation.</p>
<p>Everything else Vigil needs is just Cloudflare primitives wired together: D1 for issue state and agent logs, KV for cache, Queues for the pipeline, Workers AI for the models, Secrets Store for tokens, GitHub API for the PRs, Telegram for notifications. No dedicated server, no always-on process, no external services beyond GitHub and Telegram.</p>
<h2 id="two-loops-same-rule">Two Loops, Same Rule</h2>
<p>The two systems share the one-per-run constraint but otherwise make opposite choices.</p>
<p><strong>Local loop.</strong> Runs inside Claude Code on my machine. Uses Claude as the model. Scoped to one repo. Scheduled via <code>/loop 1h</code> while the session is open. State lives in git plus throwaway files in <code>/tmp</code>. Every PR gets my eyes before it merges. Full context on hand: <code>CLAUDE.md</code>, feedback memory, the MCP servers Claude Code is already wired into. Cost: covered by my Claude Code subscription.</p>
<p><strong>Vigil.</strong> Runs on Cloudflare Workers. Uses Workers AI (Gemma 4 for the heavy agents, Qwen3 for the fast ones) routed through AI Gateway. Monitors multiple sites. Scheduled via Cloudflare Cron, always on whether my laptop is or not. State lives in D1, KV, and Queues. A reviewer agent checks the fix before it gets to me. Context is whatever the cron-triggered check output surfaces, nothing more. Cost: Workers AI per-token.</p>
<p>The local loop wins when the decision requires judgement I&#39;d struggle to write into a prompt. Design polish, copy that captures my tone, anything where &quot;looks right&quot; matters. Claude inside Claude Code has access to the same context I do, including the repo&#39;s <code>CLAUDE.md</code> and feedback memory, so its taste lines up with mine.</p>
<p>Vigil wins when the decision is mechanical and when uptime matters. A 500 at 3am needs someone looking at it. Security headers drifting after a library upgrade need catching. A broken external link on a blog post from 2026-03-16 needs finding on a crawl, not by me remembering to look. Vigil does these on cron while I sleep.</p>
<p>They overlap more than they compete. The local loop shipped the cross-origin opener policy header. Vigil shipped the broken-link alerts that got me to fix three outbound references by hand. Same site, same kind of improvement, different tradeoffs on who was driving.</p>
<h2 id="what-they-ve-actually-shipped">What They&#39;ve Actually Shipped</h2>
<p>A sample of real PRs from the last month on iammattl.com. Most of these are on the git log if you want to check them:</p>
<ul>
<li>Stop sidebar typewriter from spamming screen readers every rotation</li>
<li>Use CreativeWork (not WebSite) for URL-less archived projects in JSON-LD</li>
<li>Dispatch cookie-consent-update on Decline too, not just Accept</li>
<li>Extract requireAuth() helper; stop redirecting to the dead /admin/login</li>
<li>Set Cross-Origin-Opener-Policy: same-origin for tab isolation</li>
<li>Advertise the resume PDF alternate in /resume&#39;s Link header</li>
<li>Emit X-Cache: HIT|MISS from withEdgeCache for observability</li>
<li>Surface recent blog posts on the 404 page</li>
<li>Emit wordCount + timeRequired on BlogPosting JSON-LD</li>
<li>Route /feed.xml through withEdgeCache for per-POP caching</li>
</ul>
<p>Every one of these is a fix I would have meant to do and never got around to. Each one is small enough that reviewing it takes less time than writing the PR description. That ratio is the point. If a system like this ever produces a PR I don&#39;t want to merge, I&#39;ve broken the rule that makes it work.</p>
<h2 id="what-i-got-wrong">What I Got Wrong</h2>
<p><strong>The prompt drifted faster than I expected.</strong> Cloudflare adds a new API, I add a new binding, the prompt&#39;s Step 1 stops reflecting what the repo actually is. The first few runs after drift produce worse results than usual. The fix was making the prompt&#39;s Step 1f an explicit &quot;CLAUDE.md drift check&quot;. If the doc is meaningfully stale and no higher-priority issue exists, update the doc as the improvement for that run. The loop maintains its own onboarding surface.</p>
<p><strong>Verifying the issue actually exists matters more than I realised.</strong> Early runs would confidently fix things that were already correct, because the model inferred the problem from an old pattern in its training data rather than reading the current file. I added &quot;Verify the issue ACTUALLY exists. Do NOT fix something already correct&quot; to the rules as a hard line. It cut false-positive PRs significantly.</p>
<p><strong>The reviewer in Vigil is what makes autonomous fixes tolerable.</strong> When I ran Vigil without the reviewer stage, the fixer would produce plausible-looking diffs that missed the actual issue. Adding a separate agent, with a different model, whose only job is to say whether the fix solves the problem, moved the failure mode from &quot;wrong change merged&quot; to &quot;correct change delayed by a retry&quot;. The extra inference cost is worth it.</p>
<p><strong>Auto-merge felt more dangerous than it turned out to be.</strong> I kept it off for months. When I finally turned it on with the 0.95-confidence and 2-file thresholds, nothing bad happened because the constraints are so tight that the only things it merges are truly boring. The lesson was that the scary part isn&#39;t auto-merge, it&#39;s auto-merge without a tight gate.</p>
<h2 id="where-to-start">Where to Start</h2>
<p>If you want to try this on your own site, start with the local loop. It&#39;s the lower-commitment version and the one that teaches you what to ask for.</p>
<ol>
<li>Write a prompt in your repo at <code>.claude/prompts/hourly-improvement.md</code>. Lead with the one-per-run rule. Include a priority list so ranking is explicit. Add a &quot;check recent PRs before proposing&quot; step.</li>
<li>Run <code>/loop 1h follow .claude/prompts/hourly-improvement.md exactly</code> in Claude Code. Let it open a PR. Review it. If the PR is bad, the prompt needs work. Iterate on the prompt, not on the tool.</li>
<li>Once the PRs are consistently mergeable, graduate to scheduled tasks so the loop runs even when you&#39;re not in the session.</li>
</ol>
<p>Build the remote version only when you&#39;re running out of laptop time. Vigil makes sense because I have two sites, I travel, and I want coverage at times when I&#39;m not working. For a single site you own and actively develop, the local loop is enough.</p>
<p>Both systems live on one idea. Pick one thing. Fix it. Ship it. Do it again in an hour.</p>
]]></content:encoded>
      <category>cloudflare</category>
      <category>ai</category>
      <category>agents</category>
      <category>claude-code</category>
      <category>workers</category>
    </item>
    <item>
      <title>Cloudflare Connect London 2026: The Agentic Internet is Here</title>
      <link>https://iammattl.com/blog/cloudflare-connect-london-2026</link>
      <guid isPermaLink="true">https://iammattl.com/blog/cloudflare-connect-london-2026</guid>
      <description>A day at Cloudflare Connect London during Agents Week. Sandboxes, MCP Server Portals, Cloudflare Mesh, Moltworker, Kilo Code, and AI Crawl Control. I deployed an AI agent and hardened an MCP server before the day was over.</description>
      <pubDate>Wed, 15 Apr 2026 22:00:00 GMT</pubDate>
      <enclosure url="https://iammattl.com/images/blog/cloudflare-connect-london-2026/1776328678215.webp?w=600" type="image/webp" length="0"/>
      <content:encoded><![CDATA[<p>I spent today at Cloudflare Connect in London. The Brewery, 60+ speakers, sold out. The event landed mid-way through Cloudflare&#39;s <a href="https://www.cloudflare.com/agents-week/" target="_blank" rel="noopener noreferrer">Agents Week</a>, so the product announcements from the past few days were fresh and the demos were live. The theme across every session was the same. The internet is being rebuilt around agents.</p>
<p>Agents. Autonomous software that acts on your behalf, runs its own compute, pays for services, talks to other agents. Cloudflare is betting their platform on this shift. After a full day of sessions, I think the bet is right.</p>
<h2 id="the-keynote-welcome-to-the-agentic-internet">The Keynote: Welcome to the Agentic Internet</h2>
<p>The opening keynote framed everything that followed. The internet we built was designed for humans browsing pages. The next internet is designed for agents acting on behalf of humans. One-to-one instead of one-to-many. Each agent is a unique instance, serving one user, running one task.</p>
<p>The infrastructure implications are massive. If every knowledge worker has agents running tasks for them, you&#39;re looking at hundreds of millions of concurrent compute instances. Traditional containers don&#39;t scale to that. Cloudflare&#39;s answer is isolates and their new Sandbox environments. Lightweight, persistent, secure. They sleep when idle and wake on demand. Agents only pay for active CPU time, not for sitting around waiting on an LLM response.</p>
<p>Sandboxes hit general availability alongside Cloudflare Containers. Agents get their own persistent compute with file systems, terminal access, git, dev servers. Credentials are injected at the network layer so agents never see raw secrets. It&#39;s a full development environment that an AI can operate independently.</p>
<p>The other announcement worth noting was the x402 Foundation. It&#39;s a standard for agents to pay for services they consume. Right now, agents can browse the web and call APIs, but there&#39;s no native way for them to transact. x402 is building that payment layer. Not exciting on its own, but it matters once agents start operating at scale.</p>
<h2 id="fast-path-to-ai-securely-adopting-models-and-agents">Fast Path to AI: Securely Adopting Models and Agents</h2>
<p>This session covered the security side of the agent transition. The pitch was practical. Companies want to use AI models and deploy agents, but the security surface is genuinely new. Prompt injection, data exfiltration through tool calls, agents accessing systems they shouldn&#39;t.</p>
<p>Cloudflare&#39;s approach layers AI Gateway in front of everything. Unified logging, rate limiting, caching, content filtering across multiple model providers. The argument is that you can&#39;t retrofit security onto agents the way you did with web apps. It needs to be embedded from the start. Access controls, identity, and authorization baked into the execution model.</p>
<p>As someone running Workers AI on my own site for blog drafts and image generation, this resonated. I have a Cloudflare Access JWT check protecting my admin routes. That pattern of auth-at-the-edge is exactly what they&#39;re proposing for agents, just at a much larger scale.</p>
<p>I was convinced enough to act on it during the session. I have a <a href="https://github.com/IamMattL/truenas-mcp-server" target="_blank" rel="noopener noreferrer">TrueNAS MCP server</a> that gives Claude direct access to my NAS. 22 tools, container deployments, storage management. It runs locally over stdio. I&#39;ve wanted to make it remote for a while, accessible from anywhere, but the security story wasn&#39;t there. An MCP server that can deploy containers to your NAS shouldn&#39;t be exposed to the internet without serious access controls.</p>
<p><a href="https://developers.cloudflare.com/cloudflare-one/access-controls/ai-controls/mcp-portals/" target="_blank" rel="noopener noreferrer">MCP Server Portals</a> solve exactly this. They aggregate MCP servers behind a single Zero Trust endpoint. Identity provider authentication, device posture checks, per-tool access policies, full audit logging. You register your MCP server, attach it to a portal, and users connect through one URL protected by Cloudflare Access. The portal even collapses tools into a single code execution mode so the AI client sees a cleaner interface.</p>
<p>The other announcement that caught my attention was <a href="https://blog.cloudflare.com/mesh/" target="_blank" rel="noopener noreferrer">Cloudflare Mesh</a>. It&#39;s private networking for users, devices, and agents. Think Tailscale, but built into Cloudflare&#39;s network. You run a lightweight connector on your server, it gets a private Mesh IP, and any device or Worker on your Mesh can reach it. No port forwarding. No public exposure. Traffic routes through Cloudflare&#39;s edge across 330+ cities, so NAT traversal just works.</p>
<p>This matters for me because my TrueNAS sits on my internal network. I don&#39;t want to expose it to the internet. Cloudflare Tunnels could do it, but Mesh is bidirectional and many-to-many instead of one-directional. Run a Mesh node on the NAS, connect my devices and Workers, and the MCP server becomes reachable over a private IP with full Zero Trust policy enforcement. The free tier covers 50 nodes and 50 users.</p>
<p>Mesh plus MCP Server Portals gets me from &quot;local MCP server on my home network&quot; to &quot;remote MCP server accessible from anywhere, secured by Zero Trust, without exposing a single port.&quot;</p>
<p>I had my laptop open through most of the sessions, exploring the features as they were being discussed and working out how they&#39;d fit into my own infrastructure. The AI Controls integration for my TrueNAS server was pushed before the session ended.</p>
<h2 id="ditching-the-mac-mini-moltworker-and-openclaw">Ditching the Mac Mini: Moltworker and OpenClaw</h2>
<p>This was the most entertaining talk of the day. OpenClaw (formerly Moltbot, formerly Clawdbot) is a self-hosted personal AI agent. It connects Claude to your files, APIs, and messaging platforms. The original deployment model was a Mac mini sitting under someone&#39;s desk. Always on, always running, always your problem when it crashed at 3am.</p>
<p>Moltworker is the Cloudflare Workers port. Sid Chatterjee walked through the retrospective of packaging OpenClaw to run in a Sandbox container on Cloudflare&#39;s network. No hardware. No maintenance. It sleeps when idle, wakes on request, and runs across 300+ data centers. The talk covered the full migration story. Every pain point of self-hosting a persistent AI agent, power outages, OS updates that break things, the Mac mini&#39;s fan noise, all gone.</p>
<p>The <a href="https://github.com/cloudflare/moltworker" target="_blank" rel="noopener noreferrer">Moltworker repo</a> is open source. Cloudflare published it with the Sandbox SDK built in. R2 storage for persistence across container restarts. It&#39;s a reference implementation for how to deploy a personal agent on their platform.</p>
<p>The talk was honest about the engineering challenges. Adapting an agent designed for a persistent local machine to a sleep/wake serverless model wasn&#39;t straightforward. But the result is a self-hosted AI agent that you deploy with a single command and stop thinking about.</p>
<p>I had a sandbox running by the end of the talk. Forked the repo, configured it, deployed. I&#39;d been running OpenClaw on an old laptop to tinker with. The Sandbox deployment replaced that entirely. No hardware to keep running, no laptop lid that needs to stay open.</p>
<h2 id="kilo-code">Kilo Code</h2>
<p>John Fawcett from <a href="https://kilo.ai/" target="_blank" rel="noopener noreferrer">Kilo Code</a> presented in one of Ade Oshineye&#39;s lightning sessions. It&#39;s an open-source AI coding agent. VS Code, JetBrains, CLI. Over 2 million users, 500+ model options, and an orchestrator mode that coordinates planner, coder, and debugger agents on complex tasks. It forked from Cline and Roo Code, raised $8 million, and recently launched KiloClaw, a hosted version that runs coding tasks in the cloud without tying up your local machine. The talk focused on orchestrating tens of coding agents per developer using Cloudflare Containers and Sandboxes.</p>
<p>The orchestrator concept is familiar. I built something similar with <a href="/blog/agents-when-claude-works-autonomously">autonomous-coder</a>, a multi-agent system that coordinates 7 specialised agents (frontend, backend, design, QA, DevOps, docs, research) with dependency graphs, heartbeats, and checkpoint recovery. 2,757 lines of coordination code. The hard lesson from building it: the coordination layer is more work than the agents themselves. Kilo Code is productising that same pattern. Break a complex task into subtasks, assign each to a specialised agent, coordinate the results. The difference is they&#39;ve packaged it into something 2 million people can use without writing the orchestration from scratch.</p>
<h2 id="media-industry-meetup-ai-crawl-control-security-and-monetization">Media Industry Meetup: AI Crawl Control, Security and Monetization</h2>
<p>This session was aimed at the publishing industry. Cloudflare now <a href="https://blog.cloudflare.com/introducing-ai-crawl-control/" target="_blank" rel="noopener noreferrer">blocks all AI crawlers by default</a> on new websites. That&#39;s the baseline. From there, publishers get three options for each crawler: allow free access, charge per request, or block entirely.</p>
<p><a href="https://blog.cloudflare.com/introducing-pay-per-crawl/" target="_blank" rel="noopener noreferrer">Pay-per-crawl</a> is the interesting middle ground. It uses the HTTP 402 status code (the same standard the x402 Foundation is building on) to let publishers set a flat per-request price. The crawler authenticates, pays, gets the content. Cloudflare handles billing, aggregation, and distribution. Publishers like DMGT, Associated Press, and Conde Nast are already on board.</p>
<p>The room was mostly media and publishing people, not developers. The questions were practical. How do you price access? How do you differentiate between a crawler training a model and one fetching a snippet for a citation? What happens when agents replace the traffic that ad revenue depends on?</p>
<p>Nobody had clean answers. But the questions are the right ones. The agentic internet needs economic infrastructure as much as it needs compute and security. Pricing models for agent access to content don&#39;t exist yet. They&#39;re being figured out now, and the publishers in that room were trying to work out if the numbers would add up.</p>
<h2 id="what-i-took-away">What I Took Away</h2>
<p>I run my site on Cloudflare Workers. Blog data in D1, images in R2, AI features powered by Workers AI. I&#39;ve been on this platform for over a year. What struck me at Connect wasn&#39;t any single announcement. It was the coherence of the vision.</p>
<p>Every product slots into the agent story. Workers for compute, Durable Objects for state, Sandboxes for persistent environments, AI Gateway for security, R2 and D1 for storage. It&#39;s not a pivot. It&#39;s a logical extension of what they already built. The serverless edge platform designed for web applications turns out to be what AI agents need too.</p>
<p>Right now, agents still browse websites and fill in forms because that&#39;s the interface that exists. The agentic internet means building the native ones. MCP servers instead of screen scraping. Agent-to-agent authentication instead of OAuth flows designed for humans. Programmatic payments instead of checkout pages.</p>
<p>I left The Brewery thinking about what this means for the tools I use daily. My MCP servers already give Claude access to Cloudflare, GitHub, and my NAS. The Sandbox model could let those agents run persistently instead of dying when I close the terminal. Mesh and MCP Server Portals give me a path to making my TrueNAS MCP server remotely accessible without exposing my home network.</p>
<p>The infrastructure is shipping faster than I can explore it. Every session introduced something I wanted to try, and I ran out of day before I ran out of ideas. The agentic internet isn&#39;t a concept deck anymore. It&#39;s live, and the challenge now is finding the time to build on it.</p>
]]></content:encoded>
      <category>cloudflare</category>
      <category>ai</category>
      <category>agents</category>
      <category>mcp</category>
      <category>events</category>
    </item>
    <item>
      <title>Agents: When Claude Works Autonomously</title>
      <link>https://iammattl.com/blog/agents-when-claude-works-autonomously</link>
      <guid isPermaLink="true">https://iammattl.com/blog/agents-when-claude-works-autonomously</guid>
      <description>Skills tell Claude how. MCP servers give Claude access. Agents let Claude work autonomously. The final post in the Extending Claude Code series covers subagents, agent libraries, multi-agent orchestration, and the trust question.</description>
      <pubDate>Mon, 13 Apr 2026 08:18:00 GMT</pubDate>
      <enclosure url="https://iammattl.com/images/blog/agents-when-claude-works-autonomously/1776068536216.webp?w=600" type="image/webp" length="0"/>
      <content:encoded><![CDATA[<p>The <a href="/blog/mcp-servers-connecting-claude-to-real-infrastructure">last post</a> covered MCP servers. Giving Claude direct access to your infrastructure. Your NAS, your databases, your running services. Skills tell Claude how to do things. MCP servers give Claude access to the systems where things happen.</p>
<p>But in both cases, you&#39;re still driving. You ask a question, Claude answers. You give an instruction, Claude executes. Every step goes through you.</p>
<p>Agents change that. You define a task and a set of boundaries. Claude figures out the steps, delegates work, runs things in parallel, and comes back with results. The shift isn&#39;t from manual to automatic. It&#39;s from directing every action to defining the scope and letting execution happen within it.</p>
<p>This is the final post in the series. It&#39;s also where the other pieces come together. Skills define methodology. MCP servers provide access. Agents use both to work independently.</p>
<h2 id="what-an-agent-actually-is">What an Agent Actually Is</h2>
<p>In Claude Code, an agent is a scoped instance of Claude that handles one part of a larger task. You&#39;ll see them called subagents. The idea is straightforward: instead of one Claude doing everything in sequence, you spin up focused instances that each handle a specific job.</p>
<p>Each subagent gets its own context window, its own tool access, its own area of focus. This matters more than it sounds. Context windows are finite. A subagent that only thinks about schema validation doesn&#39;t waste tokens on performance metrics or content analysis. It does one thing, and it does it with full attention.</p>
<p>An agent definition is a markdown file with frontmatter. A name, a description, the tools it&#39;s allowed to use. Below that, its instructions. Same format as a skill, but the intent is different. A skill tells Claude how to do something. An agent tells Claude to go do it.</p>
<pre><code class="language-yaml">---
name: seo-technical
description: Technical SEO specialist. Analyzes crawlability,
  indexability, security, URL structure, mobile optimization,
  Core Web Vitals, and JavaScript rendering.
tools: [Read, Bash, Write, Glob, Grep]
---
</code></pre>
<p>The description serves the same purpose as a skill trigger. It tells the orchestrating agent what this subagent is good at, so it knows when to delegate.</p>
<h2 id="subagents-in-practice">Subagents in Practice</h2>
<p>The clearest example I have is the SEO audit from the <a href="/blog/plugins-and-skills-making-claude-work-your-way">plugins post</a>. I mentioned it there but didn&#39;t go deep. Here&#39;s what actually happens.</p>
<p>When I run <code>/seo audit</code> on a URL, the orchestrator skill spawns 6 subagents in parallel:</p>
<ul>
<li><strong>Technical</strong> analyses crawlability, indexability, security headers, URL structure, mobile optimisation, Core Web Vitals</li>
<li><strong>Content</strong> evaluates E-E-A-T signals, readability, content depth, thin content detection</li>
<li><strong>Schema</strong> detects and validates structured data, generates missing markup</li>
<li><strong>Sitemap</strong> validates XML sitemaps, checks URL coverage, identifies gaps</li>
<li><strong>Performance</strong> measures Core Web Vitals, analyses page load waterfall</li>
<li><strong>Visual</strong> takes screenshots at desktop and mobile breakpoints, checks above-the-fold content</li>
</ul>
<p>Each runs independently. They don&#39;t share context. They don&#39;t wait for each other. The orchestrator waits for all 6 to complete, then synthesises the results into a scored report with a prioritised action plan.</p>
<p>What would take an hour of sequential analysis finishes in minutes. Not because any individual check is faster, but because they all run at the same time. The parallelism is the point.</p>
<p>The other benefit is less obvious. Each subagent is a specialist. The schema agent knows schema types, validation rules, and Google&#39;s current requirements. It doesn&#39;t need to know about robots.txt parsing or content readability scores. Narrower focus means better results on each individual check.</p>
<h2 id="agent-libraries-context-without-repetition">Agent Libraries: Context Without Repetition</h2>
<p>Subagents solve the parallelism problem. Agent libraries solve the knowledge problem.</p>
<p>I have a homelab. TrueNAS server, n8n for workflow automation, Docker containers, Nginx Proxy Manager for routing. Multiple projects deploy to it. This site, a price comparison tool, a YouTube automation pipeline, a file converter app. Every project needs the same infrastructure knowledge. IP addresses, deployment procedures, Docker conventions, n8n API patterns.</p>
<p>The obvious approach is to put all of that in each project&#39;s CLAUDE.md. It works, but it duplicates everything. Update the n8n API endpoint? Change it in 5 files. Add a new deployment convention? Same story. And every project loads context it doesn&#39;t need for the current task.</p>
<p>So I built a homelab agent library. It&#39;s a layered context system with four levels:</p>
<p><strong>Global</strong> loads every time. The infrastructure map. IP addresses, service endpoints, network layout, conventions that apply everywhere.</p>
<p><strong>Technology</strong> loads when working with specific tools. There&#39;s an n8n layer with API patterns, workflow design rules, and known gotchas. A Docker layer with container management patterns. Each one only loads when relevant.</p>
<p><strong>Purpose</strong> loads for specific activities. The deployment layer knows how to get a service from a local Docker Compose file to a running container on TrueNAS. It doesn&#39;t load when you&#39;re just editing code.</p>
<p><strong>Project</strong> loads for specific codebases. The iammattl layer knows this site runs on Cloudflare Workers. The techpartprices layer knows its deployment target is different. Project-specific context without polluting the global scope.</p>
<pre><code class="language-yaml">layers:
  - path: layers/global
    scope: always
  - path: layers/n8n
    scope: technology
  - path: layers/docker
    scope: technology
  - path: layers/deployment
    scope: purpose
  - path: layers/projects/iammattl
    scope: project
</code></pre>
<p>Alongside the layers, there are skills and rules. Skills are reusable procedures. <code>deploy-container</code> knows the exact steps: validate the compose file, transfer to TrueNAS, build and start, verify the health check, optionally set up the reverse proxy. Rules are hard constraints. <code>deployment-safety.md</code> defines what&#39;s not allowed regardless of which agent runs. <code>docker-wsl.md</code> captures a specific gotcha about Docker credential helpers in WSL2.</p>
<p>The compound effect is that new projects get deployment knowledge without duplicating anything. I add a project layer with the specifics, and the existing infrastructure knowledge is already there.</p>
<h2 id="multi-agent-orchestration">Multi-Agent Orchestration</h2>
<p>The first two examples are practical and approachable. This one is the far end of the spectrum. Most people won&#39;t need it. But it shows where the model goes when you push it.</p>
<p>I forked and extended a multi-agent orchestration system called autonomous-coder. It coordinates 7 specialised agents: frontend, backend, design, QA, DevOps, documentation, and research. Given a set of tasks with dependencies, it figures out what can run in parallel and executes them simultaneously.</p>
<p>The process works like this:</p>
<ol>
<li><strong>Plan.</strong> Analyse task dependencies. Build a dependency graph. Group tasks into levels where everything in a level can run concurrently.</li>
<li><strong>Spawn.</strong> Each task gets assigned to a specialised agent based on its type. Agents launch as separate OS processes. True parallelism, not async.</li>
<li><strong>Coordinate.</strong> A state manager handles inter-agent communication through file-based IPC with proper locking. Each agent sends heartbeats every 10 seconds. If a heartbeat stops for 60 seconds, the coordinator flags it as crashed.</li>
<li><strong>Verify.</strong> Design tasks hit a quality gate. The system checks for screenshots at desktop and mobile breakpoints. No screenshots, no pass. It auto-creates blocker tasks with Playwright instructions if the verification is missing.</li>
<li><strong>Recover.</strong> Checkpoints save progress. If an agent crashes mid-task, work resumes from the last checkpoint instead of restarting from scratch.</li>
</ol>
<p>The result is 2-3x speedup on multi-component tasks. 13 Python modules, 2,757 lines of coordination code. The agents themselves are the simple part. The coordination is where the complexity lives.</p>
<p>I&#39;m being specific about the numbers because they tell the real story. The orchestrator, the state manager, the heartbeat monitor, the recovery system. That&#39;s more code than the agents do actual work. If you&#39;re thinking about building something like this, know that the hard problem isn&#39;t giving Claude tasks. It&#39;s managing what happens when multiple Claude instances work on the same codebase at the same time.</p>
<h2 id="the-trust-question">The Trust Question</h2>
<p>This is the part people actually want to talk about. How much can you trust an agent to work unsupervised?</p>
<p>The honest answer: it depends entirely on the task.</p>
<p><strong>Where agents work well:</strong></p>
<ul>
<li>Well-scoped tasks with clear success criteria. &quot;Analyse this page for SEO issues and score it&quot; has a defined output.</li>
<li>Repetitive work across a known pattern. Deploying containers, running audits, generating boilerplate.</li>
<li>Parallel analysis where each piece is independent. The SEO audit works because the 6 subagents don&#39;t need to coordinate.</li>
<li>Anything where the methodology is fully defined and the cost of being wrong is low.</li>
</ul>
<p><strong>Where they don&#39;t:</strong></p>
<ul>
<li>Ambiguous requirements. If you can&#39;t define the success criteria, an agent can&#39;t either.</li>
<li>Novel architecture decisions. Agents are good at following established patterns, not inventing new ones.</li>
<li>High-stakes operations with slow feedback loops. An agent that deploys to production needs more guardrails than one that reads logs.</li>
<li>Tasks that require cross-agent coordination on shared state. This is technically solvable (autonomous-coder does it) but the overhead is significant.</li>
</ul>
<p>The practical rule I use: if I&#39;d hand the task to a competent developer with clear written instructions, an agent can probably handle it. If the task needs judgement that comes from experience and context I can&#39;t easily write down, I stay in the loop.</p>
<p>Guardrails matter more than capability. The TrueNAS MCP server from the last post blocks privileged containers and dangerous mounts by default. That&#39;s a guardrail baked into the infrastructure, not into a prompt. When an agent has deployment access, the constraints need to live in the system, not in the instructions. Instructions get ignored under edge cases. System-level constraints don&#39;t.</p>
<p>Trust builds incrementally. Start with read-only agents. Things that analyse, report, and suggest but don&#39;t modify anything. Once you&#39;re confident in the analysis, graduate to write access. Then to autonomous execution. Same way you&#39;d onboard a new team member. You don&#39;t hand someone production access on day one.</p>
<h2 id="what-i-got-wrong">What I Got Wrong</h2>
<p><strong>Too many concurrent agents hit limits faster than expected.</strong> Six subagents running simultaneously means six context windows, six sets of tool calls, six streams of output. The resource consumption scales linearly but the coordination overhead scales worse than that. I&#39;ve learned to be deliberate about how many agents run at once rather than parallelising everything because I can.</p>
<p><strong>Overly broad agent definitions produce mediocre work.</strong> Same lesson as skills. An agent defined as &quot;handle all frontend tasks&quot; makes worse decisions than one defined as &quot;analyse CSS specificity issues and propose fixes.&quot; Narrower scope, better results.</p>
<p><strong>Autonomous doesn&#39;t mean unchecked.</strong> The visual verification gate in autonomous-coder exists because I shipped broken UI without it. The agent finished the task, reported success, and the layout was wrong. Now design tasks don&#39;t pass without screenshots proving the output looks right. Every quality gate I&#39;ve added was in response to something going wrong.</p>
<p><strong>Coordination is harder than execution.</strong> The state management, heartbeats, and recovery system in autonomous-coder account for more code than the agents themselves. If your agents need to share state or depend on each other&#39;s output, expect the coordination layer to be the bulk of the work.</p>
<h2 id="where-to-start">Where to Start</h2>
<p>If you&#39;ve followed this series and have skills and MCP servers set up, adding agents is the natural next step.</p>
<p><strong>Start with a subagent in an existing skill.</strong> Take something that runs sequentially and parallelise one piece. If your deployment skill checks three things in sequence and they&#39;re independent, make them three subagents.</p>
<p><strong>Start read-only.</strong> An agent that analyses but doesn&#39;t modify is low risk and immediately useful. Let it prove itself before you give it write access.</p>
<p><strong>Define boundaries before capabilities.</strong> What the agent can&#39;t do matters more than what it can. Blocked operations, restricted file paths, required verification steps. Set these first.</p>
<p><strong>Build a context library when you see duplication.</strong> If you&#39;re copying the same infrastructure context into multiple CLAUDE.md files, extract it into a shared library. The layered loading means agents only get the context they need.</p>
<h2 id="the-series-arc">The Series Arc</h2>
<p>Five posts. One progression.</p>
<p><a href="/blog/getting-started-with-claude">Getting started</a>. Claude as a conversation partner. Give it good inputs, get better outputs.</p>
<p><a href="/blog/what-ive-learned-building-projects-with-claude-code">Building projects</a>. Claude as a daily tool. CLAUDE.md as institutional memory. The workflow that makes it reliable.</p>
<p><a href="/blog/plugins-and-skills-making-claude-work-your-way">Skills and plugins</a>. Claude remembers how to do things. Package expertise so it runs the same way every time.</p>
<p><a href="/blog/mcp-servers-connecting-claude-to-real-infrastructure">MCP servers</a>. Claude connects to real infrastructure. Your databases, your servers, your running services. Access without tab switching.</p>
<p>Agents. Claude works autonomously within your boundaries. Delegation, parallelism, and knowing when to step back.</p>
<p>Each layer compounds on the last. Skills are more useful with MCP access. Agents are more useful with skills and MCP servers combined. The whole stack works because each piece does one thing and they compose naturally.</p>
<p>The goal was never full autonomy. It&#39;s the right amount of autonomy for the task at hand. Sometimes that&#39;s a chat message. Sometimes it&#39;s 6 agents running in parallel across your infrastructure. The skill isn&#39;t in building the most autonomous system possible. It&#39;s in knowing which level of autonomy the current task actually needs.</p>
]]></content:encoded>
      <category>claude-code</category>
      <category>ai</category>
      <category>agents</category>
      <category>automation</category>
      <category>developer-tools</category>
    </item>
    <item>
      <title>MCP Servers: Connecting Claude to Real Infrastructure</title>
      <link>https://iammattl.com/blog/mcp-servers-connecting-claude-to-real-infrastructure</link>
      <guid isPermaLink="true">https://iammattl.com/blog/mcp-servers-connecting-claude-to-real-infrastructure</guid>
      <description>Skills tell Claude how to do things. MCP servers tell it where to look. How I use Cloudflare, GitHub, Context7, Chrome DevTools, and a custom TrueNAS server to give Claude direct access to real infrastructure.</description>
      <pubDate>Tue, 07 Apr 2026 07:59:00 GMT</pubDate>
      <enclosure url="https://iammattl.com/images/blog/mcp-servers-connecting-claude-to-real-infrastructure/1775497740178.webp?w=600" type="image/webp" length="0"/>
      <content:encoded><![CDATA[<p>The <a href="/blog/plugins-and-skills-making-claude-work-your-way">last post</a> covered skills and plugins. Reusable expertise that tells Claude how to do things. A skill knows the methodology. It knows the steps. But it can only work with what Claude can already see.</p>
<p>That&#39;s the codebase in front of it. Files, terminal output, whatever you paste into the conversation. Everything else, your infrastructure, your databases, your running services, lives behind a wall Claude can&#39;t reach.</p>
<p>MCP servers remove that wall.</p>
<h2 id="what-mcp-actually-is">What MCP Actually Is</h2>
<p>MCP stands for Model Context Protocol. The name is more intimidating than the concept.</p>
<p>An MCP server is a small program that gives Claude access to an external system. It exposes tools. Claude calls those tools the same way it runs a shell command or reads a file. The difference is that the tool might query a database, take a browser screenshot, or deploy a container to your NAS.</p>
<p>Add a server, Claude gets new capabilities. Remove it, those capabilities go away. The interface is standardised. Any MCP server works with any MCP-compatible client. Claude Code, the desktop app, the web app, other AI tools that support the protocol.</p>
<p>You don&#39;t need to understand the protocol to use them. You install a server, point it at your infrastructure, and Claude starts using the tools it provides. The protocol handles the plumbing.</p>
<h2 id="the-servers-i-use">The Servers I Use</h2>
<p>I have a handful of MCP servers that stay on permanently. Cloudflare, GitHub, Context7, and Chrome DevTools. The rest I enable when I need them and disable when I don&#39;t. Here&#39;s how I use the core ones, and a few of the situational servers that are worth mentioning.</p>
<h3 id="cloudflare-where-my-sites-run">Cloudflare — Where My Sites Run</h3>
<p>This site runs on Cloudflare Workers. The blog data lives in D1. Images live in R2. The Cloudflare MCP server gives Claude direct access to all of it.</p>
<p>I can query the blog database mid-conversation. Check how many posts are published, pull content for review, verify a migration ran correctly. I can list Workers, check KV namespaces, manage R2 buckets. It&#39;s infrastructure management without leaving the terminal.</p>
<p>The moment this clicked for me was when I was writing the previous blog post. I needed to check the exact slug and status of a draft in D1. Instead of opening the Cloudflare dashboard, finding the database, writing a SQL query, I just asked. Claude queried D1, showed me the results, and we kept working. Trivial on its own. But those small context switches add up across a day of work.</p>
<h3 id="github-pr-and-issue-management">GitHub — PR and Issue Management</h3>
<p>GitHub is the other server I can&#39;t turn off. PR creation, issue management, code search across repos. It handles the full workflow. Create a branch, push changes, open a PR with a description, all from conversation. No tab switching to the GitHub UI for routine operations.</p>
<h3 id="context7-current-documentation-on-demand">Context7 — Current Documentation on Demand</h3>
<p>This one is deceptively important. Context7 fetches current library documentation in real time. When Claude is writing code that uses a specific library, it can pull the latest docs instead of relying on training data.</p>
<p>Training data has a cutoff. Libraries change. APIs get deprecated, new methods get added, configuration formats evolve. Without Context7, Claude sometimes generates code using outdated patterns. With it, Claude checks the current documentation first.</p>
<p>I use it constantly when working with Next.js, Cloudflare Workers, and Drizzle ORM. All three move fast. The difference between &quot;this worked six months ago&quot; and &quot;this works now&quot; matters when you&#39;re deploying to production.</p>
<h3 id="chrome-devtools-live-browser-inspection">Chrome DevTools — Live Browser Inspection</h3>
<p>The Chrome DevTools MCP server connects Claude to a running browser. It can navigate pages, take screenshots, inspect the DOM, read console output, monitor network requests, and run Lighthouse audits.</p>
<p>For frontend work, this is the one that changes the workflow most. Instead of describing what you see on screen, Claude sees it directly. &quot;The layout breaks on mobile&quot; becomes Claude taking a screenshot, identifying the issue, fixing the CSS, and taking another screenshot to confirm. The feedback loop tightens from minutes to seconds.</p>
<p>I use it alongside the SEO skills from the last post. The visual analysis agent takes screenshots at desktop and mobile breakpoints. The performance agent runs Lighthouse. Having real browser data instead of guessing makes the analysis credible.</p>
<h3 id="enabled-when-needed">Enabled When Needed</h3>
<p>The rest come and go depending on the task.</p>
<p><strong>TrueNAS</strong> is the one I&#39;m most proud of. I <a href="https://github.com/svnstfns/truenas-mcp-server" target="_blank" rel="noopener noreferrer">forked an existing server</a> and heavily customised it. Rewrote authentication, added security validation that blocks privileged containers and dangerous mounts, built Docker Compose to TrueNAS Custom App conversion, added auto-reconnect for dead WebSocket connections. The <a href="https://github.com/IamMattL/truenas-mcp-server" target="_blank" rel="noopener noreferrer">fork</a> has 22 tools, 165 tests, and 80% coverage. When I need to deploy a service to my NAS, I enable it. Claude reads a Docker Compose file, converts it to TrueNAS format, deploys it, and verifies it&#39;s running. One conversation instead of thirty minutes of tab switching.</p>
<p><strong>n8n</strong> handles workflow automation. It runs on my homelab. The MCP server lets Claude create, test, and manage workflows conversationally. Faster than clicking through the node editor for anything beyond a simple two-step automation. The documentation server alongside it means Claude pulls current n8n docs instead of guessing at node configurations.</p>
<p><strong>Playwright</strong> provides browser automation for testing. <strong>Serena</strong> does semantic code navigation, understanding symbols and their relationships rather than just text search.</p>
<h2 id="building-your-own">Building Your Own</h2>
<p>If the system you need isn&#39;t covered by an existing server, you have two options. Fork one that&#39;s close and adapt it, or build from scratch. I&#39;d check first. The TrueNAS server started as a fork. Most of my work was enhancing it to fit my setup, not writing MCP plumbing from zero.</p>
<p>The MCP SDK is available in Python and TypeScript. You define tools with names, descriptions, and parameters. Each tool is a function that does something and returns a result. The SDK handles the protocol, transport, and communication with the client.</p>
<pre><code class="language-python">@server.tool()
async def get_system_info() -&gt; dict:
    &quot;&quot;&quot;Get TrueNAS system information.&quot;&quot;&quot;
    client = await get_client()
    info = await client.get_system_info()
    return {&quot;hostname&quot;: info.hostname, &quot;version&quot;: info.version, ...}
</code></pre>
<p>That&#39;s the shape of it. Define what the tool does, handle the API call, return structured data. The description matters because it&#39;s how Claude decides when to use the tool. Same principle as skill trigger descriptions from the last post.</p>
<p>The harder parts are authentication, error handling, and security validation. Exposing your NAS to an AI tool means thinking about what operations should be allowed. My server blocks privileged containers and dangerous filesystem mounts by default. That kind of guardrail belongs in the server, not in a prompt.</p>
<p>Test thoroughly. The mock mode in the TrueNAS server lets me run the full test suite without a live NAS connection. 165 tests might seem like overkill for an MCP server, but when the tool is managing your storage infrastructure, you want confidence it does what you expect.</p>
<p>If you build something useful, open source it. I published my TrueNAS fork because other homelabbers have the same needs. The original author gets contributions back, the ecosystem grows, and someone else doesn&#39;t have to solve the same problems from scratch.</p>
<h2 id="what-i-got-wrong">What I Got Wrong</h2>
<p>A few lessons from accumulating MCP servers.</p>
<p><strong>Too many servers at once creates noise.</strong> Each server adds tools to Claude&#39;s context. A dozen servers can mean over 100 tools available in every conversation. Most of the time, you need three or four. The rest are consuming context for nothing. I&#39;m more selective now about which servers are active globally versus enabled per project.</p>
<p><strong>Security needs thought, not afterthoughts.</strong> An MCP server with write access to your NAS or your production database is powerful. It&#39;s also a risk if the tool descriptions are ambiguous or the guardrails are missing. Think about what you&#39;re exposing before you connect it. Least privilege applies here the same way it applies everywhere else.</p>
<p><strong>Not all servers are equal quality.</strong> Some community servers are well-tested and maintained. Others are weekend projects with no error handling. Before connecting a server to anything important, read the code. Check the test coverage. Understand what it&#39;s doing with your credentials.</p>
<p><strong>Server descriptions matter more than you&#39;d expect.</strong> If the tool descriptions are vague, Claude either won&#39;t use the server when it should, or will use it when it shouldn&#39;t. Good descriptions include when to use the tool and what it returns. This is the same lesson as skill trigger descriptions. The description is the interface between Claude and the capability.</p>
<h2 id="what-s-next">What&#39;s Next</h2>
<p>Skills tell Claude how to do things. MCP servers give Claude access to the systems where things happen. But in both cases, you&#39;re still driving. You ask, Claude acts, you review, you ask again.</p>
<p>The next step is agents. Claude working autonomously. Spawning subagents that run in parallel, delegating tasks, making decisions within defined boundaries. That&#39;s the final post in this series.</p>
]]></content:encoded>
      <category>Claude Code</category>
      <category>AI</category>
      <category>MCP</category>
      <category>Infrastructure</category>
      <category>DevTools</category>
    </item>
    <item>
      <title>Plugins and Skills: Making Claude Work Your Way</title>
      <link>https://iammattl.com/blog/plugins-and-skills-making-claude-work-your-way</link>
      <guid isPermaLink="true">https://iammattl.com/blog/plugins-and-skills-making-claude-work-your-way</guid>
      <description>Skills and plugins let you package expertise so Claude works consistently across projects. Here&apos;s how I built an SEO suite with 13 skills and 6 subagents, and the patterns that apply to any workflow.</description>
      <pubDate>Mon, 30 Mar 2026 07:00:00 GMT</pubDate>
      <enclosure url="https://iammattl.com/images/blog/plugins-and-skills-making-claude-work-your-way/1774823563642.webp?w=600" type="image/webp" length="0"/>
      <content:encoded><![CDATA[<p>In the <a href="/blog/getting-started-with-claude">last post</a>, I walked through how to get more out of Claude. Give it real source material, iterate until it sounds like you, extract your tone of voice, build up context so each conversation isn&#39;t starting from scratch.</p>
<p>That post ended with &quot;build up context over time.&quot; Claude now does this automatically. It has a persistent memory system that learns your preferences, your role, how you like to work, and carries that across conversations. Combined with CLAUDE.md files that give it <a href="/blog/what-ive-learned-building-projects-with-claude-code">project-specific context</a>, Claude remembers who you are and what you&#39;re working on.</p>
<p>But there&#39;s still a gap. Memory knows your preferences. CLAUDE.md knows your codebase. Neither one captures <em>how you want things done</em>. The methodology. The steps you follow when reviewing a PR, auditing a page for SEO issues, or writing a commit message. You&#39;ve figured out what works through trial and error. You&#39;re still explaining the process manually every time.</p>
<p>Skills and plugins fill that gap. They&#39;re reusable expertise that travels with you across projects. The difference between &quot;let me explain how I want this done&quot; and &quot;just do it the way we agreed.&quot;</p>
<p>If you&#39;ve ever created a shell alias, a code snippet, or an editor macro, you already understand the principle. This is the same thing, applied to AI.</p>
<h2 id="the-landscape">The Landscape</h2>
<p>Before getting into the details, here&#39;s the mental model. Three layers of context, then the automation on top.</p>
<p><strong>Memory</strong> is personal context. Claude learns your preferences, your role, your working style and carries it across conversations automatically. This is the &quot;build up context over time&quot; from the <a href="/blog/getting-started-with-claude">getting started post</a>, but built in.</p>
<p><strong>CLAUDE.md</strong> is project context. It lives in your repo and tells Claude how this specific codebase works. The architecture, the gotchas, the rules. Covered in a <a href="/blog/what-ive-learned-building-projects-with-claude-code">previous post</a>.</p>
<p><strong>Skills</strong> are reusable playbooks. A skill defines a methodology or workflow that works across any project. Think &quot;how to run an SEO audit&quot; rather than &quot;how this repo is structured.&quot;</p>
<p><strong>Slash commands</strong> are the user-facing shortcuts. Type <code>/commit</code> or <code>/seo audit</code> and a full workflow runs. The interface layer on top of skills.</p>
<p><strong>Hooks</strong> are guardrails. They run automatically before or after Claude takes an action. You don&#39;t invoke them. They fire when something happens and prevent mistakes before they land.</p>
<p><strong>Plugins</strong> bundle everything together. Skills, commands, hooks, and agents in a single installable package. Like a VS Code extension, but for Claude.</p>
<h3 id="where-they-live">Where They Live</h3>
<p>All three surfaces support these concepts now. The web app (claude.ai), the desktop app, and Claude Code in the terminal.</p>
<p>On the web and desktop, skills are installed through Settings as ZIP packages. Connectors give you one-click access to external services like GitHub, Slack, and Google Drive. The Cowork plugin marketplace has pre-built plugins for specific workflows. Slash commands come bundled with installed skills and plugins.</p>
<p>In Claude Code, everything is file-driven. Skills are markdown files in directories. MCP servers are configured in <code>settings.json</code>. Slash commands are <code>.md</code> files you write yourself. Hooks give you full lifecycle automation. It&#39;s more hands-on, but the tradeoff is complete control over how everything works.</p>
<p>The underlying format is the same. A skill is a <code>SKILL.md</code> file whether you&#39;re uploading it through the GUI or placing it in a directory. The <em>why</em> is identical across surfaces. Package your expertise so Claude does it consistently.</p>
<p>One thing worth knowing. Skills created in Claude Code don&#39;t automatically appear in the desktop or web app, and vice versa. But Claude Code&#39;s remote control feature lets you connect the CLI to the desktop app, giving you access to your CLI skills and tools from the desktop interface.</p>
<h2 id="skills-in-practice">Skills in Practice</h2>
<p>The best way to explain skills is to show one. I use <a href="https://github.com/searchfit/searchfit-seo" target="_blank" rel="noopener noreferrer">an SEO analysis suite</a> that has 13 specialised skills and 6 subagents. I&#39;ll walk through three levels of complexity so you can see where to start and where it can go.</p>
<h3 id="level-1-a-focused-skill">Level 1: A Focused Skill</h3>
<p>Here&#39;s <code>seo-schema</code>, the simplest skill in the suite. It detects, validates, and generates Schema.org structured data for any page.</p>
<pre><code class="language-yaml">---
name: seo-schema
description: &gt;
  Detect, validate, and generate Schema.org structured data.
  JSON-LD format preferred. Use when user says &quot;schema&quot;,
  &quot;structured data&quot;, &quot;rich results&quot;, &quot;JSON-LD&quot;, or &quot;markup&quot;.
---
</code></pre>
<p>That&#39;s the frontmatter. A name, and a description. The description is doing more work than it looks. This is how Claude decides whether to activate the skill. Those trigger phrases at the end (&quot;schema&quot;, &quot;structured data&quot;, &quot;rich results&quot;) mean that when I type &quot;check the structured data on this page&quot;, Claude automatically loads the skill and follows its methodology.</p>
<p>Get the description wrong and the skill never fires. Too broad and it fires when you don&#39;t want it. This is the single most important line in any skill file.</p>
<p>Below the frontmatter is plain markdown. Detection steps, validation rules, a list of current and deprecated schema types, output format. The skill tells Claude exactly how to approach the task, what to check, and how to present the results. It&#39;s the methodology I&#39;d follow myself, written down once so I never have to explain it again.</p>
<p>One detail worth calling out. The skill references external files (<code>references/schema-types.md</code>) but explicitly says &quot;do NOT load all at startup.&quot; Claude loads reference material on demand, only when it&#39;s actually needed. This is progressive disclosure. It keeps the context window clean when you have dozens of skills installed, and means Claude isn&#39;t burning tokens reading about deprecated schema types unless it&#39;s actually validating markup.</p>
<h3 id="level-2-the-orchestrator">Level 2: The Orchestrator</h3>
<p>Individual skills are useful on their own. But the real power shows up when they compose.</p>
<p>The main <code>/seo</code> skill acts as a router. It doesn&#39;t do analysis itself. It reads what you&#39;re asking for, detects the business type from homepage signals, and delegates to the right specialist.</p>
<pre><code>/seo audit &lt;url&gt;        → Full website audit with parallel delegation
/seo schema &lt;url&gt;       → Schema detection and generation
/seo technical &lt;url&gt;    → Technical SEO (8 categories)
/seo content &lt;url&gt;      → E-E-A-T and content quality
/seo geo &lt;url&gt;          → AI search optimisation
/seo plan &lt;type&gt;        → Strategic SEO planning
</code></pre>
<p>Twelve sub-commands, each mapping to a specialist skill. One entry point, many capabilities.</p>
<p>The industry detection is a good example of why this works better as a skill than as a prompt you type each time. The orchestrator analyses homepage signals to classify the site. SaaS sites have pricing pages and free trial CTAs. Local businesses have phone numbers and service areas. E-commerce sites have product schemas and cart functionality. The analysis adjusts based on what it finds. That&#39;s logic that was refined over multiple iterations. Once it&#39;s in the skill, it runs the same way every time, whether you&#39;re auditing a SaaS product or a local plumber&#39;s website.</p>
<h3 id="level-3-parallel-delegation">Level 3: Parallel Delegation</h3>
<p><code>/seo audit</code> takes it further. Instead of running checks sequentially, it spawns 6 subagents in parallel. Technical SEO, content quality, schema validation, sitemap analysis, performance measurement, and visual testing. Each subagent runs independently with its own tools and area of focus.</p>
<p>The output is a scored report (0-100), a prioritised action plan grouped by severity (Critical, High, Medium, Low), and desktop plus mobile screenshots. What would take an hour of sequential analysis finishes in minutes.</p>
<p>I won&#39;t go deep on agents here. That&#39;s a topic for its own post. The point is that skills can delegate to agents, and the skill defines when and how that delegation happens.</p>
<h3 id="the-file-structure">The File Structure</h3>
<p>Here&#39;s what the full suite looks like on disk:</p>
<pre><code>~/.claude/skills/
├── seo/                    # Main orchestrator
│   ├── SKILL.md            # Router + scoring methodology
│   ├── references/         # On-demand knowledge files
│   ├── schema/             # JSON-LD templates
│   └── scripts/            # Python analysis tools
├── seo-audit/SKILL.md      # Full audit workflow
├── seo-schema/SKILL.md     # Schema detection/generation
├── seo-technical/SKILL.md  # Technical SEO
├── seo-content/SKILL.md    # E-E-A-T analysis
├── seo-sitemap/SKILL.md    # Sitemap analysis
├── seo-images/SKILL.md     # Image optimisation
├── seo-geo/SKILL.md        # AI search optimisation
├── seo-plan/SKILL.md       # Strategic planning
├── seo-page/SKILL.md       # Single page analysis
├── seo-programmatic/SKILL.md
├── seo-competitor-pages/SKILL.md
└── seo-hreflang/SKILL.md

~/.claude/agents/
├── seo-technical.md        # 6 specialist subagents
├── seo-content.md          # for parallel audit
├── seo-schema.md           # delegation
├── seo-sitemap.md
├── seo-performance.md
└── seo-visual.md
</code></pre>
<p>13 skills, 6 agents, supporting references and scripts. It started as one file. Each new capability was just another <code>SKILL.md</code> following the same pattern.</p>
<p>The full suite is <a href="https://github.com/searchfit/searchfit-seo" target="_blank" rel="noopener noreferrer">open source on GitHub</a> if you want to see the complete implementation.</p>
<h2 id="slash-commands">Slash Commands</h2>
<p>Skills fire automatically when Claude detects relevance. Slash commands are the explicit version. You type <code>/something</code> and a workflow runs on demand.</p>
<p>In Claude Code, a command is a markdown file in <code>.claude/commands/</code>. It can accept arguments, reference files, and run shell commands. On the web and desktop, commands come bundled with installed skills and plugins.</p>
<p>The value is consistency. Take <code>/commit</code> as an example. Without it, committing is a multi-step conversation. &quot;Stage these files, look at the recent commit style, write a message that matches, create the commit.&quot; With the command, it&#39;s one word. Same result every time.</p>
<p>The rule of thumb: if you do something more than three times and the steps are always the same, make it a command.</p>
<h2 id="hooks">Hooks</h2>
<p>Hooks are the part most people skip. They shouldn&#39;t.</p>
<p>A hook runs automatically in response to an event. You don&#39;t type anything. Claude is about to take an action, and your hook intercepts it. Five event types cover most cases:</p>
<ul>
<li><strong>PreToolUse</strong> fires before Claude runs a tool. Block dangerous commands before they execute.</li>
<li><strong>PostToolUse</strong> fires after. Run linting after every file edit, for example.</li>
<li><strong>Stop</strong> fires when Claude finishes a response. Good for notifications or cleanup.</li>
<li><strong>SessionStart</strong> fires when a new conversation begins. Set up context automatically.</li>
<li><strong>UserPromptSubmit</strong> fires when you send a message. Validate or transform input.</li>
</ul>
<p>The practical pattern: every time Claude does something you didn&#39;t want, add a hook. Force-pushed to main? Add a PreToolUse hook that blocks <code>git push --force</code> on protected branches. Forgot to lint? Add a PostToolUse hook that runs the linter after file edits.</p>
<p>Over time, the guardrails build up. The mistakes stop repeating. It&#39;s the same principle as CLAUDE.md, but for actions instead of knowledge.</p>
<p>Hooks are currently a Claude Code feature. The web and desktop apps don&#39;t expose hook authoring directly, though plugins can include hook definitions.</p>
<h2 id="plugins">Plugins</h2>
<p>Once you have a few related skills, some commands, and a hook or two, you&#39;re looking at a plugin. A plugin bundles everything into a single installable package with a <code>plugin.json</code> manifest.</p>
<p>I use several. <a href="https://github.com/nicholasgriffintn/chrome-devtools-mcp" target="_blank" rel="noopener noreferrer">Chrome DevTools MCP</a> for live browser debugging. The <a href="https://github.com/anthropics/claude-code-plugins" target="_blank" rel="noopener noreferrer">GitHub plugin</a> for PR management. <a href="https://github.com/oramasearch/serena" target="_blank" rel="noopener noreferrer">Serena</a> for semantic code navigation. And my own <a href="https://github.com/searchfit/searchfit-seo" target="_blank" rel="noopener noreferrer">SEO suite</a> with 13 skills and 6 agents.</p>
<p>You don&#39;t need to start with a plugin. If it&#39;s just for you and it&#39;s a few files, loose skills work fine. Graduate to a plugin when you&#39;re sharing it, or when you have skills, commands, hooks, and agents that need to work together as a unit.</p>
<h2 id="where-to-start">Where to Start</h2>
<p>If you&#39;ve read this far and want to try it, here&#39;s the progression I&#39;d follow.</p>
<p><strong>Start with one skill</strong> for a task you do weekly. Something focused, like a code review checklist or a deployment verification. Write the <code>SKILL.md</code>, get the trigger description right, and test it by chatting naturally to see if Claude picks it up.</p>
<p><strong>Add a slash command</strong> for anything you do more than three times with the same steps. Commits, PR creation, test runs. One command, consistent output.</p>
<p><strong>Add hooks reactively.</strong> Don&#39;t try to anticipate every failure. Wait until Claude does something you didn&#39;t want, then add the guardrail. They build up naturally.</p>
<p><strong>Graduate to a plugin</strong> when you&#39;ve got 3-4 related skills that belong together. Not before.</p>
<p>The temptation is to over-engineer early. Resist it. The first version of any skill should be embarrassingly simple. The SEO suite I use started as a single skill. It grew to 13 because each addition solved a real problem, not because someone planned it that way.</p>
<h2 id="what-i-got-wrong">What I Got Wrong</h2>
<p>A few lessons from working with these.</p>
<p>Skills that try to do too much don&#39;t work well. A skill that handles &quot;all SEO tasks&quot; is too vague for Claude to use effectively. Splitting it into focused specialists (schema, technical, content) made each one more reliable.</p>
<p>Trigger descriptions need tuning. Too broad and the skill fires on unrelated conversations. Too narrow and you have to invoke it manually every time. The sweet spot takes a few iterations.</p>
<p>Writing skills that duplicate CLAUDE.md is a waste. If the information is project-specific, it belongs in CLAUDE.md. Skills are for methodology that applies everywhere.</p>
<p>And the biggest one: treating the first version as the final version. Skills improve through use. Run them, notice what&#39;s missing, add it. The feedback loop is the point.</p>
<h2 id="what-s-next">What&#39;s Next</h2>
<p>Skills tell Claude how to do things. They encode methodology and expertise. But they can only work with what Claude can already access.</p>
<p>MCP servers change that equation. They give Claude direct access to external systems. Your NAS, your workflow automation, your live documentation. That&#39;s the next post.</p>
]]></content:encoded>
      <category>Claude Code</category>
      <category>AI</category>
      <category>Skills</category>
      <category>Plugins</category>
      <category>Automation</category>
    </item>
    <item>
      <title>Getting Started with Claude - Beyond the Chat Box</title>
      <link>https://iammattl.com/blog/getting-started-with-claude</link>
      <guid isPermaLink="true">https://iammattl.com/blog/getting-started-with-claude</guid>
      <description>Most people use Claude like a search engine with better grammar. Here&apos;s how to actually make it useful.</description>
      <pubDate>Mon, 23 Mar 2026 17:10:18 GMT</pubDate>
      <enclosure url="https://iammattl.com/images/blog/getting-started-with-claude/1774285690678.webp?w=600" type="image/webp" length="0"/>
      <content:encoded><![CDATA[<p>Most people I talk to about Claude use it the same way. Paste a question, get an answer, move on. It works, but it&#39;s barely scratching the surface. I keep getting asked how I get so much out of it, so I figured I&#39;d write down the process I actually follow.</p>
<p>This isn&#39;t about building a full website or anything complex. It&#39;s about getting Claude to work <em>with</em> you instead of just <em>for</em> you.</p>
<h2 id="start-with-something-real">Start with something real</h2>
<p>Don&#39;t open Claude and ask it to &quot;write me a blog post about leadership.&quot; That&#39;s how you get content that sounds like every other AI-generated post on LinkedIn. Instead, give it something to work with.</p>
<p>I start with the subject matter. An article I&#39;ve read, a thread from a forum, notes from a conversation, even a voice memo transcript. The more context Claude has, the less it falls back on generic filler.</p>
<p>A prompt like &quot;write a LinkedIn post about this article&quot; with the article pasted in will get you a first draft that&#39;s already more specific than starting from nothing.</p>
<h2 id="make-it-sound-like-you">Make it sound like you</h2>
<p>The first draft will sound like Claude. That&#39;s fine, it&#39;s a first draft. The real work is in the iteration.</p>
<p>Read through it and start pushing back. Tell Claude what to change and <em>why</em>. Things like:</p>
<ul>
<li>&quot;I wouldn&#39;t use the word &#39;innovative&#39;, swap it for something more specific&quot;</li>
<li>&quot;This reads like a press release, make it more conversational&quot;</li>
<li>&quot;I use shorter sentences than this&quot;</li>
<li>&quot;Drop the exclamation marks, I don&#39;t write like that&quot;</li>
</ul>
<p>Each correction teaches Claude something about how you communicate. After a few rounds, the output starts to sound less like AI and more like you.</p>
<h2 id="extract-your-tone-of-voice">Extract your tone of voice</h2>
<p>Once you&#39;ve got a piece of writing you&#39;re happy with, ask Claude to extract your tone of voice from it. Get it to describe how you write. Sentence length, vocabulary, structure, what you avoid.</p>
<p>This is the part most people skip, and it&#39;s probably the most valuable step. You end up with a reference document that captures how you actually communicate. Things like whether you use colons or semicolons, whether you lean on specific verbs, whether you quantify things or keep it vague.</p>
<p>Use that as a reference for everything you write after. Each new piece gets easier because Claude isn&#39;t starting from zero. It&#39;s starting from <em>you</em>.</p>
<h2 id="build-up-context-over-time">Build up context over time</h2>
<p>Claude doesn&#39;t remember your previous conversations by default. But you can fix that.</p>
<p>If you&#39;re using Claude Pro, you can save your tone of voice document and key preferences as project knowledge. Every new conversation in that project starts with that context already loaded.</p>
<p>If you&#39;re using Claude Code, the terminal-based version, it has a built-in memory system. I use a <code>CLAUDE.md</code> file in every project that acts as institutional memory. A plain markdown doc that tells Claude how the project works, what conventions to follow, and what to avoid. Each conversation picks up where the last one left off.</p>
<p>The pattern is the same either way. Stop treating each conversation as a blank slate.</p>
<h2 id="the-compound-effect">The compound effect</h2>
<p>The first post took me a while. Lots of back and forth, lots of corrections. The second one was noticeably faster. By the third or fourth, I was mostly just providing the subject matter and making minor tweaks.</p>
<p>That&#39;s the real payoff. Not any single conversation, but the fact that Claude gets better at being <em>your</em> writing partner the more you invest in teaching it. The same applies to code, documentation, planning. Anything where your specific style and preferences matter.</p>
<h2 id="where-to-go-from-here">Where to go from here</h2>
<p>If you&#39;re just getting started:</p>
<ol>
<li><strong>Pick one real thing to write about.</strong> Not a test, something you&#39;d actually publish.</li>
<li><strong>Give Claude the raw material.</strong> Articles, notes, whatever context you have.</li>
<li><strong>Iterate on the output.</strong> Push back on anything that doesn&#39;t sound like you.</li>
<li><strong>Extract your tone of voice.</strong> Save it somewhere you can reuse it.</li>
<li><strong>Use it as a starting point next time.</strong> The gap between first draft and final version gets smaller every time.</li>
</ol>
<p>That&#39;s it. No special tools required, no complex setup. Just a conversation with a bit more intention behind it.</p>
]]></content:encoded>
      <category>AI</category>
      <category>Claude</category>
      <category>Productivity</category>
      <category>Workflow</category>
    </item>
    <item>
      <title>What I&apos;ve Learned Building Projects with Claude Code</title>
      <link>https://iammattl.com/blog/what-ive-learned-building-projects-with-claude-code</link>
      <guid isPermaLink="true">https://iammattl.com/blog/what-ive-learned-building-projects-with-claude-code</guid>
      <description>After building multiple projects with Claude Code — from Terraform modules managing 400+ Cloudflare zones to a full-stack price comparison site — here&apos;s what actually works when using AI as a pair programmer.</description>
      <pubDate>Mon, 16 Mar 2026 14:44:31 GMT</pubDate>
      <enclosure url="https://iammattl.com/images/blog/what-ive-learned-building-projects-with-claude-code/1773672237883.webp?w=600" type="image/webp" length="0"/>
      <content:encoded><![CDATA[<p>I&#39;ve been using <a href="https://claude.ai/code" target="_blank" rel="noopener noreferrer">Claude Code</a> as my daily pair programmer for about a year now. Across multiple projects — Terraform modules managing 400+ Cloudflare zones, a full-stack price comparison platform with 4,800+ tests, automated workflows, a mobile file converter, and this website — it&#39;s become a core part of how I build software.</p>
<p>Here&#39;s what I&#39;ve picked up along the way.</p>
<h2 id="it-won-t-replace-your-thinking">It Won&#39;t Replace Your Thinking</h2>
<p>The biggest misconception is that you hand over a problem and get a solution back. It doesn&#39;t work like that. The better mental model is a pair programmer who&#39;s read every Stack Overflow answer but has never worked at your company.</p>
<p>Claude doesn&#39;t know your system&#39;s quirks. It doesn&#39;t know that your n8n Code node doesn&#39;t have <code>fetch</code>, or that TrueNAS will silently fail if you use <code>update_custom_app</code> instead of <code>update_compose_config</code>. You learn that through building — and then you teach it.</p>
<p>That&#39;s where the real workflow starts.</p>
<h2 id="the-claude-md-file-changed-everything">The CLAUDE.md File Changed Everything</h2>
<p>Early on, I was repeating myself every conversation. &quot;Don&#39;t use that API, it&#39;s deprecated.&quot; &quot;Test coverage must stay above 80%.&quot; &quot;The CI pipeline works like this.&quot; Every new chat started from zero.</p>
<p>So I started maintaining a CLAUDE.md file in each project — a plain markdown doc that acts as institutional memory. The rules, the gotchas, the architecture decisions, the hard-won lessons from previous sessions.</p>
<p>My Terraform project at work has a 500+ line CLAUDE.md. TechPartPrices has 860+ lines. They grow organically — every time I hit a wall and solve it, the fix goes into CLAUDE.md so I never hit it again.</p>
<p>The result — a single engineer delivering what would normally need a platform team. Not because AI wrote all the code, but because it remembered all the context.</p>
<h2 id="it-s-like-onboarding-a-developer-every-morning">It&#39;s Like Onboarding a Developer Every Morning</h2>
<p>The best way I can describe it is onboarding a very skilled but brand-new hire — every single morning. They&#39;re talented, they learn fast, but they don&#39;t know your codebase yet.</p>
<p>CLAUDE.md is their onboarding doc. The better you write it, the faster they&#39;re productive. I structure mine with:</p>
<ul>
<li><strong>Project overview</strong> — what this is, how it&#39;s deployed</li>
<li><strong>Commands</strong> — how to build, test, deploy</li>
<li><strong>Architecture</strong> — key patterns and why they exist</li>
<li><strong>Gotchas</strong> — the things that&#39;ll waste your afternoon if you don&#39;t know them</li>
<li><strong>Rules</strong> — test coverage thresholds, commit conventions, things that must not break</li>
</ul>
<p>Sounds like effort, but it pays for itself within a day.</p>
<h2 id="push-complexity-into-deterministic-code">Push Complexity Into Deterministic Code</h2>
<p>Here&#39;s a pattern I learned the hard way — AI is roughly 90% accurate per step. Sounds great until you chain 5 steps together and you&#39;re at 59% accuracy. For 10 steps? 35%.</p>
<p>The solution is to push complexity out of the AI&#39;s decision-making and into deterministic code. I use a three-layer approach:</p>
<ol>
<li><strong>Directive layer</strong> — SOPs written in markdown that describe what should happen</li>
<li><strong>Orchestration layer</strong> — Claude reads the directives and decides what to do next</li>
<li><strong>Execution layer</strong> — Python scripts that do the actual work, reliably, every time</li>
</ol>
<p>Claude orchestrates. Code executes. The AI decides <em>what</em> to do — the scripts guarantee <em>how</em> it&#39;s done.</p>
<h2 id="verify-visually-before-testing">Verify Visually Before Testing</h2>
<p>For anything with a UI, I verify visually before writing tests. The instinct with AI-assisted development is to write the code, write the tests, and move on. The problem — you can have a green test suite and a screen that looks like it was built during a power cut.</p>
<p>My workflow for frontend tasks: implement → screenshot → verify it looks right → then write the tests. For backend work, it&#39;s the opposite — tests first. But for UI, the eyes come first.</p>
<h2 id="fetch-the-docs-every-time">Fetch the Docs Every Time</h2>
<p>One rule I don&#39;t break — before implementing anything involving a library or framework, fetch the latest documentation first. I use <a href="https://context7.com" target="_blank" rel="noopener noreferrer">Context7</a> for this. It pulls current docs so Claude isn&#39;t working from training data that might be months out of date.</p>
<p>This single habit has saved me from countless issues with outdated API patterns, deprecated methods, and missed features. <a href="https://tailwindcss.com" target="_blank" rel="noopener noreferrer">Tailwind v4</a> changed how utility classes work under the hood. Without current docs, Claude would happily write Tailwind v3 patterns that silently break.</p>
<h2 id="extending-claude-with-mcp-servers-plugins-skills-and-agents">Extending Claude with MCP Servers, Plugins, Skills, and Agents</h2>
<p>Out of the box, Claude Code is a capable pair programmer. The real shift came when I started wiring it into my actual infrastructure — so it&#39;s not just writing code, it&#39;s operating systems.</p>
<p>I run multiple plugins and MCP servers. Here&#39;s how they fit together.</p>
<p><strong>MCP Servers — Connecting Claude to Your Infrastructure</strong></p>
<p>MCP (Model Context Protocol) servers give Claude direct access to external tools and services. Instead of copying error messages back and forth, Claude can just look.</p>
<p>I built my own TrueNAS MCP server — forked an existing project and extended it to fit my homelab. It connects Claude to my NAS with 22 tools for checking app status, updating Docker Compose configs, managing ZFS snapshots, and monitoring storage. When I&#39;m deploying docker containers, Claude doesn&#39;t need me to SSH in and paste logs. It reads them directly.</p>
<p>My <a href="https://n8n.io" target="_blank" rel="noopener noreferrer">n8n</a> MCP server does the same for workflow automation. Claude can create, update, validate, and test n8n workflows without me touching the UI. The blog post topic curator for TechPartPrices — a 49-node workflow with a two-trigger state machine, Telegram integration, and DALL-E image generation — was built almost entirely through Claude talking to the n8n API.</p>
<p>Context7 fetches live documentation for any library, so Claude is never working from stale training data. Prevents more bugs than any linter.</p>
<p><strong>Plugins — Specialised Capabilities</strong></p>
<p>Plugins add focused tools for specific tasks. Chrome DevTools MCP lets Claude inspect live pages, take screenshots, and debug CSS issues directly in the browser — I used it today to diagnose a Tailwind v4 specificity issue. Playwright handles automated UI testing and visual verification. The GitHub plugin manages PRs and issues without leaving the terminal.</p>
<p>Serena gives Claude semantic code navigation — it can find symbols, trace references, and understand architecture without reading entire files. For large codebases, that&#39;s the difference between Claude being useful and Claude being lost.</p>
<p><strong>Skills — Reusable Expertise</strong></p>
<p>Skills are like playbooks. I&#39;ve built a suite of 13 SEO skills that handle everything from technical audits to schema markup generation. Instead of explaining what an SEO audit involves every time, the skill encodes the methodology. Claude runs the audit, delegates to specialist sub-agents, and produces a scored report.</p>
<p>The pattern works for any domain expertise you find yourself repeating. Package it as a skill — it becomes a one-command operation.</p>
<p><strong>Agents — Autonomous Problem Solving</strong></p>
<p>Agents take this further. Instead of Claude doing one thing at a time, agents spin up specialised sub-processes that work in parallel. A frontend developer agent handles React and CSS. A software architect agent evaluates trade-offs. An SEO agent crawls pages and delegates to six specialist sub-agents simultaneously.</p>
<p>The key insight is delegation. When I run a full site audit, the main agent doesn&#39;t do all the work — it launches a technical SEO agent, a content quality agent, a performance agent, a schema agent, all running concurrently. What would take an hour of sequential analysis happens in minutes.</p>
<p>I&#39;ve built custom agents for specific workflows too. TechPartPrices uses agents for code review, test generation, and deployment validation. Each agent has its own tools, its own system prompt, its own area of expertise — like having a small team, each focused on what they do best.</p>
<p><strong>How It All Connects</strong></p>
<p>A typical session — I ask Claude to deploy an update. It uses the n8n MCP to check the current workflow state, the TrueNAS MCP to update the Docker Compose config, Context7 to verify the latest API patterns, and Playwright to confirm the UI still works. No tab switching. No copy-pasting. Just a conversation that drives real infrastructure.</p>
<p>That&#39;s the shift — Claude stops being a chatbot and becomes an interface to your entire development environment.</p>
<h2 id="the-projects-that-proved-it">The Projects That Proved It</h2>
<p><strong><a href="https://techpartprices.com" target="_blank" rel="noopener noreferrer">TechPartPrices</a></strong> — An Amazon price tracker following 2,400+ products. Built with Next.js, Drizzle ORM, and Cloudflare D1. 4,800+ tests at 80%+ coverage, an n8n Telegram bot for admin, and an automated blog post topic curator. The CLAUDE.md file alone documents 18 n8n gotchas I discovered through trial and error.</p>
<p><strong><a href="https://iammattl.com">This Website</a></strong> — The cyberpunk terminal UI, canvas pixelation effects, SVG cityscape, blog CMS with AI writing tools, and the deployment pipeline to Cloudflare Workers — all built with Claude Code from design to deployment.</p>
<h2 id="what-doesn-t-work">What Doesn&#39;t Work</h2>
<p>It&#39;s not all smooth.</p>
<p><strong>It forgets.</strong> Every conversation starts fresh. Without CLAUDE.md, you&#39;re re-explaining everything. Institutional memory is your workaround for the lack of persistent context.</p>
<p><strong>It&#39;s confidently wrong about edge cases.</strong> Especially newer APIs and platform-specific quirks. Claude will tell you with full confidence that an n8n node works a certain way — and it&#39;s just wrong. You learn to verify and document.</p>
<p><strong>Chained reasoning degrades.</strong> The more steps in a chain, the less reliable the output. That&#39;s why the three-layer architecture exists — you don&#39;t ask AI to do 10 things in sequence. You ask it to decide the next thing, run deterministic code, then come back.</p>
<h2 id="the-takeaway">The Takeaway</h2>
<p>Working with AI isn&#39;t about writing less code. It&#39;s about maintaining context, building institutional memory, and knowing when to let the AI think versus when to let code execute.</p>
<p>The engineers who&#39;ll get the most from these tools aren&#39;t the ones who type &quot;build me an app.&quot; They&#39;re the ones who write solid CLAUDE.md files, verify before they trust, and treat the AI like what it is — a skilled colleague with amnesia.</p>
<p>After 20+ years of building for the web, the last year with Claude Code has been the most productive stretch of my career. Not because the AI did the work for me — but because it let me operate at a scale I couldn&#39;t reach alone.</p>
]]></content:encoded>
      <category>Claude Code</category>
      <category>AI</category>
      <category>Software Engineering</category>
      <category>Pair Programming</category>
    </item>
  </channel>
</rss>