<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Dustin Boston</title>
    <link>https://dustin.boston</link>
    <description>A software engineer's notebook about modern web development.</description>
    <atom:link href="https://dustin.boston/feed" rel="self" type="application/rss+xml" />
    
    <item>
      <title><![CDATA[Harness Memory Architecture]]></title>
      <link>https://dustin.boston/blog/harness-memory-architecture</link>
      <guid isPermaLink="true">https://dustin.boston/blog/harness-memory-architecture</guid>
      <pubDate>Tue, 14 Apr 2026 07:56:00 GMT</pubDate>
      <description><![CDATA[Here's how Claude Code handles memory....]]></description>
      <content:encoded><![CDATA[<p>Claude Code's memory architecture <a target="_blank" rel="noopener noreferrer nofollow" href="https://x.com/himanshustwts/status/2038924027411222533">works like this</a>:</p><ol><li><p>The user can create memories at any time with a slash command.</p></li><li><p>Memories go into a folder and then the memory index file is updated with a link to each memory.</p></li><li><p>The memory index file is injected into the system prompt.</p></li><li><p>On each turn extract memories from the conversation into memory files. GOTO #2</p></li><li><p>Memories are consolidated in the background once a day. </p></li></ol><p></p>]]></content:encoded>
      <author><name>Dustin Boston</name></author>
    </item>
    <item>
      <title><![CDATA[How to Architect a Harness]]></title>
      <link>https://dustin.boston/blog/how-to-architect-a-harness</link>
      <guid isPermaLink="true">https://dustin.boston/blog/how-to-architect-a-harness</guid>
      <pubDate>Mon, 13 Apr 2026 00:45:00 GMT</pubDate>
      <description><![CDATA[Garry Tan, CEO of Y Combinator, outlines an architecture for a harness (a wrapper around a model) that relies almost entirely on skills, not code....]]></description>
      <content:encoded><![CDATA[<p>Garry Tan, CEO of Y Combinator, <a target="_blank" rel="noopener noreferrer nofollow" href="https://x.com/garrytan/status/2042925773300908103?s=12">outlines an architecture for a harness</a> (a wrapper around a model) that relies almost entirely on skills, not code.</p><p>He says that the productivity gap among 1x, 10x, and 100x engineers using AI coding agents has almost nothing to do with model quality. Instead, the difference comes from the architecture wrapped around the model. Tan calls this the harness, and the central claim is that the harness, not the model, determines whether someone gets mediocre results or transformative ones.</p><p>The idea is that modern models already know how to reason, synthesize, and write code. Model failures come from not understanding the specific environment they are working in. The harness exists to give the model the right context at the right moment, without overwhelming it with irrelevant information. Tan describes reading the leaked Claude Code source and discovering that the real magic is not in the model but in the wrapper that orchestrates it. Can confirm.</p><p>To explain how this works, Garry introduces five concepts: skill files, the harness, resolvers, latent and deterministic work, and diarization. These form the backbone of a system that can scale from simple tasks to complex knowledge work.</p><h3>1. Skill Files</h3><p>Skill files are reusable markdown documents that describe a process. They don’t tell the model <strong>what </strong>to do; they tell it <strong>how </strong>to do it. The user supplies the goal, and the skill supplies the method. Tan compares a skill file to a method call with parameters. A single skill can be invoked in many different contexts, producing different outcomes depending on the arguments. Tan argues that markdown is a better medium for encoding judgment and process than traditional code, because it matches the model’s native mode of thinking.</p><h3>2. The Harness</h3><p>The harness is the minimal program that runs the model. It loops the model, manages context, reads and writes files, and enforces safety. Tan warns against building a bloated harness full of tools and abstractions that slow everything down and clutter the context window. His ideal harness is thin, while the skills are fat. Modern software no longer needs to be precious or over‑engineered; it should be fast, narrow, and purpose‑built.</p><h3>3. Resolvers</h3><p>Resolvers act as routing tables for context. They decide what documents to load when a certain type of task appears. Without resolvers, developers tend to stuff everything into a single giant prompt, which degrades the model’s attention. With resolvers, the system loads only the relevant documents at the right time. Tan describes how their own massive CLAUDE.md file became unmanageable until they replaced it with a small resolver that pointed to the right documents on demand.</p><h3>4. Latent vs Deterministic Work</h3><p>The distinction between latent and deterministic work is another key idea. Latent space is where the model exercises judgment, interpretation, and synthesis. Deterministic space is where reliability matters: SQL queries, arithmetic, and other operations that must produce the same output every time. Problems arise when tasks that belong in deterministic space are forced into latent space. Scale forces us to handle queries deterministically.</p><h3>5. Diarization</h3><p>Diarization is the process of reading a large body of material and producing a <em>structured profile</em> that captures the essential judgments. This is something neither SQL nor RAG can do. It requires the model to read, compare, notice contradictions, and synthesize. Tan argues that diarization is the key to making AI useful for real knowledge work.</p><h3>Architecture</h3><p>These five ideas combine into a three‑layer architecture. At the top are the fat skills, which encode judgment and process. In the middle is the thin harness, which orchestrates the model. At the bottom is the deterministic layer, which handles reliable operations like database queries and file access. The guiding principle is to push intelligence upward into skills and push execution downward into deterministic tools.</p><p>The article ends with a principle: if a task will need to be done more than once, it should be codified into a skill. Skills become permanent upgrades. They never degrade, and they improve automatically when models improve. This compounding effect, not smarter models, is what produces the dramatic productivity gains described at the beginning.</p>]]></content:encoded>
      <author><name>Dustin Boston</name></author>
    </item>
    <item>
      <title><![CDATA[Enterprise Project Checklist]]></title>
      <link>https://dustin.boston/blog/enterprise-project-checklist</link>
      <guid isPermaLink="true">https://dustin.boston/blog/enterprise-project-checklist</guid>
      <pubDate>Sat, 11 Apr 2026 02:16:00 GMT</pubDate>
      <description><![CDATA[Here in the age of AI, projects need to be perfect when they are released. I use this enterprise software project checklist to keep track of everything I need to do....]]></description>
      <content:encoded><![CDATA[<p>Here in the age of AI, projects need to be perfect when they are released. I use this enterprise software project checklist to keep track of everything I need to do. It's modularized into distinct, LLM-executable domains. Each module is designed as an isolated context block, allowing an orchestrator LLM to dispatch them to parallel worker agents. The format uses explicit boolean constraints and declarative validation states to ensure deterministic agent evaluations.</p><h3><strong>Module 1: Scaffolding &amp; Configuration</strong></h3><ul><li><p><strong>Domain:</strong> Project initialization, environment strictness, and repository metadata.</p></li></ul><ul><li><p><strong>Execution Independence:</strong> Can run immediately upon repository creation.</p></li></ul><ul><li><p><strong>Version Control (</strong><code>.gitignore</code><strong>):</strong> Must omit <code>node_modules</code>, build directories (<code>dist</code>/<code>build</code>), <code>.env</code> files, OS artifacts, and IDE configs.</p></li><li><p><strong>Configuration Validation:</strong> Environment variables must be validated at runtime startup (e.g., via Zod or Joi). No hardcoded credentials or environment-specific URIs in source code.</p></li><li><p><strong>System Documentation (</strong><code>CLAUDE.md</code><strong>):</strong> Must exist at root. Requires: system overview, package script definitions, environment setup steps, and architectural links.</p></li><li><p><strong>Licensing:</strong> Default to <code>CC BY-NC 4.0</code>. For proprietary code, <code>package.json</code> must state <code>"license": "SEE LICENSE IN &lt;filename&gt;"</code> and <code>"private": true</code>, with a corresponding custom license file.</p></li></ul><h3><strong>Module 2: Code Quality &amp; Type Safety</strong></h3><ul><li><p><strong>Domain:</strong> Static analysis and syntax enforcement.</p></li></ul><ul><li><p><strong>Execution Independence:</strong> Can run as a continuous background linting/typing agent.</p></li></ul><ul><li><p><strong>Type Strictness:</strong> TypeScript <code>tsconfig.json</code> must have <code>"strict": true</code>. Zero tolerance for <code>any</code> types, non-null assertions (<code>!</code>), or type casting (<code>as Type</code>).</p></li><li><p><strong>Linting Rules:</strong> Must implement <code>xo</code> configured for maximum strictness. Pre-commit hooks must block non-compliant code.</p></li><li><p><strong>Dependency Auditing:</strong> Lockfiles (<code>package-lock.json</code> / <code>yarn.lock</code> / <code>pnpm-lock.yaml</code>) must be present. Automated vulnerability scanning (e.g., <code>npm audit</code> or Dependabot) must pass with zero critical/high vulnerabilities.</p></li></ul><h3>Module 3: Architecture &amp; State</h3><ul><li><p><strong>Domain:</strong> System design, persistence layers, and local infrastructure.</p></li><li><p><strong>Execution Independence:</strong> Requires schema and system design definitions.</p></li></ul><ul><li><p><strong>Architectural Patterns:</strong> Enforce separation of concerns (e.g., controllers, services, repositories). File structure must reflect domain-driven or strictly layered architecture.</p></li><li><p><strong>Data Persistence:</strong> Database schemas (e.g., PostgreSQL for relational, Pinecone for vector data) must use migration scripts. No manual schema modifications.</p></li><li><p><strong>Containerization:</strong> Local dependencies (databases, cache, messaging queues) must run via <code>docker-compose.yml</code>. Applications should have multi-stage <code>Dockerfile</code> definitions for production builds.</p></li></ul><h3>Module 4: Security &amp; Safeguards</h3><ul><li><p><strong>Domain:</strong> Threat mitigation, access control, and data protection.</p></li><li><p><strong>Execution Independence:</strong> Can review PRs for security anti-patterns in parallel with testing.</p></li></ul><ul><li><p><strong>Secrets Management:</strong> All cryptographic keys, API tokens, and database credentials must be encrypted at rest and injected via secure managers (e.g., AWS Secrets Manager, HashiCorp Vault). Require key rotation mechanisms.</p></li><li><p><strong>Destructive Operations:</strong> Any <code>DELETE</code> or <code>DROP</code> operations must implement soft-delete (boolean flags) or robust undo mechanisms. All destructive actions require an immutable audit log entry (actor, timestamp, action, resource).</p></li><li><p><strong>API Contracts:</strong> Endpoints must have defined input/output schemas (e.g., OpenAPI/Swagger) to prevent injection and enforce strict payload boundaries.</p></li></ul><h3>Module 5: Resilience &amp; Traffic Management</h3><ul><li><p><strong>Domain:</strong> System stability under load and failure conditions.</p></li><li><p><strong>Execution Independence:</strong> Can evaluate network and service-layer code.</p></li></ul><ul><li><p><strong>Error Handling:</strong> Implementation of <code>try/catch</code> on all asynchronous operations. Downstream service calls must implement the Circuit Breaker pattern to prevent cascading failures.</p></li><li><p><strong>Rate Limiting:</strong> Ingress traffic must be rate-limited by IP or API key. Outbound retry logic must implement exponential backoff with jitter to prevent thundering herd problems.</p></li></ul><h3>Module 6: Telemetry &amp; Monitoring</h3><ul><li><p><strong>Domain:</strong> Observability, health tracking, and incident alerting.</p></li><li><p><strong>Execution Independence:</strong> Can verify infrastructure-as-code and application middleware.</p></li></ul><ul><li><p><strong>Observability (Logs, Metrics, Traces):</strong> Structured JSON logging must be enforced. Spans and traces must follow requests across system boundaries (e.g., OpenTelemetry).</p></li><li><p><strong>Monitoring &amp; Alerting:</strong> Integration with APM tools. Endpoints must include a <code>/health</code> or <code>/live</code> route checking DB connectivity and memory usage. Usage analytics must be tracked without logging PII.</p></li></ul><h3>Module 7: Verification &amp; Delivery</h3><ul><li><p><strong>Domain:</strong> Automated testing and deployment.</p></li><li><p><strong>Execution Independence:</strong> Runs post-build, parallelized across test runners.</p></li></ul><ul><li><p><strong>Test Coverage:</strong> Strict 100% code coverage requirement across three layers:</p><ul><li><p><em>Unit Tests:</em> Isolated logic, mocked dependencies.</p></li><li><p><em>Integration Tests:</em> Cross-module and database interactions.</p></li><li><p><em>E2E Tests:</em> Full user journey simulation.</p></li></ul></li><li><p><strong>CI/CD Pipeline:</strong> Automated pipelines (e.g., GitHub Actions) must execute linting, type-checking, and testing. Merges to <code>main</code> require automated semantic release creation and deployment script execution.</p></li></ul><h3>Module 8: Documentation Context</h3><ul><li><p><strong>Domain:</strong> Knowledge transfer and operational guides.</p></li><li><p><strong>Execution Independence:</strong> Runs asynchronously, reviewing code to update docs.</p></li></ul><ul><li><p><strong>API Documentation:</strong> Auto-generated from code annotations or strict Markdown.</p></li><li><p><strong>Operational Guides:</strong> Must include a deployment guide, security considerations matrix, and a <code>CONTRIBUTING.md</code> outlining local setup and PR standards.</p></li></ul><p></p>]]></content:encoded>
      <author><name>Dustin Boston</name></author>
    </item>
    <item>
      <title><![CDATA[What To Know in JavaScript]]></title>
      <link>https://dustin.boston/blog/what-to-know-in-javascript</link>
      <guid isPermaLink="true">https://dustin.boston/blog/what-to-know-in-javascript</guid>
      <pubDate>Thu, 09 Apr 2026 10:08:00 GMT</pubDate>
      <description><![CDATA[What To Know in JavaScript (2026 Edition) is a great writeup of the JavaScript ecosystem as of April 2026. And also, now I have a ton of new things to learn. ...]]></description>
      <content:encoded><![CDATA[<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://frontendmasters.com/blog/what-to-know-in-javascript-2026-edition/">What To Know in JavaScript (2026 Edition)</a> is a great writeup of the JavaScript ecosystem as of April 2026. And also, now I have a ton of new things to learn. </p>]]></content:encoded>
      <author><name>Dustin Boston</name></author>
    </item>
    <item>
      <title><![CDATA[Human in the loop]]></title>
      <link>https://dustin.boston/blog/human-in-the-loop</link>
      <guid isPermaLink="true">https://dustin.boston/blog/human-in-the-loop</guid>
      <pubDate>Tue, 31 Mar 2026 06:46:00 GMT</pubDate>
      <description><![CDATA[The current narrative around AI in tech misses a fundamental reality: humans have biological limits....]]></description>
      <content:encoded><![CDATA[<p>The current narrative around AI in tech misses a fundamental reality: humans have biological limits. Big tech pushes the ideal that AI will mint "10x engineers" by drastically increasing throughput. While AI undeniably accelerates workflows, attempting to match that artificial pace with human output is a guaranteed recipe for burnout within six months. There is a physical ceiling to how fast we can type and how much cognitive load we can process at once. AI presents an opportunity to reduce our workload and free up mental bandwidth. Instead, the industry is using it to strap developers to ever-increasing responsibilities. When the system eventually breaks under this pressure, it will be the human in the loop that gives out.</p>]]></content:encoded>
      <author><name>Dustin Boston</name></author>
    </item>
    <item>
      <title><![CDATA[Coding Font]]></title>
      <link>https://dustin.boston/blog/coding-font</link>
      <guid isPermaLink="true">https://dustin.boston/blog/coding-font</guid>
      <pubDate>Mon, 30 Mar 2026 09:25:00 GMT</pubDate>
      <description><![CDATA[Coding Font is a fun bracket game that you can use to find your favorite coding font. I got JetBrains Mono. I think it has a lot of character, and the ligatures are great....]]></description>
      <content:encoded><![CDATA[<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://www.codingfont.com/">Coding Font</a> is a fun bracket game that you can use to find your favorite coding font. I got JetBrains Mono. I think it has a lot of character, and the ligatures are great.</p>]]></content:encoded>
      <author><name>Dustin Boston</name></author>
    </item>
    <item>
      <title><![CDATA["Nothing" is the secret to structuring your work]]></title>
      <link>https://dustin.boston/blog/nothing-is-the-secret-to-structuring-your-work</link>
      <guid isPermaLink="true">https://dustin.boston/blog/nothing-is-the-secret-to-structuring-your-work</guid>
      <pubDate>Wed, 25 Mar 2026 07:22:00 GMT</pubDate>
      <description><![CDATA[The next time you begin your workday, try this: clear your work surface completely. Close all browser tabs. Create a fresh page in your notebook. Open only the one file you need....]]></description>
      <content:encoded><![CDATA[<blockquote><p>The next time you begin your workday, try this: clear your work surface completely. Close all browser tabs. Create a fresh page in your notebook. Open only the one file you need.</p></blockquote><p>Source: <a href="https://www.vangemert.dev/blog/nothing">"Nothing" is the secret to structuring your work</a></p>]]></content:encoded>
      <author><name>Dustin Boston</name></author>
    </item>
    <item>
      <title><![CDATA[The 52-Minute Developer]]></title>
      <link>https://dustin.boston/blog/the-52-minute-developer</link>
      <guid isPermaLink="true">https://dustin.boston/blog/the-52-minute-developer</guid>
      <pubDate>Wed, 25 Mar 2026 07:11:00 GMT</pubDate>
      <description><![CDATA[You can code only 4 hours per day, but don't worry, you're only using 52 minutes....]]></description>
      <content:encoded><![CDATA[<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://newsletter.techworld-with-milan.com/p/you-can-code-only-4-hours-per-day">You can code only 4 hours per day</a>, but don't worry, you're only using 52 minutes.</p><blockquote><ol><li><p><strong>The cognitive ceiling.</strong> Research by Ericsson, Mark, and Newport shows that 3-4 hours is the daily maximum for concentrated effort. Beyond that, diminishing returns.</p></li><li><p><strong>Where developer time actually goes.</strong> Data reveal that the median coding time is 52 minutes/day. Meetings consume 11+ hours per week, pushing peak coding to the afternoons when mornings should be prime.</p></li><li><p><strong>The cost of interruptions.</strong> 23 minutes to recover from one interruption. For programmers, 30-45 minutes to rebuild the full context. A single meeting can destroy an entire afternoon.</p></li><li><p><strong>Flow as a force multiplier.</strong> Csikszentmihalyi’s research: 500% increase in productivity in the flow state. But flow requires 15-25 minutes of uninterrupted time just to begin.</p></li></ol></blockquote><p></p>]]></content:encoded>
      <author><name>Dustin Boston</name></author>
    </item>
    <item>
      <title><![CDATA[Anant Jain on Agency]]></title>
      <link>https://dustin.boston/blog/anant-jain-on-agency</link>
      <guid isPermaLink="true">https://dustin.boston/blog/anant-jain-on-agency</guid>
      <pubDate>Wed, 25 Mar 2026 06:22:00 GMT</pubDate>
      <description><![CDATA[Agency is the ability to hold the entire [development] loop in your head and act on it......]]></description>
      <content:encoded><![CDATA[<blockquote><p>Agency is the ability to hold the entire [development] loop in your head and act on it. What does the user actually need? What should this feel like to use? What's the fastest way to build it that isn't embarrassing? How do we know if it worked? A high-agency person can move through that whole sequence without waiting for someone else to hand them the next step.</p></blockquote><p>Source: <a target="_blank" rel="noopener noreferrer nofollow" href="https://www.anantjain.xyz/posts/agency?utm_source=tldrnewsletter">Agency</a></p>]]></content:encoded>
      <author><name>Dustin Boston</name></author>
    </item>
    <item>
      <title><![CDATA[Software Engineering is More than Just Code]]></title>
      <link>https://dustin.boston/blog/software-engineering-is-more-than-just-code</link>
      <guid isPermaLink="true">https://dustin.boston/blog/software-engineering-is-more-than-just-code</guid>
      <pubDate>Mon, 23 Mar 2026 09:55:00 GMT</pubDate>
      <description><![CDATA[There's a lot more to creating good software than code....]]></description>
      <content:encoded><![CDATA[<p>All this stuff can probably be automated, but it's a good reminder of everything we have to do to create <a target="_blank" rel="noopener noreferrer nofollow" href="https://dustin.boston/blog/good-code-is-still-expensive">GOOD Code</a>.</p><blockquote><p>Aside from coding itself, software engineering involves: </p><ul><li><p>Project scoping: Defining what the software will do, and the processes it will follow in order to get it done, including setting safety guardrails. </p></li><li><p>Architecture: Defining the different elements that come together to create the tool, and how they all fit together. </p></li><li><p>User interface and user experience design: Designing the interface that users will interact with the software through, and ensuring that using it is as streamlined and friction-free as possible. </p></li><li><p>Data engineering: Structuring and managing the flow of data through the tool. </p></li><li><p>Testing: Ensuring that errors and unexpected user behavior are handled correctly. </p></li><li><p>Version control and documentation: Tracking changes and updates to the code as it’s developed. </p></li></ul><p>While AI can generate code quickly, understanding these other aspects of software engineering is essential if we want to turn that code into tools that are coherent, usable and trustworthy.</p></blockquote><p>Source: <a target="_blank" rel="noopener noreferrer nofollow" href="https://www.forbes.com/sites/bernardmarr/2026/03/20/why-vibe-coders-still-need-to-think-like-software-engineers/">Why Vibe Coders Still Need To Think Like Software Engineers</a></p>]]></content:encoded>
      <author><name>Dustin Boston</name></author>
    </item>
    <item>
      <title><![CDATA[Tokens Are Now a Recruiting Tool]]></title>
      <link>https://dustin.boston/blog/tokens-are-now-a-recruiting-tool</link>
      <guid isPermaLink="true">https://dustin.boston/blog/tokens-are-now-a-recruiting-tool</guid>
      <pubDate>Fri, 20 Mar 2026 06:14:00 GMT</pubDate>
      <description><![CDATA[Jensen Huang, CEO of Nvidia, said that tokens are now a recruiting tool (and he wants to give engineers half their salary in tokens)....]]></description>
      <content:encoded><![CDATA[<p>Jensen Huang, CEO of Nvidia, said that <a target="_blank" rel="noopener noreferrer nofollow" href="https://finance.yahoo.com/news/jensen-huang-floats-giving-engineers-040201197.html">tokens are now a recruiting tool</a> (and he wants to give engineers half their salary in tokens):</p><blockquote><p>They're going to make a few hundred thousand dollars a year, their base pay," said Huang of engineers. "I'm going to give them probably half of that on top of it as tokens so that they could be amplified 10X. Of course, we would."</p><p>"It is now one of the recruiting tools in Silicon Valley: How many tokens comes along with my job?" Huang added. "And the reason for that is very clear, because every engineer that has access to tokens will be more productive.</p></blockquote><p>But it's not like we actually want tokens. We want money. Tokens are incidental. What I DO care about is not having enough tokens to meet demand. And employers are demanding ALL THE TOKENS. Regardless of my salary, if an employer expects me to use AI but can't afford to give me the tokens to use it effectively, is that a place that I would want to work? The way I see it, tokens are not an incentive, they are fundamental to modern work. You have a computer, an internet connection, and a shit load of tokens to burn. </p>]]></content:encoded>
      <author><name>Dustin Boston</name></author>
    </item>
    <item>
      <title><![CDATA[Barry's Economics on Helplessness]]></title>
      <link>https://dustin.boston/blog/barrys-economics-on-helplessness</link>
      <guid isPermaLink="true">https://dustin.boston/blog/barrys-economics-on-helplessness</guid>
      <pubDate>Fri, 20 Mar 2026 00:00:00 GMT</pubDate>
      <description><![CDATA[I can't state it as well as Barry's Economics, but this video has a lot of good stuff to say about "the science of learned helplessness, social tipping points, and why your brain is catastrophically underestimating the power of what you can actually do."...]]></description>
      <content:encoded><![CDATA[<p>I can't state it as well as Barry's Economics, but <a target="_blank" rel="noopener noreferrer nofollow" href="https://www.youtube.com/watch?v=66wen6C4UNw">this video has a lot to say</a> about "the science of learned helplessness, social tipping points, and why your brain is catastrophically underestimating the power of what you can actually do." Helplessness is the default (that's why doom scrolling is so easy). To experience agency and fight helplessness, do something that makes a change. Even if it's small.</p><p></p>]]></content:encoded>
      <author><name>Dustin Boston</name></author>
    </item>
    <item>
      <title><![CDATA[Vibe Coding Alone isn't Enough, You Need an Engineer in the Loop]]></title>
      <link>https://dustin.boston/blog/vibe-coding-isnt-enough</link>
      <guid isPermaLink="true">https://dustin.boston/blog/vibe-coding-isnt-enough</guid>
      <pubDate>Tue, 17 Mar 2026 06:59:00 GMT</pubDate>
      <description><![CDATA[Vibe coding is powerful and fun, but to develop high-quality software you need an engineer in the loop....]]></description>
      <content:encoded><![CDATA[<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://thenewstack.io/ai-agents-software-engineering/">Agents write code. They don't do software engineering</a></p><blockquote><p>Writing code is pattern recognition. Take what’s been done before, apply it to a new context, and scaffold it out. Large language models are exceptional at this because that’s exactly what they do: recognize and reproduce patterns from massive corpora of prior work.</p><p>Software engineering is something else. It’s trade-offs. Constraints. Decisions that require context no model has access to: your business domain, your product strategy, your customers, your technical debt, the conversation your team had last week about why you chose one approach over another.</p></blockquote><p>Working with an LLM in a professional manner involves creating a requirements document, generating or manually updating code, creating and enforcing style guides (via linters), testing and code coverage (plus automation), build and deployment (CI/CD), security, project maintenance, SLAs, guarantees about project timing and delivery, negotiating features, managing complexity, creating documentation, and most importantly the years of experience to know when to do what.</p><h3>Division of Labor</h3><p>Here's a good rule of thumb for dividing the work between an engineer and an LLM:</p><blockquote><p>Developers own the work where the output is a decision, not an artifact: what to build, what to cut, and which technical bets to place six months from now. Agents can generate options. They cannot tell you which option is right for your situation because “right” depends on factors that reside in human heads and organizational contexts, not in training data.</p></blockquote><p>And for LLMs:</p><blockquote><p>There is a mountain of work in every codebase that is a waste of human brainpower. Boilerplate, scaffolding, repetitive refactors, unit test generation, configuration templating, and data formatting. This work is rote, mechanical, and can be reasoned entirely from prior patterns. Agents should own it.</p></blockquote><p>In other words, LLMs are a tool that engineers can use to make development faster, but for software that you can depend on you still need an Engineer in the Loop. </p>]]></content:encoded>
      <author><name>Dustin Boston</name></author>
    </item>
    <item>
      <title><![CDATA[John Nosta on Language]]></title>
      <link>https://dustin.boston/blog/john-nosta-on-language</link>
      <guid isPermaLink="true">https://dustin.boston/blog/john-nosta-on-language</guid>
      <pubDate>Mon, 16 Mar 2026 12:31:00 GMT</pubDate>
      <description><![CDATA["The written word earned its authority because it preserved ideas. But also because it seemed to carry the trace of a person behind them. That authority is now being weakened by AI that can generate language without the lived experience or the cognitive burden that once stood behind the words."...]]></description>
      <content:encoded><![CDATA[<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://www.psychologytoday.com/us/blog/the-digital-self/202603/when-writing-becomes-detached-from-thought">When Writing Becomes Detached From Thought</a></p><blockquote><p>The written word earned its authority because it preserved ideas. But also because it seemed to carry the trace of a person behind them. That authority is now being weakened by AI that can generate language without the lived experience or the cognitive burden that once stood behind the words.</p><p>That may be why so much of today's posts and prose feel strangely vacant. Language has become easier to separate from the human mind that once gave it both substance and meaning.</p></blockquote><p></p>]]></content:encoded>
      <author><name>Dustin Boston</name></author>
    </item>
    <item>
      <title><![CDATA[You Can Run WordPress in the Browser]]></title>
      <link>https://dustin.boston/blog/you-can-run-wordpress-in-the-browser</link>
      <guid isPermaLink="true">https://dustin.boston/blog/you-can-run-wordpress-in-the-browser</guid>
      <pubDate>Thu, 12 Mar 2026 01:21:00 GMT</pubDate>
      <description><![CDATA[You can run WordPress in the browser with the WordPress Playground (using Web Assembly). That's pretty impressive!...]]></description>
      <content:encoded><![CDATA[<p>It's wild that you can <a target="_blank" rel="noopener noreferrer nofollow" href="https://wordpress.org/playground/">run WordPress in the browser</a>.</p><p>I have been making these little single page, local-first, PWA's a lot lately. For example, I created a habit tracker that is integrated with a calendar. Now I don't know why you'd want to run WordPress as a PWA - I'd personally go with TiddlyWiki - but it's a cool idea.</p><p>Anyway, they didn't rebuild WordPress for this use-case. Instead, they compiled the PHP interpreter to Web Assembly. Then WordPress is bundled and loaded into an in-memory virtual filesystem. Finally, WordPress is executed as normal using PHP.</p><p>You can <a target="_blank" rel="noopener noreferrer nofollow" href="https://wasmer.io/posts/how-webassembly-is-powering-wordpress">read more about the architecture here</a>. <br>And <a target="_blank" rel="noopener noreferrer nofollow" href="https://ma.tt/2026/03/wordpress-everywhere/">here's the "Press Release"</a>.</p>]]></content:encoded>
      <author><name>Dustin Boston</name></author>
    </item>
    <item>
      <title><![CDATA[Durable business patterns]]></title>
      <link>https://dustin.boston/blog/durable-business-patterns</link>
      <guid isPermaLink="true">https://dustin.boston/blog/durable-business-patterns</guid>
      <pubDate>Thu, 05 Mar 2026 06:52:00 GMT</pubDate>
      <description><![CDATA[In an AI‑accelerated world where anyone can clone a product in days, the only startups that survive are the ones that accumulate advantages that compound over time....]]></description>
      <content:encoded><![CDATA[<p>In an AI‑accelerated world where anyone can clone a product in days, the only startups that survive are the ones that accumulate advantages that compound over time. Specifically, advantages that cannot be copied with code, capital, or a weekend hackathon.</p><p><a target="_blank" rel="noopener noreferrer nofollow" href="https://x.com/sidrmsh/status/2029339145114374256">Sid Ramesh argues</a> that true defensibility is not a moat you build at the end - it’s a direction you compound in. The seven compounding advantages:</p><ol><li><p>Proprietary, compounding data, that improves the product with every interaction and cannot be shortcut. For example, Spotify’s decade of listening behavior.</p></li><li><p>Infrastructure‑level trust including reliability, uptime, auditability, and deep integration into workflows. Stripe isn’t just a tool - it’s plumbing. Switching costs come from risk, not fees.</p></li><li><p>Permission moats (regulatory, compliance, licenses) are slow to build, impossible to copy quickly. Coinbase’s years of licensing became a structural advantage once regulators cleared them.</p></li><li><p>Distribution you can’t copy with code, like being the default, the marketplace integration, or the ecosystem hub. Hyperliquid became the coordination layer for decentralized derivatives.</p></li><li><p>Community and brand that exist beyond the product. Notion’s ecosystem of templates, creators, and workflows is uncopyable. You can clone the editor, not the culture.</p></li><li><p>Capital and liquidity depth like Aave’s safety module, loss history, and liquidity pool create a moat no fork can replicate. Liquidity begets liquidity.</p></li><li><p>Physical infrastructure such as warehouses, sensors, manufacturing, logistics, charging networks - atoms don’t compress like bits.</p></li></ol><p>So, the real question is "How do I build something that gets harder to kill the longer it exists?"<strong> </strong>Most founders chase growth, demos, and pitch decks instead of building something that would materially hurt users if it disappeared.</p><p>Durability starts with obsession over a specific user, not a market size slide.</p>]]></content:encoded>
      <author><name>Dustin Boston</name></author>
    </item>
    <item>
      <title><![CDATA[Four Ways to Use the Popover API - From Declarative to Imperative]]></title>
      <link>https://dustin.boston/blog/four-ways-to-use-the-popover-api-from-declarative-to-imperative</link>
      <guid isPermaLink="true">https://dustin.boston/blog/four-ways-to-use-the-popover-api-from-declarative-to-imperative</guid>
      <pubDate>Mon, 02 Mar 2026 00:45:00 GMT</pubDate>
      <description><![CDATA[I've been working on a native HTML+CSS pattern library, covering about 60 different components. One thing I noticed as I worked my way through the list is how often the Popover API came up. Specifically, in popovers, tooltips, hover cards, and context menus....]]></description>
      <content:encoded><![CDATA[<p>I've been working on a native HTML+CSS pattern library, covering about 60 different components. One thing I noticed as I worked my way through the list is how often the Popover API came up. Specifically, in popovers, tooltips, hover cards, and context menus.</p><p>The Popover API is one of the most versatile additions to the web platform in recent years. A single attribute - <code>popover</code> - gives any element top-layer promotion, light-dismiss behavior, and accessible focus management for free. But the API is not one-size-fits-all. Depending on the interaction pattern, you can lean entirely on HTML attributes, mix in a little JavaScript, or take full manual control.</p><p>This post walks through four real components that each use the Popover API differently, arranged from the most declarative to the most imperative.</p><h3><strong>1. Popover</strong></h3><p>The simplest use of the Popover API requires zero JavaScript. A <code>popovertarget</code> attribute on the button points at the popover's <code>id</code>, and the browser wires up all the toggle logic automatically.</p><pre><code class="language-html">&lt;button type="button" popovertarget="p1"&gt;Open popover&lt;/button&gt;
&lt;div id="p1" popover&gt;
  &lt;h4&gt;Dimensions&lt;/h4&gt;
  &lt;p&gt;Set the dimensions for the layer.&lt;/p&gt;
&lt;/div&gt;</code></pre><pre><code class="language-css">[popover] {
  inset: unset;
}
</code></pre><p>The bare <code>popover</code> attribute defaults to <code>auto</code> mode, which gives you two behaviors for free: light-dismiss (clicking outside closes the popover) and exclusive stacking (opening one <code>auto</code> popover closes any other). The <code>popovertarget</code> attribute defaults to toggle behavior — click once to open, click again to close. The CSS resets <code>inset: unset</code> because the browser applies a default <code>inset: 0</code> to popover elements, which would center them in the viewport rather than letting us position them near the trigger.</p><h3><strong>2. Tooltip</strong></h3><p>Tooltips need <code>popover="manual"</code> because they should never light-dismiss — the user did not click to open them, so clicking elsewhere should not be intercepted. They also should not compete with other popovers for exclusive stacking; a tooltip and a dropdown menu should be able to coexist.</p><pre><code class="language-html">&lt;button type="button" popovertarget="t1" popovertargetaction="toggle"&gt;Hover me&lt;/button&gt;
&lt;div id="t1" popover="manual" role="tooltip"&gt;Add to library&lt;/div&gt;
</code></pre><pre><code class="language-css">[role="tooltip"] {
  inset: unset;
}
</code></pre><pre><code class="language-js">const button = document.querySelector("[popovertarget]");
const tooltip = document.querySelector("[popover]");

positionPopover(tooltip, button, { placement: "top", gap: 4 });

button.addEventListener("mouseenter", () =&gt; tooltip.showPopover());
button.addEventListener("mouseleave", () =&gt; tooltip.hidePopover());
button.addEventListener("focus", () =&gt; tooltip.showPopover());
button.addEventListener("blur", () =&gt; tooltip.hidePopover());
</code></pre><p>Since manual mode disables all built-in triggers, we call <code>showPopover()</code> and <code>hidePopover()</code> from four event listeners: <code>mouseenter</code>/<code>mouseleave</code> for hover, and <code>focus</code>/<code>blur</code> for keyboard accessibility. The <code>popovertargetaction="toggle"</code> on the button is a fallback that lets the tooltip also work via click if the JavaScript has not loaded yet. The <code>role="tooltip"</code> ensures screen readers announce the content as a tooltip description rather than a generic region.</p><h3><strong>3. Hover Card</strong></h3><p>Hover cards are richer than tooltips — they contain structured content like profile information or previews, and the user should be able to move their mouse into the card to interact with it. Unlike the tooltip, a hover card uses <code>popover="auto"</code> because it benefits from light-dismiss: if the user clicks somewhere else, the card should close.</p><pre><code class="language-html">&lt;a href="#" popovertarget="my-hovercard" popovertargetaction="show"&gt;@dustinboston&lt;/a&gt;
&lt;div id="my-hovercard" popover="auto"&gt;
  &lt;h4&gt;Dustin&lt;/h4&gt;
  &lt;p&gt;Software engineer. Joined March 2002.&lt;/p&gt;
&lt;/div&gt;
</code></pre><pre><code class="language-css">[popover] {
  inset: unset;
  position: fixed;
}
</code></pre><pre><code class="language-js">let hideTimeout;
const show = () =&gt; { clearTimeout(hideTimeout); card.showPopover(); };
const hide = () =&gt; { hideTimeout = setTimeout(() =&gt; card.hidePopover(), 100); };

button.addEventListener("mouseenter", show);
button.addEventListener("mouseleave", hide);
card.addEventListener("mouseenter", show);
card.addEventListener("mouseleave", hide);

positionPopover(card, button, { placement: "top" });
</code></pre><p>The <code>popovertargetaction="show"</code> on the anchor is a subtle detail — it means if a user clicks the link, the card is shown rather than toggled closed. The real runtime drivers are the mouse event listeners, but there is an important difference from the tooltip: a delayed hide. When the cursor leaves the trigger, a 100ms timeout starts before <code>hidePopover()</code> fires. If the cursor enters the card within that window, the timeout is cancelled. This lets the user cross the gap between the trigger and the card without the card flickering away. Both the trigger and the card share the same <code>show</code>/<code>hide</code> functions, so hovering either element keeps it open. This is the hybrid sweet spot: the element still gets top-layer promotion and <code>auto</code>-mode light-dismiss from the platform, while JavaScript only handles the hover timing.</p><h3><strong>4. Context Menu</strong></h3><p>A right-click context menu is the furthest from the declarative ideal. There is no trigger button to wire <code>popovertarget</code> to — the menu appears wherever the cursor happens to be when the user right-clicks. This calls for <code>popover="manual"</code>.</p><pre><code class="language-html">&lt;div id="context-menu"&gt;
  &lt;div id="trigger"&gt;Right click here&lt;/div&gt;
  &lt;div id="menu" role="menu" popover="manual"&gt;
    &lt;button role="menuitem" type="button"&gt;Back&lt;/button&gt;
    &lt;button role="menuitem" type="button"&gt;Forward&lt;/button&gt;
    &lt;button role="menuitem" type="button"&gt;Reload&lt;/button&gt;
    &lt;hr data-separator /&gt;
    &lt;button role="menuitem" type="button"&gt;Save As...&lt;/button&gt;
    &lt;button role="menuitem" type="button"&gt;Print...&lt;/button&gt;
  &lt;/div&gt;
&lt;/div&gt;
</code></pre><pre><code class="language-css">[popover] {
  inset: unset;
  position: fixed;
}
</code></pre><pre><code class="language-js">const trigger = document.querySelector("#trigger");
const menu = document.querySelector("#menu");

trigger.addEventListener("contextmenu", (e) =&gt; {
  e.preventDefault();
  menu.style.left = e.clientX + "px";
  menu.style.top = e.clientY + "px";
  menu.showPopover();
});

document.addEventListener("click", (e) =&gt; {
  if (!menu.contains(e.target)) menu.hidePopover();
});
</code></pre><p>Manual mode disables every automatic behavior: no light-dismiss, no Escape-to-close, no exclusive stacking. The <code>contextmenu</code> event provides the cursor coordinates, which are set as inline <code>style.left</code> and <code>style.top</code> before calling <code>showPopover()</code>. Dismissal is handled by a document-level click listener that checks whether the click landed outside the menu. The component is responsible for the entire lifecycle — but it still benefits from top-layer rendering, which means it paints above dialogs and other popovers without z-index hacks or stacking context headaches.</p><h2><strong>The Spectrum</strong></h2><p>These four components sit on a clear spectrum:</p><ol><li><p>Popover - fully auto, no JS required</p></li><li><p>Tooltip - manual, minimal JS required</p></li><li><p>Hover Card - auto, moderate JS required</p></li><li><p>Context Menu - manual, full JS required</p></li></ol><p>The lesson is straightforward: start with <code>popover</code> and <code>popovertarget</code>. Add <code>popovertargetaction</code> if you need directional control. Reach for <code>showPopover()</code> and <code>hidePopover()</code> only when the trigger is not a click. Switch to <code>manual</code> only when you need to own the entire lifecycle. At every step, the platform is doing the heavy lifting — you are just choosing how much of it to use.</p>]]></content:encoded>
      <author><name>Dustin Boston</name></author>
    </item>
    <item>
      <title><![CDATA[AI Usage as a Factor in Performance Reviews]]></title>
      <link>https://dustin.boston/blog/ai-usage-as-a-factor-in-performance-reviews</link>
      <guid isPermaLink="true">https://dustin.boston/blog/ai-usage-as-a-factor-in-performance-reviews</guid>
      <pubDate>Wed, 25 Feb 2026 02:07:00 GMT</pubDate>
      <description><![CDATA[AI usage is now being considered a factor in performance reviews. The WSJ reports that AI usage is already part of the reviews at Google, Amazon, and Meta....]]></description>
      <content:encoded><![CDATA[<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://www.wsj.com/tech/ai/tech-firms-arent-just-encouraging-their-workers-to-use-ai-theyre-enforcing-it-d43ebf84?st=tC5Bx3&amp;reflink=desktopwebshare_permalink&amp;utm_source=tldrnewsletter">AI usage is now being considered a factor in performance reviews</a>. The WSJ reports that AI usage is already part of the reviews at Google, Amazon, and Meta. I saw this coming at Disney when the KPIs (key performance indicators) started to incorporate AI usage. It makes sense that companies would need to <em>motivate</em> developers who are worried about losing their jobs to AI. </p>]]></content:encoded>
      <author><name>Dustin Boston</name></author>
    </item>
    <item>
      <title><![CDATA[Don't Feel Bad About Using AI]]></title>
      <link>https://dustin.boston/blog/dont-feel-bad-about-using-ai</link>
      <guid isPermaLink="true">https://dustin.boston/blog/dont-feel-bad-about-using-ai</guid>
      <pubDate>Wed, 25 Feb 2026 01:05:00 GMT</pubDate>
      <description><![CDATA[The cultural stigma surrounding AI usage is fundamentally misplaced, as AI functions not as a shortcut for the lazy, but as a legitimate force multiplier and natural evolution of democratized knowledge that amplifies human craftsmanship....]]></description>
      <content:encoded><![CDATA[<p>Andreas Kling wrote an article about Ladybird adopting Rust, with help from AI. It stood out to me because of this paragraph:</p><blockquote><p>This was human-directed, not autonomous code generation. I decided what to port, in what order, and what the Rust code should look like. It was hundreds of small prompts, steering the agents where things needed to go. After the initial translation, I ran multiple passes of adversarial review, asking different models to analyze the code for mistakes and bad patterns.</p></blockquote><p>It's interesting because Kling goes out of the way to explain his AI usage. I think a lot of people feel this way - having to make sure that folks know you're not using AI for slop. Those who wage the great war against slop tend to have an air of superiority that makes you feel shame for using AI. This defensive posture - the need to justify the use of a tool - stems from a cultural narrative that frames AI as a shortcut for the lazy rather than a lever for the ambitious. But the shame surrounding AI is misplaced, rooted in a misunderstanding of how technology evolves and how human knowledge is meant to be shared.</p><p>Here are five reasons why using AI is nothing to be ashamed of:</p><ol><li><p>The internet was founded on the principle of freely accessible information. The outrage over AI training models often relies on a rigid interpretation of copyright that runs counter to this original ethos. If the web was designed to democratize access to human knowledge, AI is simply the next iteration of that democratization. It is an engine that synthesizes the collective public output of humanity. Using it is not participating in theft; it is engaging with the ultimate distillation of our shared digital history.</p></li><li><p>Critics frequently cite the energy consumption of data centers as a reason to boycott AI. Yet, society readily accepts the massive ecological footprints of other ambitious human endeavors—like launching rockets into orbit or powering global financial systems—because they are implicitly understood as investments in the "greater good." AI demands significant resources, but it also offers unprecedented potential to solve macro-level problems, optimize logistics, and accelerate scientific discovery. The energy cost is an investment in a cognitive infrastructure that benefits humanity at scale.</p></li><li><p>The fear of "slop" assumes that AI operates autonomously to flood the world with mediocrity. As Kling’s experience demonstrates, high-quality output requires high-level human orchestration. AI does not replace the human mind; it acts as a compiler for human intent. True software craftsmanship is no longer just about manually typing every character of syntax; it is about architecture, logic, and directing agents to execute a vision. The shame belongs to those who output thoughtless work, regardless of whether they used a keyboard or a prompt to generate it.</p></li><li><p>There is a persistent, romanticized notion that "harder" means "better." When high-level programming languages first appeared, developers writing in Assembly viewed them with similar skepticism. Refusing to use AI out of a sense of purity is a false economy. Efficiency is not a sin, and leveraging the most powerful tools available to execute an idea faster and with fewer errors is the hallmark of a skilled professional, not a hack.</p></li><li><p>AI acts as a force multiplier, dramatically lowering the barrier to entry for complex problem-solving. It allows an individual to act as an entire team, bridging the gap between a conceptual idea and a deployed reality. Making individuals feel ashamed for utilizing a tool that elevates their capabilities only serves to protect established monopolies and gatekeepers. Embracing AI is embracing a more level playing field where execution is limited only by imagination, not headcount.</p></li></ol><p></p>]]></content:encoded>
      <author><name>Dustin Boston</name></author>
    </item>
    <item>
      <title><![CDATA[Common Performance Pitfalls with Next.js React Server Components]]></title>
      <link>https://dustin.boston/blog/common-performance-pitfalls-with-nextjs-react-server-components</link>
      <guid isPermaLink="true">https://dustin.boston/blog/common-performance-pitfalls-with-nextjs-react-server-components</guid>
      <pubDate>Tue, 24 Feb 2026 23:00:00 GMT</pubDate>
      <description><![CDATA[In the article 6 React Server Component performance pitfalls in Next.js, Temitope Oyedele identifies common implementation errors that negate the performance benefits of React Server Components (RSCs) and the Next.js App Router....]]></description>
      <content:encoded><![CDATA[<p>In the article <a target="_blank" rel="noopener" class="ng-star-inserted" href="https://blog.logrocket.com/react-server-components-performance-mistakes/">6 React Server Component performance pitfalls in Next.js</a>, Temitope Oyedele<strong> </strong>identifies common implementation errors that negate the performance benefits of React Server Components (RSCs) and the Next.js App Router. I copied the entire article into a skill and had Claude track down these issues in my codebase. There were a surprising amount of them!</p><h3>Core Perf Pitfalls</h3><ul><li><p>Using top-level <code>await</code> in a page component prevents the server from streaming the initial UI shell. This leaves users staring at a blank screen until the slowest data fetch completes. </p></li><li><p>Passing entire database objects across the server-client boundary bloats the HTML and increases hydration time. Use only the fields the client actually needs.</p></li><li><p>Placing the <code>use client</code> directive too high in the component tree forces static elements to be included in the JavaScript bundle and hydrated unnecessarily.</p></li><li><p>Failing to use <code>Suspense</code> for non-essential, slow-loading data prevents the browser from showing "fast" content (like headers or sidebars) immediately.</p></li><li><p>Forgetting to use <code>revalidatePath</code> or <code>revalidateTag</code> in Server Actions can lead to stale UI where the database updates but the view remains unchanged until a manual refresh.</p></li><li><p>Using <code>async</code> logic directly in a root layout blocks the entire application's rendering. Data-heavy elements should be moved to isolated components wrapped in <code>Suspense</code>.</p></li></ul><p>The article emphasizes that RSC performance is often about perceived speed and visible progress. By isolating slow work behind <code>Suspense</code> boundaries and keeping the client-side bundle lean, developers can ensure the shell of an application renders instantly, even if back-end processes are slow.</p>]]></content:encoded>
      <author><name>Dustin Boston</name></author>
    </item>
  </channel>
</rss>