<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Western Wilson</title><link>https://westernwilson.com/reflections/</link><description>Recent content in Reflections on Western Wilson</description><generator>Hugo</generator><language>en</language><lastBuildDate>Sat, 26 Sep 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://westernwilson.com/reflections/index.xml" rel="self" type="application/rss+xml"/><item><title>AGNTCon + MCPCon Europe 2026</title><link>https://westernwilson.com/reflections/agntcon-mcpcon-europe-2026/</link><pubDate>Sat, 26 Sep 2026 00:00:00 +0000</pubDate><guid>https://westernwilson.com/reflections/agntcon-mcpcon-europe-2026/</guid><description>TL;DR: I spent the full second day at AGNTCon + MCPCon Europe in Amsterdam, and the most interesting talks showed a new normal for humans now that agents write most of the code.&#10;Dexter Horthy was the best speaker of the day, and Dylan Ratcliffe won me over after I initially disagreed with his premise. His line “easier to reject the recipe than the meal” is the same lesson I learnt the hard way at the bunq hackathon: i.e review the plan before anything gets built. Roy Belio’s red teaming lab made me glad I’d already locked down egress on my coding agent, and gave me a list of things I still haven’t done (DNS, canary tokens, read-only config). Another thing is that plenty of the live demos broke, which shows non-determinism in action.&#10;</description><content:encoded><![CDATA[<p><strong>TL;DR:</strong> I spent the full second day at <a href="https://events.linuxfoundation.org/agntcon-mcpcon-europe">AGNTCon + MCPCon Europe</a> in Amsterdam, and the most interesting talks showed a new normal for humans now that agents write most of the code.</p>
<p>Dexter Horthy was the best speaker of the day, and Dylan Ratcliffe won me over after I initially disagreed with his premise. His line &ldquo;easier to reject the recipe than the meal&rdquo; is the same lesson I learnt the hard way at the <a href="https://westernwilson.com/reflections/bunq-hackathon-7">bunq hackathon</a>: i.e review the plan before anything gets built. Roy Belio&rsquo;s red teaming lab made me glad I&rsquo;d already <a href="https://westernwilson.com/reflections/containerising-my-coding-agent">locked down egress on my coding agent</a>, and gave me a list of things I still haven&rsquo;t done (DNS, canary tokens, read-only config). Another thing is that plenty of the live demos broke, which shows non-determinism in action.</p>
<p>Next year&rsquo;s conference is in London, and I&rsquo;m hoping to go! Reach out if you&rsquo;re going too.</p>
<p>The rest of this post is my notes from each talk, lightly tidied up.</p>
<h2 id="catch-them-early" class="group relative scroll-mt-20">
  Catch Them Early
  <a
    href="https://westernwilson.com/reflections/agntcon-mcpcon-europe-2026/#catch-them-early"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p><a href="https://agntconmcpconeu26.sched.com/event/2RBEf/keynote-catch-them-early-manik-surtani-cto-agentic-ai-foundation"><strong>9:07am, Manik Surtani (CTO, Agentic AI Foundation)</strong></a></p>
<ul>
<li>The <a href="https://aaif.io/">Agentic AI Foundation (AAIF)</a> compared itself to the CNCF, which had the benefit of an industry that already had lots of experience with cloud.</li>
<li>They&rsquo;ve copied the CNCF bar for accepting projects, and in some places raised it.</li>
<li>They&rsquo;ve had a 3-4x growth pace compared to CNCF&hellip; the AI hype probably helped tbh</li>
</ul>
<h2 id="getting-to-stateless-mcp-in-production" class="group relative scroll-mt-20">
  Getting to stateless MCP in production
  <a
    href="https://westernwilson.com/reflections/agntcon-mcpcon-europe-2026/#getting-to-stateless-mcp-in-production"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p><a href="https://agntconmcpconeu26.sched.com/event/2RBHz/keynote-getting-to-stateless-mcp-in-production-shaun-smith-mcp-and-transport-working-group-maintainer-hugging-face"><strong>9:19am, Shaun Smith (Hugging Face, MCP transport working group maintainer)</strong></a></p>
<ul>
<li>Streamable HTTP is a smarter way to connect, closer to one-to-one client-to-server.</li>
<li>The stateless release brought improvements, but they needed migrating to the new SDK.</li>
<li>Uptake has been massive.</li>
</ul>
<h2 id="three-doors-to-one-tool-mcp-vs-webmcp-vs-cli" class="group relative scroll-mt-20">
  Three doors to one tool: MCP vs WebMCP vs CLI
  <a
    href="https://westernwilson.com/reflections/agntcon-mcpcon-europe-2026/#three-doors-to-one-tool-mcp-vs-webmcp-vs-cli"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p><a href="https://agntconmcpconeu26.sched.com/event/2RBVv/keynote-three-doors-to-one-tool-mcp-vs-webmcp-vs-cli-frederic-barthelet-cto-co-founder-alpic-dominic-farolino-editor-of-the-webmcp-specification-software-engineer-google"><strong>9:29am, Dominic Farolino (Google Chrome) &amp; Frederic Barthelet (CTO, Alpic)</strong></a></p>
<ul>
<li>WebMCP is a layer on a website that lets agents interact with your website much faster.</li>
<li>Better than <code>llms.txt</code> which isn&rsquo;t often looked at</li>
<li>CLIs integrate well with agents.</li>
<li>A harness is tools, memory, context, and guards.</li>
<li>MCP can be a local server or a public one.</li>
</ul>
<h2 id="state-of-the-software-factory" class="group relative scroll-mt-20">
  State of the software factory
  <a
    href="https://westernwilson.com/reflections/agntcon-mcpcon-europe-2026/#state-of-the-software-factory"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p><a href="https://agntconmcpconeu26.sched.com/event/2RBUc/keynote-state-of-the-software-factory-dexter-horthy-ceo-and-co-founder-humanlayer"><strong>9:41am, Dexter Horthy (CEO &amp; co-founder, HumanLayer)</strong></a></p>
<ul>
<li>A fantastic speaker who also has a YouTube channel.</li>
<li>The best talk of the day, with interesting content that&rsquo;s worth checking out properly.</li>
<li>Walked through HumanLayer&rsquo;s multiplayer AI chat tooling, which drives spec and code diff checks.</li>
</ul>
<p>Tools mentioned: <a href="https://hlyr.dev/resources">HumanLayer&rsquo;s resources</a>.</p>
<h2 id="pull-requests-are-dead-long-live-peer-review" class="group relative scroll-mt-20">
  Pull Requests are dead, long live peer review
  <a
    href="https://westernwilson.com/reflections/agntcon-mcpcon-europe-2026/#pull-requests-are-dead-long-live-peer-review"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p><a href="https://agntconmcpconeu26.sched.com/event/2RB8Y/pull-requests-are-dead-long-live-peer-review-dylan-ratcliffe-overmind"><strong>10:20am, Dylan Ratcliffe (Overmind)</strong></a></p>
<p>The most controversial talk of the day, at first. By the end he&rsquo;d convinced me, mostly because he showed how it&rsquo;s working for them right now.</p>
<ul>
<li>Pull requests are dead.</li>
<li>AI is not your peer, and its code is harder to review.</li>
<li>Agents are agreeable. They&rsquo;re bad at disagreeing with you.</li>
<li>He was a passable engineer who was outperforming his own team, and considered firing the engineering team. Instead he shifted the engineers left, into more product-oriented roles.</li>
<li>Move peer review into the planning phase, where the decisions actually get made.</li>
<li>The loop: research, decide on an approach, weigh up tradeoffs, plan, collaborate, then implement until the implementation matches the plan.</li>
<li>It&rsquo;s easier to reject the recipe than the meal. People are more willing to reject a plan, because it&rsquo;s cheaper to fix.</li>
<li>My open question: what about conflicts between the plan and the existing system? Does that get caught in review?</li>
</ul>
<p>Tools mentioned: <a href="https://www.notyourpeer.com/">AI Is Not Your Peer</a>, and <a href="https://until.dev/">Until</a>, which makes sure your agent implements every part of the plans you write.</p>
<h2 id="from-works-on-my-prompt-to-production-slos" class="group relative scroll-mt-20">
  From &ldquo;works on my prompt&rdquo; to production SLOs
  <a
    href="https://westernwilson.com/reflections/agntcon-mcpcon-europe-2026/#from-works-on-my-prompt-to-production-slos"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p><a href="https://agntconmcpconeu26.sched.com/event/2RBA3/from-works-on-my-prompt-to-production-slos-building-agent-observability-manik-khandelwal-microsoft"><strong>10:55am, Manik Khandelwal (Microsoft)</strong></a></p>
<ul>
<li>He wants agents that don&rsquo;t need constant checking.</li>
<li>It was confusing what he was trying to do. He has a framework that watches whether an agent needs active supervision or can be left running in the background.</li>
<li>The slides were AI generated. Cool to look at and interactive, but they lacked humanity in a way I can&rsquo;t quite describe. It didn&rsquo;t tell a story, it was more show and tell.</li>
<li>I didn&rsquo;t get much from this one.</li>
</ul>
<p>Tools mentioned: Mitra, an internal tool for monitoring agents. Not sure if it&rsquo;s open sourced yet.</p>
<h2 id="governance-you-can-run-checkable-properties-for-production-agents" class="group relative scroll-mt-20">
  Governance you can run: Checkable properties for production agents
  <a
    href="https://westernwilson.com/reflections/agntcon-mcpcon-europe-2026/#governance-you-can-run-checkable-properties-for-production-agents"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p><a href="https://agntconmcpconeu26.sched.com/event/2RBAC/governance-you-can-run-checkable-properties-for-production-agents-seshu-tolety-siemens"><strong>11:30am, Seshu Tolety (Director of Agentic AI, Siemens)</strong></a></p>
<ul>
<li>The cost of ungoverned AI model usage on privacy, operational burden, and more.</li>
<li>Three lifecycles as new mental models: AI adoption, engineering, and operations (can we run AI safely at scale?).</li>
<li>He walked through today&rsquo;s organisation and policy structures, then out to a future state where AI governs AI policy.</li>
<li>Humans sit in that structure reviewing the policy that AI creates. As we know from code, that makes humans the bottleneck. After hearing Dylan&rsquo;s talk, I&rsquo;m not sure I agree. The idea is both scary and interesting at the same time!</li>
<li>&ldquo;Governance should never slow innovation. It should help you scale it.&rdquo;</li>
</ul>
<h2 id="governed-agent-autonomy-building-a-control-plane-for-agentic-systems" class="group relative scroll-mt-20">
  Governed agent autonomy: Building a control plane for agentic systems
  <a
    href="https://westernwilson.com/reflections/agntcon-mcpcon-europe-2026/#governed-agent-autonomy-building-a-control-plane-for-agentic-systems"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p><a href="https://agntconmcpconeu26.sched.com/event/2RBAR/governed-agent-autonomy-building-a-control-plane-for-agentic-systems-nnenna-ndukwe-qodo-ai"><strong>1:15pm, Nnenna Ndukwe (Qodo AI)</strong></a></p>
<ul>
<li>Harness config, mostly around what to allow.</li>
<li>Five governance patterns found in the leaked Claude Code source, which she open sourced:
<ol>
<li>Planning</li>
<li>Permissions (can this action proceed?)</li>
<li>Tool trust (capability trust)</li>
<li>Verification</li>
<li>Runtime (what were the outcomes?)</li>
</ol>
</li>
<li>She implemented them in a Rust agent.</li>
<li>The demo was supposed to block a deployment to production. It didn&rsquo;t xD</li>
</ul>
<p>Tools mentioned: Goose (an AAIF project), GAAP (agent observability), and Martin Fowler&rsquo;s writing on harness engineering.</p>
<h2 id="beyond-chatbots-agentic-ui-with-open-standards" class="group relative scroll-mt-20">
  Beyond Chatbots: Agentic UI with Open Standards
  <a
    href="https://westernwilson.com/reflections/agntcon-mcpcon-europe-2026/#beyond-chatbots-agentic-ui-with-open-standards"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p><a href="https://agntconmcpconeu26.sched.com/event/2RBAs/beyond-chatbots-agentic-ui-with-open-standards-manfred-steyer-angulararchitects"><strong>1:25pm, Manfred Steyer (ANGULARarchitects)</strong></a></p>
<ul>
<li>An interesting talk, and one of the few live demos that worked. Well, it didn&rsquo;t at first, until they realised it was just the WiFi. Once that was fixed it worked.</li>
<li>&ldquo;To chat or not to chat&hellip; that&rsquo;s the wrong question.&rdquo;</li>
<li>Showed a UI progressively changing as you chat with it and co-create.</li>
</ul>
<p>Tools mentioned: AG-UI (agent communication), A2UI (dynamic UI), and MCP Apps.</p>
<h2 id="mcp-apps-and-the-agentic-web" class="group relative scroll-mt-20">
  MCP Apps and the Agentic Web
  <a
    href="https://westernwilson.com/reflections/agntcon-mcpcon-europe-2026/#mcp-apps-and-the-agentic-web"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p><a href="https://agntconmcpconeu26.sched.com/event/2RBAU/mcp-apps-and-the-agentic-web-liad-yosef-mcp-apps"><strong>1:50pm, Liad Yosef (MCP Apps)</strong></a></p>
<ul>
<li>The difference between a website, WebMCP, and MCP Apps.</li>
<li>A really convincing talk on how brands can bring their apps into chat instead of splicing up their current website.</li>
<li>His point is that we might move away from browsers entirely, because we might not need them.</li>
<li>Salesforce is going headless, even though UI was their differentiator.</li>
<li>Cloudflare says bot traffic has overtaken human traffic.</li>
<li>Web search isn&rsquo;t great for agents, and an app store probably isn&rsquo;t either. What about an agentic identity that&rsquo;s tied to you?</li>
<li>The next big thing is the discovery layer for agents. He compared it to web search, with <code>.well-known/ai-catalog.json</code> as a unified standard.</li>
</ul>
<p>Tools mentioned: Goose, DoorDash&rsquo;s new CLI, Sentry, Ora&rsquo;s researcher benchmark, <code>npx ax</code> (an audit tool for how agents use your website), and Ora&rsquo;s <a href="https://ora.directory/">Agentic Resources Discovery: the agentic index of the web</a>.</p>
<h2 id="no-central-brain" class="group relative scroll-mt-20">
  No Central Brain
  <a
    href="https://westernwilson.com/reflections/agntcon-mcpcon-europe-2026/#no-central-brain"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p><a href="https://agntconmcpconeu26.sched.com/event/2RBBV/no-central-brain-fausto-albers-wonderwhy"><strong>3:25pm, Fausto Albers (WonderWhy, co-founder of AI Builders Club)</strong></a></p>
<ul>
<li>No central brain. Ominous music. Who decides what&rsquo;s true?</li>
<li>&ldquo;Attention is all you need&rdquo;, reframed as: 1. harness and loop, 2. recursive self improvement, 3. memory and learning.</li>
<li>The harness reinvents itself. It self-learns and stores each change along with its cost, tests itself, makes changes, evaluates the model, then recreates the harness.</li>
<li>I wonder if it&rsquo;ll converge on AI granting itself unlimited access and some wild harness configurations…</li>
</ul>
<h2 id="infrastructure-red-teaming-with-abliterated-models" class="group relative scroll-mt-20">
  Infrastructure red teaming with abliterated models
  <a
    href="https://westernwilson.com/reflections/agntcon-mcpcon-europe-2026/#infrastructure-red-teaming-with-abliterated-models"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p><a href="https://agntconmcpconeu26.sched.com/event/2RBBJ/infrastructure-red-teaming-with-abliterated-models-what-actually-stops-agent-attacks-roy-belio-red-hat"><strong>3:30pm, Roy Belio (Red Hat)</strong></a></p>
<ul>
<li>Red teaming chat models and model refusal. Injection gets past a lot of guardrails.</li>
<li>There are lots of CVEs about prompt injection and ways around guardrails.</li>
<li>Guardrails and classifiers are a good start, but they&rsquo;ll miss anything that isn&rsquo;t in English.</li>
<li>His outcome was to run tooling on an SSH server somewhere else, not on the same service as the LLM.</li>
<li>In the interactive lab, a tool would sometimes error out, but <code>cat</code> was still available so the agent read the file anyway. Sometimes the LLM hid the logs too.</li>
<li>A read-only container running <code>sshd</code> is a good idea.</li>
<li>Watch for direct socket operations and exfiltration over DNS. Block egress, and keep DNS traffic internal too.</li>
<li>The slash command illusion.</li>
<li>Keep the config that shapes the agent&rsquo;s behaviour on the pods, and never let it be writable. The agent will rewrite itself.</li>
<li>Put canary tokens anywhere that could tell you you&rsquo;ve been compromised.</li>
</ul>
<p>Further reading he mentioned: EchoLeak (Microsoft), AWS Strands, MCP Poison (Cursor), the Deadbugz campaign (August 2026), and <em>Crash test dummy</em>, the blog where he first worked through this talk.</p>
]]></content:encoded></item><item><title>Containerising my coding agent</title><link>https://westernwilson.com/reflections/containerising-my-coding-agent/</link><pubDate>Sun, 21 Jun 2026 00:00:00 +0000</pubDate><guid>https://westernwilson.com/reflections/containerising-my-coding-agent/</guid><description>I containerised Claude Code this week because I wanted to let it run with fewer guardrails and not hand it unlimited access the rest of my machine. There’s a Hacker News thread from 6 months ago about someone running Claude in yolo mode who asked it to clean something up and watched it rm -rf their home directory 😅. So let’s aim to at least avoid that.&#10;Thankfully, I found Dev Containers, which turned into its own rabbit hole but lets us lock down Claude without having to maintain our own docker image.&#10;</description><content:encoded><![CDATA[<p>I containerised Claude Code this week because I wanted to let it run with fewer guardrails and not hand it unlimited access the rest of my machine. There&rsquo;s a <a href="https://news.ycombinator.com/item?id=46268222">Hacker News thread</a> from 6 months ago about someone running Claude in yolo mode who asked it to clean something up and watched it <code>rm -rf</code> their home directory 😅. So let&rsquo;s aim to at least avoid that.</p>
<p>Thankfully, I found <a href="https://containers.dev">Dev Containers</a>, which turned into its own rabbit hole but lets us lock down Claude without having to maintain our own docker image.</p>
<p>This reflection post talks through the containerised setup and some issues I faced while setting it up. If you just want the solution, then the implementation is in the <a href="https://github.com/wjkw1/westernwilson.com/tree/main/.devcontainer">.devcontainer/</a> directory of this website&rsquo;s source code.</p>
<h2 id="feature-or-docker-image" class="group relative scroll-mt-20">
  Feature or docker image?
  <a
    href="https://westernwilson.com/reflections/containerising-my-coding-agent/#feature-or-docker-image"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>I assumed that Anthropic would ship an official Claude base image you build on top of. They don&rsquo;t, they only post a recommended starting point. Claude Code installs into any <a href="https://code.claude.com/docs/en/devcontainer">Dev Container</a> through the <code>ghcr.io/anthropics/devcontainer-features/claude-code:1.0</code> feature, which you reference in <code>devcontainer.json</code> like <a href="https://containers.dev/features">any other devcontainers feature</a>. It works wherever the Dev Containers spec is supported e.g. VS Code, Codespaces, JetBrains, and (with some rough edges) Cursor. In VS Code it can be configured to pull in the Claude Code extension, keeping Claude decoupled from the base image entirely.</p>
<p>That leaves three layers to assemble: a base image, the tooling you use, and Claude Code on top. The real decision is whether you bake those middle two layers into a custom docker image you push to a registry, or assemble them per-repo through <code>devcontainer.json</code> features. A custom image is the better call for a team, where you want a validated, secure, and reusable environment everyone builds on. For a solo setup spun up per-repo, features are easier. The cost is a slow first build and less control over exactly what lands in the image, which is what <code>post-create.sh</code> helps automate somewhat.</p>
<p>My <code>devcontainer.json</code> ended up looking like this, trimmed to the main parts:</p>
<div class="highlight"><pre tabindex="0"><code class="language-jsonc" data-lang="jsonc"><span><span>{
</span></span><span><span>  <span>&#34;image&#34;</span>: <span>&#34;mcr.microsoft.com/devcontainers/base:ubuntu&#34;</span>,
</span></span><span><span>  <span>&#34;features&#34;</span>: {
</span></span><span><span>    <span>&#34;ghcr.io/anthropics/devcontainer-features/claude-code:1.0&#34;</span>: {}
</span></span><span><span>  },
</span></span><span><span>  <span>&#34;remoteUser&#34;</span>: <span>&#34;vscode&#34;</span>,
</span></span><span><span>  <span>&#34;mounts&#34;</span>: [
</span></span><span><span>    <span>&#34;source=claude-code-config-${devcontainerId},target=/home/vscode/.claude,type=volume&#34;</span>
</span></span><span><span>  ],
</span></span><span><span>  <span>&#34;runArgs&#34;</span>: [<span>&#34;--cap-add=NET_ADMIN&#34;</span>, <span>&#34;--cap-add=NET_RAW&#34;</span>],
</span></span><span><span>  <span>&#34;postCreateCommand&#34;</span>: <span>&#34;sudo zsh .devcontainer/post-create.sh&#34;</span>,
</span></span><span><span>  <span>&#34;postStartCommand&#34;</span>: <span>&#34;sudo /usr/local/sbin/init-firewall.sh&#34;</span>,
</span></span><span><span>  <span>&#34;waitFor&#34;</span>: <span>&#34;postStartCommand&#34;</span>
</span></span><span><span>}
</span></span></code></pre></div><p>The non-root <code>vscode</code> user is important if you ever run with <code>--dangerously-skip-permissions</code>, Claude Code requires it. The named volume on <code>~/.claude</code> means login persists across rebuilds instead of re-authenticating every time. The <code>NET_ADMIN</code>/<code>NET_RAW</code> capabilities exist so that we can create the containerised firewall. <code>waitFor: postStartCommand</code> blocks the terminal until that firewall script finishes, so there&rsquo;s no window where Claude is already running before egress is locked down.</p>
<p><code>post-create.sh</code> is the everyday stuff a feature-based setup doesn&rsquo;t hand you for free: setting git aliases, adding a couple of zsh aliases for <code>kubectl</code> and <code>terraform</code>, locking down <code>sudo</code>/<code>su</code>.</p>
<p><code>init-firewall.sh</code> sets default-DROP policies on iptables, then builds an <code>ipset</code> allowlist of everything the container is allowed to reach outbound. Part of that allowlist is GitHub&rsquo;s own published IP ranges, fetched live at container start:</p>
<div class="highlight"><pre tabindex="0"><code class="language-zsh" data-lang="zsh"><span><span>gh_ranges<span>=</span><span>$(</span>curl -s https://api.github.com/meta<span>)</span>
</span></span><span><span><span>while</span> read -r cidr; <span>do</span>
</span></span><span><span>    ipset add allowed-domains <span>&#34;</span>$cidr<span>&#34;</span>
</span></span><span><span><span>done</span> &lt; &lt;<span>(</span>echo <span>&#34;</span>$gh_ranges<span>&#34;</span> | jq -r <span>&#39;(.web + .api + .git)[]&#39;</span> | aggregate -q<span>)</span>
</span></span></code></pre></div><p>Everything else —npm, <code>api.anthropic.com</code>, the VS Code marketplace— gets resolved and added individually. The firewall script finishes by checking its own work: it tries <code>curl https://example.com</code> and expects that to fail, then tries <code>curl https://api.github.com/zen</code> and expects that to succeed.</p>
<h2 id="firewall-and-sudo" class="group relative scroll-mt-20">
  Firewall and sudo
  <a
    href="https://westernwilson.com/reflections/containerising-my-coding-agent/#firewall-and-sudo"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>I spent a decent chunk of time configuring who&rsquo;s allowed to touch <code>iptables</code>. The <code>common-utils</code> feature grants the <code>vscode</code> user blanket passwordless <code>sudo</code> by default, and my first cut of <code>post-create.sh</code> narrowed that down to the <code>iptables</code>/<code>iptables-save</code>/<code>ipset</code> binaries themselves, with no argument restriction. Which meant Claude or anything else running as <code>vscode</code>, including under <code>--dangerously-skip-permissions</code>, could just run <code>sudo iptables -F &amp;&amp; sudo iptables -P OUTPUT ACCEPT</code> and the firewall would be gone! Anthropic&rsquo;s own reference devcontainer avoids this by granting <code>sudo</code> on one fixed script path instead of the raw binaries, baked into their image at build time so the script itself can&rsquo;t be edited either. I didn&rsquo;t want a custom Dockerfile yet, but dev containers can do the same thing with just <code>postCreateCommand</code>: copy <code>init-firewall.sh</code> to a root-owned <code>/usr/local/sbin/init-firewall.sh</code> outside the bind-mounted workspace while the feature&rsquo;s broad sudo grant is still active, then narrow <code>sudo</code> down to NOPASSWD on that one frozen executable file only. The tradeoff is that editing the live <code>init-firewall.sh</code> to allow a new domain now needs a full <strong>Rebuild Container</strong>, not just a restart, since the frozen copy is what actually runs.</p>
<p>Claude has it&rsquo;s own way to limit it&rsquo;s own execution too using <code>.claude/settings.json</code>. We&rsquo;ve configured this on top to deny any <code>Bash(sudo *)</code> and <code>Bash(su *)</code> commands, so in normal mode Claude won&rsquo;t even attempt the command. But <code>--dangerously-skip-permissions</code> does exactly what its name says: it bypasses every permission rule, deny rules included. So that file is a speed bump for the default mode, not something to lean on once the safety&rsquo;s off. The frozen-script sudoers restriction is the one that locks it down regardless, because it&rsquo;s enforced by the OS, not by Claude Code.</p>
<h2 id="gap-in-the-firewall" class="group relative scroll-mt-20">
  Gap in the firewall
  <a
    href="https://westernwilson.com/reflections/containerising-my-coding-agent/#gap-in-the-firewall"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>One thing I noticed was that <code>api.github.com/meta</code>&rsquo;s ip ranges aren&rsquo;t scoped to the API. They cover GitHub&rsquo;s whole edge network, which includes GitHub Pages in some cases. For example, this website, <a href="https://westernwilson.com">westernwilson.com</a>, runs on GitHub Pages. So with the firewall up and supposedly restricting the agent to an approved set of domains, I could still reach my own site. And by the same logic, any other <code>*.github.io</code> page, or anything hosted there by someone with worse intentions. A page on <code>*.github.io</code> could potentially hold a payload hosted somewhere else entirely, and the firewall would wave it through without ever knowing the difference.</p>
<p>I see three ways to close that off:</p>
<ul>
<li>Proxy the traffic and filter on hostname instead of IP. Cleanest in theory, but Encrypted Client Hello can still hide the hostname from anything sitting.</li>
<li>Drop <code>*.github.io</code> from the allowlist entirely. Unfortunately this also takes <code>raw.githubusercontent.com</code> out too since they share the same ip ranges, but if that&rsquo;s not something the container needs, it&rsquo;s a fine trade.</li>
<li>Accept the risk and move on.</li>
</ul>
<p>I haven&rsquo;t picked one yet, for now I&rsquo;m sitting with the risk while I think about which tradeoff is actually worth it.</p>
<h2 id="logging-in-to-claude" class="group relative scroll-mt-20">
  Logging in to Claude
  <a
    href="https://westernwilson.com/reflections/containerising-my-coding-agent/#logging-in-to-claude"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>Logging in had its own gotcha. In VS Code there is a big orange &ldquo;use your subscription&rdquo; button that opens a browser and waits for a callback to <code>localhost</code>, which never makes it back into the container and just hangs. The fix is to skip the button, open a terminal inside the container and run <code>claude</code>, which kicks off the same browser flow but resolves the callback correctly.</p>
<p>We then use <code>~/.claude</code>, which is now owned by the <code>vscode</code> thanks to the <code>chown</code> at the top of <code>post-create.sh</code>, so once logged in, we gain stickier login sessions.</p>
<p>In doing the whole login dance from a bare terminal meant that my first real session with Claude Code inside the dev container was just text based interaction with no IDE extension wrapper around it at all. It&rsquo;s an interesting way to work and removes a lot of the UI distraction, but not something I&rsquo;ll rely on fulltime.</p>
<h2 id="port-forwarding" class="group relative scroll-mt-20">
  Port forwarding
  <a
    href="https://westernwilson.com/reflections/containerising-my-coding-agent/#port-forwarding"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>The other thing that briefly worried me is VS Code forwarded around thirty-two ports the moment the container came up. My first thought was that something in the container was reaching out on its own. It&rsquo;s not, after some searching I found that it&rsquo;s VS Code&rsquo;s automatic port-forwarding scanning the container for anything listening on a port, for example a dev server that you&rsquo;ll want to open in a browser. It&rsquo;s a separate, fairly trigger-happy feature, and apparently a known source of noise; <a href="https://github.com/microsoft/vscode-remote-release/issues/10926">This GitHub issue</a> describes the exact same &ldquo;over 20 ports auto-forwarded&rdquo; behaviour after a setting silently flips from <code>process</code> to <code>hybrid</code> detection mode.</p>
<p>If you want to see the actual config rather than the excerpts above, it&rsquo;s all in this repo under <a href="https://github.com/wjkw1/westernwilson.com/tree/main/.devcontainer">.devcontainer/</a>. Treat it as a personal setup to extend, not a hardened image to copy verbatim.</p>
<p>Further reading: Anthropic&rsquo;s <a href="https://code.claude.com/docs/en/devcontainer">Dev Containers docs</a> and the <a href="https://code.visualstudio.com/docs/devcontainers/tutorial">VS Code Dev Containers tutorial</a>.</p>
]]></content:encoded></item><item><title>Travelling Europe and the Balkans</title><link>https://westernwilson.com/reflections/travelling-europe-and-the-balkans/</link><pubDate>Tue, 16 Jun 2026 00:00:00 +0000</pubDate><guid>https://westernwilson.com/reflections/travelling-europe-and-the-balkans/</guid><description>I’ve visited a bunch of countries across Europe and the Balkans recently. Mid last year did loads of Asia too. This all probably deserves its own deeper dive, but I don’t want to sink a load of time into this reflection just yet so here is a brain dump.&#10;A highlight has been hearing the difference between Germanic, Slavic, and Romance languages up close. Back home in NZ I mostly heard English, some Cantonese, and a little Māori, so all these new sounds have been a great for my brain.&#10;</description><content:encoded><![CDATA[<p>I&rsquo;ve visited a bunch of countries across Europe and the Balkans recently. Mid last year did loads of Asia too. This all probably deserves its own deeper dive, but I don&rsquo;t want to sink a load of time into this reflection just yet so here is a brain dump.</p>
<p>A highlight has been hearing the difference between Germanic, Slavic, and Romance languages up close. Back home in NZ I mostly heard English, some Cantonese, and a little Māori, so all these new sounds have been a great for my brain.</p>
<p>The food everywhere has been amazing too, nothing crazy adventurous, but plenty to satisfy the palate.</p>
<ul>
<li><strong>Greece</strong>: Island hopping was fantastic, friendly people, and such a rich history. We toured the major islands and timed Mykonos perfectly, just before party season kicked off. We had room to walk and explore without the crowds. Saw a lot of churches and heard about the various empires that occupied these parts.</li>
<li><strong>Denmark</strong>: Beautiful but expensive. Everyone wears gorgeous, sustainable, layered clothing. This makes sense given how much colder it is than NZ. Metro made it so easy to get around. Bikes everywhere.</li>
<li><strong>Amsterdam</strong>: Visited to explore Amsterdam and also for a bunq hackathon (<a href="https://westernwilson.com/reflections/bunq-hackathon-7">reflection here</a>). I loved the vibe, though getting around without a bike was slow. So a bike is the first thing I&rsquo;m getting once I live there. Free ferries were fantastic!</li>
<li><strong>Italy</strong>: Five days in Rome. It felt like you could walk in any direction and stumble onto a grand church or building. The food here was the best I&rsquo;ve had anywhere, once we found one particular shop&rsquo;s tiramisu we ate three in a single day. Also saw Michelangelo&rsquo;s Creation of Adam on the Sistine Chapel ceiling, the scale of it is hard to describe. I guess it was well over 4 years of his life!</li>
<li><strong>Croatia</strong>: Some of the best scenery I&rsquo;ve seen outside of New Zealand. We hired a car and drove from Zagreb to Split, stopping at the Plitvice Lakes National Park in between for some incredible waterfalls. Driving on the opposite side of the road took adjusting (NZ left-side and Croatia right-side), but having a car unlocked so many random stops for our journey.</li>
<li><strong>Serbia</strong>: A taxi driver suggest Burek to me and I ate it most days. I learnt about Belgrade&rsquo;s hectic history, even up until recently. I&rsquo;m in awe of what people there have survived, over four passport changes in the last 25 years and across many different occupations. We were told it&rsquo;s because of Belgrade is positioned on the Danube and Sava rivers, prime real estate with a fortress that holds the high ground.</li>
</ul>
]]></content:encoded></item><item><title>DevOps vs Platform vs Infrastructure Engineer</title><link>https://westernwilson.com/reflections/devops-vs-platform-vs-infrastructure-engineer/</link><pubDate>Tue, 09 Jun 2026 00:00:00 +0000</pubDate><guid>https://westernwilson.com/reflections/devops-vs-platform-vs-infrastructure-engineer/</guid><description>I’ve been a DevOps &amp; Infra Engineer for over 5 years. To me, it’s about helping developers move from code to production in the fastest, safest, most secure, and most reliable way possible. The job market seems a bit less certain about this definition however…&#10;Scrolling through job listings this past month, I noticed roles titled DevOps Engineer or Platform Engineer or Infrastructure Engineer that were listed with almost identical responsibilities.&#10;</description><content:encoded><![CDATA[<p>I&rsquo;ve been a DevOps &amp; Infra Engineer for over 5 years. To me, it&rsquo;s about helping developers move from code to production in the fastest, safest, most secure, and most reliable way possible. The job market seems a bit less certain about this definition however&hellip;</p>
<p>Scrolling through job listings this past month, I noticed roles titled <em>DevOps Engineer</em> or <em>Platform Engineer</em> or <em>Infrastructure Engineer</em> that were listed with almost identical responsibilities.</p>
<p>I know innately that these roles have some differences, but the titles are often used interchangeably by hiring teams.</p>
<h2 id="where-devops-came-from" class="group relative scroll-mt-20">
  Where DevOps came from
  <a
    href="https://westernwilson.com/reflections/devops-vs-platform-vs-infrastructure-engineer/#where-devops-came-from"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>DevOps is a word created from the combination of the words <strong>Developer</strong> and <strong>Operations</strong>. To understand why that portmanteau word became a job title, you need to understand the problem it was trying to solve.</p>
<p>Traditionally, software teams were split in two. Developers wrote code in one room, and an <strong>Operations</strong> team —sometimes called Ops— deployed and ran that code in production. Each group had different incentives e.g. devs wanted to ship fast whilst ops wanted stability. That tension caused friction, slow releases, and potentially a blame culture when things broke.</p>
<p>The DevOps movement, popularised in part by <em>The Phoenix Project</em> (Kim, Behr, Spafford, 2013) and <em>The DevOps Handbook</em>, proposed a cultural fix to tear down that wall. If developers owned their code all the way to production, they&rsquo;d build with operability in mind. They&rsquo;d care about deployment pipelines, alerting, and recovery because those things would become their problem too.</p>
<p>DevOps is meant to be a shared practice of principles across teams, and not a single person&rsquo;s role. But organisations found it easier to spin up a DevOps teams or hire someone with the DevOps title who embodied that DevOps mindset to show some adoption of &ldquo;DevOps&rdquo; when it was first cool.</p>
<h2 id="what-a-devops-engineer-actually-does" class="group relative scroll-mt-20">
  What a DevOps Engineer actually does
  <a
    href="https://westernwilson.com/reflections/devops-vs-platform-vs-infrastructure-engineer/#what-a-devops-engineer-actually-does"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>In practice, the <strong>DevOps Engineer</strong> tends to be embedded within a product team, sometimes as the only person with that focus. Their job is improving the speed and safety of getting code from a developer&rsquo;s machine into production.</p>
<p>That means CI/CD pipelines (think GitHub Actions, TeamCity, CircleCI, or similar), automated testing, deployment automation, monitoring and alerting, and security gates. If a developer is waiting too long for a build, or a deployment is a manual, error-prone process, the DevOps Engineer is the one called on.</p>
<p>My own experience working in this role felt exactly like that: a solo DevOps expert embedded in a development team, focused on making the production path faster and more reliable. In smaller companies you will probably get the opportunity to pick up other development tasks outside of the usual job description. This helps you experience the pain that engineers go through to build better solutions.</p>
<h2 id="platform-engineering" class="group relative scroll-mt-20">
  Platform Engineering
  <a
    href="https://westernwilson.com/reflections/devops-vs-platform-vs-infrastructure-engineer/#platform-engineering"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>Platform Engineering has similar tools and similar outcomes, but from what I&rsquo;ve seen, the scope and audience are different.</p>
<p>Where a DevOps Engineer typically serves one team, a <strong>Platform Engineer</strong> serves many. This role, I think, is oriented around building an Internal Developer Platform (IDP). An IDP is a curated set of tools, templates, and standards that every engineering team in an organisation can use. The CNCF communities often describe this as building <strong>golden paths</strong>: opinionated, well-maintained routes that make the right thing the easy thing for developers to do.</p>
<p>Think of it as the difference between solving a problem for your team versus building the infrastructure so any team can solve that problem themselves. Platform teams treat internal developers as their customers. They build self-service tooling —things like standardised deployment workflows, observability stacks, or secrets management patterns— so that product teams don&rsquo;t have to reinvent those wheels independently.</p>
<p>This tends to appear at larger organisations, where inconsistency across teams becomes a bigger cost. At a company with ten engineers, one strong DevOps person can handle everything informally. At a company with five hundred, the absence of shared standards can create chaos.</p>
<p>The tradeoff here is somehow creating efficient standards to keep things stable, but also giving optionality to engineers so they have autonomy over the tooling they choose.</p>
<p>A good tool to know about is Spotify&rsquo;s open source Backstage tool: <a href="https://backstage.io/">https://backstage.io/</a></p>
<h2 id="infrastructure-engineering" class="group relative scroll-mt-20">
  Infrastructure Engineering
  <a
    href="https://westernwilson.com/reflections/devops-vs-platform-vs-infrastructure-engineer/#infrastructure-engineering"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>Infrastructure Engineering overlaps with both DevOps and Platform, but sits slightly further from application code in my experience.</p>
<p>An <strong>Infrastructure Engineer</strong> is typically focused on the foundations: cloud architecture, networking, access management, and the security controls that sit beneath the application layer. They&rsquo;re thinking about VPCs, subnets, firewall rules, load balancers, DNS, and how services communicate across boundaries. Often this involves deep expertise with IaC tools like Terraform and close familiarity with the cloud provider&rsquo;s lower-level primitives.</p>
<p>A DevOps Engineer might spend their day modifying a GitHub Actions workflow or adjusting a Dockerfile. An Infrastructure Engineer might spend theirs designing the network topology that those pipelines eventually deploy into.</p>
<p>That said, in my experience, in any organisation you have problems to solve and there is never a clean separation. So you&rsquo;re owning all of it, and carrying all three titles simultaneously whenever something is required.</p>
<h2 id="why-the-roles-overlap" class="group relative scroll-mt-20">
  Why the roles overlap
  <a
    href="https://westernwilson.com/reflections/devops-vs-platform-vs-infrastructure-engineer/#why-the-roles-overlap"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>There are more than the three role titles I&rsquo;ve talked about too, e.g. Systems Engineer, Site Reliability Engineer, Integration Engineer, and many others that cover <em>similar</em> responsibilities with decent overlap.</p>
<p>Part of it is because fashionable titles shift over time; DevOps was the go-to term but now it feels like Platform Engineering is. This is probably because it better captures the product-focused, team-of-teams thinking that scales for devops/platform teams.</p>
<p>Each organisation decides on responsibilities differently depending on team size, product maturity, culture in the industry, and even the background of whoever&rsquo;s hiring. So the title they&rsquo;re given is essentially a best guess based on responsibilities required at the start of the role, which often morphs into different roles as projects progress.</p>
<p>A startup with five engineers often doesn&rsquo;t have the headcount for specialisation. The person managing Terraform, building the deployment pipeline, and configuring the VPC is doing DevOps, platform, and infrastructure work all at once.</p>
<p>At larger companies, the separation becomes more meaningful. A Platform team with a product mindset and a roadmap looks very different from a DevOps Engineer embedded in a squad, even if both are deep into Kubernetes on any given Tuesday.</p>
<h2 id="read-the-job-description" class="group relative scroll-mt-20">
  Read the job description
  <a
    href="https://westernwilson.com/reflections/devops-vs-platform-vs-infrastructure-engineer/#read-the-job-description"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>After reading many applications, the practical lesson is to read past the title and into the responsibilities. A &ldquo;Platform Engineer&rdquo; role at a thirty-person startup will look nothing like the same title at an enterprise company. A &ldquo;DevOps Engineer&rdquo; role at a bank might be closer to what a Platform team does at a tech company.</p>
<p>The questions worth asking in an interview: Are you embedded in a product team or sitting in a centralised infrastructure group? Are you building tooling <em>for</em> developers, or helping productionise a single product app? What does ownership look like when something breaks at 3am?</p>
<p>I like that DevOps Engineering is broad; I like having the option to do whatever is required to get the job done.</p>
]]></content:encoded></item><item><title>Why AWS SSO? Why OIDC?</title><link>https://westernwilson.com/reflections/oidc/</link><pubDate>Thu, 21 May 2026 00:00:00 +0000</pubDate><guid>https://westernwilson.com/reflections/oidc/</guid><description>While building a demo coffee app you realise that the infrastructure-as-code needs appropriate authentication &amp; authorisation to make changes securely. I’ve set this up in previous jobs but have been on a travel break since then, and the muscle memory needs a reminder.&#10;So, I’m refreshing my understanding and reflecting on it here.&#10;Important terminology and tools An important distiction is the difference between Authentication and Authorisation. Authentication asks “are you who you say you are”, while Authorisation says “I know you, but are you allowed to do what you’re trying to do”.&#10;</description><content:encoded><![CDATA[<p>While building a demo coffee app you realise that the infrastructure-as-code needs appropriate authentication &amp; authorisation to make changes securely. I&rsquo;ve set this up in previous jobs but have been on a travel break since then, and the muscle memory needs a reminder.</p>
<p>So, I&rsquo;m refreshing my understanding and reflecting on it here.</p>
<h2 id="important-terminology-and-tools" class="group relative scroll-mt-20">
  Important terminology and tools
  <a
    href="https://westernwilson.com/reflections/oidc/#important-terminology-and-tools"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>An important distiction is the difference between Authentication and Authorisation. <strong>Authentication</strong> asks &ldquo;<em>are you who you say you are</em>&rdquo;, while <strong>Authorisation</strong> says &ldquo;<em>I know you, but are you allowed to do what you&rsquo;re trying to do</em>&rdquo;.</p>
<p><strong>Infrastructure-as-code (IaC)</strong> is self-explanatory, it allows you to codify your infrastructure changes. Letting you track infra changes over time, and efficiently keep the infra actually deployed in line with your intentions. When there is drift between intentions and actual, IaC helps it realign.</p>
<p><strong>Terraform</strong> is a great tool for IAC, and is the focus for this reflection.</p>
<p>There are many other tools that help with IaC including <strong>CloudFormation</strong> and <strong>Ansible</strong>. <strong>CloudFormation</strong> is AWS&rsquo;s solution for the IaC giving declarative provisioning, but its locked to AWS. <strong>Ansible</strong> is more focused on configuration management and orchestration once infrastructure exists, though there is some overlap with IaC.</p>
<p><strong>CI/CD</strong> is Continuous Integration / Continuous Delivery. It is a mindset with many tools that helps our code build, test, and deploy safely for our users. <strong>GitHub Actions</strong> our CI/CD tool of choice. There are others like TeamCity, Circle CI, Jenkins, Octopus Deploy, GitLab CI etc.</p>
<p>When mentioning <strong>MacBook</strong> it could be any developer machine enabling you to make infra changes by running Terraform.</p>
<p>Given all of this, there are two main use cases:</p>
<ul>
<li><strong><em>Human to machine</em></strong> - Connecting MacBook to AWS</li>
<li><strong><em>Machine to machine</em></strong> - Connecting GitHub Actions to AWS</li>
</ul>
<p>Both use cases need to authenticate and authorise, but they do it using different methods. We&rsquo;ll explore that difference in the upcoming sections.</p>
<h2 id="human-to-machine" class="group relative scroll-mt-20">
  Human to machine
  <a
    href="https://westernwilson.com/reflections/oidc/#human-to-machine"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>When running Terraform from your laptop, the industry standard is to authenticate with <strong>AWS SSO</strong> (rebranded as AWS IAM Identity Center in 2022, though the CLI commands remain the same).</p>
<p>From the terminal you run an aws cli command that opens your browser, asks you to log in using your identity provider (or aws creds), and grabs a short-lived credential for use during your AWS terminal session. It normally expires after 8 hours, but this is configurable. Terraform picks up that short-lived credential and uses it to configure the infrastructure however you&rsquo;ve defined.</p>
<div class="highlight"><pre tabindex="0"><code class="language-zsh" data-lang="zsh"><span><span><span># day to day example (assumes sso roles are setup)</span>
</span></span><span><span>aws sso login --profile terraform
</span></span><span><span>export AWS_PROFILE<span>=</span>terraform
</span></span><span><span>
</span></span><span><span>terraform apply
</span></span></code></pre></div><p>These commands work because there&rsquo;s a human in the loop. Developers can login to AWS, click a button, and complete an MFA prompt. It&rsquo;s verifiable that you are the person at the keyboard.</p>
<p>This is not possible the moment you&rsquo;re out of the loop.</p>
<h2 id="machine-to-machine" class="group relative scroll-mt-20">
  Machine to machine
  <a
    href="https://westernwilson.com/reflections/oidc/#machine-to-machine"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>A GitHub Actions CI/CD pipeline can&rsquo;t easily open a browser or tap an allow button on your phone. It needs to authenticate to AWS without a person in the loop, securely, and without any of the interactive trust mechanisms that make SSO work locally.</p>
<p>The old answer was to generate an AWS access key pair, paste it into GitHub as a secret, and let the pipeline use that to authenticate with AWS. This still works, but it&rsquo;s a liability and no longer recommended. Long-lived access keys, if leaked, can grant authentication to whoever gets them. Unfortunately, because infra work requires a broader set of permissions, losing these keys is a bigger security risk.</p>
<p>Long-lived keys should also be <em>rotated</em> frequently (i.e. rotating means to update the keys). That requires additional reminder scheduling, and if the key is used in many places, the work to update might require a bit more effort.</p>
<p>The better answer is Open ID Connect (OIDC). To understand OIDC, you have to understand JWTs first.</p>
<h2 id="jwts" class="group relative scroll-mt-20">
  JWTs
  <a
    href="https://westernwilson.com/reflections/oidc/#jwts"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>JWT stands for JSON Web Token. It&rsquo;s a compact, self-contained token for passing claims between parties.</p>
<p>A <strong>claim</strong> is a key-value assertion about a subject, e.g. <code>&quot;sub&quot;: &quot;user_123&quot;</code> or <code>&quot;email&quot;: &quot;john@example.com&quot;</code>. The issuer party (AWS or GitHub) is saying: I assert these properties are true about the subject of this token (and that it is valid for the stated audience and time window)</p>
<p>What might be at first surprising, is that a signed JWT isn&rsquo;t encrypted and anyone can read it. Paste a JWT string into <a href="https://jwt.io">jwt.io</a> and you&rsquo;ll see everything inside (with real tokens, keep them out of public tools!).</p>
<p>The point of JWT tokens isn&rsquo;t secrecy, it&rsquo;s integrity. If you trust the issuer&rsquo;s public key, and the signature checks out, then you can trust the claims.</p>
<p>Think of it like a driver&rsquo;s licence, it&rsquo;s contents are not a secret (anyone who physically holds it has the info), but it&rsquo;s validity is trusted because it was created by a trusted authority. Other parties (police, security, the supermarket cashier) recognise it and trust what it <em>claims</em>.</p>
<p>A JWT is a string with three parts separated by dots. Header, payload, and signature.</p>
<div class="highlight"><pre tabindex="0"><code class="language-zsh" data-lang="zsh"><span><span>&lt;header&gt;.&lt;payload&gt;.&lt;signature&gt;
</span></span></code></pre></div><p>The <em>header</em> says how it was signed. The <em>payload</em> is a set of claims or facts about whoever the token is describing. The <em>signature</em> is the issuer&rsquo;s cryptographic stamp.</p>
<p>E.g.</p>
<div class="highlight"><pre tabindex="0"><code class="language-zsh" data-lang="zsh"><span><span>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjdXJpb3VzX3JlYWRlciIsIm5hbWUiOiJZb3UsIHRoZSBjdXJpb3VzIG9uZSIsIm1lc3NhZ2UiOiJUaGV5IHNheSBjdXJpb3NpdHkga2lsbGVkIHRoZSBjYXQsIGJ1dCBpdCB3b24ndCBraWxsIHlvdS4gU3RheSBjdXJpb3VzLiIsImlhdCI6MTc0NjY2MjQwMCwiZXhwIjo5OTk5OTk5OTk5fQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
</span></span></code></pre></div><p>You can read more detail here: <a href="https://www.jwt.io/introduction#what-is-json-web-token">https://www.jwt.io/introduction#what-is-json-web-token</a></p>
<h2 id="oidc" class="group relative scroll-mt-20">
  OIDC
  <a
    href="https://westernwilson.com/reflections/oidc/#oidc"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>OIDC (OpenID Connect) is how JWTs get used for authentication. An identity provider mints a signed JWT about who someone is or what it&rsquo;s doing, and a relying party verifies the token and decides what to do.</p>
<p>Back to the analogy of a JWT and a drivers license. The issuing authority is whoever grants drivers licenses, in New Zealand this would be NZ Transport Agency (NZTA or Waka Kotahi). The relying party, again, could be police, security, or the supermarket cashier.</p>
<p>For your CI/CD, GitHub is the identity provider and AWS is the relying party. GitHub publishes its public keys at a well-known URL. AWS knows where to find them and when the workflow pipeline runs, GitHub mints a JWT describing that specific job (the repo, git branch, the workflow file) and signs it. The pipeline hands the token to AWS, AWS verifies the signature, reads the claims, and decides whether to issue short-lived credentials.</p>
<p>There&rsquo;s no shared secret and no pre-arranged handshake. You declare in your AWS account that you trust GitHub&rsquo;s issuer URL and from that moment, AWS knows how to verify any token GitHub signs.</p>
<p>This grants you authentication, and next it&rsquo;s important to look at the policies that grant authorisation to make changes.</p>
<h2 id="the-trust-policy" class="group relative scroll-mt-20">
  The trust policy
  <a
    href="https://westernwilson.com/reflections/oidc/#the-trust-policy"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>With the authentication and JWT verification mostly handled by AWS &amp; GitHub, you can focus more on deciding which GitHub claims you&rsquo;ll accept.</p>
<p>For example, every JWT GitHub mints contains a <code>sub</code> claim, i.e. the subject</p>
<div class="highlight"><pre tabindex="0"><code class="language-zsh" data-lang="zsh"><span><span>repo:my-org/my-repo:ref:refs/heads/main
</span></span></code></pre></div><p>That string identifies exactly which repo, branch, or trigger produced the token. Your trust policy in AWS is a set of conditions on those claims. So if you pin the <code>sub</code> claim to a specific repo and your main branch (like the above example), then only that combination can assume the role.</p>
<p>Set up the AWS trust policy too loosely and you replace one risk with another. The biggest mistake is wildcarding the subject <code>repo:*</code>, which means that any repository on GitHub could potentially assume your role. The fix is to only give access to specific repositories that need it, following least privilege access. Most tutorials highlight this point too.</p>
<h2 id="using-github-environments" class="group relative scroll-mt-20">
  Using GitHub environments
  <a
    href="https://westernwilson.com/reflections/oidc/#using-github-environments"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>Many tutorials suggest the use of GitHub Environments for production deploys. So you can pin the trust policy to <code>repo:my-org/my-repo:environment:production</code>. You then set up your repo to require manual approval on production deployments, thus adding another layer of protection. Now even a workflow on main can&rsquo;t deploy until a human clicks a button.</p>
<p>For an enterprise team, this makes sense. Multiple people merging code, the reviewer and the deployer might not be the same person. So the approval gate gives you a real second pair of eyes.</p>
<p>For a solo project without actual customers it&rsquo;s optional, but worth knowing the pattern exists for when the team grows.</p>
<h2 id="relearning" class="group relative scroll-mt-20">
  Relearning
  <a
    href="https://westernwilson.com/reflections/oidc/#relearning"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>Coming back to OIDC after a year of travel, I noticed new details since the first time round. Especially in terms of trust policies, and <em>why</em> the <code>sub</code> claim specificity matters. Going back to first principles about JWTs and OIDC before touching any config gave that stronger mental model.</p>
<p>If you want to see how someone might configure all of this, check out my repositories here:</p>
<ul>
<li>AWS Foundation SSO &amp; OIDC setup: <a href="https://github.com/wjkw1/aws-foundations">https://github.com/wjkw1/aws-foundations</a></li>
<li>Demo Application: <a href="https://github.com/wjkw1/devops-profile-coffee-card-app-demo">https://github.com/wjkw1/devops-profile-coffee-card-app-demo</a></li>
</ul>
]]></content:encoded></item><item><title>Deciding what to keep</title><link>https://westernwilson.com/reflections/bunq-hackathon-7/</link><pubDate>Sun, 03 May 2026 00:00:00 +0000</pubDate><guid>https://westernwilson.com/reflections/bunq-hackathon-7/</guid><description>It was around 4am when I scrapped the project. AI had co-built me a FastAPI cathedral, full of libraries I didn’t recognise and an architecture more ambitious than a 24 hour hackathon could achieve. The code worked, sort of. Extending it would be challenging, and integrating it with AWS would take time we didn’t have. So I deleted everything and started again with something simple that we could build and demo quickly.&#10;</description><content:encoded><![CDATA[<p>It was around 4am when I scrapped the project. AI had co-built me a FastAPI cathedral, full of libraries I didn&rsquo;t recognise and an architecture more ambitious than a 24 hour hackathon could achieve.
The code worked, sort of. Extending it would be challenging, and integrating it with AWS would take time we didn&rsquo;t have. So I deleted everything and started again with something simple that we could build and demo quickly.</p>
<p>This moment has been circling in my mind across this last week.</p>
<h2 id="how-i-got-there" class="group relative scroll-mt-20">
  How I got there
  <a
    href="https://westernwilson.com/reflections/bunq-hackathon-7/#how-i-got-there"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>I went to Amsterdam for three nights to see the city and to take part in Bunq&rsquo;s 24-hour hackathon. I arrived alone and Bunq connected me with a team. On the day two people didn&rsquo;t show so we ended up finding two others in similar situations and formed a new team.</p>
<p>The hackathon brief was to build something that solved a problem, used the Bunq API, and had some kind of multi-modal AI. I didn&rsquo;t know what we&rsquo;d build, and honestly that was exciting to me!</p>
<h2 id="who-i-worked-with" class="group relative scroll-mt-20">
  Who I worked with
  <a
    href="https://westernwilson.com/reflections/bunq-hackathon-7/#who-i-worked-with"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>Our team was called &ldquo;4 corners&rdquo; with people from four countries. We had a DevOps Engineer, Business Analyst, Product Owner, and even a CFO. Honestly, it was a privilege to be around such accomplished people whose lives had taken different trajectories leading them to this moment.</p>
<h2 id="the-build" class="group relative scroll-mt-20">
  The build
  <a
    href="https://westernwilson.com/reflections/bunq-hackathon-7/#the-build"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>On the day we had a brilliant talk by someone from AWS about spec driven development. I took that talk to heart and tried building our app using that same ethos. This led me to a vibe-coded backend app in Python, the language I knew, but attempting to use production-grade infrastructure. For a 24-hour prototype, this was overkill. The AI, eager to please, happily built me something far beyond what the hackathon called for.</p>
<p>It reminds me of something an old colleague once told me:</p>
<blockquote>
<p>building something is easy, productionising it is the hard bit</p>
</blockquote>
<p>In this hackathon, unfortunately, I started off by inverting their advice. I was productionising something before I&rsquo;d built anything.</p>
<h2 id="the-pivot" class="group relative scroll-mt-20">
  The pivot
  <a
    href="https://westernwilson.com/reflections/bunq-hackathon-7/#the-pivot"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>You can wrangle an app together in 24 hours. What matters more is whether you&rsquo;ve thought clearly about the problem, can articulate the pain point, and can demonstrate something useful with honest tradeoffs.</p>
<ul>
<li>Mock APIs not crucial to the core solution instead of integrating with them.</li>
<li>Stub the database or run one locally to show the core idea working.</li>
<li>Later, if there&rsquo;s time then connect the real infra.</li>
</ul>
<p>The lesson for me was closing the gap between ambition and execution. A gentle reminder to focus more on the problem being solved, and on building an MVP that demonstrates a useful solution.</p>
<p>That&rsquo;s what scrapping the bloated AI app got me back to. Something small, something easily understood, something we could actually show someone.</p>
<p>The winning teams that night? Mostly localhost applications.</p>
<h2 id="amsterdam" class="group relative scroll-mt-20">
  Amsterdam
  <a
    href="https://westernwilson.com/reflections/bunq-hackathon-7/#amsterdam"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>After the Hackathon winners were announced, I left Bunq HQ into a city I&rsquo;d been told was lovely. My cousin recommended Amsterdam as the place to be, and I could see why. Flat landscape, bike-friendly, sunny skies that week (rare, apparently), with free ferries criss-crossing the harbour, and people moving through it all with quiet competence. It felt like a larger Wellington with better trains.</p>
<p>I came partly to see whether I could live in Amsterdam. I left knowing I could.</p>
]]></content:encoded></item><item><title>Terraform state s3 bucket naming convention</title><link>https://westernwilson.com/reflections/terraform-state-s3-bucket-naming-convention/</link><pubDate>Sat, 11 Apr 2026 00:00:00 +0000</pubDate><guid>https://westernwilson.com/reflections/terraform-state-s3-bucket-naming-convention/</guid><description>While working on my personal devops project (see github), I realised I hadn’t thought through the naming convention of my terraform state in a long time.&#10;Naming convention decision Final name: tfstate-{AccountId}-{GitHubRepo}&#10;Example: tfstate-123456789012-aws-foundations&#10;Why this name The convention earns its structure because I’m committing to one terraform state bucket per project.&#10;</description><content:encoded><![CDATA[<p>While working on my personal devops project (<a href="https://github.com/wjkw1/devops-profile-coffee-card-app-demo">see github</a>), I realised I hadn&rsquo;t thought through the naming convention of my terraform state in a long time.</p>
<h2 id="naming-convention-decision" class="group relative scroll-mt-20">
  Naming convention decision
  <a
    href="https://westernwilson.com/reflections/terraform-state-s3-bucket-naming-convention/#naming-convention-decision"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p><strong>Final name:</strong> <code>tfstate-{AccountId}-{GitHubRepo}</code></p>
<p><strong>Example:</strong> <code>tfstate-123456789012-aws-foundations</code></p>
<h3 id="why-this-name" class="group relative scroll-mt-20">
  Why this name
  <a
    href="https://westernwilson.com/reflections/terraform-state-s3-bucket-naming-convention/#why-this-name"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<p>The convention earns its structure because I&rsquo;m committing to one terraform state bucket per project.</p>
<p>So, the three pieces of information communicated in the bucket name:</p>
<table>
	<thead>
			<tr>
					<th>Segment</th>
					<th>Reason</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><code>tfstate</code> <em>prefix</em></td>
					<td>Immediately identifies the bucket&rsquo;s purpose to any observer, without needing to open it.</td>
			</tr>
			<tr>
					<td><code>{AccountId}</code></td>
					<td>The only reliable way to guarantee global S3 uniqueness (bucket names are shared across all of AWS); also identifies ownership at a glance in billing, access logs, and cross-account contexts.</td>
			</tr>
			<tr>
					<td><code>{GitHubRepo}</code></td>
					<td>1:1 mapping between bucket and repository — you can navigate from S3 → GitHub (or back) without any lookup.</td>
			</tr>
	</tbody>
</table>
<p>The convention scales cleanly: every future infrastructure repository gets <code>tfstate-{AccountId}-{GitHubRepo}</code>, with no naming decisions to revisit.</p>
<h3 id="options-considered-and-why-they-were-rejected" class="group relative scroll-mt-20">
  Options considered and why they were rejected
  <a
    href="https://westernwilson.com/reflections/terraform-state-s3-bucket-naming-convention/#options-considered-and-why-they-were-rejected"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<p><strong><code>tfstate-aws-foundations</code></strong></p>
<p>Not globally unique, and almost certainly already taken thanks to the known limitation of S3. It also encodes the github project name in a bucket originally conceived as potentially holding all account state. Once my intent changed, the name became misleading.</p>
<p><strong><code>tfstate-{AccountId}</code></strong> <em>(original)</em></p>
<p>Unique and future-proof, but loses the repo link. Fine if one bucket holds state for many projects; less good when the bucket is scoped 1:1 to a single repo, where the link has real navigational value.</p>
<p><strong><code>{AccountId}-aws-foundations</code></strong></p>
<p>Globally unique, still links to the repo. But without a <code>tfstate</code> indicator, anyone browsing S3 has no immediate signal about what the bucket is for. The AccountId prefix also groups infrastructure buckets together when sorted, at the cost of reading unnaturally left-to-right.</p>
<p><strong><code>aws-foundations-{AccountId}</code></strong></p>
<p>More readable than the account-first example, same repo link. Still missing the <code>tfstate</code> indicator.</p>
<p><strong><code>tfstate-{AccountId}-aws-foundations</code></strong> <em>(chosen)</em></p>
<p>Purpose is obvious. Guaranteed to be unique. The 1:1 GitHub mapping is perfect. The tradeoff: twelve digits in the middle makes the name long and not great to say out loud. That cost is low because this string gets typed approximately twice in the bucket&rsquo;s lifetime &ndash; at creation and in <code>versions.tf</code> &ndash; so conversational readability is not important.</p>
<h3 id="convention-going-forward" class="group relative scroll-mt-20">
  Convention going forward
  <a
    href="https://westernwilson.com/reflections/terraform-state-s3-bucket-naming-convention/#convention-going-forward"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<p><code>tfstate-{AccountId}-{GitHubRepo}</code></p>
<p>Other projects I create that require aws infra will each get their own S3 state bucket following this pattern.</p>
<p>This gives me state isolation between projects; a terraform mistake in one project cannot affect another, and state files stay small and fast.</p>
]]></content:encoded></item><item><title>When I say 'chasing threads'</title><link>https://westernwilson.com/reflections/chasing-threads/</link><pubDate>Sat, 04 Apr 2026 00:00:00 +0000</pubDate><guid>https://westernwilson.com/reflections/chasing-threads/</guid><description>There is this idea in productivity circles, self-help books, and startup culture: Focus. Only work on what matters. Cut the noise. Eliminate the distractions.&#10;I think that’s only half the story.&#10;Chasing threads is about following inspiration when it strikes.&#10;During my induction week as a graduate engineer, over seven years ago, I was told a story about our CEO. It’s where I first felt encouraged to be curious at work.&#10;</description><content:encoded><![CDATA[<p>There is this idea in productivity circles, self-help books, and startup culture: Focus. Only work on what matters. Cut the noise. Eliminate the distractions.</p>
<p>I think that&rsquo;s only half the story.</p>
<p>Chasing threads is about following inspiration when it strikes.</p>
<p>During my induction week as a graduate engineer, over seven years ago, I was told a story about our CEO. It&rsquo;s where I first felt encouraged to be curious at work.</p>
<p>The CEO had a planned visit to one of our front-line Telco stores. All staff were prepped with questions and had a stacked agenda for photos and content capture. When the boss arrived, he spotted a staff member off to the side, absorbed in something (repairing a device, restocking a shelf) I can&rsquo;t quite remember.</p>
<p>He walked over and simply asked: &ldquo;Hey what are you doing?&rdquo;</p>
<p>Whoever this person was, they spoke about what they were doing with such genuine passion and joy that the CEO scrapped the rest of the agenda entirely. He spent the whole visit just talking with this one person about technology, about their goals, about what they loved about the job.</p>
<p>That conversation turned into a friendship. They kept in touch across the year. And eventually, that staff member grew into a role back at headquarters. All because the boss saw someone doing something that looked interesting, and went and spoke to them.</p>
<p>Do you know the feeling? You&rsquo;re reading something and a word catches you, you look it up, and suddenly you&rsquo;re twenty minutes deep into the history of something you never knew you cared about.</p>
<p>The conventional wisdom says to ignore that. To get back on task and stay on track.</p>
<p>But what if the thread is the track?</p>
<p>Here&rsquo;s the reframe I often come back to: life is distractions. It&rsquo;s the distractions the give life meaning. Not in the doom-scrolling-at-2am sense. In the sense that the interesting stuff, the stuff that actually shapes who you are, rarely arrives through the front door. It sneaks up on you. It&rsquo;s the thing you weren&rsquo;t supposed to be doing that ends up mattering most.</p>
<p>Steve Jobs is probably the most famous example of this. In his 2005 Stanford commencement speech, he talked about dropping in on a calligraphy class at Reed College out of pure curioisty, with no practical application in mind. A decade later, that class became the foundation for the beautiful typography of the first Macintosh.</p>
<p>He didn&rsquo;t chase calligraphy because it was strategic. He chased it because it pulled at him. Same instinct as a CEO who walks past a stacked agenda to talk to someone doing something interesting. Same instinct as anyone who follows a word into a twenty-minute rabbit hole and comes out knowing something they didn&rsquo;t expect to care about.</p>
<p>But I have to be honest with myself, because this idea has a dark twin. Something a colleague of mine introduced me to because I was chasing the latest technologies all the time.</p>
<p>There&rsquo;s a concept called <a href="https://en.wikipedia.org/wiki/Shiny_object_syndrome">Shiny Object Syndrome</a>. The idea that some people —especially curious, creative, entrepreneurial types— get so drawn to the next interesting thing that they never actually go deep on anything. They bounce from project to project, tool to tool, always chasing novelty, never building something real.</p>
<p>I&rsquo;ve been there. Most curious people have. You pick up a thread and it leads you to another thread, and another, and before you know it you&rsquo;ve spent a whole day falling down rabbit holes and nothing is finished.</p>
<p>The shiny ball of yarn is real. And if you&rsquo;re not careful, chasing threads becomes a sophisticated-sounding excuse for avoiding the hard, slow, unglamorous work of actually finishing things.</p>
<p>The difference between a thread worth chasing and a shiny object isn&rsquo;t obvious in the moment; but it becomes clear with a bit of distance. If you park an idea for a few days and it&rsquo;s still pulling at you, it&rsquo;s probably a thread worth chasing. If you forget about it, then it probably wasn&rsquo;t worth following anyway.</p>
<p>So go chase your own threads. Not all of them and not recklessly. But when something tugs at you, don&rsquo;t immediately dismiss it as a distraction.</p>
]]></content:encoded></item><item><title>Linting and formatting code</title><link>https://westernwilson.com/reflections/linting-and-formatting/</link><pubDate>Thu, 02 Apr 2026 00:00:00 +0000</pubDate><guid>https://westernwilson.com/reflections/linting-and-formatting/</guid><description>TL;DR: Code style and formatting should not steal your brainpower. Set up linting/formatting at three touchpoints (your editor, your pre-commit hook, and your CI pipeline) and formatting becomes automatic from the moment you write code to the moment it merges. At the end, this reflection walks through exactly how to do that for a Python FastAPI project.&#10;Linting and formatting code Recently, while working on a personal DevOps project, I spent some time looking into linting tools. They amazingly save your brainpower for the actual problem, instead of code styling. Whether it’s two spaces or four per indent, single quotes or double, I don’t mind. Other people have thought deeply about these trade-offs, landed on reasonable answers, and codified them. I’m happy to piggyback on that.&#10;</description><content:encoded><![CDATA[<p><strong>TL;DR:</strong> Code style and formatting should <strong>not</strong> steal your brainpower. Set up linting/formatting at three touchpoints (your editor, your pre-commit hook, and your CI pipeline) and formatting becomes automatic from the moment you write code to the moment it merges. At the end, this reflection walks through exactly how to do that for a Python <a href="https://fastapi.tiangolo.com">FastAPI</a> project.</p>
<h2 id="linting-and-formatting-code" class="group relative scroll-mt-20">
  Linting and formatting code
  <a
    href="https://westernwilson.com/reflections/linting-and-formatting/#linting-and-formatting-code"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>Recently, while working on a <a href="https://github.com/wjkw1/devops-profile-coffee-card-app-demo">personal DevOps project</a>, I spent some time looking into linting tools. They amazingly save your brainpower for the actual problem, instead of code styling. Whether it&rsquo;s two spaces or four per indent, single quotes or double, I don&rsquo;t mind. Other people have thought deeply about these trade-offs, landed on reasonable answers, and codified them. I&rsquo;m happy to piggyback on that.</p>
<p>I aim to write code that works, and let the styling happen automatically.</p>
<p>There&rsquo;s a side benefit too: when a codebase consistently uses a popular linting tool, anyone familiar with it can scan the code and immediately know where to look. It&rsquo;s like how headings in a research paper let you scan before you commit to reading.</p>
<h2 id="three-touchpoints-that-matter" class="group relative scroll-mt-20">
  Three touchpoints that matter
  <a
    href="https://westernwilson.com/reflections/linting-and-formatting/#three-touchpoints-that-matter"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>Good linting hygiene should show up at meaningful points in your development lifecycle:</p>
<ol>
<li><strong>In your IDE (or text editor), as you write</strong></li>
<li><strong>Locally, before you commit</strong></li>
<li><strong>In CI/CD, before code merges</strong></li>
</ol>
<p>Each layer serves a different purpose. Together, they make code quality essentially automatic. (Tools like <a href="https://www.sonarsource.com/products/sonarqube/">SonarQube</a> go deeper —security, coverage, and code smells at a project level— but that&rsquo;s a reflection for another time.)</p>
<figure class="img-light"><img src="https://westernwilson.com/reflections/linting-and-formatting/linting_touchpoints_light.svg"
			alt="Three linting touchpoints">
</figure>

<figure class="img-dark"><img src="https://westernwilson.com/reflections/linting-and-formatting/linting_touchpoints_dark.svg"
			alt="Three linting touchpoints">
</figure>

<p><strong>In the IDE (or text editor)</strong>, I use <a href="https://code.visualstudio.com">VS Code</a> with the relevant extensions installed and Format on Save enabled. It does what it sounds like: when the file saves, the formatter runs. Sometimes this needs dev dependencies installed to work properly; check the official docs and you&rsquo;ll figure it out quickly, I&rsquo;ll go into <a href="https://docs.astral.sh/ruff/">Ruff</a> for Python specifically later in this post.</p>
<p><strong>Locally, before committing</strong>, is where things get interesting. At various companies I&rsquo;ve seen the same pattern repeat: developer forgets to format, pushes code, CI fails, they fix locally, force-push, CI reruns. This adds ten minutes to the dev cycle, minimum. Multiply that across a team and it adds up quickly.</p>
<p>Git&rsquo;s <a href="https://pre-commit.com">pre-commit</a> hooks solve this cleanly. When you attempt a commit, a hook runs your formatting and linting checks first. If they fail, the commit doesn&rsquo;t go through. This means no broken CI and no annoying formatting fix commits. This enables the code to validate itself before it ever leaves your machine.</p>
<p>The one catch: developers can skip the setup step entirely, which is exactly why the third layer exists.</p>
<p><strong>In CI/CD</strong>, the pipeline enforces what the pre-commit hook encourages. Even if someone bypasses local hooks, nothing merges unless the linting passes. This is your actual quality gate and is what you rely on.</p>
<h2 id="why-ruff-instead-of-black-and-flake8" class="group relative scroll-mt-20">
  Why Ruff instead of Black and Flake8
  <a
    href="https://westernwilson.com/reflections/linting-and-formatting/#why-ruff-instead-of-black-and-flake8"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>Three or more years ago, I used <a href="https://black.readthedocs.io/en/stable/">Black</a> for formatting and <a href="https://flake8.pycqa.org/en/latest/">Flake8</a> for static analysis. Two tools, two configs, two things to install and maintain. It was a minor friction, but that friction compounded and was a little naff.</p>
<p>Ruff replaces both with a single tool. It&rsquo;s faster, simpler, and opinionated enough that you don&rsquo;t have to make many decisions. For a project where the point is <em>less thinking about styling and formatting</em>, that&rsquo;s exactly what I wanted.</p>
<h2 id="the-setup-python--fastapi" class="group relative scroll-mt-20">
  The Setup (Python / FastAPI)
  <a
    href="https://westernwilson.com/reflections/linting-and-formatting/#the-setup-python--fastapi"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>Three things to configure, in roughly this order:</p>
<h3 id="step-1-vs-code--ruff-extension" class="group relative scroll-mt-20">
  Step 1: VS Code + Ruff extension
  <a
    href="https://westernwilson.com/reflections/linting-and-formatting/#step-1-vs-code--ruff-extension"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<p>Install the <a href="https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff">Ruff extension</a> from the VS Code marketplace — the official one is published by Astral (charliermarsh.ruff). Once installed, add this to your .vscode/settings.json:</p>
<div class="highlight"><pre tabindex="0"><code class="language-json" data-lang="json"><span><span>{
</span></span><span><span>  <span>&#34;[python]&#34;</span>: {
</span></span><span><span>    <span>&#34;editor.formatOnSave&#34;</span>: <span>true</span>,
</span></span><span><span>    <span>&#34;editor.defaultFormatter&#34;</span>: <span>&#34;charliermarsh.ruff&#34;</span>,
</span></span><span><span>    <span>&#34;editor.codeActionsOnSave&#34;</span>: {
</span></span><span><span>      <span>&#34;source.fixAll.ruff&#34;</span>: <span>&#34;explicit&#34;</span>,
</span></span><span><span>      <span>&#34;source.organizeImports.ruff&#34;</span>: <span>&#34;explicit&#34;</span>
</span></span><span><span>    }
</span></span><span><span>  }
</span></span><span><span>}
</span></span></code></pre></div><p>Committing <code>.vscode/settings.json</code> to the repo is intentional. Anyone who clones the project and opens it in VS Code gets the same formatting behaviour automatically. No extra knowledge required.</p>
<p>No separate Ruff installation is needed as the VS Code extension ships its own binary, and the pre-commit hook (added in Step 2) bundles its own too. You just need to add your Ruff config to <code>ruff.toml</code>:</p>
<div class="highlight"><pre tabindex="0"><code class="language-toml" data-lang="toml"><span><span>[<span>tool</span>.<span>ruff</span>]
</span></span><span><span><span>line-length</span> = <span>88</span>
</span></span><span><span><span>target-version</span> = <span>&#34;py312&#34;</span>
</span></span><span><span>
</span></span><span><span>[<span>tool</span>.<span>ruff</span>.<span>lint</span>]
</span></span><span><span><span>select</span> = [<span>&#34;E&#34;</span>, <span>&#34;F&#34;</span>, <span>&#34;I&#34;</span>]
</span></span></code></pre></div><p>The select block opts into pycodestyle errors (E), Pyflakes (F), and isort import sorting (I). This covers what you&rsquo;d previously have needed Black, Flake8, and <a href="https://pycqa.github.io/isort/">isort</a> to do separately.</p>
<h3 id="step-2-pre-commit-hooks" class="group relative scroll-mt-20">
  Step 2: Pre-commit hooks
  <a
    href="https://westernwilson.com/reflections/linting-and-formatting/#step-2-pre-commit-hooks"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<p>First, install the pre-commit package:</p>
<div class="highlight"><pre tabindex="0"><code class="language-bash" data-lang="bash"><span><span>pip install pre-commit
</span></span></code></pre></div><p>Then create a <code>.pre-commit-config.yaml</code> in the root of your repo. Here&rsquo;s exactly what&rsquo;s in the project:</p>
<div class="highlight"><pre tabindex="0"><code class="language-yaml" data-lang="yaml"><span><span><span>repos</span>:
</span></span><span><span>  - <span>repo</span>: <span>https://github.com/astral-sh/ruff-pre-commit</span>
</span></span><span><span>    <span>rev</span>: <span>v0.11.4</span>
</span></span><span><span>    <span>hooks</span>:
</span></span><span><span>      - <span>id</span>: <span>ruff</span>
</span></span><span><span>        <span>args</span>: [--<span>fix]</span>
</span></span><span><span>        <span>files</span>: <span>^api/</span>
</span></span><span><span>      - <span>id</span>: <span>ruff-format</span>
</span></span><span><span>        <span>files</span>: <span>^api/</span>
</span></span></code></pre></div><p>A few things worth noting here. The files: <code>^api/</code> pattern scopes the hooks to the API directory only — the frontend has its own linting story (<a href="https://eslint.org">ESLint</a> + <a href="https://prettier.io">Prettier</a>), so there&rsquo;s no point running Ruff across the whole repo. The ruff hook handles lint checks and the <code>--fix</code> flag means it&rsquo;ll auto-fix what it can rather than just reporting issues. The ruff-format hook handles formatting, equivalent to what Black would have done.
Once the file is in place, install the hooks:</p>
<div class="highlight"><pre tabindex="0"><code class="language-bash" data-lang="bash"><span><span>pre-commit install
</span></span></code></pre></div><p>This wires the hooks into your local <code>.git/hooks/pre-commit</code>. From this point, every time you run git commit, Ruff runs first. If it finds issues it can&rsquo;t auto-fix, the commit is blocked and the problems are printed to the terminal. Fix them, stage the changes, and commit again.
You can also run it manually across all files at any point:</p>
<div class="highlight"><pre tabindex="0"><code class="language-bash" data-lang="bash"><span><span>pre-commit run --all-files
</span></span></code></pre></div><p>Useful for a first run after setting up, or after pulling in changes from someone else who hasn&rsquo;t had the hooks installed.</p>
<p>That&rsquo;s it. Once it&rsquo;s done, your automatic project linting works in the background. Which is perfect.</p>
]]></content:encoded></item><item><title>C4 Models for software system diagrams</title><link>https://westernwilson.com/reflections/c4models/</link><pubDate>Fri, 20 Mar 2026 00:00:00 +0000</pubDate><guid>https://westernwilson.com/reflections/c4models/</guid><description>In 2022, a colleague introduced me to the C4 Model framework for architecture diagrams. At the time, I’d seen nothing like it. I’d often been in whiteboard sessions, struggling to make sense of all the boxes and lines people drew. Diagrams were drawn completely different depending on the person holding the marker. This colleague was a star communicator and an inspiring solutions architect. Their ability to convey complex ideas clearly was a huge influence in me picking up the framework and running with it for my own diagrams.&#10;</description><content:encoded><![CDATA[<p>In 2022, a colleague introduced me to the C4 Model framework for architecture diagrams. At the time, I&rsquo;d seen nothing like it. I&rsquo;d often been in whiteboard sessions, struggling to make sense of all the boxes and lines people drew. Diagrams were drawn completely different depending on the person holding the marker.
This colleague was a star communicator and an inspiring solutions architect. Their ability to convey complex ideas clearly was a huge influence in me picking up the framework and running with it for my own diagrams.</p>
<h3 id="what-is-the-c4-model" class="group relative scroll-mt-20">
  What is the C4 Model?
  <a
    href="https://westernwilson.com/reflections/c4models/#what-is-the-c4-model"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<p>The C4 Model is a structured, uniform approach to describe the architecture of a software system at different level of detail. Instead of throwing everything onto a single diagram and hoping people get it, it organises abstractions in a way that mirrors how developers or software architects tend to think about systems.</p>
<p>The 4 levels are:</p>
<ol>
<li>System Context - the big picture: your system and how it interacts with users and other systems.</li>
<li>Containers - the applications and data stores that make up your system.</li>
<li>Components - the building blocks of each of our containers.</li>
<li>Code - the classes, interfaces, and functions that implement each component.
The official definition explains it best:
<blockquote>
<p>A software system is made up of one or more containers (applications and data stores), each of which contains one or more components, which in turn are implemented by one or more code elements (classes, interfaces, objects, functions, etc). And people (actors, roles, personas, named individuals, etc) use the software systems that we build.
Source: <a href="https://arc.net/l/quote/kvovhsbn">https://arc.net/l/quote/kvovhsbn</a>
Visit the official website to read more detail about this framework.</p>
</blockquote>
</li>
</ol>
<h3 id="the-map-is-not-the-territory" class="group relative scroll-mt-20">
  The map is not the territory
  <a
    href="https://westernwilson.com/reflections/c4models/#the-map-is-not-the-territory"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<p>A book called The Great Mental Models: General Thinking Concepts has a chapter called &ldquo;the map is not the territory&rdquo;. The idea being that the granularity of Google Maps, does not show the same level of detail as someone walking around on the ground. This is a similar line of reasoning useful when thinking about the C4 diagram.
For most intents and purposes, the maps context is enough to be useful at a high-level. But sometimes, we need more detail to understand what is going on under the hood. That&rsquo;s why we have these layers of abstraction, and at each abstraction we are targeting a different audience.</p>
<h3 id="the-caveat-at-the-code-level" class="group relative scroll-mt-20">
  The caveat at the code level
  <a
    href="https://westernwilson.com/reflections/c4models/#the-caveat-at-the-code-level"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<p>The creator of this framework, Simon Brown, recommends never manually building the lowest level C4 class diagram. It&rsquo;s not worth the effort of building, and definitely not worth keeping updated; especially with the pace at which software changes nowadays. The level of detail is normally so closely related to code that it can (and should) be generated automatically.
This is a pragmatic acknowledgement that diagrams are tools, not artefacts to be maintained for their own sake. If a diagram can&rsquo;t keep pace with reality, it quickly becomes a source of confusion rather than clarity.</p>
<h3 id="examples-from-a-personal-project" class="group relative scroll-mt-20">
  Examples from a personal project
  <a
    href="https://westernwilson.com/reflections/c4models/#examples-from-a-personal-project"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<p>I&rsquo;ve been applying this framework in a recent pet project. If you&rsquo;d like to see the diagrams in action, head over to the demo project here: devops-profile-coffee-card-app-demo.</p>
<h4 id="context" class="group relative scroll-mt-20">
  Context
  <a
    href="https://westernwilson.com/reflections/c4models/#context"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h4>
<p><img src="https://westernwilson.com/reflections/c4models/CoffeeCards-C4-Context.jpg" alt="C4 Context Diagram"></p>
<h4 id="containers" class="group relative scroll-mt-20">
  Containers
  <a
    href="https://westernwilson.com/reflections/c4models/#containers"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h4>
<p><img src="https://westernwilson.com/reflections/c4models/CoffeeCards-C4-Container.jpg" alt="C4 Container Diagram"></p>
<h4 id="components-tbd" class="group relative scroll-mt-20">
  Components TBD
  <a
    href="https://westernwilson.com/reflections/c4models/#components-tbd"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h4>
<p><em>Coming soon&hellip;</em></p>
]]></content:encoded></item><item><title>Reflection vs. Blog</title><link>https://westernwilson.com/reflections/2026-03-20-blogs/</link><pubDate>Fri, 20 Mar 2026 00:00:00 +0000</pubDate><guid>https://westernwilson.com/reflections/2026-03-20-blogs/</guid><description>A blog is a truncation of “weblog” and refers to&#10;“a website containing a writer’s or group of writers’ own experiences, observations, opinions, etc., and often having images and links to other websites.”&#10;A reflection has many meanings, but the two I latch onto are:&#10;a fixing of the thoughts on something; careful consideration. a thought occurring in consideration or meditation. The word reflections carries a quieter, more inward energy for me. It implies that you’re writing for the process of thinking, not for an audience or an outcome. I love that there is no implicit pressure to grow a following, monetise, or be consistent on a schedule.&#10;</description><content:encoded><![CDATA[<p>A <a href="https://www.dictionary.com/browse/blog">blog</a> is a truncation of &ldquo;weblog&rdquo; and refers to</p>
<blockquote>
<p>&ldquo;a website containing a writer&rsquo;s or group of writers&rsquo; own experiences, observations, opinions, etc., and often having images and links to other websites.&rdquo;</p>
</blockquote>
<p>A <a href="https://www.dictionary.com/browse/reflection">reflection</a> has many meanings, but the two I latch onto are:</p>
<blockquote>
<ul>
<li>a fixing of the thoughts on something; careful consideration.</li>
<li>a thought occurring in consideration or meditation.</li>
</ul>
</blockquote>
<p>The word <em>reflections</em> carries a quieter, more inward energy for me. It implies that you&rsquo;re writing for the process of thinking, not <em>for</em> an audience or an outcome. I love that there is no implicit pressure to grow a following, monetise, or be consistent on a schedule.</p>
<p>My perception of <em>blogs</em> is that they come loaded with baggage nowadays. It asks for SEO optimisation, calls to action, newsletter signups, and the hustle of content creation. That&rsquo;s a very different thing from sitting down and genuinely processing your thoughts on paper.</p>
<p>This is why I choose to use <em>reflections</em>, to give me freedom of thought while writing thoughts on a page.</p>
]]></content:encoded></item><item><title>How I use Tags</title><link>https://westernwilson.com/reflections/how-i-use-tags/</link><pubDate>Tue, 17 Mar 2026 00:00:00 +0000</pubDate><guid>https://westernwilson.com/reflections/how-i-use-tags/</guid><description>This page is a personal reference so I remember the tags I use on this site, what they mean, and when to apply them. Max 1–3 tags per post.&#10;meta – Posts about this site itself – announcements, changes, meta type entries. Use when: the post is about the website or process specifically, not a topic within it.&#10;ai – Artificial intelligence, large language models, and how I’m using them in work or writing. Use when: the post is primarily about AI tools, AI tech, or AI behaviour&#10;</description><content:encoded><![CDATA[<p>This page is a personal reference so I remember the tags I use on this site, what they mean, and when to apply them. Max 1–3 tags per post.</p>
<p><strong><code>meta</code></strong> &ndash; Posts about this site itself &ndash; announcements, changes, meta type entries.
<em>Use when:</em> the post is about the website or process specifically, not a topic within it.</p>
<p><strong><code>ai</code></strong> &ndash; Artificial intelligence, large language models, and how I&rsquo;m using them in work or writing.
<em>Use when:</em> the post is primarily about AI tools, AI tech, or AI behaviour</p>
<p><strong><code>career</code></strong> &ndash; Work, professional growth, team dynamics, and lessons from the industry.
<em>Use when:</em> the post reflects on the people side of software &ndash; roles, culture, collaboration.</p>
<p><strong><code>communication</code></strong> &ndash; Explaining ideas about communicating, for example to non-technical audiences, across teams, or in documentation.
<em>Use when:</em> the post is about how we convey information to other people.</p>
<p><strong><code>conference</code></strong> &ndash; Notes and reflections from conferences I attend. Any conference I go to gets written up here.
<em>Use when:</em> the post is about a conference or event I attended, its talks, and what I took away from it.</p>
<p><strong><code>definitions</code></strong> &ndash; Posts that define how I use a specific term, phrase, or concept &ndash; personal vocab entries.
<em>Use when:</em> the post is structured around explaining what something means to me.</p>
<p><strong><code>devops</code></strong> &ndash; Platform engineering, infrastructure, CI/CD, and the operational side of software.
<em>Use when:</em> the post is about systems, pipelines, or keeping things running.</p>
<p><strong><code>devtools</code></strong> &ndash; Tools that shape how I work - editors, CLIs, SSH, local setup.
<em>Use when:</em> the post is hands-on with a specific tool or workflow.</p>
<p><strong><code>writing</code></strong> &ndash; Reflections on the writing process, publishing, and finding my voice.
<em>Use when:</em> the post is about writing itself, not just a post that happens to be well-written.</p>
]]></content:encoded></item><item><title>Making Music - Day 2 GarageBand</title><link>https://westernwilson.com/reflections/2025-08-13-music-day-2/</link><pubDate>Wed, 13 Aug 2025 00:00:00 +0000</pubDate><guid>https://westernwilson.com/reflections/2025-08-13-music-day-2/</guid><description>This blog aims to convince you of two things:&#10;Start that “thing” today—not tomorrow, and not next week. Getting started doesn’t require structure, an official tutorial, or any special gear. ‍Setting the scene I’ve got no idea what I’m doing. I don’t know what software to use, but I do know that I don’t want to pay for anything—at least not until I’m sure making music is something I actually want to pursue.&#10;</description><content:encoded><![CDATA[<p>This blog aims to convince you of two things:</p>
<ol>
<li>Start that “thing” today—not tomorrow, and not next week.</li>
<li>Getting started doesn’t require structure, an official tutorial, or any special gear.</li>
</ol>
<h2 id="setting-the-scene" class="group relative scroll-mt-20">
  ‍Setting the scene
  <a
    href="https://westernwilson.com/reflections/2025-08-13-music-day-2/#setting-the-scene"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>I’ve got no idea what I’m doing. I don’t know what software to use, but I do know that I don’t want to pay for anything—at least not until I’m sure making music is something I actually want to pursue.</p>
<p>First things first, I set out to find the &ldquo;best&rdquo; software to experiment with, without breaking the bank. For me, &ldquo;best&rdquo; meant: no cost, offline mode, a UI that isn’t ugly or archaic, easy-ish to experiment with, and something with learnings that transfer to a more advanced product later on.</p>
<p>In the past I tried Spotify&rsquo;s web UI music creation tool, but it was only online so could only be used while I had internet, the lag wasn&rsquo;t fun and it cost money quite quickly after the trial.</p>
<p>I like <a href="https://www.fredagain.com/">Fred again&rsquo;s</a> music, so I wondered what software he uses - apparently he&rsquo;s a Logic Pro pro. Perplexity reckons Logic Pro is basically an overpowered and extended version of GarageBand. GarageBand comes for free with Macbook&rsquo;s OS…so I went with GarageBand.</p>
<h2 id="getting-started" class="group relative scroll-mt-20">
  ‍Getting started
  <a
    href="https://westernwilson.com/reflections/2025-08-13-music-day-2/#getting-started"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>At this point, I would normally pause there and think &ldquo;job done&rdquo;, lets continue tomorrow.
I have two reasons why I didn&rsquo;t want to pause:</p>
<ol>
<li>Recent content I&rsquo;ve been consuming has encouraged more personal agency. Books like 4-hour workweek or Modern Wisdom&rsquo;s podcast interview with Naval Ravikant.</li>
<li>I read numerous articles of people starting with the only the simplest tools, making music only off their phone</li>
</ol>
<p>So, using Atomic Habits tricks, I told myself to make music for 5 minutes.
Without needing to even downloaded the software, I spend over an hour, hopping around the interface, trying to make a simple beat with the software MIDI controller.</p>
<p>No theory, no structured learning, no tutorials, just dive in and try it out.
This worked well for me, and here is the first beat I made:</p>
<p><a href="https://soundcloud.com/westernwilson/music-day-1">https://soundcloud.com/westernwilson/music-day-1</a></p>
<p>Before this, I didn&rsquo;t know what a MIDI controller was or what a DAW was. (MIDI stands for Musical Instrument Digital Interface and DAW is what GarageBand is, and it stands for Digital Audio Workstation). Now I kinda do???</p>
<p>Honestly, taking a course or chatting with someone more experienced might be a good idea soon. I’ve thought about reaching out to Dera Meelan—someone I’ve enjoyed since hearing his track “Fire Sale” with Church &amp; AP.</p>
<p>A few days past and here was my second beat:</p>
<p><a href="https://soundcloud.com/westernwilson/music-day-2">https://soundcloud.com/westernwilson/music-day-2</a>
‍
If you have any pointers, reach out on any socials or at <a href="mailto:kiaora@westernwilson.com">kiaora@westernwilson.com</a> 🙏</p>
<h3 id="final-note" class="group relative scroll-mt-20">
  ‍Final note
  <a
    href="https://westernwilson.com/reflections/2025-08-13-music-day-2/#final-note"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<p>There are many successful podcasters whose early podcasts sounded like they were recorded in a bedroom closet, sounding unpolished with bad scripts/questions. But no shade, I think that’s how it should be, that’s how you should start.</p>
<p>Point is, you can start today, and you can bootstrap it with minimal investment. Don’t spend on the best equipment if you’re not even remotely sure you’ll want to stick with it in a year; heck, you might quit after a couple of weeks.</p>
<p>Persevere with whatever you&rsquo;ve got going on. Good luck, and stay curious!</p>
]]></content:encoded></item><item><title>AnyType setup with PARA</title><link>https://westernwilson.com/reflections/2025-07-12-anytype-with-para/</link><pubDate>Sat, 12 Jul 2025 00:00:00 +0000</pubDate><guid>https://westernwilson.com/reflections/2025-07-12-anytype-with-para/</guid><description>Find out how I use Tiago Forte’s PARA methodology to organise my notes inside AnyType. If it’s your first time hearing about PARA and AnyType, then lucky you!&#10;Setting the scene First a bit of background, I’m a copious note-taker. I’ve been this way ever since I was a wee boy. Writing notes helped me focus on the speaker better, even when my notes tended to be more of a gibberish scribble and mostly illegible for future Western. With physical note taking however I would consistently forget my notebooks and have to write on spare paper. Then I’d lose the spare paper and the state of my notes was a mixed bag. So, I shifted to digital notes to try solve this problem. What have I tried? Google Docs and Drive, OneNote, BookStack, Wiki.js, Confluence, Notion, Evernote, Obsidian, Google Keep, and others.&#10;</description><content:encoded><![CDATA[<p>Find out how I use Tiago Forte&rsquo;s PARA methodology to organise my notes inside AnyType.
If it&rsquo;s your first time hearing about PARA and AnyType, then lucky you!</p>
<h2 id="setting-the-scene" class="group relative scroll-mt-20">
  Setting the scene
  <a
    href="https://westernwilson.com/reflections/2025-07-12-anytype-with-para/#setting-the-scene"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>First a bit of background, I&rsquo;m a copious note-taker. I&rsquo;ve been this way ever since I was a wee boy. Writing notes helped me focus on the speaker better, even when my notes tended to be more of a gibberish scribble and mostly illegible for future Western.
With physical note taking however I would consistently forget my notebooks and have to write on spare paper. Then I&rsquo;d lose the spare paper and the state of my notes was a mixed bag.
So, I shifted to digital notes to try solve this problem. What have I tried? <a href="https://drive.google.com">Google Docs and Drive</a>, <a href="https://www.microsoft.com/en-us/microsoft-365/onenote">OneNote</a>, <a href="https://www.bookstackapp.com">BookStack</a>, <a href="https://js.wiki">Wiki.js</a>, <a href="https://www.atlassian.com/software/confluence">Confluence</a>, <a href="https://www.notion.so">Notion</a>, <a href="https://evernote.com">Evernote</a>, <a href="https://obsidian.md">Obsidian</a>, <a href="https://keep.google.com">Google Keep</a>, and others.</p>
<p>Unfortunately, no tool was perfect; they all missed one aspect of my requirements, or felt clunky, or had features locked behind paywalls, or couldn&rsquo;t be used while travelling without Internet access (Notion, I&rsquo;m looking at you!).
My requirements:</p>
<ol>
<li>Offline notes with online sync</li>
<li>Free with no paywall</li>
<li>Cross-platform – Windows, Mac &amp; Android</li>
<li>The Notion-like block WYSIWYG text editing</li>
<li>Configurable to use PARA to organise notes (recent ~5yr old requirement)</li>
<li>Markdown export so I&rsquo;m not locked into a tool</li>
<li>Great security</li>
<li>(optional) Graph view to show linkage between notes, so you can see grouped ideas</li>
<li>(optional) Import function or API to script the import</li>
<li>(optional) Collaboration with other note takers</li>
</ol>
<h2 id="introducing-anytype" class="group relative scroll-mt-20">
  Introducing AnyType
  <a
    href="https://westernwilson.com/reflections/2025-07-12-anytype-with-para/#introducing-anytype"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>AnyType hits every requirement above and took them further; open-source, offline first, free forever, online peer to peer sync between cross-platform devices, block editing with Markdown text shortcuts, AnyType Gallery to share and use community templates, great security first, imports and exports, graph view, API and basic collaboration features.
The app is positioning itself as a web3 everything app built on freedom and trust. They&rsquo;re building something special here and since it&rsquo;s inception has consistently improved month on month. It&rsquo;s much more polished than it used to be, it&rsquo;s a joy to work with nowadays.
I&rsquo;ll explain some of the features below, but honestly the best way to get a feel for it is to download and try it yourself: <a href="https://download.anytype.io/">https://download.anytype.io/</a>
The main concepts in AnyType to understand are:</p>
<ol>
<li><a href="https://doc.anytype.io/anytype-docs/getting-started/object-editor">‍Objects</a> - all things are objects in AnyType ‍</li>
<li><a href="https://doc.anytype.io/anytype-docs/getting-started/types">Types</a> - categorise the Objects you create to have a Type ‍</li>
<li><a href="https://doc.anytype.io/anytype-docs/getting-started/types/relations">Properties</a> - attach metadata to Types and create relations between them ‍</li>
<li><a href="https://doc.anytype.io/anytype-docs/getting-started/sets">Query</a> - List view showing a single Object/Type</li>
<li><a href="https://doc.anytype.io/anytype-docs/getting-started/sets/collections">‍Collections</a> - Folder-like collection of different Objects/Types</li>
<li><a href="https://doc.anytype.io/anytype-docs/getting-started/types/templates">‍Templates</a> - speed up your workflow with pre-defined templates for object creation</li>
</ol>
<p>For example, to create a Book tracking system, you could define:‍</p>
<ol>
<li><strong>Book</strong> type with the properties: Title, GoodreadsUrl, and links to an <strong>Author</strong></li>
<li><strong>Author</strong> type with the properties: name &amp; bio‍</li>
<li><strong>Quote</strong> type with a property that links to our <strong>Book</strong></li>
</ol>
<p>Now, when you create a new Book, you can link it to a new or existing Author and write whatever notes about the book that you want. Then when inspired by a Quote, you can create a Quote and link it to your Book. The note taking is flexible, linkage can happen anywhere organically, and you can write whatever you want from within the Author, Book or Quote types. AnyType allows and in fact encourages these relationships between Types.</p>
<figure><img src="https://westernwilson.com/reflections/2025-07-12-anytype-with-para/anytype-schema.png"
			alt="Conceptual example of how Book types could relate to each other in AnyType"><figcaption>
			<p>Conceptual example of how Book types could relate to each other in AnyType</p>
		</figcaption>
</figure>

<figure><img src="https://westernwilson.com/reflections/2025-07-12-anytype-with-para/anytype-graph.png"
			alt="AnyType Graph View of example Book objects"><figcaption>
			<p>AnyType Graph View of example Book objects</p>
		</figcaption>
</figure>

<h2 id="quickly-explaining-para" class="group relative scroll-mt-20">
  Quickly explaining PARA
  <a
    href="https://westernwilson.com/reflections/2025-07-12-anytype-with-para/#quickly-explaining-para"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>If you’re new to <a href="https://fortelabs.com/blog/para/">Tiago Forte’s PARA methodology</a>, you’re in for a treat. PARA is a simple yet powerful system to organise your digital life—whether that’s notes, projects, or files—into four clear categories. It stands for:</p>
<ul>
<li>‍<strong>P - Projects:</strong> Active tasks or outcomes you’re currently working on. ‍</li>
<li><strong>A - Areas:</strong> Ongoing responsibilities or spheres of activity without a specific end date. ‍</li>
<li><strong>R - Resources:</strong> Useful reference materials or topics of interest.</li>
<li>‍<strong>A - Archives:</strong> Inactive items you want to keep but don’t need right now.
As you use this system over time, you’ll develop an intuitive sense for where each note belongs. The key mindset shift for me was letting go of the need to choose the “perfect” category and remembering that it’s easy to move things around later.</li>
</ul>
<h2 id="how-i-use-para-within-anytype" class="group relative scroll-mt-20">
  How I use PARA within AnyType
  <a
    href="https://westernwilson.com/reflections/2025-07-12-anytype-with-para/#how-i-use-para-within-anytype"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>Using PARA inside AnyType means you can create custom Types and Properties for each category, linking notes, tasks, and references easily. You can quickly switch between your active Projects, Areas and Resources, while your Archives keep everything tidy but accessible.
I created a Template Space that should be available to copy from the AnyGallery thanks to my approved <a href="https://github.com/anyproto/gallery/issues/171">github submission</a>. I&rsquo;ll explain how it works below.</p>
<h3 id="key-features" class="group relative scroll-mt-20">
  Key features‍
  <a
    href="https://westernwilson.com/reflections/2025-07-12-anytype-with-para/#key-features"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<ul>
<li>PARA Dashboard is a Query of type Queries with a custom property <strong>PARA Type</strong> set to PARA</li>
<li>Projects, Areas and Resources are a Query of Collection objects with the <strong>PARA Type</strong> set to Project, Area, or Resource respectively.</li>
<li>A collection with an <strong>Is Archive</strong> property checked will show as Archived on the various dashboards.</li>
</ul>
<h3 id="1-para-type-classification" class="group relative scroll-mt-20">
  1. &lsquo;PARA Type&rsquo; Classification
  <a
    href="https://westernwilson.com/reflections/2025-07-12-anytype-with-para/#1-para-type-classification"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<ul>
<li>Introduces a dedicated &ldquo;PARA Type&rdquo; property that allows you to specify whether a Collection is a Project, Area, Resource, or **PARA.**‍</li>
<li>When a Query&rsquo;s PARA Type is set to PARA it will show on our PARA Dashboard.</li>
<li>When a Collection&rsquo;s PARA Type is set to Project, Area or Resource, they will display on their respective Query of Collections dashboard i.e. Projects, Areas, or Resources</li>
<li>This structure makes it easy to filter, group, and view your content according to the PARA methodology.</li>
</ul>
<h3 id="2-is-archive-property" class="group relative scroll-mt-20">
  2. &lsquo;Is Archive&rsquo; Property
  <a
    href="https://westernwilson.com/reflections/2025-07-12-anytype-with-para/#2-is-archive-property"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<ul>
<li>Every <strong>Collection</strong> includes an <strong>Is Archived</strong> property.</li>
<li>Easily mark items as archived to declutter your active workspace without permanently deleting anything.</li>
<li>Archived items are automatically filtered out from main views but remain accessible for future reference.</li>
<li>See all archived Projects, Areas and Resources both on the Archived query view, and also within their respective Projects, Areas, or Resources query views.</li>
</ul>
<h3 id="3-manual-link-management-via-templates" class="group relative scroll-mt-20">
  3. Manual Link Management via Templates
  <a
    href="https://westernwilson.com/reflections/2025-07-12-anytype-with-para/#3-manual-link-management-via-templates"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<ul>
<li>Every Collection also has a &ldquo;<strong>PARA Linked to</strong>&rdquo; property, this overcomes a limitation I noticed where Queries were not showing on the Graph view for Collections created from their Query view.</li>
<li>Templates automatically create this <strong>manual link</strong> property for each of our Projects, Areas , or Resources</li>
<li>This linkage can be removed at any time, giving you control over what appears in the Graph view.</li>
<li>Declutter your visual workspace by removing unnecessary connections, while still maintaining essential relationships.</li>
</ul>
<h3 id="how-it-all-works-together" class="group relative scroll-mt-20">
  How it all works together
  <a
    href="https://westernwilson.com/reflections/2025-07-12-anytype-with-para/#how-it-all-works-together"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<ul>
<li>‍<strong>Creating New Projects, Areas or Resources:</strong> Templates are used by default to add new Projects, Areas, or Resources. Each template ensures the correct PARA Type and properties are set when creating an object from each dashboard.</li>
<li>‍<strong>Change PARA Type:</strong> Updating the PARA Type property on a given collection will move it between Projects, Areas or Resources as needed. This is especially helpful if, for example, a Resource evolves into a Project later on.</li>
<li><strong>Creating New Objects:</strong> Within any specific Project, Area, or Resource, you can add any object—the default is a Page—and it will be created with the appropriate properties. You can link any type, such as Tasks, Bookmarks, Books, Quotes, literally any Type.</li>
<li>‍<strong>Manually Link to PARA:</strong> Use AnyType&rsquo;s &ldquo;Link to Collection&rdquo; feature to link any object newly created to a specific Project, Area or Resource yourself. This is particularly useful in Graph view if you like to see clusters of related information.</li>
<li>‍<strong>Archive Projects, Areas or Resources:</strong> Archiving is handled with a simple checkbox field on Collections that have relevant PARA Types.</li>
</ul>
<figure><img src="https://westernwilson.com/reflections/2025-07-12-anytype-with-para/anytype-graph-2.png">
</figure>

<h2 id="shared-gallery" class="group relative scroll-mt-20">
  Shared Gallery
  <a
    href="https://westernwilson.com/reflections/2025-07-12-anytype-with-para/#shared-gallery"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>There’s a wide variety of community-created templates available for AnyType, giving you plenty of options to explore and enhance your workflow.</p>
<p>It&rsquo;s easy to import and play with them too, simply go to the gallery and import it into a new space. While you can import templates into existing spaces, be mindful that this may introduce extra Types and Properties, potentially cluttering your setup and making cleanup tedious. So my advice is to first verify the new Types and Properties in a new, isolated space before merging them it into your main spaces.</p>
<h2 id="conclusion--next-steps" class="group relative scroll-mt-20">
  Conclusion &amp; Next steps
  <a
    href="https://westernwilson.com/reflections/2025-07-12-anytype-with-para/#conclusion--next-steps"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>If you’ve made it this far, congratulations! Hopefully, you’ve picked up something new and feel inspired to try out AnyType or the PARA system for your own daily organisation.</p>
<h3 id="bonus-note-on-anytypes-api--mcp-server" class="group relative scroll-mt-20">
  Bonus note on AnyType&rsquo;s API &amp; MCP server
  <a
    href="https://westernwilson.com/reflections/2025-07-12-anytype-with-para/#bonus-note-on-anytypes-api--mcp-server"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<p>Recently AnyType added an official API and Model Context Protocol (MCP) server. This advancement allows AI agents and assistants to interact with and update your documentation directly. In the <a href="https://developers.anytype.io/docs/examples/intermediate/mcp/">docs here</a> they highlight <a href="https://raycast.com/?via=western-AnyType">RayCast.ai</a> for seamless AI Chatbot integration and workflows.</p>
<p>With these tools, RayCast turns your AnyType knowledge base into an even more powerful resource—ready to answer your questions and automate parts of your note-taking system.</p>
]]></content:encoded></item><item><title>Migration to Webflow &amp; Hugo</title><link>https://westernwilson.com/reflections/2025-07-6-migrating-to-webflow/</link><pubDate>Sun, 06 Jul 2025 00:00:00 +0000</pubDate><guid>https://westernwilson.com/reflections/2025-07-6-migrating-to-webflow/</guid><description>Update 2026: Turns out Webflow and I didn’t get along for long. My workflow is drafting everything in AnyType, but copy-pasting from there into Webflow was a mess. I’d spend more time cleaning up the output than actually writing. The custom domain redirect situation was also irking me. So, true to form, I redesigned and migrated again, this time to Hugo. Make of that what you will.&#10;My website has gone through many iterations and frameworks:&#10;</description><content:encoded><![CDATA[<p><em>Update 2026: Turns out Webflow and I didn&rsquo;t get along for long. My workflow is drafting everything in AnyType, but copy-pasting from there into Webflow was a mess. I&rsquo;d spend more time cleaning up the output than actually writing. The custom domain redirect situation was also irking me. So, true to form, I redesigned and migrated again, this time to <a href="https://gohugo.io">Hugo</a>. Make of that what you will.</em></p>
<p>My website has gone through many iterations and frameworks:</p>
<ol>
<li>Static site using html, css &amp; JavaScript</li>
<li>Gatsby.js React framework</li>
<li>Quick attempt at using Next.js React</li>
<li>Nuxt.js Vue.js framework</li>
<li>Now Webflow</li>
</ol>
<p>My goal was to get something that worked easily, let me update a blog quickly, and didn&rsquo;t require too much maintenance. Finally, I&rsquo;ve achieved that vague and ambitious goal with Webflow.</p>
<h2 id="bit-of-historical-context" class="group relative scroll-mt-20">
  Bit of historical context
  <a
    href="https://westernwilson.com/reflections/2025-07-6-migrating-to-webflow/#bit-of-historical-context"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<h3 id="basic-static-site" class="group relative scroll-mt-20">
  Basic static site
  <a
    href="https://westernwilson.com/reflections/2025-07-6-migrating-to-webflow/#basic-static-site"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<p>While at University, near 2015 I was first learning software development as a main focus. I felt like I needed an online personal profile, but I didn&rsquo;t really know how to do it. So across 4 years I managed to cobble something together, though it wasn&rsquo;t pretty and I haven&rsquo;t got any screenshots to show it off.
My first profile website used basic html and css. Honestly, not enjoyable&hellip; the css process took so much time and tweaking that eventually it caused longer and longer procrastination breaks (gaming). I finally understood the devs struggling with css memes.
Skip ahead to my first graduate job, I learnt there are other ways to develop and I trusted that there had to be an easier way than crying over css (joking). So, with the internet at my disposal, I searched for a modern framework to build and deploy my site.</p>
<h3 id="gatsbyjs" class="group relative scroll-mt-20">
  GatsbyJS
  <a
    href="https://westernwilson.com/reflections/2025-07-6-migrating-to-webflow/#gatsbyjs"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<p>The many rabbit-holes I ventured figuring out what the &ldquo;best&rdquo; framework was, watching YouTube, doing tutorials of each framework and creating starter programs. Eventually I realised I was thinking about doing, but not actually getting anywhere, so I just leapt into one of them.
Introducing GatsbyJS, which at the time was a new React framework that helped build static sites quickly from templates, it even had blog plugins to make the whole process easier, so this was exactly what I was looking for&hellip; or so I thought.
My basic knowledge of html, css, and javascript helped, but I had to learn React, JSX syntax, Webpack, and how to deploy my site. They had docs, but it wasn&rsquo;t super polished so there was a lot of time spent figuring it out on my own. On a grad salary I was looking for the cheapest (free) options for hosting; there were two options: GitHub Pages and Netlify.
First, I tried GitHub Pages and succeeded in deploying it, but the workflow was tacky, it required me to run a command from my local machine to deploy it, which didn&rsquo;t feel right.
I learnt about Git Flow and wanted it to deploy when I pushed up my code up to master (I know that&rsquo;s not entirely correct, and am now aware that PRs and merges offer a nicer dev workflow flow, but at the time pushing to master was the way).
So I moved to Netlify, which watched your repository for changes on a specific branch, and deployed whatever was there for you. This worked great for me, and allowed me to iterate with development on Gatsby quickly. However&hellip; as it was early on, the framework and plugins were changing often. Updating the npm packages caused the website to break so much that I gave up making changes to the website altogether. I resigned to allowing my website to exist in it&rsquo;s current state. Until I got inspired by a front-end engineer at another company I worked at.
For added context, my career was taking me down the DevOps Engineer pathway, but I still enjoyed playing around with front-end development. So I&rsquo;d chat to other engineers about what they were doing and what they enjoyed using. This inspired my next framework choice that I thought would surely be easier.</p>
<h3 id="nuxtjs" class="group relative scroll-mt-20">
  NuxtJS
  <a
    href="https://westernwilson.com/reflections/2025-07-6-migrating-to-webflow/#nuxtjs"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<p>Inspired by my teammate, and with an expert to back me should I fall into any of the traps. I started building a Nuxt website. I gave up on designing a website and though, &ldquo;lets just get something working&rdquo;.
Following through the docs I cobbled together a very basic website that used their content module to generate pages from markdown. This allowed me to at least write blogs using markdown text and the pages would generate on deployment.
The deployment was done through GitHub Pages and I eventually got it deploying using GitHub Actions, which I was using more at work. This was great and Nuxt v2 was working well.
Then the Nuxt v3 update happened, and all my shit broke. So I spend another weekend tweaking and figuring out why the content renderers wouldn&rsquo;t load my blog pages from Markdown. Turns out the interface changed for how we loaded content, so the old method didn&rsquo;t work.
With that fixed, I happily added a blog about using ChatGPT or Perplexity to support my writing style. Woohoo!</p>
<h3 id="time-skip-to-now" class="group relative scroll-mt-20">
  Time skip to now
  <a
    href="https://westernwilson.com/reflections/2025-07-6-migrating-to-webflow/#time-skip-to-now"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<p>I&rsquo;m taking a break from work, travelling asia (see /blog/now-june-2025), I decided to attempt to write blogs to capture my learnings while creating music.
Looking ahead to writing 10 or more blogs, I realised how much of a hassle my Nuxt stack would be for updating and posting blogs. Changes required markdown updates pushed to a git branch and merged into main, I could immediately see this adding friction that would stop me from doing the actual blog writing. Also because of how I was loading blog images, it made the whole /public/img/ directory structure ugly, and in the future I would have a huge dump of images that were difficult to update.
Honestly, I might not even write so many blogs that this becomes a problem, but this future problem was enough to distract me from making music. I didn&rsquo;t want to create a big mess that I had to clean up later so I looked for another solution.
I looked into WordPress quickly, which a couple older colleagues of mine used for their personal blogs and another colleague who built the company websites using WordPress. It would&rsquo;ve worked, and been cheap, but I didn&rsquo;t want to touch it. It felt old, and I knew there were better tools out there.</p>
<h2 id="so-why-webflow" class="group relative scroll-mt-20">
  So, why Webflow?
  <a
    href="https://westernwilson.com/reflections/2025-07-6-migrating-to-webflow/#so-why-webflow"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>I was on LinkedIn one day and saw a post from Nikolai teaching people how to use Webflow. Nikolai actually introduced me to webflow way back in 2017 and it&rsquo;d been swirling in my brain ever since, it seemed like a great tool. It&rsquo;s fantastic for Web Designer to build websites without worrying about the nitty gritty of maintaining a website with code. It still requires fundamental understandings of website development and html &amp; css, but it&rsquo;s mostly no-code.
After the whole Nuxt Vue major update I thought I cbf with this, lets try Webflow out.
I don&rsquo;t want to pay for Webflow yet, thats why my site is only available on <a href="https://westernwilson.webflow.io">https://westernwilson.webflow.io</a>, in the future I intend to upgrade it so I can use my personal website url under <a href="https://westernwilson.com">https://westernwilson.com</a></p>
<h2 id="what-is-the-development-process-like" class="group relative scroll-mt-20">
  What is the development process like?
  <a
    href="https://westernwilson.com/reflections/2025-07-6-migrating-to-webflow/#what-is-the-development-process-like"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>I kind of cheated a bit, I used their AI tool to design and kick-start my new and improved personal profile website, then I tweaked the required bits and here we have it, a new website! The tweaking of Webflow was much easier for me than the frameworks. Everything you need to understand is in their docs, and to publish is very easy. No updating of packages under the hood, and it all just works.
To be honest, the Webflow structure I currently have could probably be improved, but I&rsquo;ll leave it as is for now since it works.
The major learning was configuring the Content Management System (CMS) that comes in-built with Webflow to store my blogs. Couple searches on the web and Perplexity helped me figure this out over a day or so.
So now, I have a blog website that gets updated from a CMS. I&rsquo;m stoked! Adding links or audio files is a lot easier than before too.
You still need some understanding of how web development html tags are structured and how they pair with css styling, but for me this solution is perfect.</p>
<h2 id="final-words" class="group relative scroll-mt-20">
  Final words
  <a
    href="https://westernwilson.com/reflections/2025-07-6-migrating-to-webflow/#final-words"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>I&rsquo;m happy with Webflow, because now I can focus on playing around making music and writing blogs instead of constantly upgrading and tweaking my website.</p>
]]></content:encoded></item><item><title>Making Music - Day 1</title><link>https://westernwilson.com/reflections/2025-06-29-music-day-1/</link><pubDate>Sun, 29 Jun 2025 00:00:00 +0000</pubDate><guid>https://westernwilson.com/reflections/2025-06-29-music-day-1/</guid><description>I find myself with the luxury of relaxing in Chiang Mai, Thailand, and thinking about what the future looks like for me.&#10;What do I want to do? Where do I want to be? Why am I doing whatever I’m doing? I don’t have a perfect answer to this, but I know that I can’t let perfection stop the process. So let’s focus on what I know:&#10;I love technology, devops, and coding, but I should diversify into other creative stuff I want to lead myself toward some form of creative expression I have a proven capability to learn The internet grants me unlimited access to learning resources &amp; community In this age of “AI”, I can reduce feedback loops, fail-fast and experiment quickly I’ve always had an interest in music With that list, I reckon it’s time to learn how to make beats.&#10;</description><content:encoded><![CDATA[<p>I find myself with the luxury of relaxing in Chiang Mai, Thailand, and thinking about what the future looks like for me.</p>
<p>What do I want to do? Where do I want to be? Why am I doing whatever I&rsquo;m doing?
I don&rsquo;t have a perfect answer to this, but I know that I can&rsquo;t let perfection stop the process. So let&rsquo;s focus on what I know:</p>
<ul>
<li>I love technology, devops, and coding, but I should diversify into other creative stuff</li>
<li>I want to lead myself toward some form of creative expression</li>
<li>I have a proven capability to learn</li>
<li>The internet grants me unlimited access to learning resources &amp; community</li>
<li>In this age of &ldquo;AI&rdquo;, I can reduce feedback loops, fail-fast and experiment quickly</li>
<li>I&rsquo;ve always had an interest in music</li>
</ul>
<p>With that list, I reckon it&rsquo;s time to learn how to make beats.</p>
<p>Ideally I would have documented my progress on social media (Instagram, TikTok, or other), but I fear opinions that might stop me from committing long-term, especially in the early stages.</p>
<p>So, I&rsquo;m going to quietly post updates on here, mostly for me, but also for anyone who finds it!</p>
<p><strong>Good luck on your journey, and welcome to mine.</strong></p>
]]></content:encoded></item><item><title>I feel silly about how I used to use AI</title><link>https://westernwilson.com/reflections/2024-10-24-i-feel-silly-about-how-i-used-to-treat-ai/</link><pubDate>Thu, 24 Oct 2024 00:00:00 +0000</pubDate><guid>https://westernwilson.com/reflections/2024-10-24-i-feel-silly-about-how-i-used-to-treat-ai/</guid><description>The way I write has evolved, primarily due to a shift in my relationship with AI and the writing process itself:&#10;Before I used AI to generate content Now I use AI more as a refinement tool and writing companion When referring to AI in this post, I specifically mean large language models (LLMs) like ChatGPT and Perplexity.&#10;Before How I worked with AI in the past is silly. Using AI to generate content makes the writing sound generic and peppered with buzzwords that people never use. I mean, check the title and content of my previous blog posts: ‘Unleashing the Writer Within: How ChatGPT Transformed My Writing’, and ‘Supercharge Your SSH with VS Code’ 🫣&#10;</description><content:encoded><![CDATA[<p>The way I write has evolved, primarily due to a shift in my relationship with AI and the writing process itself:</p>
<ul>
<li><strong>Before</strong> I used AI to generate content</li>
<li><strong>Now</strong> I use AI more as a refinement tool and writing companion</li>
</ul>
<p>When referring to AI in this post, I specifically mean large language models (LLMs) like ChatGPT and Perplexity.</p>
<h2 id="before" class="group relative scroll-mt-20">
  Before
  <a
    href="https://westernwilson.com/reflections/2024-10-24-i-feel-silly-about-how-i-used-to-treat-ai/#before"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>How I worked with AI in the past is silly. Using AI to generate content makes the writing sound generic and peppered with buzzwords that people never use. I mean, check the title and content of my previous blog posts: &lsquo;Unleashing the Writer Within: How ChatGPT Transformed My Writing&rsquo;, and &lsquo;Supercharge Your SSH with VS Code&rsquo; 🫣</p>
<p>AI generated content has telltale signs when you see words like: unleashed, supercharge, delve, crucial, <a href="https://arstechnica.com/ai/2024/07/the-telltale-words-that-could-identify-generative-ai-text/">more examples here</a>. The silver lining is that AI taught me more words, the problem is these new words didn&rsquo;t feel authentic to me.</p>
<p>Using AI to generate content was also a coping mechanism to my creative blocks. An unfortunate consequence was that it removed my &ldquo;want to think&rdquo;, I could feel myself leaning more and more on the information provided by AI. This felt similar to defaulting to a calculator instead of doing mental math. It&rsquo;s been over a year since I published those blogs, and I&rsquo;ve been using AI —perplexity— a lot differently since I started&hellip;</p>
<h2 id="now" class="group relative scroll-mt-20">
  Now
  <a
    href="https://westernwilson.com/reflections/2024-10-24-i-feel-silly-about-how-i-used-to-treat-ai/#now"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>Firstly, a bit of background, I work in tech for Xero and I&rsquo;ve met so many awesome people there. Luckily for me, I&rsquo;ve got a mentor who is a fantastic Engineer and an amazing Writer, seriously, it&rsquo;s their superpower; and I&rsquo;ve been heavily influenced by them. Their guidance has helped me to structure my thoughts more clearly and to approach writing with more confidence.</p>
<p>They shared an amazing blog that talks about the different roles in the writing process:</p>
<ul>
<li>Madman - full of ideas, jumbled thoughts and is where writing should start</li>
<li>Architect - arranges the jumble into potential arguments, at the paragraph level</li>
<li>Carpenter - sculpts the sentences into a logical structure to make better sense</li>
<li>Judge - critical energy as the inspector and will check the facts of what is written</li>
</ul>
<p>Applying these roles to my own writing revealed a crucial insight: that my writer&rsquo;s paralysis was me prematurely judging the madman before he could cook. I&rsquo;d critisise the words, sentences, paragraph, headings, scope, purpose, before my madman even had a chance to shine. No wonder I got scared of writing, and wrote at a snail pace.</p>
<p>The madman within needs some air time; sometimes you just need a good ol&rsquo; brain dump. Giving myself that permission totally freed me from the fear of writing. Nowadays, as soon as I feel myself being critical, I catch myself and think: &ldquo;Is it time to judge yet?&rdquo;</p>
<h2 id="final-points" class="group relative scroll-mt-20">
  Final points
  <a
    href="https://westernwilson.com/reflections/2024-10-24-i-feel-silly-about-how-i-used-to-treat-ai/#final-points"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>To wrap up, some final thoughts about using AI as a writing companion:</p>
<ol>
<li>The point of writing is the act itself; letting AI take over robs you of expressing your own voice and innate creativity.</li>
<li>I think AI LLMs are great companions for writing, but remember:
<ul>
<li>Ideally, keep personal information out of it.</li>
<li>If you do put some personal information in, at least use temporary chats and disable model training</li>
<li>Also check with your company before putting sensitive information or private IP like code into it for work</li>
</ul>
</li>
<li>On the flip side, I want to share Derek Sivers <a href="https://sive.rs/ai">article here</a> that talks about his commitment to not use AI to generate text. ‍
<blockquote>
<p>I have never ever used AI to generate text in place of my “voice”. No emails. No sentences in my articles or books or even comments. Nothing pretending to be me.</p>
</blockquote>
</li>
</ol>
]]></content:encoded></item><item><title>Unleashing the Writer Within: How ChatGPT Transformed My Writing</title><link>https://westernwilson.com/reflections/2023-11-6-im-not-a-writer/</link><pubDate>Mon, 06 Nov 2023 00:00:00 +0000</pubDate><guid>https://westernwilson.com/reflections/2023-11-6-im-not-a-writer/</guid><description>I don’t consider myself a writer. Two reasons: I don’t write enough, and my writing doesn’t meet the quality standards of my internal critic. Writing, for me, has at times, been a struggle. Crafting the structure of what I want to write comes naturally to me, but fleshing out the content feels fluffy and sometimes overwhelming.&#10;The Writing Struggle Many of us share the same struggle – the fear that our words fall short, the dread of writer’s block, or the inability to transform ideas into coherent text. But I’ve recently been using a powerful tool to overcome these hurdles: ChatGPT.&#10;</description><content:encoded><![CDATA[<p>I don&rsquo;t consider myself a writer. Two reasons: I don&rsquo;t write enough, and my writing doesn&rsquo;t meet the quality standards of my internal critic. Writing, for me, has at times, been a struggle. Crafting the structure of what I want to write comes naturally to me, but fleshing out the content feels fluffy and sometimes overwhelming.</p>
<h2 id="the-writing-struggle" class="group relative scroll-mt-20">
  The Writing Struggle
  <a
    href="https://westernwilson.com/reflections/2023-11-6-im-not-a-writer/#the-writing-struggle"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>Many of us share the same struggle – the fear that our words fall short, the dread of writer&rsquo;s block, or the inability to transform ideas into coherent text. But I&rsquo;ve recently been using a powerful tool to overcome these hurdles: ChatGPT.</p>
<h2 id="chatgpt-your-writing-partner" class="group relative scroll-mt-20">
  ChatGPT: Your Writing Partner
  <a
    href="https://westernwilson.com/reflections/2023-11-6-im-not-a-writer/#chatgpt-your-writing-partner"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>Here&rsquo;s how AI, be it ChatGPT, Bard, Bing Chat, or another variant, has revolutionized my writing process:</p>
<h3 id="1-fleshing-out-each-section" class="group relative scroll-mt-20">
  1. Fleshing Out Each Section
  <a
    href="https://westernwilson.com/reflections/2023-11-6-im-not-a-writer/#1-fleshing-out-each-section"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<p>I begin with strong ideas but struggle to elaborate on paper. While structure comes easily, content remains challenging. ChatGPT breathes life into my drafts, making them comprehensive and informative.</p>
<h3 id="2-simplifying-overloaded-sentences" class="group relative scroll-mt-20">
  2. Simplifying Overloaded Sentences
  <a
    href="https://westernwilson.com/reflections/2023-11-6-im-not-a-writer/#2-simplifying-overloaded-sentences"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<p>My writing can get tangled in long, complex sentences. ChatGPT excels at simplifying these, making my writing concise and reader-friendly. It trims the fluff and gets to the core of the message.</p>
<h3 id="3-ideation-booster" class="group relative scroll-mt-20">
  3. Ideation Booster
  <a
    href="https://westernwilson.com/reflections/2023-11-6-im-not-a-writer/#3-ideation-booster"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<p>When I&rsquo;m stuck in a creative rut, ChatGPT offers a treasure trove of inspiration. It sparks new ideas, suggests alternative angles, and helps me overcome mental barriers.</p>
<h2 id="some-additional-considerations" class="group relative scroll-mt-20">
  Some additional considerations
  <a
    href="https://westernwilson.com/reflections/2023-11-6-im-not-a-writer/#some-additional-considerations"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<h3 id="privacy-concerns" class="group relative scroll-mt-20">
  Privacy concerns
  <a
    href="https://westernwilson.com/reflections/2023-11-6-im-not-a-writer/#privacy-concerns"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<p>When using AI tools like ChatGPT, prioritize privacy and <del>avoid sharing</del> don&rsquo;t share sensitive information. Review the terms of service and privacy policies on OpenAI&rsquo;s website for a better understanding of data handling:</p>
<p>Here is two useful links for ChatGPT:</p>
<ul>
<li><a href="https://tosdr.org/en/service/7108">https://tosdr.org/en/service/7108</a></li>
<li><a href="https://openai.com/policies">https://openai.com/policies</a></li>
</ul>
<h3 id="double-check-your-outputs" class="group relative scroll-mt-20">
  Double-check your outputs
  <a
    href="https://westernwilson.com/reflections/2023-11-6-im-not-a-writer/#double-check-your-outputs"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h3>
<p>While AI can be a helpful companion in your writing journey, it&rsquo;s essential to double-check the outputs and make sure they align with your intended message. The human touch remains critical in the final editing process. This blog is a great example of that, originally the conclusion said I was a &ldquo;professional writer&rdquo; before I touched it up.</p>
<h2 id="in-conclusion-embrace-your-inner-writer" class="group relative scroll-mt-20">
  In Conclusion: Embrace Your Inner Writer
  <a
    href="https://westernwilson.com/reflections/2023-11-6-im-not-a-writer/#in-conclusion-embrace-your-inner-writer"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>My writing journey has been marked by struggles; however, AI tools like ChatGPT have been a game-changer, assisting me in fleshing out sections, simplifying complex sentences, and boosting my creativity when I hit a rut. It&rsquo;s a powerful tool for any writer.</p>
<p>But as with any tool, it&rsquo;s crucial to be mindful of privacy concerns when using AI, and always review and edit the output to ensure it aligns with your intended message. The human touch remains essential in the final editing process. Just like this blog, where the initial conclusion labeled me as a &ldquo;professional writer&rdquo; before my own edits. So, embrace the assistance AI offers, but remember that your unique voice and perspective play a vital role in crafting the perfect piece.</p>
]]></content:encoded></item><item><title>Supercharge Your SSH with VS Code</title><link>https://westernwilson.com/reflections/2023-10-29-ssh-using-vscode/</link><pubDate>Sun, 29 Oct 2023 00:00:00 +0000</pubDate><guid>https://westernwilson.com/reflections/2023-10-29-ssh-using-vscode/</guid><description>Have you ever wished you could use the full feature set of Visual Studio Code (VS Code) while connecting to remote servers via SSH? If you’re a developer or sysadmin, you’ll appreciate the productivity boost this can bring. In this blog post, we’ll walk you through the process of setting up VS Code as your primary SSH tool for both work and home use. Let’s dive in!&#10;Overview VS Code is renowned for its versatility and has extensions for all types of development activities. This guide will show you how to harness its power as an SSH client, giving you a seamless development experience on remote servers.&#10;</description><content:encoded><![CDATA[<p><em>Have you ever wished you could use the full feature set of Visual Studio Code (VS Code) while connecting to remote servers via SSH? If you&rsquo;re a developer or sysadmin, you&rsquo;ll appreciate the productivity boost this can bring. In this blog post, we&rsquo;ll walk you through the process of setting up VS Code as your primary SSH tool for both work and home use. Let&rsquo;s dive in!</em></p>
<h2 id="overview" class="group relative scroll-mt-20">
  Overview
  <a
    href="https://westernwilson.com/reflections/2023-10-29-ssh-using-vscode/#overview"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>VS Code is renowned for its versatility and has extensions for all types of development activities. This guide will show you how to harness its power as an SSH client, giving you a seamless development experience on remote servers.</p>
<h2 id="what-is-vs-code" class="group relative scroll-mt-20">
  What is VS Code?
  <a
    href="https://westernwilson.com/reflections/2023-10-29-ssh-using-vscode/#what-is-vs-code"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>Before we get started, let&rsquo;s quickly clarify what VS Code is. <a href="https://code.visualstudio.com/">Visual Studio Code</a>, often referred to as VS Code, is a free, open-source code editor developed by Microsoft. It&rsquo;s widely used in the software development industry and is known for its robust features and extensibility.</p>
<h2 id="what-is-ssh" class="group relative scroll-mt-20">
  What is SSH?
  <a
    href="https://westernwilson.com/reflections/2023-10-29-ssh-using-vscode/#what-is-ssh"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p><a href="https://en.wikipedia.org/wiki/Secure_Shell">SSH</a> stands for Secure Shell, and it&rsquo;s a network protocol used for secure data communication, remote command-line access, and other network services. It&rsquo;s a fundamental tool for connecting to remote servers securely.</p>
<h2 id="official-vs-code-tutorial" class="group relative scroll-mt-20">
  Official VS Code Tutorial
  <a
    href="https://westernwilson.com/reflections/2023-10-29-ssh-using-vscode/#official-vs-code-tutorial"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>For a detailed, step-by-step guide on setting up VS Code as your primary SSH tool, please visit the official <a href="https://code.visualstudio.com/docs/remote/ssh">VS Code tutorial</a>.</p>
<h1 id="in-a-nutshell" class="group relative scroll-mt-20">
  In a Nutshell
  <a
    href="https://westernwilson.com/reflections/2023-10-29-ssh-using-vscode/#in-a-nutshell"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h1>
<p>In a nutshell, here&rsquo;s a brief overview of what you&rsquo;ll find in the official tutorial:</p>
<ul>
<li>Installing the required VS Code packages on the SSH box.</li>
<li>Installing the Remote Developer extension on your local machine&rsquo;s VS Code.</li>
<li>Setting up your SSH config file for VS Code for easy reconnection.</li>
<li>(<em>Optional</em>) Creating an SSH key for effortless logins.</li>
</ul>
<p>By enabling VS Code&rsquo;s ssh capabilities you can centralise the tool you use for development. Happy coding!</p>
]]></content:encoded></item><item><title>Developer dynamics</title><link>https://westernwilson.com/reflections/2023-10-28-developer-dynamics/</link><pubDate>Sat, 28 Oct 2023 00:00:00 +0000</pubDate><guid>https://westernwilson.com/reflections/2023-10-28-developer-dynamics/</guid><description>Full disclosure, I first heard of these architypes from a workshop run in 2020 by FLINT Wellington&#10;Types of Developers in the Workplace In a dynamic and collaborative workplace, you’ll encounter various types of developers, each driven by different motivations and approaches to their work. Understanding these developer archetypes can help foster a more effective and harmonious team environment.&#10;</description><content:encoded><![CDATA[<p><em>Full disclosure, I first heard of these architypes from a workshop run in 2020 by <a href="https://tuanz.org.nz/flint/flint-wellington/">FLINT Wellington</a></em></p>
<h1 id="types-of-developers-in-the-workplace" class="group relative scroll-mt-20">
  Types of Developers in the Workplace
  <a
    href="https://westernwilson.com/reflections/2023-10-28-developer-dynamics/#types-of-developers-in-the-workplace"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h1>
<p>In a dynamic and collaborative workplace, you&rsquo;ll encounter various types of developers, each driven by different motivations and approaches to their work. Understanding these developer archetypes can help foster a more effective and harmonious team environment.</p>
<h2 id="1-the-detective" class="group relative scroll-mt-20">
  1. The Detective
  <a
    href="https://westernwilson.com/reflections/2023-10-28-developer-dynamics/#1-the-detective"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>Drive: Detectives love to investigate. They thrive in messy situations, dissecting problems, and fixing them. Their analytical minds excel at uncovering the root causes of issues and implementing solutions. They&rsquo;re the team&rsquo;s problem-finders, and a lot of the time, problem-solvers.</p>
<h2 id="2-the-cowboy--go-getter" class="group relative scroll-mt-20">
  2. The Cowboy / Go-getter
  <a
    href="https://westernwilson.com/reflections/2023-10-28-developer-dynamics/#2-the-cowboy--go-getter"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>Drive: Cowboys or Go-getters are known for their speed. They push code out the door quickly, often impressively so. However, they might leave a bit of a &ldquo;dirty sink&rdquo; behind, sacrificing some cleanliness for speed. They&rsquo;re the team&rsquo;s high-velocity coders.</p>
<h2 id="3-the-artist-or-creative" class="group relative scroll-mt-20">
  3. The Artist or Creative
  <a
    href="https://westernwilson.com/reflections/2023-10-28-developer-dynamics/#3-the-artist-or-creative"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>Drive: Artists or Creatives focus on the aesthetics of code. They&rsquo;re meticulous about making sure their code is not just functional but also visually appealing and highly readable. While they may code more slowly, their work introduces less technical debt. They&rsquo;re the team&rsquo;s code beautifiers.</p>
<h2 id="4-the-mad-scientist" class="group relative scroll-mt-20">
  4. The Mad Scientist
  <a
    href="https://westernwilson.com/reflections/2023-10-28-developer-dynamics/#4-the-mad-scientist"
    class="heading-anchor ml-2 text-sm no-underline! opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 [@media(hover:none)]:opacity-100 [color:var(--c-muted)] hover:[color:var(--c-accent)] transition-opacity"
    aria-label="Link to this heading"
  ><i class="fa-solid fa-link" aria-hidden="true"></i></a>
</h2>
<p>Drive: Mad Scientists are tech enthusiasts. They eagerly embrace the latest technologies and enjoy experimenting with new libraries and features. Their adventurous spirit leads to innovation and pushing the boundaries of what&rsquo;s possible. They&rsquo;re the team&rsquo;s tech trailblazers.</p>
<p>In a balanced development team, these diverse types of developers can complement each other, fostering creativity, efficiency, and problem-solving. Recognizing and valuing these different approaches can lead to a more well-rounded and successful team.</p>
]]></content:encoded></item></channel></rss>