<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Fikayo Adepoju</title>
    <description>The latest articles on DEV Community by Fikayo Adepoju (@coderonfleek).</description>
    <link>https://dev.to/coderonfleek</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F69518%2F3ffe14aa-7393-42ea-a054-2acbdf6ca5fe.jpg</url>
      <title>DEV Community: Fikayo Adepoju</title>
      <link>https://dev.to/coderonfleek</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/coderonfleek"/>
    <language>en</language>
    <item>
      <title>Harness Engineering - Part 10: Decomposing Claude Code</title>
      <dc:creator>Fikayo Adepoju</dc:creator>
      <pubDate>Sat, 15 Aug 2026 18:36:33 +0000</pubDate>
      <link>https://dev.to/coderonfleek/harness-engineering-part-10-decomposing-claude-code-3h27</link>
      <guid>https://dev.to/coderonfleek/harness-engineering-part-10-decomposing-claude-code-3h27</guid>
      <description>&lt;p&gt;&lt;em&gt;Welcome back to the Harness Engineering series — a 10-part journey from raw language model to production-ready agentic system. Made by builders. For builders.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In Part 9, I promised the last article would be where the whole series pays off. Nine articles laying out a taxonomy — six components, three verbs, one architectural picture. This article points all of that at a real, working, publicly-known agent: &lt;strong&gt;Claude Code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We're not going to speculate about how Claude Code works. We're going to walk through it the way you'll walk through any agent from here forward — component by component, asking six specific questions, and putting the answers in the six boxes we've been carrying around this whole series.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's ahead:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-1-the-raw-model-problem-54hg"&gt;Part 1: The Raw Model Problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-2-defining-the-harness-the-six-components-2gpk"&gt;Part 2: Defining the Harness — The Six Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-3-the-control-loop-3khk"&gt;Part 3: The Control Loop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-4-the-tool-layer-2p3f"&gt;Part 4: The Tool Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-5-context-engineering-94d"&gt;Part 5: Context Engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-6-the-filesystem-environment-17m0"&gt;Part 6: The Filesystem &amp;amp; Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-7-the-memory-layer-3oon"&gt;Part 7: The Memory Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-8-observability-3gc1"&gt;Part 8: Observability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-9-the-harness-architecture-i5e"&gt;Part 9: The Harness Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Decomposing Claude Code&lt;/strong&gt; ← You are here&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the end of this article, you'll have seen the six-component framework applied to a real agent from start to finish — and you'll have a repeatable method you can use on any agent you encounter from now on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's get started.&lt;/strong&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;h3&gt;
  
  
  📚 Want to go deeper than the articles?
&lt;/h3&gt;

&lt;p&gt;While you follow along with this series, I've put together two hands-on resources that go further than any single article can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.udemy.com/course/agentic-harness-engineering/?couponCode=7FA3B8BE5D143E73653B" rel="noopener noreferrer"&gt;Build a Harness from Scratch — Udemy Course&lt;/a&gt;&lt;/strong&gt; — A self-paced course where I walk you through building a production-grade agentic harness from the ground up, in code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://maven.com/fikayo-adepoju/harness-engineering-for-ai-agents" rel="noopener noreferrer"&gt;Harness Engineering for AI Agents — Live Maven Workshop&lt;/a&gt;&lt;/strong&gt; — A live, cohort-based workshop for builders who want direct feedback, Q&amp;amp;A, and to work through the material with peers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are optional — the series stands on its own. But if you want the full studio-quality version, that's where it lives.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Setup
&lt;/h2&gt;

&lt;p&gt;We've spent nine articles laying out a shared vocabulary and framework. Now we point that framework at something concrete.&lt;/p&gt;

&lt;p&gt;The picture below is what a full decomposition looks like when you draw it out on a whiteboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F524hmma6jelq0tg4qu1y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F524hmma6jelq0tg4qu1y.png" alt="Claude Code - Harness Breakdown" width="799" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every component we've named has a box. Every arrow between them is a coupling we've discussed. And in the middle sits Claude Code — the agent we're pulling apart to see what fills each of those boxes when the theory meets a real, shipping product.&lt;/p&gt;

&lt;p&gt;This is the exercise you can now do with any agent. What you're about to read is one worked example.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Six-Component Decomposition
&lt;/h2&gt;

&lt;p&gt;Here's Claude Code, broken down component by component using the framework from the rest of this series.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Loop
&lt;/h3&gt;

&lt;p&gt;Claude Code's Loop is a classic &lt;strong&gt;ReAct&lt;/strong&gt; loop — the shape we identified in Part 3 as the default for most modern agents. It cycles through &lt;em&gt;call the model → decide an action → execute the tool → inspect the result → back to the model&lt;/em&gt;, and it keeps going until either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The model indicates the task is done&lt;/li&gt;
&lt;li&gt;A step budget is hit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two clear termination conditions, both explicit, both mechanical. Exactly the pattern Part 3 argued for.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The Tools
&lt;/h3&gt;

&lt;p&gt;Claude Code has the &lt;strong&gt;small, sharp tool surface&lt;/strong&gt; we made a big deal of in Part 4: &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;edit&lt;/code&gt;, &lt;code&gt;bash&lt;/code&gt;, &lt;code&gt;glob&lt;/code&gt;, &lt;code&gt;grep&lt;/code&gt;, plus a task-management tool and an MCP connector for extending the tool set.&lt;/p&gt;

&lt;p&gt;That's it. No &lt;code&gt;refactor_python_function&lt;/code&gt;. No &lt;code&gt;run_pytest_and_summarize&lt;/code&gt;. No &lt;code&gt;open_pr_with_generated_summary&lt;/code&gt;. Every specialized job a bloated toolset would have its own function for is composed instead from the general primitives.&lt;/p&gt;

&lt;p&gt;This is the "compose, don't enumerate" principle from Part 4, made real. When Claude Code needs to do something novel, it doesn't need a new tool — it reaches for &lt;code&gt;bash&lt;/code&gt; and &lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;read&lt;/code&gt; and figures it out.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The Context
&lt;/h3&gt;

&lt;p&gt;On every turn, Claude Code assembles the Context from four ingredients:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;system prompt&lt;/strong&gt; (built into the agent)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CLAUDE.md&lt;/strong&gt; files and other repo-level context&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;conversation history&lt;/strong&gt; so far&lt;/li&gt;
&lt;li&gt;All prior &lt;strong&gt;tool results&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And on top of those, any files the user explicitly references with &lt;code&gt;@&lt;/code&gt; get pulled in for that turn.&lt;/p&gt;

&lt;p&gt;Notice how this maps directly to Part 5. The system prompt is the built-in control plane. CLAUDE.md is the user-layered instruction file we called out by name. Conversation history is the short-term memory feeding forward. Tool results are outputs of previous turns being made available to the next. And &lt;code&gt;@&lt;/code&gt; references are an explicit-attachment mechanism the user drives.&lt;/p&gt;

&lt;p&gt;Different names on the whiteboard, but every ingredient came from the vocabulary in Part 5.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. The Environment
&lt;/h3&gt;

&lt;p&gt;Claude Code's Environment is your local machine — the actual thing sitting on your desk.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;read&lt;/code&gt; and &lt;code&gt;edit&lt;/code&gt; tools touch your real filesystem. &lt;code&gt;bash&lt;/code&gt; runs commands in your real shell. Network calls hit the real network. This is a &lt;strong&gt;bounded but not sandboxed&lt;/strong&gt; environment: bounded because Claude Code doesn't reach outside the working directory casually, and gated by a permissioning system that prompts you before destructive operations — deleting files, running risky commands, and so on.&lt;/p&gt;

&lt;p&gt;Compare that to Codex from Part 6, which runs in a fully sandboxed disposable container. Claude Code makes a different trade: less isolation, more directness, safety enforced through &lt;em&gt;permissioning&lt;/em&gt; rather than through &lt;em&gt;walls&lt;/em&gt;. Same component, different design choice. Both defensible for their respective use cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. The Memory Layer
&lt;/h3&gt;

&lt;p&gt;Claude Code has the exact &lt;strong&gt;two-flavor design&lt;/strong&gt; from Part 7:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Short-term memory&lt;/strong&gt; is the running conversation — the messages exchanged so far, replayed on every turn.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Long-term memory&lt;/strong&gt; lives in &lt;code&gt;CLAUDE.md&lt;/code&gt; files at the repo and user level, plus the user's &lt;code&gt;~/.claude&lt;/code&gt; directory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Short-term is full-fidelity. Long-term is compressed and structured — files, not raw history. And critically, the long-term memory is &lt;em&gt;user-managed&lt;/em&gt;: the user writes into &lt;code&gt;CLAUDE.md&lt;/code&gt;; Claude Code reads from it. That's a very deliberate design choice — the write triggers for long-term memory are essentially &lt;em&gt;"the user decided to write something down."&lt;/em&gt; No auto-summarization guessing what to remember. An explicit gate, controlled by a human.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Observability
&lt;/h3&gt;

&lt;p&gt;Claude Code's Observability shows up as a &lt;strong&gt;visible tool-call log&lt;/strong&gt; in the UI. Every &lt;code&gt;read&lt;/code&gt;, every &lt;code&gt;edit&lt;/code&gt;, every &lt;code&gt;bash&lt;/code&gt; invocation is shown to the user as it happens, in real time.&lt;/p&gt;

&lt;p&gt;That's not just a UI feature. That's the exact observability principle from Part 8 made visible: the user (and, by extension, an engineer debugging the agent) can see what the agent is doing as a stream of concrete events. Nothing important happens in the dark.&lt;/p&gt;

&lt;p&gt;The user-visible tool log is essentially a real-time trace, presented as UX rather than as a debugging tool. That's a signal about how much Claude Code's designers trust the value of observability — enough to put it on the surface of the product, not hide it behind a &lt;code&gt;--verbose&lt;/code&gt; flag.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Decomposition Shows Us
&lt;/h2&gt;

&lt;p&gt;Three things stand out once the whole picture is on the wall.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First, every box has something in it.&lt;/strong&gt; No component is missing. Every one of the six we've talked about has a concrete implementation in Claude Code. This is what a complete harness looks like — a real product where all six concerns have been thought through, not left to chance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second, the design choices are internally consistent.&lt;/strong&gt; The small-sharp tool surface fits the general-purpose model bet. The direct-not-sandboxed environment fits the coding-in-your-real-repo use case. The user-managed long-term memory fits a product where the user is a technical operator, not a passive consumer. Nothing feels bolted on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Third, none of this required insider knowledge to see.&lt;/strong&gt; Every observation we just made is available to anyone who uses Claude Code and knows what to look for. That's the whole point of a taxonomy — it turns opaque products into readable systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every real agent decomposes into these six components.&lt;/strong&gt; That's the claim this series has been driving toward. Claude Code is one worked example of what it looks like when you actually do the decomposition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do This to Any Agent
&lt;/h2&gt;

&lt;p&gt;The exercise we just did with Claude Code — six questions, six answers, one honest whiteboard — is now a tool you own. You can point it at anything.&lt;/p&gt;

&lt;p&gt;Try it on &lt;strong&gt;Cursor&lt;/strong&gt;. What's Cursor's Loop like when a completion fires? What's on its tool surface? What does it assemble into context on every keystroke? What's its environment? Where does memory live? What's its observability story?&lt;/p&gt;

&lt;p&gt;Try it on &lt;strong&gt;a framework you're evaluating&lt;/strong&gt;. If you can't quickly answer all six questions about it, that's a signal — either the framework is genuinely lightweight (and expects you to fill in the missing components), or its design isn't as thought-through as its marketing suggests.&lt;/p&gt;

&lt;p&gt;Try it on &lt;strong&gt;your own work&lt;/strong&gt;. If you're prototyping an agent, sketch out the six-component picture before you write any code. Which pieces are you designing deliberately? Which are you leaving to chance? Which ones already exist in libraries you're using, and which ones will you have to write yourself?&lt;/p&gt;

&lt;p&gt;That kind of thinking — the ability to look at any agent, sketch its six components, and reason about the tradeoffs at each — is what a good taxonomy buys you.&lt;/p&gt;

&lt;h2&gt;
  
  
  That's a Wrap
&lt;/h2&gt;

&lt;p&gt;And that brings us to the end.&lt;/p&gt;

&lt;p&gt;Ten articles. Six components. Three verbs. One raw model problem, and the entire discipline of engineering that sits around it to make agentic systems actually work.&lt;/p&gt;

&lt;p&gt;Thank you for reading through the whole series. If it made the fog around AI agents feel more like structure, then it did what it was meant to do. Whether you go on to build your own harness, evaluate someone else's, or just have sharper conversations about agents from here on out — the vocabulary you've picked up is yours to keep.&lt;/p&gt;

&lt;p&gt;If you want to go deeper — actually build a harness end-to-end, or work through the material with peers and direct feedback — the course and the workshop linked at the top of every article in this series are where that happens.&lt;/p&gt;

&lt;p&gt;Until then: use what you've learned. Point it at real systems. Notice what fits the framework and what doesn't. That's the whole game.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This was the final article in a 10-part series that walked through every component of an agentic harness.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's the full roadmap you just completed:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-1-the-raw-model-problem-54hg"&gt;Part 1: The Raw Model Problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-2-defining-the-harness-the-six-components-2gpk"&gt;Part 2: Defining the Harness — The Six Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-3-the-control-loop-3khk"&gt;Part 3: The Control Loop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-4-the-tool-layer-2p3f"&gt;Part 4: The Tool Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-5-context-engineering-94d"&gt;Part 5: Context Engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-6-the-filesystem-environment-17m0"&gt;Part 6: The Filesystem &amp;amp; Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-7-the-memory-layer-3oon"&gt;Part 7: The Memory Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-8-observability-3gc1"&gt;Part 8: Observability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-9-the-harness-architecture-i5e"&gt;Part 9: The Harness Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Decomposing Claude Code&lt;/strong&gt; ← You just finished this one — and the series.&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's the series. Thanks for coming along.&lt;/p&gt;

&lt;p&gt;Happy coding :)&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>python</category>
      <category>llm</category>
    </item>
    <item>
      <title>Harness Engineering - Part 9: The Harness Architecture</title>
      <dc:creator>Fikayo Adepoju</dc:creator>
      <pubDate>Sat, 15 Aug 2026 18:36:02 +0000</pubDate>
      <link>https://dev.to/coderonfleek/harness-engineering-part-9-the-harness-architecture-i5e</link>
      <guid>https://dev.to/coderonfleek/harness-engineering-part-9-the-harness-architecture-i5e</guid>
      <description>&lt;p&gt;&lt;em&gt;Welcome back to the Harness Engineering series — a 10-part journey from raw language model to production-ready agentic system. Made by builders. For builders.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In Parts 3 through 8, I walked through the six components of an agentic harness one at a time — the Loop, the Tools, the Context, the Environment, the Memory Layer, and Observability. But naming the parts isn't the same as understanding how they fit together.&lt;/p&gt;

&lt;p&gt;In this article, we zoom out. We look at the whole architecture at once, trace the flow of a single agent turn through it, and see what shape a real harness has when you draw it as a system.&lt;/p&gt;

&lt;p&gt;This shape isn't unique to any one framework. It's the &lt;strong&gt;canonical shape&lt;/strong&gt; — the picture every real agent, from Claude Code to Cursor to whatever custom harness a company is building for its own internal use — is some variation of. Once you can see it clearly, you can look at any agent and spot which pieces are present, which are missing, and where the interesting design decisions were made.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's ahead:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-1-the-raw-model-problem-54hg"&gt;Part 1: The Raw Model Problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-2-defining-the-harness-the-six-components-2gpk"&gt;Part 2: Defining the Harness — The Six Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-3-the-control-loop-3khk"&gt;Part 3: The Control Loop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-4-the-tool-layer-2p3f"&gt;Part 4: The Tool Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-5-context-engineering-94d"&gt;Part 5: Context Engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-6-the-filesystem-environment-17m0"&gt;Part 6: The Filesystem &amp;amp; Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-7-the-memory-layer-3oon"&gt;Part 7: The Memory Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-8-observability-3gc1"&gt;Part 8: Observability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;The Harness Architecture&lt;/strong&gt; ← You are here&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-10-decomposing-claude-code-3h27"&gt;Part 10: Decomposing Claude Code&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the end of this article, you'll have a mental picture of the whole harness as a system — how the six components connect, why the shape looks the way it does, and where the tightest coupling and cleanest seams are. That picture is the tool you'll use to look at any real-world agent and see through it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's get started.&lt;/strong&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;h3&gt;
  
  
  📚 Want to go deeper than the articles?
&lt;/h3&gt;

&lt;p&gt;While you follow along with this series, I've put together two hands-on resources that go further than any single article can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.udemy.com/course/agentic-harness-engineering/?couponCode=7FA3B8BE5D143E73653B" rel="noopener noreferrer"&gt;Build a Harness from Scratch — Udemy Course&lt;/a&gt;&lt;/strong&gt; — A self-paced course where I walk you through building a production-grade agentic harness from the ground up, in code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://maven.com/fikayo-adepoju/harness-engineering-for-ai-agents" rel="noopener noreferrer"&gt;Harness Engineering for AI Agents — Live Maven Workshop&lt;/a&gt;&lt;/strong&gt; — A live, cohort-based workshop for builders who want direct feedback, Q&amp;amp;A, and to work through the material with peers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are optional — the series stands on its own. But if you want the full studio-quality version, that's where it lives.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Architecture at a Glance
&lt;/h2&gt;

&lt;p&gt;Before we go further, take a moment to look at the diagram below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx6u9sxwx1qjo783130a9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx6u9sxwx1qjo783130a9.png" alt=" " width="800" height="948"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's the whole picture. Six components, arranged as a system: &lt;strong&gt;Observability&lt;/strong&gt; wraps the outside; &lt;strong&gt;the Loop&lt;/strong&gt; drives everything inside it; &lt;strong&gt;Context&lt;/strong&gt; sits at the assembly point between memory and the model; &lt;strong&gt;the Model&lt;/strong&gt; emits either an answer or a tool call; &lt;strong&gt;Tools&lt;/strong&gt; dispatch through the loop into the &lt;strong&gt;Environment&lt;/strong&gt;; and results flow back into &lt;strong&gt;Memory&lt;/strong&gt;, which feeds the next Context.&lt;/p&gt;

&lt;p&gt;The rest of this article walks through what that picture is telling us.&lt;/p&gt;

&lt;h2&gt;
  
  
  How a Single Turn Flows Through It
&lt;/h2&gt;

&lt;p&gt;Follow the arrows in the diagram, and here's the flow of one agent turn:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Loop starts a turn.&lt;/strong&gt; It's the outermost control structure — the piece that decides "keep going" or "stop." Every step below happens inside one iteration of the Loop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Loop assembles a Context.&lt;/strong&gt; It pulls from short-term memory (the conversation so far), from long-term memory (things the agent should remember across sessions), from the environment (files being worked on, tool results from prior turns), and from anywhere else that might be relevant. That assembled payload becomes the input for this turn.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Context goes to the Model.&lt;/strong&gt; The model reads it and produces a response. That response is either a final answer (in which case the Loop terminates) or a request to call a Tool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Loop dispatches the Tool.&lt;/strong&gt; Not the model — the Loop. The model emits a structured request; the Loop is the piece of code that reads that request, looks up the actual tool implementation, and runs it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Tool executes in the Environment.&lt;/strong&gt; Whatever side effect the tool has — reading a file, hitting an API, running a shell command — lands inside the harness's Environment, with its bounded filesystem, shell, and network.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The result flows into Memory and back into Context.&lt;/strong&gt; The tool result gets recorded in short-term memory (always) and may get promoted into long-term memory (if a write trigger fires). Then the Loop starts a new turn, which begins with assembling the next Context — now including the fresh result.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observability watches all of it.&lt;/strong&gt; Every model call is logged. Every tool invocation is traced. Every state transition is recorded. Observability wraps the whole cycle without participating in it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's one turn. Every capable agent you've ever seen is doing some version of this, over and over, until either the task is done, the budget runs out, or an error threshold is hit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Architecture Tells Us
&lt;/h2&gt;

&lt;p&gt;Once you can see the shape clearly, a few structural facts about the design become obvious.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Loop Is Outermost Because It's the Only Thing That Runs Continuously
&lt;/h3&gt;

&lt;p&gt;Everything else in the diagram fires in response to a Loop step. The Model doesn't drive anything on its own. Neither do the Tools. Neither does Memory or the Environment. They all wait to be invoked. The Loop is the piece that keeps the cycle moving, and it's why it sits on the outside of everything else.&lt;/p&gt;

&lt;p&gt;If you removed the Loop, every other component would still exist — but nothing would ever happen. There'd be a filesystem no one is touching, tool functions no one is calling, a model no one is sending payloads to. The Loop is what turns a collection of parts into a running system.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Context Is Where Everything Converges
&lt;/h3&gt;

&lt;p&gt;Look at where the arrows meet in the diagram. Memory feeds Context. Tool results feed Context. Retrieval feeds Context. Environmental state feeds Context. Then Context feeds the Model.&lt;/p&gt;

&lt;p&gt;The Context isn't a component that &lt;em&gt;does&lt;/em&gt; things — it's the surface where everything else's decisions get packaged and handed to the model, freshly, on every turn. That's why Part 5 argued context engineering is &lt;em&gt;"the deepest engineering discipline in the whole harness."&lt;/em&gt; It's not that context is more important than the other components. It's that context is the point where every other component's contribution has to actually get expressed in something the model can read.&lt;/p&gt;

&lt;p&gt;Get context assembly wrong, and even a beautifully-designed set of tools and a spotless environment don't help — the model never sees the right things at the right time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Observability Is Intentionally Decoupled
&lt;/h3&gt;

&lt;p&gt;Notice that Observability wraps the &lt;em&gt;outside&lt;/em&gt; of the diagram, not the inside. It doesn't participate in the cycle. It doesn't decide anything. It just watches and records.&lt;/p&gt;

&lt;p&gt;That decoupling is a design choice. An observability system that's tangled up with the components it observes ends up being unreliable when those components fail — exactly when you need it most. If Observability lives outside the cycle, it can keep working when the cycle breaks. And that's what makes it usable as the tool you reach for when something goes wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Canonical Shape
&lt;/h2&gt;

&lt;p&gt;The picture in the diagram isn't a specific framework's architecture. It's not opinionated toward LangChain or LangGraph or any particular library. It's the underlying shape that any agent capable of multi-step work has to have — because each component solves a real problem, and none of them are optional in a real production system.&lt;/p&gt;

&lt;p&gt;Different agents put their engineering effort into different parts of the same shape:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cursor&lt;/strong&gt; puts most of its differentiation in &lt;strong&gt;Context&lt;/strong&gt;. Its architecture has the same shape as this diagram, but Cursor's innovation lives inside the Context box — what it assembles, how it retrieves, what it prioritizes on every keystroke.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codex&lt;/strong&gt; puts most of its differentiation in &lt;strong&gt;Environment&lt;/strong&gt;. Same shape as everyone else, but Codex's innovation lives in that sandboxed container per task, and everything else is designed to defer to what the environment enables.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude Code&lt;/strong&gt; distributes its differentiation across &lt;strong&gt;Tools and Observability&lt;/strong&gt;. A small, sharp tool surface; visible live tool logging that doubles as a real-time trace.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you can look at an agent and spot which box it's investing engineering effort in, you understand what makes it different. And, more importantly, you know where to look when it fails, or when you want to reason about the tradeoffs in your own design.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Leaves Us
&lt;/h2&gt;

&lt;p&gt;We've now named the six components, walked through each one, and seen how they fit together into a coherent architecture. That's the theoretical spine of the series done.&lt;/p&gt;

&lt;p&gt;The last article is where it all pays off. In Part 10, we take a real, working, publicly-known agent — &lt;strong&gt;Claude Code&lt;/strong&gt; — and decompose it component by component using the exact framework we've built up here. What's Claude Code's Loop shape? What's on its tool surface? How does it engineer context? What does its environment look like? How does it handle memory? Where's its observability?&lt;/p&gt;

&lt;p&gt;By the end of that decomposition, you'll be able to look at any agent — any framework, any product, any research demo — and slice it up the same way. That's the payoff of a good taxonomy: you don't just understand the parts, you can take apart any real system into them.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Remember that this article is part of a longer 10-part series that walks you through every component of an agentic harness.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's the roadmap:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-1-the-raw-model-problem-54hg"&gt;Part 1: The Raw Model Problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-2-defining-the-harness-the-six-components-2gpk"&gt;Part 2: Defining the Harness — The Six Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-3-the-control-loop-3khk"&gt;Part 3: The Control Loop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-4-the-tool-layer-2p3f"&gt;Part 4: The Tool Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-5-context-engineering-94d"&gt;Part 5: Context Engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-6-the-filesystem-environment-17m0"&gt;Part 6: The Filesystem &amp;amp; Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-7-the-memory-layer-3oon"&gt;Part 7: The Memory Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-8-observability-3gc1"&gt;Part 8: Observability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;The Harness Architecture&lt;/strong&gt; ← You just finished this one.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-10-decomposing-claude-code-3h27"&gt;Part 10: Decomposing Claude Code&lt;/a&gt; ← &lt;em&gt;Move to this one.&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;See you in the next one.&lt;/p&gt;

&lt;p&gt;Happy coding :)&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>python</category>
      <category>llm</category>
    </item>
    <item>
      <title>Harness Engineering - Part 8: Observability</title>
      <dc:creator>Fikayo Adepoju</dc:creator>
      <pubDate>Sat, 15 Aug 2026 18:35:30 +0000</pubDate>
      <link>https://dev.to/coderonfleek/harness-engineering-part-8-observability-3gc1</link>
      <guid>https://dev.to/coderonfleek/harness-engineering-part-8-observability-3gc1</guid>
      <description>&lt;p&gt;&lt;em&gt;Welcome back to the Harness Engineering series — a 10-part journey from raw language model to production-ready agentic system. Made by builders. For builders.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In Part 7, I closed on a line worth expanding: &lt;strong&gt;"I built an agent"&lt;/strong&gt; vs &lt;strong&gt;"I built an agent I can actually operate."&lt;/strong&gt; The difference between those two sentences is the sixth and final component of the harness. It's called &lt;strong&gt;Observability&lt;/strong&gt;, and without it, everything else you've read in this series is a bet you can't check.&lt;/p&gt;

&lt;p&gt;Every previous component in this series does something the agent needs to &lt;em&gt;work.&lt;/em&gt; Observability does something the &lt;em&gt;engineer&lt;/em&gt; needs — to see what happened, to know when things are going wrong, and to have any hope of making the harness better over time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's ahead:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-1-the-raw-model-problem-54hg"&gt;Part 1: The Raw Model Problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-2-defining-the-harness-the-six-components-2gpk"&gt;Part 2: Defining the Harness — The Six Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-3-the-control-loop-3khk"&gt;Part 3: The Control Loop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-4-the-tool-layer-2p3f"&gt;Part 4: The Tool Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-5-context-engineering-94d"&gt;Part 5: Context Engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-6-the-filesystem-environment-17m0"&gt;Part 6: The Filesystem &amp;amp; Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-7-the-memory-layer-3oon"&gt;Part 7: The Memory Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Observability&lt;/strong&gt; ← You are here&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-9-the-harness-architecture-i5e"&gt;Part 9: The Harness Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-10-decomposing-claude-code-3h27"&gt;Part 10: Decomposing Claude Code&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the end of this article, you'll know what Observability actually is, why non-deterministic multi-step systems can't be operated without it, and the three properties — full-fidelity logs, session-level traces, and fixed evals — that separate a real observability setup from an aspirational one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's get started.&lt;/strong&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;h3&gt;
  
  
  📚 Want to go deeper than the articles?
&lt;/h3&gt;

&lt;p&gt;While you follow along with this series, I've put together two hands-on resources that go further than any single article can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.udemy.com/course/agentic-harness-engineering/?couponCode=7FA3B8BE5D143E73653B" rel="noopener noreferrer"&gt;Build a Harness from Scratch — Udemy Course&lt;/a&gt;&lt;/strong&gt; — A self-paced course where I walk you through building a production-grade agentic harness from the ground up, in code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://maven.com/fikayo-adepoju/harness-engineering-for-ai-agents" rel="noopener noreferrer"&gt;Harness Engineering for AI Agents — Live Maven Workshop&lt;/a&gt;&lt;/strong&gt; — A live, cohort-based workshop for builders who want direct feedback, Q&amp;amp;A, and to work through the material with peers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are optional — the series stands on its own. But if you want the full studio-quality version, that's where it lives.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What Observability Is
&lt;/h2&gt;

&lt;p&gt;Observability is the instrumentation that exposes what the agent is doing. Concretely, it includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Logs of each model call&lt;/strong&gt; — what went in, what came out, how long it took, how many tokens it cost&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traces of each tool execution&lt;/strong&gt; — which tool ran, with what arguments, with what result, in what order&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency and token metrics&lt;/strong&gt; — the operational health of the agent, tracked over time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evals&lt;/strong&gt; — a fixed set of tasks you can run the agent against to score its behavior and catch regressions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together, this instrumentation lets you answer basic operational questions about your agent: &lt;em&gt;What happened on this run? Why did it fail? Is it getting better or worse over time?&lt;/em&gt; Without instrumentation, none of those questions have an answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Observability Exists
&lt;/h2&gt;

&lt;p&gt;Agents are hard to operate. Three properties make them so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They're &lt;strong&gt;non-deterministic&lt;/strong&gt; — the same input can produce different outputs on different runs&lt;/li&gt;
&lt;li&gt;They're &lt;strong&gt;multi-step&lt;/strong&gt; — a single task can involve dozens of model calls and tool invocations&lt;/li&gt;
&lt;li&gt;They &lt;strong&gt;run for minutes or hours&lt;/strong&gt; — long enough that you often can't watch every step live&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now stack those three properties on top of each other. When something goes wrong — and something &lt;em&gt;always&lt;/em&gt; goes wrong — you need to be able to answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What did the agent actually do, in what order, with what inputs, and why?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can't answer any of that without instrumentation. If your agent burned $12 in tokens producing a plausible-looking but wrong result, and you have no logs, then you have no way to know whether the failure was a bad tool call, a bad retrieval, a bad prompt, or the model just getting it wrong. Every failure becomes a mystery you can't investigate.&lt;/p&gt;

&lt;p&gt;There's a second reason observability matters, and it's forward-looking rather than reactive: &lt;strong&gt;you can't improve a harness you can't measure.&lt;/strong&gt; If you change the system prompt, or reshape the tools, or swap in a new model, and you have no way to compare "before" and "after" on a real set of tasks — then you're not iterating on the harness. You're rearranging deck chairs and hoping.&lt;/p&gt;

&lt;p&gt;Observability is what turns agentic work from a black-box guessing game into an engineering discipline.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a Good Observability Design Looks Like
&lt;/h2&gt;

&lt;p&gt;Three properties separate a real observability setup from an aspirational one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Log Every Call — Model and Tool
&lt;/h3&gt;

&lt;p&gt;Both kinds of calls need to be logged in full, but the data you capture is slightly different for each.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;every model call&lt;/strong&gt;, log the full context sent to the model, the full response returned, the latency of the call, and the token counts (in and out, and by whatever model tier the call hit). Model calls are the most expensive thing the agent does and the source of most surprising behavior — you'll want everything.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;every tool call&lt;/strong&gt;, log the tool name, the arguments passed in, the result returned, and the duration of the execution. Tool calls are where the model's decisions meet the environment, so their logs are where you'll find the story of what actually happened in the world during a run.&lt;/p&gt;

&lt;p&gt;The word "log" here is doing a lot of work. It doesn't just mean &lt;em&gt;"print to stdout."&lt;/em&gt; It means: &lt;strong&gt;persisted, structured, queryable.&lt;/strong&gt; If you can't go back a week later, filter by task ID, and pull up the exact prompt-response pair that caused a failure — you don't have logs. You have console output.&lt;/p&gt;

&lt;h3&gt;
  
  
  Traces That Tie a Session Together
&lt;/h3&gt;

&lt;p&gt;Logs alone tell you what happened at each step. Traces tell you the &lt;em&gt;shape of the run.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A trace stitches together every event in a single agent session — every model call, every tool invocation, every retry, every error — in a single timeline. With a good trace, you can replay an agent run end-to-end and see exactly what the agent tried, in what order, and how each step led to the next.&lt;/p&gt;

&lt;p&gt;This is the difference between "I have 200 log lines" and "I have a story of one agent run." Debugging a multi-step failure without traces is like trying to diagnose a car accident from only the odometer readings of every car involved. You have data. You don't have narrative.&lt;/p&gt;

&lt;h3&gt;
  
  
  Evals That Let You Measure Regressions
&lt;/h3&gt;

&lt;p&gt;The first two properties are about understanding runs that already happened. Evals are the proactive side — a fixed set of tasks you run the agent against to measure its behavior over time.&lt;/p&gt;

&lt;p&gt;Evals don't need to be complicated. Ten to fifty representative tasks with known-good answers is often plenty. What matters is that they're &lt;strong&gt;fixed&lt;/strong&gt; — the same tasks, run the same way, so that the numbers are comparable across changes.&lt;/p&gt;

&lt;p&gt;Then, whenever you change something in the harness — a new system prompt, a reshaped tool, a different model, a memory-layer tweak — you re-run the eval set. If the score drops, you introduced a regression. If the score climbs, the change was probably good.&lt;/p&gt;

&lt;p&gt;Without evals, you cannot tell whether the harness is getting better or worse. You can only tell whether the &lt;em&gt;last thing you tested by hand&lt;/em&gt; worked or not. And "worked by hand" is not a reliable signal for a non-deterministic system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: Claude Code
&lt;/h2&gt;

&lt;p&gt;Watch Claude Code work, and you'll see observability baked into the surface itself.&lt;/p&gt;

&lt;p&gt;Every tool call Claude Code makes is visible in the UI, live, as it happens. You can see exactly what file it read, what it edited, what shell command it ran, in what order. When it makes a decision that surprises you, you can scroll back and see the sequence of events that led there.&lt;/p&gt;

&lt;p&gt;That's not just a UX choice. It's an observability decision that makes the agent &lt;strong&gt;debuggable&lt;/strong&gt;. The visible tool log is essentially a trace, presented to the user in real time.&lt;/p&gt;

&lt;p&gt;Compare that to a black-box agent that just hands you a result at the end. Something magical happened in the middle, and either it worked or it didn't, and you have no idea what actually went on. When it fails, you can't investigate. When it succeeds, you can't verify.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can't trust what you can't see.&lt;/strong&gt; That principle applies to human coworkers, and it applies double to AI agents. Observability is what makes trust possible — not in the sense of hoping the agent is right, but in the sense of being able to &lt;em&gt;check.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Leaves Us
&lt;/h2&gt;

&lt;p&gt;We now have all six components. &lt;strong&gt;The Loop&lt;/strong&gt; drives the cycle. &lt;strong&gt;The Tools&lt;/strong&gt; give the model reach. &lt;strong&gt;The Context&lt;/strong&gt; decides what the model sees on each call. &lt;strong&gt;The Environment&lt;/strong&gt; provides where side effects land. &lt;strong&gt;The Memory Layer&lt;/strong&gt; lets the agent carry state forward. And &lt;strong&gt;Observability&lt;/strong&gt; makes the whole thing debuggable, measurable, and improvable.&lt;/p&gt;

&lt;p&gt;Six components. Three verbs — &lt;strong&gt;action, persistence, measurable behavior&lt;/strong&gt; — from the formal definition all the way back in Part 2. Every piece we've walked through serves at least one of those verbs, and together they add up to what an agentic harness actually &lt;em&gt;is.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But naming the pieces is only half the job. So how do these six components fit together in practice? What does the architecture of a real harness look like when you draw it as a whole? That's what Part 9 is about: &lt;strong&gt;The Harness Architecture.&lt;/strong&gt; We zoom out from individual components to see how they compose, where the seams are, and how a well-designed harness holds together as a system.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Remember that this article is part of a longer 10-part series that walks you through every component of an agentic harness.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's the roadmap:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-1-the-raw-model-problem-54hg"&gt;Part 1: The Raw Model Problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-2-defining-the-harness-the-six-components-2gpk"&gt;Part 2: Defining the Harness — The Six Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-3-the-control-loop-3khk"&gt;Part 3: The Control Loop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-4-the-tool-layer-2p3f"&gt;Part 4: The Tool Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-5-context-engineering-94d"&gt;Part 5: Context Engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-6-the-filesystem-environment-17m0"&gt;Part 6: The Filesystem &amp;amp; Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-7-the-memory-layer-3oon"&gt;Part 7: The Memory Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Observability&lt;/strong&gt; ← You just finished this one.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-9-the-harness-architecture-i5e"&gt;Part 9: The Harness Architecture&lt;/a&gt; ← &lt;em&gt;Move to this one.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-10-decomposing-claude-code-3h27"&gt;Part 10: Decomposing Claude Code&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;See you in the next one.&lt;/p&gt;

&lt;p&gt;Happy coding :)&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>python</category>
      <category>llm</category>
    </item>
    <item>
      <title>Harness Engineering - Part 7: The Memory Layer</title>
      <dc:creator>Fikayo Adepoju</dc:creator>
      <pubDate>Sat, 15 Aug 2026 18:32:49 +0000</pubDate>
      <link>https://dev.to/coderonfleek/harness-engineering-part-7-the-memory-layer-3oon</link>
      <guid>https://dev.to/coderonfleek/harness-engineering-part-7-the-memory-layer-3oon</guid>
      <description>&lt;p&gt;&lt;em&gt;Welcome back to the Harness Engineering series — a 10-part journey from raw language model to production-ready agentic system. Made by builders. For builders.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In Part 6, we closed on a limitation the previous four components can't solve on their own: &lt;strong&gt;the agent forgets.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once a session ends — or the context window fills up mid-task — everything the agent learned, discovered, or decided vanishes. Next time the user comes back, the agent greets them like a stranger. Next time the token budget runs out, earlier turns get truncated away, and the agent's earlier reasoning is just gone.&lt;/p&gt;

&lt;p&gt;That's the gap this article closes. The &lt;strong&gt;Memory Layer&lt;/strong&gt; is how the harness gives the agent persistence — inside a task, and across sessions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's ahead:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-1-the-raw-model-problem-54hg"&gt;Part 1: The Raw Model Problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-2-defining-the-harness-the-six-components-2gpk"&gt;Part 2: Defining the Harness — The Six Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-3-the-control-loop-3khk"&gt;Part 3: The Control Loop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-4-the-tool-layer-2p3f"&gt;Part 4: The Tool Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-5-context-engineering-94d"&gt;Part 5: Context Engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-6-the-filesystem-environment-17m0"&gt;Part 6: The Filesystem &amp;amp; Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;The Memory Layer&lt;/strong&gt; ← You are here&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-8-observability-3gc1"&gt;Part 8: Observability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-9-the-harness-architecture-i5e"&gt;Part 9: The Harness Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-10-decomposing-claude-code-3h27"&gt;Part 10: Decomposing Claude Code&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the end of this article, you'll know what a Memory Layer actually is, why short-term and long-term memory are two different systems (not one with a dial), and the three design decisions — flavor, write triggers, and bounded retrieval — that separate a real memory system from a naive one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's get started.&lt;/strong&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;h3&gt;
  
  
  📚 Want to go deeper than the articles?
&lt;/h3&gt;

&lt;p&gt;While you follow along with this series, I've put together two hands-on resources that go further than any single article can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.udemy.com/course/agentic-harness-engineering/?couponCode=7FA3B8BE5D143E73653B" rel="noopener noreferrer"&gt;Build a Harness from Scratch — Udemy Course&lt;/a&gt;&lt;/strong&gt; — A self-paced course where I walk you through building a production-grade agentic harness from the ground up, in code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://maven.com/fikayo-adepoju/harness-engineering-for-ai-agents" rel="noopener noreferrer"&gt;Harness Engineering for AI Agents — Live Maven Workshop&lt;/a&gt;&lt;/strong&gt; — A live, cohort-based workshop for builders who want direct feedback, Q&amp;amp;A, and to work through the material with peers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are optional — the series stands on its own. But if you want the full studio-quality version, that's where it lives.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What The Memory Layer Is
&lt;/h2&gt;

&lt;p&gt;The Memory Layer is state that persists beyond a single model call.&lt;/p&gt;

&lt;p&gt;That's the one-line definition. But memory in an agent isn't one thing — it's &lt;em&gt;two&lt;/em&gt; things, and the difference between them is critical enough to name upfront.&lt;/p&gt;

&lt;h3&gt;
  
  
  Short-Term Memory
&lt;/h3&gt;

&lt;p&gt;Short-term memory is &lt;strong&gt;state within a task.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's the conversation history so far, intermediate scratchpads the agent has scribbled on, tool results from calls it's already made, files it's read or written during this session. It's everything the agent has generated or observed since the current task began, and it's what lets the agent stay coherent from one Loop iteration to the next.&lt;/p&gt;

&lt;p&gt;If you asked the agent &lt;em&gt;"what did we just try?"&lt;/em&gt; — the answer lives in short-term memory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Long-Term Memory
&lt;/h3&gt;

&lt;p&gt;Long-term memory is &lt;strong&gt;state across tasks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's the stuff the agent should remember beyond the end of a session — things about the user, the codebase, its own past behavior, patterns it learned last week that are still relevant this week. It's what lets the agent stop feeling like a stranger every time you come back to it.&lt;/p&gt;

&lt;p&gt;If you asked the agent &lt;em&gt;"what did we decide last time?"&lt;/em&gt; — the answer, if there is one, lives in long-term memory.&lt;/p&gt;

&lt;p&gt;These two flavors have very different lifecycles, very different budgets, and — importantly — very different designs. A single "memory system" that tries to do both usually does neither well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why The Memory Layer Exists
&lt;/h2&gt;

&lt;p&gt;Because the model itself remembers nothing.&lt;/p&gt;

&lt;p&gt;We've noted this in every previous article, but it's worth restating in this specific frame: without an explicit memory layer in the harness, every interaction starts cold. The model has no idea what happened in this conversation five turns ago (unless the harness resent those turns). It has no idea what happened in the last conversation you had with it. It doesn't remember the user's name, the codebase's conventions, or the mistake it made yesterday that you patiently corrected.&lt;/p&gt;

&lt;p&gt;Anything that feels like &lt;em&gt;"the agent is learning over time"&lt;/em&gt; — anything that feels like &lt;em&gt;"the agent recalls our previous work"&lt;/em&gt; — is harness work, not model work. There is no "the model remembers." There is only "the harness put the right stuff back in the context."&lt;/p&gt;

&lt;p&gt;That's why designing this layer well matters. The Memory Layer is what turns a stateless-per-call system into something that behaves, from the outside, like a system with continuity.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a Good Memory Design Looks Like
&lt;/h2&gt;

&lt;p&gt;Three design decisions separate a real memory system from a naive one.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Two Flavors Are Designed Differently
&lt;/h3&gt;

&lt;p&gt;Short-term and long-term memory should not be built as one system with a dial. They have different natures and different constraints.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Short-term is usually full-fidelity.&lt;/strong&gt; Within a task, you generally want the actual messages, the actual tool results, the actual file contents. Fidelity matters because the agent is reasoning over recent events step by step — losing detail here means losing coherence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Long-term is usually compressed.&lt;/strong&gt; Summaries, extracted facts, embeddings. This isn't a style choice; it's a &lt;em&gt;budget&lt;/em&gt; one. Look at what already competes for the context window on any given turn: the system prompt, the active conversation, current tool definitions, tool results just returned, files being worked on right now. All of that has priority. Whatever slice is left for "things pulled from the long-term store" is small — and it's small for a reason: those slots are competing with things the model needs &lt;em&gt;right now&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So long-term memory is designed around fitting &lt;em&gt;useful&lt;/em&gt; information into a &lt;em&gt;small&lt;/em&gt; slice. That means aggressive compression up front, precise retrieval at query time, and a willingness to leave things out. A long-term memory that tries to be full-fidelity ends up either useless (nothing gets retrieved because there's no room) or destructive (it pushes out the things the model needed for the current turn).&lt;/p&gt;

&lt;h3&gt;
  
  
  Write Triggers Are an Explicit Harness Decision
&lt;/h3&gt;

&lt;p&gt;Long-term memory needs a rule for &lt;strong&gt;when&lt;/strong&gt; something gets saved. This rule lives in the harness, not in the model's reasoning.&lt;/p&gt;

&lt;p&gt;There are several places you can put the trigger:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;At the end of every session&lt;/strong&gt; — you sweep the conversation for anything worth remembering and write it to the long-term store&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When an explicit tool is called&lt;/strong&gt; — you expose a &lt;code&gt;remember&lt;/code&gt; tool the model can invoke deliberately&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When a specific event happens&lt;/strong&gt; — a user correction, a successful task completion, an error the agent learned from&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whichever rule you pick, it should be a &lt;strong&gt;clear mechanism in the harness code&lt;/strong&gt;, not a vibe the model is expected to observe as part of its normal output. If you leave "decide what to remember" up to the model as an implicit part of every response, you get a memory system that saves different things on different runs and is impossible to debug.&lt;/p&gt;

&lt;p&gt;The clean division: &lt;strong&gt;the model contributes the content, the harness controls the gate.&lt;/strong&gt; The model can propose &lt;em&gt;"here's a fact worth saving"&lt;/em&gt; — but the harness decides whether that proposal actually results in a write.&lt;/p&gt;

&lt;h3&gt;
  
  
  Retrieval from Memory Is Bounded
&lt;/h3&gt;

&lt;p&gt;The mirror image of the write triggers is the retrieval logic. When you're pulling from long-term memory into the current context, you don't dump the whole store — you pull what's relevant to the task at hand.&lt;/p&gt;

&lt;p&gt;This is essentially the retrieval problem from Part 5 all over again, applied to memory. Rank aggressively. Filter conservatively. Send less than the context window can hold. The same design principle applies: if your long-term memory is filling half the context, it probably isn't memory — it's a hoarder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: Cursor
&lt;/h2&gt;

&lt;p&gt;Cursor is a nice example because it treats short-term and long-term memory as two different systems — and you can feel the difference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Short-term memory&lt;/strong&gt; in Cursor is the chat history within a single conversation. Full fidelity, live, growing turn by turn. You can scroll back through it, reference earlier things, hand messages back into the context. That's the short-term flavor at work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Long-term memory&lt;/strong&gt; shows up somewhere else entirely. It's the project rules you configure (things like &lt;em&gt;"this codebase uses snake_case"&lt;/em&gt; or &lt;em&gt;"always add type hints to new Python functions"&lt;/em&gt;), and the &lt;code&gt;@-memory&lt;/code&gt; feature that lets you tell Cursor to remember specific things across sessions. This layer isn't in the chat history at all — it's stored separately, retrieved when relevant, and injected into future contexts.&lt;/p&gt;

&lt;p&gt;Two very different systems. Different UIs. Different lifecycles. Different retrieval mechanisms. Both correctly called "memory." That separation isn't cosmetic — it reflects the fact that the two flavors have genuinely different jobs, and treating them as one thing would leave both jobs poorly done.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Leaves Us
&lt;/h2&gt;

&lt;p&gt;We now have five of the six components. &lt;strong&gt;The Loop&lt;/strong&gt; drives the cycle. &lt;strong&gt;The Tools&lt;/strong&gt; give the model reach. &lt;strong&gt;The Context&lt;/strong&gt; decides what the model sees on each call. &lt;strong&gt;The Environment&lt;/strong&gt; provides where side effects land. And &lt;strong&gt;the Memory Layer&lt;/strong&gt; lets the agent carry state forward.&lt;/p&gt;

&lt;p&gt;Together, those five turn a raw language model into something that can take multi-step action, work inside bounds, and remember what it's done — the shape of what most people mean when they say &lt;em&gt;"agent."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But there's one more component, and it's the one that turns &lt;em&gt;"I built an agent"&lt;/em&gt; into &lt;em&gt;"I built an agent I can actually operate."&lt;/em&gt; Without it, when the agent misbehaves — and it &lt;em&gt;will&lt;/em&gt; misbehave — you have no way to figure out why. That's Part 8: &lt;strong&gt;Observability.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Remember that this article is part of a longer 10-part series that walks you through every component of an agentic harness.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's the roadmap:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-1-the-raw-model-problem-54hg"&gt;Part 1: The Raw Model Problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-2-defining-the-harness-the-six-components-2gpk"&gt;Part 2: Defining the Harness — The Six Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-3-the-control-loop-3khk"&gt;Part 3: The Control Loop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-4-the-tool-layer-2p3f"&gt;Part 4: The Tool Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-5-context-engineering-94d"&gt;Part 5: Context Engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-6-the-filesystem-environment-17m0"&gt;Part 6: The Filesystem &amp;amp; Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;The Memory Layer&lt;/strong&gt; ← You just finished this one.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-8-observability-3gc1"&gt;Part 8: Observability&lt;/a&gt; ← &lt;em&gt;Move to this one.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-9-the-harness-architecture-i5e"&gt;Part 9: The Harness Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-10-decomposing-claude-code-3h27"&gt;Part 10: Decomposing Claude Code&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;See you in the next one.&lt;/p&gt;

&lt;p&gt;Happy coding :)&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>python</category>
      <category>llm</category>
    </item>
    <item>
      <title>Harness Engineering - Part 6: The Filesystem &amp; Environment</title>
      <dc:creator>Fikayo Adepoju</dc:creator>
      <pubDate>Sat, 15 Aug 2026 18:32:09 +0000</pubDate>
      <link>https://dev.to/coderonfleek/harness-engineering-part-6-the-filesystem-environment-17m0</link>
      <guid>https://dev.to/coderonfleek/harness-engineering-part-6-the-filesystem-environment-17m0</guid>
      <description>&lt;p&gt;&lt;em&gt;Welcome back to the Harness Engineering series — a 10-part journey from raw language model to production-ready agentic system. Made by builders. For builders.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In Part 5, we looked at the Context — the payload the model sees on every call. Now we look at what happens &lt;em&gt;after&lt;/em&gt; the model, having seen that Context, decides to do something.&lt;/p&gt;

&lt;p&gt;The model calls a tool. The tool has to execute somewhere. That somewhere is &lt;strong&gt;the Environment&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It's easy to under-appreciate. The Environment feels like plumbing — the filesystem, the shell, the network, the machine underneath. But it's where every side effect the model requests actually lands, and how you design it is what separates &lt;em&gt;"an AI agent doing things on your behalf"&lt;/em&gt; from &lt;em&gt;scary&lt;/em&gt; to &lt;em&gt;routine&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's ahead:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-1-the-raw-model-problem-54hg"&gt;Part 1: The Raw Model Problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-2-defining-the-harness-the-six-components-2gpk"&gt;Part 2: Defining the Harness — The Six Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-3-the-control-loop-3khk"&gt;Part 3: The Control Loop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-4-the-tool-layer-2p3f"&gt;Part 4: The Tool Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-5-context-engineering-94d"&gt;Part 5: Context Engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;The Filesystem &amp;amp; Environment&lt;/strong&gt; ← You are here&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-7-the-memory-layer-3oon"&gt;Part 7: The Memory Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-8-observability-3gc1"&gt;Part 8: Observability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-9-the-harness-architecture-i5e"&gt;Part 9: The Harness Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-10-decomposing-claude-code-3h27"&gt;Part 10: Decomposing Claude Code&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the end of this article, you'll know what the Environment actually is, why every tool with side effects depends on it, and the three properties (bounded, reproducible, inspectable) that separate a production-ready environment from a demo one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's get started.&lt;/strong&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;h3&gt;
  
  
  📚 Want to go deeper than the articles?
&lt;/h3&gt;

&lt;p&gt;While you follow along with this series, I've put together two hands-on resources that go further than any single article can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.udemy.com/course/agentic-harness-engineering/?couponCode=7FA3B8BE5D143E73653B" rel="noopener noreferrer"&gt;Build a Harness from Scratch — Udemy Course&lt;/a&gt;&lt;/strong&gt; — A self-paced course where I walk you through building a production-grade agentic harness from the ground up, in code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://maven.com/fikayo-adepoju/harness-engineering-for-ai-agents" rel="noopener noreferrer"&gt;Harness Engineering for AI Agents — Live Maven Workshop&lt;/a&gt;&lt;/strong&gt; — A live, cohort-based workshop for builders who want direct feedback, Q&amp;amp;A, and to work through the material with peers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are optional — the series stands on its own. But if you want the full studio-quality version, that's where it lives.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What The Environment Is
&lt;/h2&gt;

&lt;p&gt;The Environment is the runtime that tools operate inside. Concretely, it includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;filesystem&lt;/strong&gt; they read from and write to&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;shell&lt;/strong&gt; they exec commands in&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;network&lt;/strong&gt; they can reach&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;compute resources&lt;/strong&gt; they're permitted to consume — CPU, memory, disk, wall-clock time, API quotas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a tool has any kind of side effect, the Environment is where that side effect materializes. When your &lt;code&gt;read_file&lt;/code&gt; tool opens a file, it's opening a file &lt;em&gt;in an environment&lt;/em&gt;. When your &lt;code&gt;bash&lt;/code&gt; tool runs &lt;code&gt;ls&lt;/code&gt;, it's running that in &lt;em&gt;some&lt;/em&gt; shell, on &lt;em&gt;some&lt;/em&gt; filesystem. When your &lt;code&gt;fetch_url&lt;/code&gt; tool fires an HTTP request, it's doing so from &lt;em&gt;some&lt;/em&gt; network stack, subject to &lt;em&gt;some&lt;/em&gt; rules about what it can reach.&lt;/p&gt;

&lt;p&gt;None of this is exotic. If you've ever set up a CI pipeline, you've made environment decisions — what OS the runner uses, what dependencies are pre-installed, what secrets are exposed, what artifacts persist between steps. The Environment for an agent is the same kind of concern, applied to the same kind of question: &lt;strong&gt;inside what world does this thing run?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why The Environment Exists
&lt;/h2&gt;

&lt;p&gt;Because tools can't exist in a vacuum.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;read_file&lt;/code&gt; tool is meaningless without a filesystem to read from. A &lt;code&gt;bash&lt;/code&gt; tool is meaningless without a shell to run in. A &lt;code&gt;fetch_url&lt;/code&gt; tool is meaningless without a network to reach out through. Every tool with side effects needs a target for those side effects, and the Environment is that target.&lt;/p&gt;

&lt;p&gt;Put another way: the Tools (Part 4) are the model's &lt;em&gt;reach&lt;/em&gt;, but the Environment is &lt;em&gt;what they reach into&lt;/em&gt;. You can't separate the two. A well-designed tool set embedded in a poorly-designed environment produces an agent that either can't act (because the environment blocks it) or acts too freely (because the environment doesn't).&lt;/p&gt;

&lt;h2&gt;
  
  
  What a Good Environment Design Looks Like
&lt;/h2&gt;

&lt;p&gt;Three properties separate a production-ready Environment from a demo one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bounded
&lt;/h3&gt;

&lt;p&gt;The Environment defines the scope within which the agent can operate. Good environments are bounded — the agent can do the things it needs to do, and nothing else.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The agent can't accidentally &lt;code&gt;rm -rf&lt;/code&gt; the host machine&lt;/li&gt;
&lt;li&gt;The agent can't reach across into networks it shouldn't touch — production databases, internal services, and so on&lt;/li&gt;
&lt;li&gt;The agent can't quietly exfiltrate data through unexpected channels&lt;/li&gt;
&lt;li&gt;The agent can't burn through cloud credits by spinning up resources unchecked&lt;/li&gt;
&lt;li&gt;The agent can't stay running forever if it gets stuck&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Boundedness isn't about not trusting the model. It's about &lt;strong&gt;containing blast radius&lt;/strong&gt;. Even a perfectly-behaved model, working on a legitimate task, will occasionally make mistakes — hallucinate a filename, misread an argument, run a command with unintended flags. In an unbounded environment, one of those mistakes can wreck real things. In a bounded environment, the same mistake gets caught by the walls.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reproducible
&lt;/h3&gt;

&lt;p&gt;Every run starts from a clean, identical state. The Environment is recreated cleanly per task, not reused across tasks.&lt;/p&gt;

&lt;p&gt;This one takes a moment to appreciate. In a reproducible environment, the agent doesn't inherit anything from previous work — no leftover files, no mutated database rows, no dirty processes, no stale caches. Every task begins from the same known baseline.&lt;/p&gt;

&lt;p&gt;Why does this matter? Two reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;When something goes wrong, you can re-run it and see the same failure.&lt;/strong&gt; That means the failure is the &lt;em&gt;agent's&lt;/em&gt;, not the environment's. Debugging becomes possible. Without reproducibility, "it worked yesterday" becomes an unanswerable question, and you spend hours chasing environmental drift instead of actual bugs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runs don't contaminate each other.&lt;/strong&gt; An agent that made a mess in Task A doesn't ship that mess into Task B.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reproducibility is what makes agentic behavior &lt;em&gt;testable&lt;/em&gt;. Without it, every run is bespoke, and the whole system stops being an engineering artifact and starts being an unpredictable pet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inspectable
&lt;/h3&gt;

&lt;p&gt;Engineers need to be able to see what the agent did to the Environment after a run.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What files changed?&lt;/li&gt;
&lt;li&gt;What commands ran?&lt;/li&gt;
&lt;li&gt;What processes were spawned?&lt;/li&gt;
&lt;li&gt;What network calls were made?&lt;/li&gt;
&lt;li&gt;What resources were consumed?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inspectability is the Environment's contribution to observability (which we look at in Part 8). It's not enough to know &lt;em&gt;what the model said&lt;/em&gt;; you need to see &lt;em&gt;what actually happened in the world as a result&lt;/em&gt;. Those two things do not always agree.&lt;/p&gt;

&lt;p&gt;The model can claim it "successfully updated the config" while the config file, on inspection, hasn't been touched. Or it can claim to have "cleaned up temporary files" while &lt;code&gt;/tmp&lt;/code&gt; is stuffed with leftovers. An inspectable environment gives you ground truth to check the model's story against.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: Codex
&lt;/h2&gt;

&lt;p&gt;Codex is a clean example of what a well-designed Environment enables.&lt;/p&gt;

&lt;p&gt;When you hand Codex a task, it runs inside a sandboxed container that gets a fresh clone of your repository. Inside that container, the agent can do essentially anything — read files, edit them, run tests, spin up services, execute arbitrary code, hit the network. And critically, it does all of that without ever touching your real machine.&lt;/p&gt;

&lt;p&gt;When the task is done, the container is destroyed. The agent's changes come back to you as a pull request you can review before anything real changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That environment is why engineers trust Codex to run code they didn't write.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Notice the trade the sandbox enables. Inside the sandbox, the agent has a lot of freedom — it can delete files, run wild &lt;code&gt;bash&lt;/code&gt;, hit external services. The freedom is what makes it useful. But the &lt;strong&gt;blast radius&lt;/strong&gt; is bounded to a disposable container. Whatever damage the agent could theoretically do stays inside walls that get torn down at the end of the task.&lt;/p&gt;

&lt;p&gt;Without the sandbox, the same agent doing the same work would be touching your real filesystem, your real credentials, your real repositories. The tools would be identical. The model would be identical. But the &lt;em&gt;risk profile&lt;/em&gt; would be completely different.&lt;/p&gt;

&lt;p&gt;The sandbox is what turns &lt;em&gt;"let an AI run arbitrary code"&lt;/em&gt; from a reckless idea into a routine engineering practice. That's the Environment doing the load-bearing work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Leaves Us
&lt;/h2&gt;

&lt;p&gt;The Environment is the runtime that everything else takes place inside. The Loop drives the cycle. The Tools define what the model can request. The Context defines what the model sees when it decides. And the Environment defines &lt;em&gt;where the doing happens&lt;/em&gt; and &lt;em&gt;what the doing is allowed to touch.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Together, those four components already give you an agent that can act on the world within bounds. But there's still something missing — something you feel the absence of the moment a session ends or the context window fills up. The agent forgets. Everything it learned, discovered, or decided during a task disappears.&lt;/p&gt;

&lt;p&gt;That's what Part 7 is about: &lt;strong&gt;the Memory Layer.&lt;/strong&gt; How to give the harness persistence — within a task, and across sessions.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Remember that this article is part of a longer 10-part series that walks you through every component of an agentic harness.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's the roadmap:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-1-the-raw-model-problem-54hg"&gt;Part 1: The Raw Model Problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-2-defining-the-harness-the-six-components-2gpk"&gt;Part 2: Defining the Harness — The Six Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-3-the-control-loop-3khk"&gt;Part 3: The Control Loop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-4-the-tool-layer-2p3f"&gt;Part 4: The Tool Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-5-context-engineering-94d"&gt;Part 5: Context Engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;The Filesystem &amp;amp; Environment&lt;/strong&gt; ← You just finished this one.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-7-the-memory-layer-3oon"&gt;Part 7: The Memory Layer&lt;/a&gt; ← &lt;em&gt;Move to this one.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-8-observability-3gc1"&gt;Part 8: Observability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-9-the-harness-architecture-i5e"&gt;Part 9: The Harness Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-10-decomposing-claude-code-3h27"&gt;Part 10: Decomposing Claude Code&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;See you in the next one.&lt;/p&gt;

&lt;p&gt;Happy coding :)&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>python</category>
      <category>llm</category>
    </item>
    <item>
      <title>Harness Engineering - Part 5: Context Engineering</title>
      <dc:creator>Fikayo Adepoju</dc:creator>
      <pubDate>Sat, 15 Aug 2026 18:31:14 +0000</pubDate>
      <link>https://dev.to/coderonfleek/harness-engineering-part-5-context-engineering-94d</link>
      <guid>https://dev.to/coderonfleek/harness-engineering-part-5-context-engineering-94d</guid>
      <description>&lt;p&gt;&lt;em&gt;Welcome back to the Harness Engineering series — a 10-part journey from raw language model to production-ready agentic system. Made by builders. For builders.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In Part 4, we looked at the Tools — the set of functions the model can call. But there's still one big open question hanging over every turn of the Loop: &lt;strong&gt;what does the model actually see when the Loop calls it?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The answer is: whatever the harness put in the payload. That payload — the entire package of instructions, history, retrieved documents, tool definitions, and everything else — is called &lt;strong&gt;the Context&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Some readers know this territory under an older name: &lt;em&gt;prompt engineering&lt;/em&gt;. That name isn't wrong, but it's narrow. A prompt sounds like something you write once and ship. The reality of running an agent is that the payload changes every turn, and designing what goes in it is an ongoing discipline. Hence the newer, more accurate term: &lt;strong&gt;context engineering&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's ahead:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-1-the-raw-model-problem-54hg"&gt;Part 1: The Raw Model Problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-2-defining-the-harness-the-six-components-2gpk"&gt;Part 2: Defining the Harness — The Six Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-3-the-control-loop-3khk"&gt;Part 3: The Control Loop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-4-the-tool-layer-2p3f"&gt;Part 4: The Tool Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Context Engineering&lt;/strong&gt; ← You are here&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-6-the-filesystem-environment-17m0"&gt;Part 6: The Filesystem &amp;amp; Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-7-the-memory-layer-3oon"&gt;Part 7: The Memory Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-8-observability-3gc1"&gt;Part 8: Observability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-9-the-harness-architecture-i5e"&gt;Part 9: The Harness Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-10-decomposing-claude-code-3h27"&gt;Part 10: Decomposing Claude Code&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the end of this article, you'll know what the Context actually is, why every turn forces you to answer &lt;em&gt;"what should the model know right now?"&lt;/em&gt; from scratch, and the three moving pieces (system prompt, history, retrieval) that make up a well-designed context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's get started.&lt;/strong&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;h3&gt;
  
  
  📚 Want to go deeper than the articles?
&lt;/h3&gt;

&lt;p&gt;While you follow along with this series, I've put together two hands-on resources that go further than any single article can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.udemy.com/course/agentic-harness-engineering/?couponCode=7FA3B8BE5D143E73653B" rel="noopener noreferrer"&gt;Build a Harness from Scratch — Udemy Course&lt;/a&gt;&lt;/strong&gt; — A self-paced course where I walk you through building a production-grade agentic harness from the ground up, in code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://maven.com/fikayo-adepoju/harness-engineering-for-ai-agents" rel="noopener noreferrer"&gt;Harness Engineering for AI Agents — Live Maven Workshop&lt;/a&gt;&lt;/strong&gt; — A live, cohort-based workshop for builders who want direct feedback, Q&amp;amp;A, and to work through the material with peers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are optional — the series stands on its own. But if you want the full studio-quality version, that's where it lives.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What The Context Is
&lt;/h2&gt;

&lt;p&gt;The Context is everything fed into the model on a given API call. &lt;strong&gt;All of it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Concretely, on any single turn, the payload sent to the model typically includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;system prompt&lt;/strong&gt; — the model's persona and instructions&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;conversation history&lt;/strong&gt; — the messages exchanged so far&lt;/li&gt;
&lt;li&gt;Any &lt;strong&gt;retrieved documents&lt;/strong&gt; relevant to the current turn&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;tool definitions&lt;/strong&gt; — what tools the model can call, and how&lt;/li&gt;
&lt;li&gt;Prior &lt;strong&gt;tool results&lt;/strong&gt; — from calls the model made earlier&lt;/li&gt;
&lt;li&gt;Any &lt;strong&gt;attached files or images&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Anything else the harness thinks the model needs to know right now&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That entire package goes over the wire. The model reads all of it. Then it produces one response. Then, on the next iteration of the Loop, the harness assembles a &lt;em&gt;new&lt;/em&gt; package — probably with the previous response added, maybe with new tool results appended, maybe with different retrieved content — and sends that.&lt;/p&gt;

&lt;p&gt;Every turn is a new context. Every turn.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why The Context Exists
&lt;/h2&gt;

&lt;p&gt;Because the model is stateless. We noted this back in Part 1: every API call is independent on the model's side. Nothing persists between calls unless something outside the model puts it there.&lt;/p&gt;

&lt;p&gt;Which means the question &lt;strong&gt;"what should the model know right now?"&lt;/strong&gt; turns into a very different question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"What do we put in the context?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And that question has to be answered on every single turn.&lt;/p&gt;

&lt;p&gt;There is no shortcut. You can't tell the model "remember what I said five minutes ago." You can't say "reference the file we discussed earlier." Every relevant thing — every fact, every prior message, every result, every document — has to physically be in the payload for the current call, or the model doesn't know about it.&lt;/p&gt;

&lt;p&gt;This is why context engineering is arguably the deepest engineering discipline in the whole harness. Deciding &lt;em&gt;what to include, what to compress, what to leave out, and when&lt;/em&gt; — that's the work. And it's ongoing. The context is a &lt;strong&gt;moving target&lt;/strong&gt;, different every turn. There is no version to "ship." There's only the version being assembled right now, for this call.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a Good Context Design Looks Like
&lt;/h2&gt;

&lt;p&gt;There are three moving pieces in any context, and each is worth being deliberate about: the system prompt, the history, and any retrieved knowledge.&lt;/p&gt;

&lt;h3&gt;
  
  
  The System Prompt
&lt;/h3&gt;

&lt;p&gt;The system prompt is the top layer of the context — the part that gets prepended to every turn and stays roughly the same throughout the conversation. It tells the model &lt;em&gt;who it is, what tools it has, and what good behavior looks like.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Think of the system prompt as the &lt;strong&gt;control plane&lt;/strong&gt; of the agent. It's set by the agent's builder — the person designing the harness — and it defines the model's role, constraints, and preferred style.&lt;/p&gt;

&lt;p&gt;There's a related but distinct pattern worth noting: files like &lt;code&gt;AGENTS.md&lt;/code&gt; (or &lt;code&gt;.cursorrules&lt;/code&gt;, or &lt;code&gt;CLAUDE.md&lt;/code&gt;) that let the &lt;em&gt;user&lt;/em&gt; — not the agent builder — inject their own instructions into the context. These are user-controlled additions layered on top of the built-in system prompt. Same mechanism, different owner. When you're designing a harness, you have to decide whether to support this and how the two layers interact.&lt;/p&gt;

&lt;h3&gt;
  
  
  A History Strategy
&lt;/h3&gt;

&lt;p&gt;The conversation history — every message the user and the model have exchanged — is the second big chunk of the context. And here's where things get interesting: &lt;strong&gt;you can't just send all of it forever.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Context windows are finite. Every token you spend re-sending old messages is a token you can't spend on the current turn. So a history strategy is a decision about how much of the past to include, and in what shape.&lt;/p&gt;

&lt;p&gt;The common strategies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Full replay&lt;/strong&gt; — send every message from the start of the conversation. Simple. Works fine for short sessions. Falls over on long ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Truncation&lt;/strong&gt; — keep the most recent N messages and drop the rest. Cheap. Loses long-range context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compaction / summarization&lt;/strong&gt; — periodically replace older messages with a compressed summary. Preserves the gist without the token cost. Requires care to not summarize away critical details.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured memory&lt;/strong&gt; — pull historical content out of the message stream entirely and store it in a separate memory layer that the Loop can query on demand. We look at this in Part 7.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The right strategy depends on the task's &lt;strong&gt;time horizon&lt;/strong&gt; — what the model needs to remember for the sub-step it's currently on, versus what can safely be forgotten. A quick lookup doesn't need much history. A long-running refactor needs a strategy that keeps the model coherent across hundreds of turns.&lt;/p&gt;

&lt;h3&gt;
  
  
  Retrieval
&lt;/h3&gt;

&lt;p&gt;The third piece is retrieval — pulling in relevant outside knowledge and injecting it into the context. Documentation, code snippets, database records, prior conversations, whatever the task requires.&lt;/p&gt;

&lt;p&gt;The design principle here is simple to state and hard to do: bring in &lt;strong&gt;just enough&lt;/strong&gt; to be useful, without burying the model.&lt;/p&gt;

&lt;p&gt;Too little retrieval, and the model is missing information it needs. Too much retrieval, and the important stuff is drowning in noise. The model has to &lt;em&gt;find&lt;/em&gt; the relevant part of what you injected, which uses attention budget it could have spent actually answering the question.&lt;/p&gt;

&lt;p&gt;Good retrieval systems rank aggressively and are willing to send &lt;em&gt;less&lt;/em&gt; than the context window can hold. If your retrieval is filling half the context on every call, it probably isn't retrieval — it's a hedge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: Cursor
&lt;/h2&gt;

&lt;p&gt;Cursor's context engineering is most of why it feels different from using raw ChatGPT — even when the underlying model is the same.&lt;/p&gt;

&lt;p&gt;Look at what Cursor is quietly assembling into the context on every keystroke that triggers a completion:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cursor rules&lt;/strong&gt; (the system prompt layer — user-defined, layered on top of the built-in system prompt)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codebase indexing&lt;/strong&gt; (retrieval — searching across your files for relevant context)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The file you have open&lt;/strong&gt; (focus — the model gets the current file, in full or in relevant windows)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The files you've @-mentioned&lt;/strong&gt; (explicit attachment — you telling Cursor "make sure the model sees this")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your recent edits&lt;/strong&gt; (short-term history — what you were just doing)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's five distinct context sources, all being packaged into a single API call, every time you trigger a completion. And the API call itself is going to a foundation model that anyone with an API key can call.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The model is the same model anyone can call. The context is the product.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's the punchline of this whole article. When you compare two agents built on the same foundation model, the differences you feel between them are almost always context-engineering differences. What each one puts in the context, how much of it, in what order, at what moments — that's the design surface where agents differentiate themselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Leaves Us
&lt;/h2&gt;

&lt;p&gt;The Context is what the model gets to see on any given call. The Loop drives the cycle. The Tools define what the model can request. The Context defines what state the model has when it decides what to request. Three components, tightly coupled, each depending on the others.&lt;/p&gt;

&lt;p&gt;But context engineering has one dependency the other components don't: it depends on &lt;strong&gt;something being available to inject&lt;/strong&gt;. The system prompt is easy — you wrote it. Recent history is easy — the harness holds it. But retrieval? Memory? Files that came from somewhere? Those all need a place to live. That "somewhere" is what the next few articles are about: the Environment (Part 6) that files and tool outputs live in, and the Memory Layer (Part 7) that lets the harness carry state forward across turns and sessions.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Remember that this article is part of a longer 10-part series that walks you through every component of an agentic harness.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's the roadmap:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-1-the-raw-model-problem-54hg"&gt;Part 1: The Raw Model Problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-2-defining-the-harness-the-six-components-2gpk"&gt;Part 2: Defining the Harness — The Six Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-3-the-control-loop-3khk"&gt;Part 3: The Control Loop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-4-the-tool-layer-2p3f"&gt;Part 4: The Tool Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Context Engineering&lt;/strong&gt; ← You just finished this one.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-6-the-filesystem-environment-17m0"&gt;Part 6: The Filesystem &amp;amp; Environment&lt;/a&gt; ← &lt;em&gt;Move to this one.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-7-the-memory-layer-3oon"&gt;Part 7: The Memory Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-8-observability-3gc1"&gt;Part 8: Observability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-9-the-harness-architecture-i5e"&gt;Part 9: The Harness Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-10-decomposing-claude-code-3h27"&gt;Part 10: Decomposing Claude Code&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;See you in the next one.&lt;/p&gt;

&lt;p&gt;Happy coding :)&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>python</category>
      <category>llm</category>
    </item>
    <item>
      <title>Harness Engineering - Part 4: The Tool Layer</title>
      <dc:creator>Fikayo Adepoju</dc:creator>
      <pubDate>Sat, 15 Aug 2026 18:29:15 +0000</pubDate>
      <link>https://dev.to/coderonfleek/harness-engineering-part-4-the-tool-layer-2p3f</link>
      <guid>https://dev.to/coderonfleek/harness-engineering-part-4-the-tool-layer-2p3f</guid>
      <description>&lt;p&gt;&lt;em&gt;Welcome back to the Harness Engineering series — a 10-part journey from raw language model to production-ready agentic system. Made by builders. For builders.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In Part 3, we looked at the Loop — the outermost machinery of a harness, the piece that drives everything else. But a Loop on its own is a hollow shell. It calls the model. The model responds. And then, if the model wants to affect anything outside the text it just produced, it needs to reach for a tool.&lt;/p&gt;

&lt;p&gt;That's what this article is about: &lt;strong&gt;the Tool Layer.&lt;/strong&gt; The set of functions the harness makes available to the model, and the design decisions that separate a tool surface a model can actually use from one that constantly frustrates it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's ahead:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-1-the-raw-model-problem-54hg"&gt;Part 1: The Raw Model Problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-2-defining-the-harness-the-six-components-2gpk"&gt;Part 2: Defining the Harness — The Six Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-3-the-control-loop-3khk"&gt;Part 3: The Control Loop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;The Tool Layer&lt;/strong&gt; ← You are here&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-5-context-engineering-94d"&gt;Part 5: Context Engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-6-the-filesystem-environment-17m0"&gt;Part 6: The Filesystem &amp;amp; Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-7-the-memory-layer-3oon"&gt;Part 7: The Memory Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-8-observability-3gc1"&gt;Part 8: Observability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-9-the-harness-architecture-i5e"&gt;Part 9: The Harness Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-10-decomposing-claude-code-3h27"&gt;Part 10: Decomposing Claude Code&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the end of this article, you'll know what tools actually are, why they exist, and — more usefully — how to tell a well-designed tool surface from a badly-designed one the moment you look at one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's get started.&lt;/strong&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;h3&gt;
  
  
  📚 Want to go deeper than the articles?
&lt;/h3&gt;

&lt;p&gt;While you follow along with this series, I've put together two hands-on resources that go further than any single article can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.udemy.com/course/agentic-harness-engineering/?couponCode=7FA3B8BE5D143E73653B" rel="noopener noreferrer"&gt;Build a Harness from Scratch — Udemy Course&lt;/a&gt;&lt;/strong&gt; — A self-paced course where I walk you through building a production-grade agentic harness from the ground up, in code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://maven.com/fikayo-adepoju/harness-engineering-for-ai-agents" rel="noopener noreferrer"&gt;Harness Engineering for AI Agents — Live Maven Workshop&lt;/a&gt;&lt;/strong&gt; — A live, cohort-based workshop for builders who want direct feedback, Q&amp;amp;A, and to work through the material with peers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are optional — the series stands on its own. But if you want the full studio-quality version, that's where it lives.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What The Tools Are
&lt;/h2&gt;

&lt;p&gt;The Tools are the set of functions the harness exposes to the model.&lt;/p&gt;

&lt;p&gt;Concretely: the harness tells the model &lt;em&gt;"here are the functions you can call, here are their names, here are the parameters they take, here's what they do."&lt;/em&gt; Then on any given turn, the model can decide to emit a structured request to call one of them. Something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tool"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"read_file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/etc/hosts"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The harness sees this request in the model's response, runs the actual function (in this case, opens &lt;code&gt;/etc/hosts&lt;/code&gt; and reads its contents), and feeds the result back into the model on the next Loop iteration.&lt;/p&gt;

&lt;p&gt;That's the whole mechanic. Two-way traffic: the model requests, the harness executes, the harness returns.&lt;/p&gt;

&lt;p&gt;If you're coming from traditional software, &lt;strong&gt;think of the Tool Layer as the API the harness offers to the model&lt;/strong&gt; — the same way an operating system offers system calls to a running program. Same shape, different consumer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why The Tools Exist
&lt;/h2&gt;

&lt;p&gt;Tools are the model's surface area into the world. Without them, the model produces text and that text goes nowhere. With them, the model can decide to &lt;em&gt;do a thing&lt;/em&gt; and have the thing actually happen.&lt;/p&gt;

&lt;p&gt;Look back at Part 1 — the raw model problem. Three of the five gaps we named there close through tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No execution&lt;/strong&gt; → tools that run code, touch files, hit APIs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No fresh knowledge&lt;/strong&gt; → tools that search, retrieve, or query external data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No environment&lt;/strong&gt; → tools are how the model reaches into whatever environment the harness sets up&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(The other two gaps — persistence and verification — are addressed by different components, which we look at in later parts.)&lt;/p&gt;

&lt;p&gt;Every capability you've ever seen an agent exercise came through a tool. When Claude Code writes a file, that's an &lt;code&gt;edit&lt;/code&gt; tool. When a research agent searches the web, that's a &lt;code&gt;search&lt;/code&gt; tool. When a customer-support agent looks up an order, that's a &lt;code&gt;get_order&lt;/code&gt; tool. The Loop drives the cycle; the Tools are what the model asks for inside each turn.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a Good Tool Design Looks Like
&lt;/h2&gt;

&lt;p&gt;If you look at ten agent frameworks, you'll see ten different opinions on how many tools an agent "needs" and how they should be shaped. The good ones share three properties.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Small Set That Composes Well
&lt;/h3&gt;

&lt;p&gt;There's a design failure mode where every use case gets its own bespoke tool. You end up with fifteen or fifty tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;read_python_file&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;read_javascript_file&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;read_config_file&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;list_files_in_directory&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;list_files_matching_pattern&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;run_python_script&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;run_shell_script&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;…and on it goes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That surface is almost always worse than two well-named tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;read_file(path)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bash(command)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can express &lt;em&gt;everything&lt;/em&gt; in the first list using the second — and a great many things the first list doesn't cover. The model doesn't have to memorize fifteen names and their subtle differences; it just has to think "I want to read this thing" or "I want to run this command."&lt;/p&gt;

&lt;p&gt;The rule of thumb: &lt;strong&gt;compose, don't enumerate.&lt;/strong&gt; A small set of sharp, general-purpose tools almost always outperforms a large set of specialized ones. Not always — sometimes a specific business action deserves its own named tool — but as a default posture, composition wins.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clear, Structured Outputs — Including Errors
&lt;/h3&gt;

&lt;p&gt;The model has to be able to tell success from failure from the tool result &lt;em&gt;alone&lt;/em&gt;. It doesn't get to inspect your logs. It doesn't get to look at your stack traces. Whatever came back in the tool result is all the information it has to work with.&lt;/p&gt;

&lt;p&gt;Which means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Success and failure need to look different, unambiguously.&lt;/li&gt;
&lt;li&gt;Errors should be structured, not just "Something went wrong."&lt;/li&gt;
&lt;li&gt;Whenever possible, errors should hint at how to recover.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A tool that returns &lt;code&gt;null&lt;/code&gt; on both "file not found" and "file is empty" is a tool the model can't reason about. A tool that returns &lt;code&gt;{"error": "file_not_found", "path": "/foo/bar"}&lt;/code&gt; for one case and &lt;code&gt;{"content": ""}&lt;/code&gt; for the other is a tool the model can actually use to correct course.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tools Sized So The Model Can Use Them Well
&lt;/h3&gt;

&lt;p&gt;There's a Goldilocks zone for tool granularity, and it's easy to miss on both sides.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Too small:&lt;/strong&gt; each tool does a trivial thing, so the model needs twenty tool calls to accomplish what could have been one. You spend money, you spend time, and — worse — you spend context. Every tool call bloats the conversation with request-and-result pairs the model then has to keep re-reading.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Too big:&lt;/strong&gt; a single tool does five things internally, so when it fails you can't tell &lt;em&gt;which&lt;/em&gt; of the five failed. The model gets back "operation failed" and has no way to isolate the problem. It'll usually respond by trying the same thing again, or by giving up entirely.&lt;/p&gt;

&lt;p&gt;The right size is: &lt;strong&gt;each call does enough meaningful work to be worth the round trip, but each failure is diagnosable.&lt;/strong&gt; If you look at a tool's design, imagine the model getting an error from it, and can imagine the model figuring out what to do next — the tool is probably right-sized. If you look at it and think "the model would just be confused," it's probably wrong-sized in one direction or the other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: Claude Code
&lt;/h2&gt;

&lt;p&gt;Claude Code's tool surface is famously small: &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;edit&lt;/code&gt;, &lt;code&gt;bash&lt;/code&gt;, &lt;code&gt;glob&lt;/code&gt;, &lt;code&gt;grep&lt;/code&gt;, plus a handful of others. That's it. No &lt;code&gt;refactor_python_function&lt;/code&gt; tool. No &lt;code&gt;run_pytest_and_summarize&lt;/code&gt; tool. No &lt;code&gt;open_pr_with_generated_summary&lt;/code&gt; tool.&lt;/p&gt;

&lt;p&gt;Compare that to an agent framework that ships with fifty specialized tools out of the box.&lt;/p&gt;

&lt;p&gt;The Claude Code design bet is that &lt;strong&gt;a competent model with sharp, general-purpose tools beats a constrained model with many specialized ones.&lt;/strong&gt; That's a tools-design decision, and it shapes the entire feel of the product. When Claude Code needs to do something novel — refactor across files, run a specific test harness, generate a summary of a diff — it doesn't need a new tool. It composes what it already has: &lt;code&gt;bash&lt;/code&gt; to run the test, &lt;code&gt;grep&lt;/code&gt; to find the failing pattern, &lt;code&gt;read&lt;/code&gt; to look at the file, &lt;code&gt;edit&lt;/code&gt; to fix it.&lt;/p&gt;

&lt;p&gt;When Claude Code can't do something well, the fix is usually not "add more tools." The fix is usually somewhere else in the harness — better context, better memory, better prompting. The tool surface stays lean on purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Leaves Us
&lt;/h2&gt;

&lt;p&gt;The Tools are the harness's contract with the model. They define what the model is &lt;em&gt;allowed&lt;/em&gt; to request. They don't decide when the model gets to request them (that's the Loop, from Part 3), and they don't decide what state the model has when deciding what to request (that's coming in Part 5, on Context). But the shape of the tool surface constrains everything downstream.&lt;/p&gt;

&lt;p&gt;A great Loop with a badly-designed tool set produces an agent that flails. A modest Loop with a well-designed tool set produces an agent that composes its way to solutions. Tools are that important.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Remember that this article is part of a longer 10-part series that walks you through every component of an agentic harness.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's the roadmap:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-1-the-raw-model-problem-54hg"&gt;Part 1: The Raw Model Problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-2-defining-the-harness-the-six-components-2gpk"&gt;Part 2: Defining the Harness — The Six Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-3-the-control-loop-3khk"&gt;Part 3: The Control Loop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;The Tool Layer&lt;/strong&gt; ← You just finished this one.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-5-context-engineering-94d"&gt;Part 5: Context Engineering&lt;/a&gt; ← &lt;em&gt;Move to this one.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-6-the-filesystem-environment-17m0"&gt;Part 6: The Filesystem &amp;amp; Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-7-the-memory-layer-3oon"&gt;Part 7: The Memory Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-8-observability-3gc1"&gt;Part 8: Observability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-9-the-harness-architecture-i5e"&gt;Part 9: The Harness Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-10-decomposing-claude-code-3h27"&gt;Part 10: Decomposing Claude Code&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;See you in the next one.&lt;/p&gt;

&lt;p&gt;Happy coding :)&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>python</category>
      <category>llm</category>
    </item>
    <item>
      <title>Harness Engineering - Part 3: The Control Loop</title>
      <dc:creator>Fikayo Adepoju</dc:creator>
      <pubDate>Sat, 15 Aug 2026 18:28:34 +0000</pubDate>
      <link>https://dev.to/coderonfleek/harness-engineering-part-3-the-control-loop-3khk</link>
      <guid>https://dev.to/coderonfleek/harness-engineering-part-3-the-control-loop-3khk</guid>
      <description>&lt;p&gt;&lt;em&gt;Welcome back to the Harness Engineering series — a 10-part journey from raw language model to production-ready agentic system. Made by builders. For builders.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In Part 2, I named the six components that make up a harness. Time to dig into the first one — and it's not an accident that it's first. The Loop is the outermost machinery of a harness. It's the piece everything else plugs into. Without it, none of the other components have anything to &lt;em&gt;do&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Every agent you've ever seen — whether it's Claude Code fixing a bug, a research agent skimming papers, or a customer support bot pulling up account data — has a Loop at its core. Sometimes it's obvious. Sometimes it's tucked away inside a framework. But it's always there, and how it's designed shapes what the agent is capable of.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's ahead:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-1-the-raw-model-problem-54hg"&gt;Part 1: The Raw Model Problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-2-defining-the-harness-the-six-components-2gpk"&gt;Part 2: Defining the Harness — The Six Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;The Control Loop&lt;/strong&gt; ← You are here&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-4-the-tool-layer-2p3f"&gt;Part 4: The Tool Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-5-context-engineering-94d"&gt;Part 5: Context Engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-6-the-filesystem-environment-17m0"&gt;Part 6: The Filesystem &amp;amp; Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-7-the-memory-layer-3oon"&gt;Part 7: The Memory Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-8-observability-3gc1"&gt;Part 8: Observability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-9-the-harness-architecture-i5e"&gt;Part 9: The Harness Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-10-decomposing-claude-code-3h27"&gt;Part 10: Decomposing Claude Code&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the end of this article, you'll know what the Loop is, why every agent needs one, what separates a robust loop from a fragile one, and the common shapes you'll see loops take in the wild.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's get started.&lt;/strong&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;h3&gt;
  
  
  📚 Want to go deeper than the articles?
&lt;/h3&gt;

&lt;p&gt;While you follow along with this series, I've put together two hands-on resources that go further than any single article can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.udemy.com/course/agentic-harness-engineering/?couponCode=7FA3B8BE5D143E73653B" rel="noopener noreferrer"&gt;Build a Harness from Scratch — Udemy Course&lt;/a&gt;&lt;/strong&gt; — A self-paced course where I walk you through building a production-grade agentic harness from the ground up, in code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://maven.com/fikayo-adepoju/harness-engineering-for-ai-agents" rel="noopener noreferrer"&gt;Harness Engineering for AI Agents — Live Maven Workshop&lt;/a&gt;&lt;/strong&gt; — A live, cohort-based workshop for builders who want direct feedback, Q&amp;amp;A, and to work through the material with peers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are optional — the series stands on its own. But if you want the full studio-quality version, that's where it lives.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What The Loop Is
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh1byl16owx9ubrkijo5y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh1byl16owx9ubrkijo5y.png" alt=" " width="799" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Loop is the control flow that wraps the model. It's the piece of code that turns a one-shot API call into something that can take multiple steps, react to intermediate results, and eventually stop when the job is done.&lt;/p&gt;

&lt;p&gt;At its minimum, a loop does three things, in a cycle:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Call the model&lt;/strong&gt; with the current context.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parse the response.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If the model asked for a tool&lt;/strong&gt;, run the tool and call the model again with the results attached. Otherwise, stop.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In pseudocode, that looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;has_tool_call&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;run_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tool_call&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;  &lt;span class="c1"&gt;# model is done
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Three steps, running in a cycle. Every fancy orchestration pattern you've heard of — multi-agents, sub-agents, planning phases, self-reflection — is a variation of &lt;em&gt;this shape&lt;/em&gt;. Sometimes with extra bells, sometimes with recursion, sometimes with parallelism. But underneath, the same core cycle.&lt;/p&gt;

&lt;p&gt;Another way to say it: &lt;strong&gt;the Loop is where the model does its work, and where the harness decides what to do with that work.&lt;/strong&gt; Without the Loop, the model produces one message and the process ends. With the Loop, the model gets to iterate — respond to tool results, revise its plan, keep going until something is done.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why The Loop Exists
&lt;/h2&gt;

&lt;p&gt;We established in Part 1 that a raw language model can't act. But the Loop solves a subtler problem: &lt;strong&gt;a single model call produces text and then exits.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Even if you gave the model tools, without a loop all it could do is &lt;em&gt;say&lt;/em&gt; "I'd call this tool now." The moment it finishes generating that message, control returns to your program. If your program isn't set up to look for tool requests, run them, and re-call the model, no tool actually runs. The model's request just sits there in the response object.&lt;/p&gt;

&lt;p&gt;Everything that resembles &lt;em&gt;agency&lt;/em&gt; — taking multiple steps, reacting to results, deciding to keep going or stop — has to come from a loop &lt;em&gt;around&lt;/em&gt; the model. Not from the model itself. The model doesn't know it's in a loop. Every time it's called, it just responds to whatever context it's given.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The model proposes; the Loop decides whether to keep going.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That sentence is worth writing on a Post-it. Every design decision about the Loop follows from it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a Good Loop Design Looks Like
&lt;/h2&gt;

&lt;p&gt;If you're evaluating a harness — or someone else's — three things separate a good Loop from a bad one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clear Termination Conditions
&lt;/h3&gt;

&lt;p&gt;A Loop that doesn't know when to stop is not an agent. It's a bill from your model provider. Good loops have explicit, &lt;em&gt;multiple&lt;/em&gt; termination conditions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The model signals it's done&lt;/strong&gt; — a stop phrase in the response, a specific &lt;code&gt;stop_reason&lt;/code&gt; from the API, or a &lt;code&gt;done&lt;/code&gt; tool call the model can invoke on itself&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A step budget runs out&lt;/strong&gt; — a max-iterations counter that prevents runaway loops&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An error threshold is hit&lt;/strong&gt; — too many consecutive tool failures, too many parse errors, too many empty responses in a row&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You want &lt;em&gt;all&lt;/em&gt; of these, not one. Relying on the model alone to say "I'm done" is how you end up with agents that run for 200 iterations because the model keeps thinking of one more thing to check.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sensible Error Handling
&lt;/h3&gt;

&lt;p&gt;When a tool call fails — invalid parameters, network timeout, the file doesn't exist — the Loop should not crash. It should catch the error and feed it back to the model &lt;em&gt;as an observation&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This turns errors into information. The model reads "the file you tried to open doesn't exist," realizes it hallucinated the filename, and tries a different one. That's the whole game. A Loop that crashes on the first tool failure has no way to recover. A Loop that treats errors as inputs to the next model call learns to steer around them.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Loop Has a Shape
&lt;/h3&gt;

&lt;p&gt;The two points above are about the &lt;em&gt;quality&lt;/em&gt; of a Loop. But loops also come in different &lt;em&gt;shapes&lt;/em&gt; — architectures, patterns, whatever you want to call them. And the shape determines what kinds of tasks the loop can handle.&lt;/p&gt;

&lt;p&gt;Some of the common shapes you'll run into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ReAct&lt;/strong&gt; — the model alternates between "reasoning" (thinking out loud) and "acting" (calling tools), with tool observations feeding back into the next reasoning step. The default shape for most modern agents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plan-then-Act&lt;/strong&gt; — the model produces a plan up front, then the Loop executes the plan step by step. Good for tasks with a knowable structure; brittle when the world doesn't cooperate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Agent&lt;/strong&gt; — multiple agents (each with their own Loop) coordinate on a task, often passing messages between one another. Useful when different sub-tasks call for different tools, models, or personas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deep Recursion&lt;/strong&gt; — the Loop is intentionally allowed to spawn sub-loops that dig into a task. The &lt;strong&gt;Ralph Loop&lt;/strong&gt; and &lt;strong&gt;Orchestrator/Worker&lt;/strong&gt; patterns are two variants. Powerful for tasks that decompose naturally into sub-tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these shapes is objectively "best." The right shape depends on the task, the reliability requirements, and how much you're willing to spend per invocation. Getting the shape wrong is one of the most common ways an otherwise well-built harness fails to do the thing it was designed to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: Claude Code
&lt;/h2&gt;

&lt;p&gt;If you've used Claude Code, you've already watched the Loop at work.&lt;/p&gt;

&lt;p&gt;When you ask Claude Code to fix a bug, it doesn't make one model call. It makes many. It reads a file. It edits the file. It runs the tests. It reads the failure output. It edits the file again. It re-runs the tests. It reads the diff. It might read a different file to check an import. It keeps going, iteration after iteration.&lt;/p&gt;

&lt;p&gt;The Loop is what makes that possible.&lt;/p&gt;

&lt;p&gt;And critically, the Loop is also what decides when to &lt;em&gt;stop&lt;/em&gt; — when the tests pass, or when Claude Code is confident the task is done. Without termination conditions, the same Loop that fixes bugs would keep going forever, "improving" code long after the user's actual request was satisfied.&lt;/p&gt;

&lt;p&gt;So when you see Claude Code do something impressive across ten or twenty steps, remember: the model doesn't know it's doing ten or twenty steps. Every time it's called, it just sees the current state and produces the next response. The &lt;em&gt;sense of coherent, multi-step problem-solving&lt;/em&gt; — the thing that makes it feel like an agent — comes entirely from the Loop wrapping it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Leaves Us
&lt;/h2&gt;

&lt;p&gt;The Loop is the first component of the harness because nothing else works without it. Tools have nowhere to be invoked from. Context has nothing driving its accumulation. Memory has no cycle to write into. Observability has no execution path to trace. Every other component plugs into the Loop.&lt;/p&gt;

&lt;p&gt;That's why we started here. From Part 4 onward, every component we look at slots into the Loop somewhere — and understanding the Loop is what lets you see where.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Remember that this article is part of a longer 10-part series that walks you through every component of an agentic harness.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's the roadmap:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-1-the-raw-model-problem-54hg"&gt;Part 1: The Raw Model Problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-2-defining-the-harness-the-six-components-2gpk"&gt;Part 2: Defining the Harness — The Six Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;The Control Loop&lt;/strong&gt; ← You just finished this one.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-4-the-tool-layer-2p3f"&gt;Part 4: The Tool Layer&lt;/a&gt; ← &lt;em&gt;Move to this one.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-5-context-engineering-94d"&gt;Part 5: Context Engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-6-the-filesystem-environment-17m0"&gt;Part 6: The Filesystem &amp;amp; Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-7-the-memory-layer-3oon"&gt;Part 7: The Memory Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-8-observability-3gc1"&gt;Part 8: Observability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-9-the-harness-architecture-i5e"&gt;Part 9: The Harness Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-10-decomposing-claude-code-3h27"&gt;Part 10: Decomposing Claude Code&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;See you in the next one.&lt;/p&gt;

&lt;p&gt;Happy coding :)&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>python</category>
      <category>llm</category>
    </item>
    <item>
      <title>Harness Engineering - Part 2: Defining the Harness — The Six Components</title>
      <dc:creator>Fikayo Adepoju</dc:creator>
      <pubDate>Sat, 15 Aug 2026 18:27:10 +0000</pubDate>
      <link>https://dev.to/coderonfleek/harness-engineering-part-2-defining-the-harness-the-six-components-2gpk</link>
      <guid>https://dev.to/coderonfleek/harness-engineering-part-2-defining-the-harness-the-six-components-2gpk</guid>
      <description>&lt;p&gt;&lt;em&gt;Welcome back to the Harness Engineering series — a 10-part journey from raw language model to production-ready agentic system. Made by builders. For builders.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In Part 1, we landed on a definition of a harness that was true but a little too broad to work with: &lt;em&gt;everything that is not the model is the harness.&lt;/em&gt; Fine. But if a harness is everything that isn't the model, then the word "harness" covers a &lt;em&gt;lot&lt;/em&gt; of ground — from the loop that calls the model to the logging library that writes what happened to disk.&lt;/p&gt;

&lt;p&gt;You can't reason about "everything." You need parts.&lt;/p&gt;

&lt;p&gt;So here's the promise for this article: I'll give you the six parts. Six components, each with a name, each with a job, each corresponding to a specific class of agent failure when it's missing or broken. Once these six names are in your head, every conversation you have about agents — debugging, design reviews, comparing frameworks, reading papers — gets sharper.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's ahead:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-1-the-raw-model-problem-54hg"&gt;Part 1: The Raw Model Problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Defining the Harness — The Six Components&lt;/strong&gt; ← You are here&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-3-the-control-loop-3khk"&gt;Part 3: The Control Loop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-4-the-tool-layer-2p3f"&gt;Part 4: The Tool Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-5-context-engineering-94d"&gt;Part 5: Context Engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-6-the-filesystem-environment-17m0"&gt;Part 6: The Filesystem &amp;amp; Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-7-the-memory-layer-3oon"&gt;Part 7: The Memory Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-8-observability-3gc1"&gt;Part 8: Observability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-9-the-harness-architecture-i5e"&gt;Part 9: The Harness Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-10-decomposing-claude-code-3h27"&gt;Part 10: Decomposing Claude Code&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the end of this article, you'll have a formal definition of a harness, a three-verb specification of what it has to do, and a six-component vocabulary you can carry into every conversation about agents from here on out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's get started.&lt;/strong&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;h3&gt;
  
  
  📚 Want to go deeper than the articles?
&lt;/h3&gt;

&lt;p&gt;While you follow along with this series, I've put together two hands-on resources that go further than any single article can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.udemy.com/course/agentic-harness-engineering/?couponCode=7FA3B8BE5D143E73653B" rel="noopener noreferrer"&gt;Build a Harness from Scratch — Udemy Course&lt;/a&gt;&lt;/strong&gt; — A self-paced course where I walk you through building a production-grade agentic harness from the ground up, in code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://maven.com/fikayo-adepoju/harness-engineering-for-ai-agents" rel="noopener noreferrer"&gt;Harness Engineering for AI Agents — Live Maven Workshop&lt;/a&gt;&lt;/strong&gt; — A live, cohort-based workshop for builders who want direct feedback, Q&amp;amp;A, and to work through the material with peers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are optional — the series stands on its own. But if you want the full studio-quality version, that's where it lives.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Harness Isn't One Thing
&lt;/h2&gt;

&lt;p&gt;In Part 1, we saw that a raw language model can't act on the world — it can only produce text that describes acting. We called the wrapper that closes this gap a &lt;strong&gt;harness&lt;/strong&gt;, and we defined it as &lt;em&gt;everything that is not the model.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That definition is true. It's also too broad to reason about.&lt;/p&gt;

&lt;p&gt;Because a harness isn't one thing. &lt;strong&gt;It's a stack of six concerns, each of which can be designed well or badly, and each of which corresponds to a specific class of agent failure when it's missing or broken.&lt;/strong&gt; Part 1 named the gap. This article names the parts that close it.&lt;/p&gt;

&lt;p&gt;Why bother naming them? Because once you have this vocabulary, every conversation you have about agents changes. When someone shows you a failing agent, you can point at the specific component that's broken. When a framework claims to be "an agentic runtime," you can ask &lt;em&gt;which of the six?&lt;/em&gt; When you read a paper about a new technique, you can slot it into the layer it belongs to. Without the vocabulary, "agent stuff" is a fog. With it, you can navigate.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Formal Definition
&lt;/h2&gt;

&lt;p&gt;Let's tighten the working definition from Part 1 into something more precise.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;A harness is the engineered system surrounding a language model that turns its single output channel (text) into **action&lt;/em&gt;&lt;em&gt;, **persistence&lt;/em&gt;&lt;em&gt;, and **measurable behavior&lt;/em&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Three verbs are doing the load-bearing work in that sentence. Let's unpack each one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frav25wj9fqbub60qx1qn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frav25wj9fqbub60qx1qn.png" alt="Agentic Harness Responsibilities" width="799" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Action
&lt;/h3&gt;

&lt;p&gt;The harness gives the model surface area beyond text — a filesystem, a code sandbox, web access, an API. It doesn't just let the model &lt;em&gt;describe&lt;/em&gt; things happening. It executes the things the model describes.&lt;/p&gt;

&lt;p&gt;This is the direct answer to the surface area problem from Part 1. A model that can only produce text is stuck in the pure-description layer of reality. A harness reaches into the execution layer, the data layer, and the network layer, and closes the loop between "the model said to do X" and "X actually happened."&lt;/p&gt;

&lt;h3&gt;
  
  
  Persistence
&lt;/h3&gt;

&lt;p&gt;The harness retains state the model itself cannot. Within a single task, that means holding onto tool results, intermediate reasoning, and running notes. Across sessions, it means remembering who you are, what you've been working on, and what worked before.&lt;/p&gt;

&lt;p&gt;Persistence is a harness feature, not a model feature. Every "memory" you've ever experienced from an LLM was built by something outside the model — quietly holding state and replaying it back into the prompt when the model needs to "recall" something.&lt;/p&gt;

&lt;h3&gt;
  
  
  Measurable Behavior
&lt;/h3&gt;

&lt;p&gt;The harness exposes what the agent is doing so engineers can debug it, evaluate it, and improve it. This is easy to skip when you're prototyping and painful to add later when you're not. And without it, you can't tell a working agent from a lucky one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Six Components
&lt;/h2&gt;

&lt;p&gt;Every component in the taxonomy below serves at least one of the three verbs above. Most serve more than one.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;One-line definition&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;The Loop&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The control structure that calls the model, dispatches tool calls, and decides when to stop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;The Tools&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The functions the model can invoke to have side effects in the world&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;The Context&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Everything fed into the model on a given call — system prompt, history, retrieved knowledge, tool results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;The Environment&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The runtime the tools operate inside — filesystem, shell, network, sandbox boundaries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;The Memory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;State that persists across loop iterations and across sessions — short-term and long-term&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;The Observability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;How the harness exposes what it's doing — logs, traces, evals, debuggability&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each of these six components gets its own dedicated article in the rest of this series — the Loop in Part 3, the Tools in Part 4, the Context in Part 5, the Environment in Part 6, the Memory in Part 7, and Observability in Part 8.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Leaves Us
&lt;/h2&gt;

&lt;p&gt;Six components. Three verbs. One insight worth carrying forward: &lt;strong&gt;the harness is not a thing — it's a stack of concerns&lt;/strong&gt;, and getting each one right is its own discipline.&lt;/p&gt;

&lt;p&gt;From Part 3 onward, we take each of these six components in turn and ask the same set of questions of it: What is it? What does it do? What does it look like when it's designed well? What breaks when it's missing? Different articles, same underlying method — because the harness itself has that shape.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Remember that this article is part of a longer 10-part series that walks you through every component of an agentic harness.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's the roadmap:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-1-the-raw-model-problem-54hg"&gt;Part 1: The Raw Model Problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Defining the Harness — The Six Components&lt;/strong&gt; ← You just finished this one.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-3-the-control-loop-3khk"&gt;Part 3: The Control Loop&lt;/a&gt; ← &lt;em&gt;Move to this one.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-4-the-tool-layer-2p3f"&gt;Part 4: The Tool Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-5-context-engineering-94d"&gt;Part 5: Context Engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-6-the-filesystem-environment-17m0"&gt;Part 6: The Filesystem &amp;amp; Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-7-the-memory-layer-3oon"&gt;Part 7: The Memory Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-8-observability-3gc1"&gt;Part 8: Observability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-9-the-harness-architecture-i5e"&gt;Part 9: The Harness Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-10-decomposing-claude-code-3h27"&gt;Part 10: Decomposing Claude Code&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;See you in the next one.&lt;/p&gt;

&lt;p&gt;Happy coding :)&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>python</category>
      <category>llm</category>
    </item>
    <item>
      <title>Harness Engineering - Part 1: The Raw Model Problem</title>
      <dc:creator>Fikayo Adepoju</dc:creator>
      <pubDate>Sat, 15 Aug 2026 18:25:35 +0000</pubDate>
      <link>https://dev.to/coderonfleek/harness-engineering-part-1-the-raw-model-problem-54hg</link>
      <guid>https://dev.to/coderonfleek/harness-engineering-part-1-the-raw-model-problem-54hg</guid>
      <description>&lt;p&gt;&lt;em&gt;Welcome to the Harness Engineering series — a 10-part journey from raw language model to production-ready agentic system. Made by builders. For builders.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Everyone's talking about AI agents. But when you strip away the demos, the hype, and the tweets — what actually &lt;em&gt;is&lt;/em&gt; an agent? Where does the "model" end and the "agent" begin? And why do so many prototypes that look magical in a Jupyter notebook fall apart the moment you try to ship them?&lt;/p&gt;

&lt;p&gt;Here's the uncomfortable truth: &lt;strong&gt;a language model, by itself, cannot do anything at all.&lt;/strong&gt; It can't touch a file. It can't call an API. It can't remember what you told it yesterday. It can't check its own work. It can't install &lt;code&gt;pandas&lt;/code&gt;. What we call "AI agents" are not made of models — they are made of &lt;em&gt;everything wrapped around the model&lt;/em&gt; that closes those gaps.&lt;/p&gt;

&lt;p&gt;That wrapper has a name. It's called a &lt;strong&gt;harness&lt;/strong&gt;. And harness engineering is the discipline of building that wrapper well.&lt;/p&gt;

&lt;p&gt;To help you understand what really goes into one, I've put together a 10-article series that walks straight through every component of a production-grade agentic harness — no framework hand-waving, no vibes-based tutorials. Each article breaks down one component and connects to the next.&lt;/p&gt;

&lt;p&gt;What's ahead:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;The Raw Model Problem&lt;/strong&gt; &amp;lt;- You're here&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-2-defining-the-harness-the-six-components-2gpk"&gt;Part 2: Defining the Harness — The Six Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-3-the-control-loop-3khk"&gt;Part 3: The Control Loop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-4-the-tool-layer-2p3f"&gt;Part 4: The Tool Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-5-context-engineering-94d"&gt;Part 5: Context Engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-6-the-filesystem-environment-17m0"&gt;Part 6: The Filesystem &amp;amp; Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-7-the-memory-layer-3oon"&gt;Part 7: The Memory Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-8-observability-3gc1"&gt;Part 8: Observability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-9-the-harness-architecture-i5e"&gt;Part 9: The Harness Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-10-decomposing-claude-code-3h27"&gt;Part 10: Decomposing Claude Code&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the end, you'll have a clear mental model of every component in an agentic harness — what each piece does, why it's there, and how they fit together. Enough to architect your own instead of copying somebody else's stack.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's get started.&lt;/strong&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;h3&gt;
  
  
  📚 Want to go deeper than the articles?
&lt;/h3&gt;

&lt;p&gt;While you follow along with this series, I've put together two hands-on resources that go further than any single article can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.udemy.com/course/agentic-harness-engineering/?couponCode=7FA3B8BE5D143E73653B" rel="noopener noreferrer"&gt;Build a Harness from Scratch — Udemy Course&lt;/a&gt;&lt;/strong&gt; — A self-paced course where I walk you through building a production-grade agentic harness from the ground up, in code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://maven.com/fikayo-adepoju/harness-engineering-for-ai-agents" rel="noopener noreferrer"&gt;Harness Engineering for AI Agents — Live Maven Workshop&lt;/a&gt;&lt;/strong&gt; — A live, cohort-based workshop for builders who want direct feedback, Q&amp;amp;A, and to work through the material with peers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are optional — the series stands on its own. But if you want the full studio-quality version, that's where it lives.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What Is a Harness?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbl9gy7ig924fj1zdj15t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbl9gy7ig924fj1zdj15t.png" alt="Raw Model vs Harness" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Plain English first. A harness is a &lt;strong&gt;support system for a thing&lt;/strong&gt; — a person, an animal, or an object — that lets it do work it couldn't do on its own. A climber's harness lets a body hang safely off a rope. A horse's harness lets it pull a cart. A wiring harness lets electrical current flow through a car without frying it.&lt;/p&gt;

&lt;p&gt;In agentic engineering, the "thing" being harnessed is the language model. And the work it can't do on its own turns out to be… almost everything you'd want an agent to do.&lt;/p&gt;

&lt;p&gt;Everything we break down from Part 2 onward is a response to this one limitation. So before we go any further, we need to see the limitation clearly — because if you don't understand &lt;em&gt;what&lt;/em&gt; you're working around, you can't tell whether your harness is any good.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a Raw Model Actually Is
&lt;/h2&gt;

&lt;p&gt;Most developers coming from traditional software engineering carry a mental model of the LLM as a function in a library. You call it, it does something, and it returns a result. Something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;do_thing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;summarize this file and save it to disk&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That mental model is wrong. And I don't mean "wrong in some pedantic way" — I mean it's wrong at the level that will silently break every agent you try to build.&lt;/p&gt;

&lt;p&gt;Under the hood, a language model is a &lt;strong&gt;text transformer&lt;/strong&gt;. That's it. Its full job description is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Input:&lt;/strong&gt; a sequence of tokens&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output:&lt;/strong&gt; a probability distribution over the next token&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repeat&lt;/strong&gt; until done.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No side effects. No memory between calls. No access to anything outside the prompt. The intelligence is real — genuinely, remarkably real — but the &lt;em&gt;surface area&lt;/em&gt; is limited to "tokens in, tokens out."&lt;/p&gt;

&lt;p&gt;The raw model cannot &lt;em&gt;do&lt;/em&gt; anything. It can only &lt;strong&gt;&lt;em&gt;describe&lt;/em&gt; doing things.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Read that sentence again. It's the load-bearing insight for this entire series.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 5 Gaps
&lt;/h2&gt;

&lt;p&gt;If we take that insight and expand it into concrete deficiencies, we get five gaps that a harness has to close.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Gap&lt;/th&gt;
&lt;th&gt;What the raw model cannot do&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;No execution&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Run code, call APIs, touch files, hit the network&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;No durable state&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Remember anything between sessions, or across context limits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;No fresh knowledge&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Know anything past its training cutoff, or anything private&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;No self-verification&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Check whether its own output is correct&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;No environment&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Install dependencies, configure a runtime, set up a workspace&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Let's walk through each one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gap 1: No Execution
&lt;/h3&gt;

&lt;p&gt;The model cannot read or write a file, run a script, query a database, or make an HTTP request. If the agent needs to &lt;em&gt;act on the world&lt;/em&gt;, &lt;strong&gt;something other than the model has to do the acting&lt;/strong&gt;. That "something" is the harness.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gap 2: No Durable State
&lt;/h3&gt;

&lt;p&gt;Every API call to a language model is stateless on the model's side. What you experience as "conversation memory" in ChatGPT is an illusion — the client is replaying the full message history in every call. Once the context window fills up, or the session ends, the model remembers nothing. &lt;strong&gt;Persistence is a harness feature, not a model feature.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Gap 3: No Fresh Knowledge
&lt;/h3&gt;

&lt;p&gt;The model's knowledge is frozen at its training cutoff. It doesn't know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What happened in the world last week&lt;/li&gt;
&lt;li&gt;Anything about your codebase, your company's docs, or your private data&lt;/li&gt;
&lt;li&gt;The current version of any library that has shipped updates since it stopped learning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The only way to give it this knowledge is to &lt;strong&gt;inject it into the prompt&lt;/strong&gt; — which means something has to retrieve it first. That's a harness job.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gap 4: No Self-Verification
&lt;/h3&gt;

&lt;p&gt;The model can generate code, but it cannot run the code to see if it works. It can produce a summary, but it cannot compare the summary to the source to check fidelity. It can &lt;em&gt;claim&lt;/em&gt; correctness — often very confidently — but claiming and verifying are different operations, and only one of them is available to the raw model.&lt;/p&gt;

&lt;p&gt;The harness is what builds a verification system around the agent's outputs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gap 5: No Environment
&lt;/h3&gt;

&lt;p&gt;The model is not sitting inside a Linux box with Python and git installed. It's not sitting &lt;em&gt;anywhere&lt;/em&gt; — it's a mathematical function being evaluated on a GPU somewhere in a data center.&lt;/p&gt;

&lt;p&gt;If we want the agent to use &lt;code&gt;pandas&lt;/code&gt;, something has to install &lt;code&gt;pandas&lt;/code&gt;. If we want it to use a browser, something has to give it a browser. Environments are harness-provided.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo: The Surface Area Problem
&lt;/h2&gt;

&lt;p&gt;Enough theory. Let's watch a raw model bump into these gaps in the wild.&lt;/p&gt;

&lt;p&gt;The plan is simple: we'll give a model the smallest possible task that requires it to reach outside itself — read a file, summarize it, and write the summary to disk — and see what happens.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up
&lt;/h3&gt;

&lt;p&gt;Create a folder for the project and drop into it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;harness-project
&lt;span class="nb"&gt;cd &lt;/span&gt;harness-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a Python virtual environment and activate it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv
&lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate  &lt;span class="c"&gt;# On Windows: venv\Scripts\activate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the OpenAI Python package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;openai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now create a file called &lt;code&gt;article.txt&lt;/code&gt; at the root of the project and paste the following text into it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before Gutenberg's fifteenth-century printing press, books were rare, hand-copied treasures chained to monastery libraries, accessible only to clergy and scholars. That changed irrevocably in Mainz around 1440. By combining movable metal type, oil-based inks, and an adapted screw press, Gutenberg enabled the rapid, uniform production of texts. His famous Bible of 1455 was not merely a beautiful artifact but a declaration: knowledge could now be manufactured. The consequences were explosive. For the first time, information could spread faster than political or religious authorities could suppress it. Within decades, printing shops erupted across Europe, producing millions of books. Humanist ideas, scientific observations, and navigational charts circulated widely. Most critically, the press democratized scripture and criticism; Martin Luther's vernacular pamphlets reached a literate public, igniting the Reformation. Beyond religion, it standardized languages, elevated vernacular literature, and allowed scholars to build upon corrected, shared knowledge—catalyzing the Scientific Revolution. The printing press did not merely make books; it unmoored authority from the few and anchored it in the hands of the many, laying the very groundwork for our modern world of mass media, public education, and individual conscience.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create &lt;code&gt;demo.py&lt;/code&gt; at the root of the project and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4o-mini&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Read the file article.txt in this directory, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;summarize it in 3 bullets, and save the summary &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;to summary.md.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at what this script is asking for. Three concrete actions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read a file&lt;/strong&gt; — a filesystem operation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Summarize it&lt;/strong&gt; — a text operation, which the model actually can do&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write a file&lt;/strong&gt; — another filesystem operation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Two out of three are things the model has no way to perform. Watch what it does about that.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;This file is deliberately the simplest possible LLM call — one message in, one message out. No tools, no memory, no environment. Everything a harness provides is intentionally absent here, so we can see exactly what a raw model can and cannot do on its own.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Add your OpenAI API key to the environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your-key-here&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And run the demo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python demo.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What Actually Happens
&lt;/h3&gt;

&lt;p&gt;The model responds with something close to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I don't have the ability to read files or access directories 
directly. However, I can help you with instructions on how to 
summarize the content of a file. If you provide the text or 
key points from the article, I can assist you in creating a 
summary. Once you have the summary, you can save it to a file 
named summary.md. Would you like to proceed with that?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;Exact wording will vary between runs and over time as models are updated — but the structure of the response is the durable part.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Give it credit — this is a well-behaved response. The model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Accurately reports its limitation&lt;/strong&gt; — it knows it can't access files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offers the capability it does have&lt;/strong&gt; — summarizing, if you paste the text&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Routes the I/O back to the user&lt;/strong&gt; — "you can save it to a file"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now look at your directory after the call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;span class="c"&gt;# article.txt   demo.py   venv/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The contents are identical to before. No &lt;code&gt;summary.md&lt;/code&gt;. The Python script exits with code 0. Everything ran cleanly. And yet…&lt;/p&gt;

&lt;h3&gt;
  
  
  What This Demonstrates
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Nothing happened.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's the lesson. Not "the model failed" — the model did exactly what it &lt;em&gt;could&lt;/em&gt; do, and did it gracefully. But the world outside the prompt is completely unchanged. The directory doesn't care how politely the model declined.&lt;/p&gt;

&lt;p&gt;This is the surface area problem in its purest form. The model's only output channel is text. And text can describe action, recommend action, decline action, or claim action — &lt;strong&gt;but text is not action&lt;/strong&gt;. The gap between &lt;em&gt;describing a file write&lt;/em&gt; and &lt;em&gt;writing a file&lt;/em&gt; has to be closed by something other than the model.&lt;/p&gt;

&lt;p&gt;Look at what the model itself suggested we do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Provide the text" → &lt;em&gt;manual file read&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;"I can assist you in creating a summary" → &lt;em&gt;the model's actual capability&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;"You can save it to a file" → &lt;em&gt;manual file write&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's a workflow with three steps, where the model handles the middle one and a human handles the bookends.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A harness is what automates the bookends so the human doesn't have to be the file system.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Gaps Exposed by This Demo
&lt;/h3&gt;

&lt;p&gt;Three of our five gaps just showed up on stage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No execution&lt;/strong&gt; — the model couldn't read or write, and correctly said so&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No environment&lt;/strong&gt; — there's no filesystem available to it in the first place&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No durable state&lt;/strong&gt; — even the summary it offered to help with would vanish the moment the API call ended, unless something outside the model persisted it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Gaps 3 (fresh knowledge) and 4 (self-verification) don't show up here — this task didn't require the model to fetch anything past its training cutoff, and it didn't ask the model to check its own work. Different tasks would surface those gaps just as clearly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Let's tighten this down into two definitions to carry into the rest of the series.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The long one:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A harness is every piece of code, configuration, and execution logic that surrounds the model and makes it capable of acting, remembering, learning, verifying, and persisting.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;The short one:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Everything that is not the model is the harness.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The harness is what closes the gap between description and action. And starting in Part 2, we're going to break one open — piece by piece, gap by gap — until you can see exactly how a raw model turns into an agent capable of doing the file-summary task your model just apologized for.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Remember that this article is part of a longer 10-part series that walks you through every component of an agentic harness.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's the roadmap:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;The Raw Model Problem&lt;/strong&gt; ← You just finished this one.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-2-defining-the-harness-the-six-components-2gpk"&gt;Part 2: Defining the Harness — The Six Components&lt;/a&gt; ← &lt;em&gt;Move to this one.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-3-the-control-loop-3khk"&gt;Part 3: The Control Loop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-4-the-tool-layer-2p3f"&gt;Part 4: The Tool Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-5-context-engineering-94d"&gt;Part 5: Context Engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-6-the-filesystem-environment-17m0"&gt;Part 6: The Filesystem &amp;amp; Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-7-the-memory-layer-3oon"&gt;Part 7: The Memory Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-8-observability-3gc1"&gt;Part 8: Observability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-9-the-harness-architecture-i5e"&gt;Part 9: The Harness Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/coderonfleek/harness-engineering-part-10-decomposing-claude-code-3h27"&gt;Part 10: Decomposing Claude Code&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;See you in the next one.&lt;/p&gt;

&lt;p&gt;Happy coding :)&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>python</category>
      <category>llm</category>
    </item>
    <item>
      <title>File Uploads with HTMX and Golang</title>
      <dc:creator>Fikayo Adepoju</dc:creator>
      <pubDate>Mon, 19 Aug 2024 22:15:34 +0000</pubDate>
      <link>https://dev.to/coderonfleek/file-uploads-with-htmx-and-golang-57ad</link>
      <guid>https://dev.to/coderonfleek/file-uploads-with-htmx-and-golang-57ad</guid>
      <description>&lt;p&gt;Ofcourse you have already heard about the awesomeness of HTMX (you haven’t? well, good thing you’re here 😃)&lt;/p&gt;

&lt;p&gt;Today, we will be combining the simplicity of &lt;a href="https://htmx.org/" rel="noopener noreferrer"&gt;HTMX&lt;/a&gt; with the power of &lt;a href="https://go.dev/" rel="noopener noreferrer"&gt;Golang&lt;/a&gt; to upload files to our server. Yeah, we are going to be building another exciting web feature with HTMX and Go.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;By the way, if you really want a practical project-based guide on building fullstack apps with HTMX, check out my &lt;a href="https://www.udemy.com/course/htmx-go-build-fullstack-applications-with-golang-and-htmx/?couponCode=F92B5F6CD6297B66643D" rel="noopener noreferrer"&gt;HTMX + Go: Build Fullstack Applications with Golang and HTMX course [Discount Included]&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, let’s begin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the Go Project
&lt;/h2&gt;

&lt;p&gt;The first step is to setup a simple Go project. We can do that by creating a folder, going into it and initialising it as a Go project using the commands below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;go-htmx-file-uploads
&lt;span class="nb"&gt;cd &lt;/span&gt;go-htmx-file-uploads
go mod init go-htmx-file-uploads
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we have the project initialized, let’s now install some dependencies we will be requiring within our project.&lt;/p&gt;

&lt;p&gt;This will be a simple server that will contain a single page with our upload form and also an endpoint that will be used to upload the file.&lt;/p&gt;

&lt;p&gt;For routing, we will be using the &lt;a href="https://github.com/gorilla/mux" rel="noopener noreferrer"&gt;Gorilla Mux routing library&lt;/a&gt;, but feel free to use any routing solution of your choice. We will also be using Google’s UUID library for Go to generate random names for our files when we upload them. This is a personal preference as you can generate file names in different ways.&lt;/p&gt;

&lt;p&gt;Install these two with the commands below:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gorillla Mux&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get &lt;span class="nt"&gt;-u&lt;/span&gt; github.com/gorilla/mux 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Google UUID&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get github.com/google/uuid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these two installed, our project is fully set up, and we can move to the next step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating our Templates
&lt;/h2&gt;

&lt;p&gt;We will be creating two HTML templates for this little project.&lt;/p&gt;

&lt;p&gt;The first template will be an HTML fragment that simply takes a slice of string messages that we can send from the server to the client.&lt;/p&gt;

&lt;p&gt;This fragment will take this slice of messages and loop through it to create an HTML list to be returned to the client (remember how &lt;a href="https://htmx.org/" rel="noopener noreferrer"&gt;HTMX&lt;/a&gt; works with Hypermedia APIs, pretty cool huh 😎).&lt;/p&gt;

&lt;p&gt;So, let’s create that first.&lt;/p&gt;

&lt;p&gt;At the root of the Go project, first create a &lt;code&gt;templates&lt;/code&gt; folder inside which we will be storing all our templates.&lt;/p&gt;

&lt;p&gt;Next, create a file &lt;code&gt;messages.html&lt;/code&gt; inside the &lt;code&gt;templates&lt;/code&gt; folder and add the following code to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{{define "messages"}}
&lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
    {{range .}}
        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;{{ . }}&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    {{end}}
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
{{end}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This defines a &lt;code&gt;messages&lt;/code&gt; template and loops through the incoming slice of string messages to form an HTML list.&lt;/p&gt;

&lt;p&gt;For our next template, we will be creating the file upload page itself.&lt;/p&gt;

&lt;p&gt;Inside the &lt;code&gt;templates&lt;/code&gt; folder, create a new file &lt;code&gt;upload.html&lt;/code&gt; and paste in the code below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{{define "upload"}}
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/htmx.org@1.9.12"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Upload File&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col-md-6 p-5 mt-5"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h4&amp;gt;&lt;/span&gt;Upload File&lt;span class="nt"&gt;&amp;lt;/h4&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt;  &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"messages"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mb-3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"avatarInput"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-label"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Select Image&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-control"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"avatarInput"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"avatar"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; 
                    &lt;span class="na"&gt;hx-post=&lt;/span&gt;&lt;span class="s"&gt;"/upload"&lt;/span&gt; 
                    &lt;span class="na"&gt;hx-encoding=&lt;/span&gt;&lt;span class="s"&gt;"multipart/form-data"&lt;/span&gt; 
                    &lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"#messages"&lt;/span&gt; 
                    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Upload&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;



&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
{{end}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perfect!&lt;/p&gt;

&lt;p&gt;Now let’s go through the code in this file.&lt;/p&gt;

&lt;p&gt;First, we have defined the template with the name &lt;code&gt;upload&lt;/code&gt;, this is the name we will use to reference it later in our route handlers.&lt;/p&gt;

&lt;p&gt;We then have some boilerplate HTML code in the head section, but I have included two important libraries here (well, just one is really important, the other is just for CSS vibes).&lt;/p&gt;

&lt;p&gt;The HTMX library has been included with the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag to bring in HTMX, just the library, no dependencies required.&lt;/p&gt;

&lt;p&gt;Then I have also brought in the Bootstrap CSS library, this is just to give our page elements some nice styling. It is not compulsory for this demo.&lt;/p&gt;

&lt;p&gt;In the page itself, we have a form that does the upload. Let’s break down what is within the &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;

&lt;p&gt;First we have a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; with an &lt;code&gt;id&lt;/code&gt; of &lt;code&gt;messages&lt;/code&gt; , this is the container where we will be loading all our server messages that come in as HTML. Remember the &lt;code&gt;messages&lt;/code&gt; template, yeah, this is where the list of messages will be going into.&lt;/p&gt;

&lt;p&gt;After that, we have the form input element that is set to &lt;code&gt;file&lt;/code&gt; to ensure that it displays a file upload widget. We have given it the name &lt;code&gt;avatar&lt;/code&gt; to reference it at the backend, but you can give this any name you want. I gave it &lt;code&gt;avatar&lt;/code&gt; because i was using it to upload profile images.&lt;/p&gt;

&lt;p&gt;Finally, we have the button which has been supercharged with HTMX. I have displayed it again below so we can go through it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; 
                    &lt;span class="na"&gt;hx-post=&lt;/span&gt;&lt;span class="s"&gt;"/upload"&lt;/span&gt; 
                    &lt;span class="na"&gt;hx-encoding=&lt;/span&gt;&lt;span class="s"&gt;"multipart/form-data"&lt;/span&gt; 
                    &lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"#messages"&lt;/span&gt; 
                    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Upload&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, I have added &lt;code&gt;hx-post="/upload"&lt;/code&gt; , this tells it to submit the form to the &lt;code&gt;/upload&lt;/code&gt; endpoint that we will be creating very soon and will handle the file upload.&lt;/p&gt;

&lt;p&gt;Next is &lt;code&gt;hx-encoding="multipart/form-data"&lt;/code&gt;, this is compulsory for uploading files with HTMX to let the server know you’re sending along a file with the request.&lt;/p&gt;

&lt;p&gt;Then we have &lt;code&gt;hx-target="#messages"&lt;/code&gt; which tells the button to insert any response from the server into the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; with an &lt;code&gt;id&lt;/code&gt; of &lt;code&gt;messages&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;These three define our configuration for uploading the file to our backend.&lt;/p&gt;

&lt;p&gt;Below is a preview of what our page looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr2btxcv3cbbnyahhfrtg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr2btxcv3cbbnyahhfrtg.png" alt="Upload Page" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Processing the File Upload
&lt;/h2&gt;

&lt;p&gt;Now that we have our templates, it’s time to write the code that will display our upload page and also handle our file uploads.&lt;/p&gt;

&lt;p&gt;To begin, at the root of the Go project, create a &lt;code&gt;uploads&lt;/code&gt; folder. This is the folder where all our uploaded files will be stored.&lt;/p&gt;

&lt;p&gt;With that in place, let’s write our main file.&lt;/p&gt;

&lt;p&gt;Create the file &lt;code&gt;main.go&lt;/code&gt; at the root of your project and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"html/template"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"io"&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;
    &lt;span class="s"&gt;"path/filepath"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/google/uuid"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/gorilla/mux"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tmpl&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Template&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseGlob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"templates/*.html"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


    &lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;homeHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Methods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/upload"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UploadHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Methods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Server starting on :8080"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;homeHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"upload"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;UploadHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


        &lt;span class="c"&gt;// Initialize error messages slice&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;serverMessages&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;

        &lt;span class="c"&gt;// Parse the multipart form, 10 MB max upload size&lt;/span&gt;
        &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseMultipartForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;// Retrieve the file from form data&lt;/span&gt;
        &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"avatar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrMissingFile&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;serverMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"No file submitted"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;serverMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error retrieving the file"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"messages"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c"&gt;// Generate a unique filename to prevent overwriting and conflicts&lt;/span&gt;
        &lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRandom&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;serverMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error generating unique identifier"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"messages"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Append the file extension&lt;/span&gt;

        &lt;span class="c"&gt;// Create the full path for saving the file&lt;/span&gt;
        &lt;span class="n"&gt;filePath&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"uploads"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;// Save the file to the server&lt;/span&gt;
        &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;serverMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error saving the file"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"messages"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;serverMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error saving the file"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"messages"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;


        &lt;span class="n"&gt;serverMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"File Successfully Saved"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"messages"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yope, that’s a bunch of code. Don’t worry, we’ll go through it all step by step to figure out what this is all doing.&lt;/p&gt;

&lt;p&gt;First we define our &lt;code&gt;package main&lt;/code&gt; and import a bunch of libraries we will be making use of. These imports include the Gorilla mux router and the Google UUID library that we installed earlier.&lt;/p&gt;

&lt;p&gt;After that, I create a global &lt;code&gt;tmpl&lt;/code&gt; variable to hold all the HTML templates in the project and in the &lt;code&gt;init()&lt;/code&gt; function, the templates are all loaded from the &lt;code&gt;templates&lt;/code&gt; folder.&lt;/p&gt;

&lt;h3&gt;
  
  
  The main() Function
&lt;/h3&gt;

&lt;p&gt;Now to the &lt;code&gt;main()&lt;/code&gt; function. Here, we have initlialized the Gorilla Mux router and set up two routes.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;GET /&lt;/code&gt;   base route which will be handled by a &lt;code&gt;homeHandler&lt;/code&gt; function and displays our upload form, and the &lt;code&gt;POST /upload&lt;/code&gt; route that will be handled by &lt;code&gt;UploadHandler&lt;/code&gt; and handles the upload itself.&lt;/p&gt;

&lt;p&gt;Finally, we print out a message to indicate that our server is running, and run the server on port &lt;code&gt;8080&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Handler Functions
&lt;/h3&gt;

&lt;p&gt;First we have &lt;code&gt;homeHandler&lt;/code&gt; . This is the function that handles our base route, and it simply calls &lt;code&gt;ExecuteTemplate&lt;/code&gt; on the &lt;code&gt;tmpl&lt;/code&gt; variable with the name we gave to our template&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"upload"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This call is enough to simply render our upload page to the screen when we visit the base route.&lt;/p&gt;

&lt;p&gt;After that is the &lt;code&gt;UploadHandler&lt;/code&gt; function. This is where the real magic happens, so let’s walk through the function.&lt;/p&gt;

&lt;p&gt;First, we create a slice of strings called &lt;code&gt;serverMessages&lt;/code&gt; to hold any message we want to send back to the client.&lt;/p&gt;

&lt;p&gt;After that, we call &lt;code&gt;ParseMultipartForm&lt;/code&gt; on the request pointer to limit the size of uploaded files to within 20MB.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseMultipartForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we get a hold on our file by referencing the name of the file field with &lt;code&gt;FormFile&lt;/code&gt; on the request pointer.&lt;/p&gt;

&lt;p&gt;With our reference to the file, we check if there is actually a file, and if not, we return a message saying that no file was submitted or an error was encountered when trying to retrieve the file to account for other errors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"avatar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrMissingFile&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;serverMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"No file submitted"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;serverMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error retrieving the file"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"messages"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, if our messages slice is not empty, we return the messages to the client and exit the function.&lt;/p&gt;

&lt;p&gt;If a file is found, we keep the file open and move to generating a new name for it with the UUID library and also handle the errors in that process accordingly.&lt;/p&gt;

&lt;p&gt;We build a new file name with the generated string and the file extension and set it’s path to the &lt;code&gt;uploads&lt;/code&gt; folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRandom&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;serverMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error generating unique identifier"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"messages"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

        &lt;span class="c"&gt;// Create the full path for saving the file&lt;/span&gt;
        &lt;span class="n"&gt;filePath&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"uploads"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the new file path is constructed, we then use the &lt;code&gt;os&lt;/code&gt; library to create the file path&lt;/p&gt;

&lt;p&gt;After that, we use the &lt;code&gt;io&lt;/code&gt; library to move the file from it’s temporary location to the new location and also handle errors accordingly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;serverMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error saving the file"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"messages"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;serverMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error saving the file"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"messages"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we get no errors from the file saving process, we then return a successful message to the client using our &lt;code&gt;messages&lt;/code&gt; template as we have done with previous messages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;serverMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"File Successfully Saved"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"messages"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serverMessages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that’s everything.&lt;/p&gt;

&lt;p&gt;Now let’s take this code for a spin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing the File Upload
&lt;/h2&gt;

&lt;p&gt;Save the file and head over to the command line.&lt;/p&gt;

&lt;p&gt;At the root of the project, use the command below to run our little file upload application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now go to your browser and head over to &lt;code&gt;http://localhost:8080&lt;/code&gt;, you should see the upload screen displayed.&lt;/p&gt;

&lt;p&gt;Try testing with no file to see the error message displayed. Then test with an actual file and also see that you get a successful message.&lt;/p&gt;

&lt;p&gt;Check the &lt;code&gt;uploads&lt;/code&gt; folder to confirm that the file is actually being saved there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frk2rpi427xuzwwek3ofs.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frk2rpi427xuzwwek3ofs.gif" alt="Upload Demo" width="600" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And Wholla! You can now upload files to your Go servers using HTMX. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If you have enjoyed this article, and will like to learn more about building projects with HTMX,  I’ll like you to check out &lt;a href="https://www.udemy.com/course/htmx-go-build-fullstack-applications-with-golang-and-htmx/?couponCode=F92B5F6CD6297B66643D" rel="noopener noreferrer"&gt;&lt;strong&gt;HTMX + Go: Build Fullstack Applications with Golang and HTMX&lt;/strong&gt;&lt;/a&gt;, and &lt;a href="https://www.udemy.com/course/the-complete-htmx-course/?couponCode=E3B0B3DBAC2964EE2079" rel="noopener noreferrer"&gt;&lt;strong&gt;The Complete HTMX Course: Zero to Pro with HTMX&lt;/strong&gt;&lt;/a&gt; to further expand your knowledge on building hypermedia-driven applications with HTMX.&lt;/p&gt;

</description>
      <category>go</category>
      <category>htmx</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>HTMX + Go : Build a CRUD App with Golang and HTMX</title>
      <dc:creator>Fikayo Adepoju</dc:creator>
      <pubDate>Mon, 15 Jul 2024 19:49:54 +0000</pubDate>
      <link>https://dev.to/coderonfleek/htmx-go-build-a-crud-app-with-golang-and-htmx-1le2</link>
      <guid>https://dev.to/coderonfleek/htmx-go-build-a-crud-app-with-golang-and-htmx-1le2</guid>
      <description>&lt;p&gt;One question I see going around alot about HTMX, especially amongst developers that have just tried the library is “But what can you really build with it though?”&lt;/p&gt;

&lt;p&gt;Great question, and in this article, we will start with baby steps by building a database-backed CRUD application with HTMX and Go as our backend language.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;By the way, if you really want a practical project-based guide on building fullstack apps with HTMX, check out my &lt;a href="https://www.udemy.com/course/htmx-go-build-fullstack-applications-with-golang-and-htmx/?couponCode=F92B5F6CD6297B66643D" rel="noopener noreferrer"&gt;**HTMX + Go: Build Fullstack Applications with Golang and HTMX [Discount included] course&lt;/a&gt;.**&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s begin.&lt;/p&gt;

&lt;h2&gt;
  
  
  What exactly are we building?
&lt;/h2&gt;

&lt;p&gt;I’ll like to call it a Task Management Application but I know you already figured that that’s just a fancy name for another Todo application. Don’t worry, Todo apps are great for learning fundamental operations with languages, libraries and frameworks so we will be using that same tested and trusted strategy.&lt;/p&gt;

&lt;p&gt;Our application will be able to do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Display tasks&lt;/li&gt;
&lt;li&gt;Add new tasks&lt;/li&gt;
&lt;li&gt;Update an existing task and …&lt;/li&gt;
&lt;li&gt;Delete a task&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Database Setup
&lt;/h2&gt;

&lt;p&gt;So first, we need a database, and for this demo project, I will be using MySQL. Feel free to use any database of your choice and make the necessary code changes to reference your database as you follow along with this article.&lt;/p&gt;

&lt;p&gt;We will keep things simple, no complicated schema design. First we create a database with the name &lt;code&gt;testdb&lt;/code&gt; and inside this database, we create a &lt;code&gt;todos&lt;/code&gt; table (feel free to give your database and table any name you prefer but ensure you use the same names in your SQL statements)&lt;/p&gt;

&lt;p&gt;Inside the &lt;code&gt;todos&lt;/code&gt; table, implement the schema below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt;: PK, Auto incrementing&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;task&lt;/code&gt; : VARCHAR(200) - Contains the task item&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;done&lt;/code&gt;: INT(1), default = 0 (Boolean field)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can choose to seed the database table with some tasks so that we can start seeing some tasks the first time we load the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Hypermedia API
&lt;/h2&gt;

&lt;p&gt;To begin setting up our little application, create a folder for the project at any convenient location in your development computer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;task-management
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the following command at the root of the project folder to initialize it as a Golang project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go mod init task-management
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need to install some dependencies. We already know we are using MySQL as our database, thus, we need to install the &lt;a href="https://github.com/go-sql-driver/mysql" rel="noopener noreferrer"&gt;MySQL driver for Golang&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We also need to install the &lt;a href="https://github.com/gorilla/mux" rel="noopener noreferrer"&gt;Gorilla Mux Router&lt;/a&gt; which will be the routing library for our project. Run the two commands below at the root of your project to get these libraries installed into your project&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MySQL:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get &lt;span class="nt"&gt;-u&lt;/span&gt; github.com/go-sql-driver/mysql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Gorilla Mux:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get &lt;span class="nt"&gt;-u&lt;/span&gt; github.com/gorilla/mux
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these libraries in place, create your &lt;code&gt;main.go&lt;/code&gt; file at the root of the project and add the code below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"database/sql"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"html/template"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"strconv"&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="s"&gt;"github.com/go-sql-driver/mysql"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/gorilla/mux"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tmpl&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Template&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Id&lt;/span&gt;   &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Done&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseGlob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"templates/*.html"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;initDB&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
    &lt;span class="c"&gt;// Initialize the db variable&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mysql"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"root:root@(127.0.0.1:3333)/testdb?parseTime=true"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Check the database connection&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ping&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;gRouter&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;//Setup MySQL&lt;/span&gt;
    &lt;span class="n"&gt;initDB&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;gRouter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Homepage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;//Get Tasks&lt;/span&gt;
    &lt;span class="n"&gt;gRouter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/tasks"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fetchTasks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Methods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;//Fetch Add Task Form&lt;/span&gt;
    &lt;span class="n"&gt;gRouter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/newtaskform"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;getTaskForm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;//Add Task&lt;/span&gt;
    &lt;span class="n"&gt;gRouter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/tasks"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addTask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Methods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;//Fetch Update Form&lt;/span&gt;
    &lt;span class="n"&gt;gRouter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/gettaskupdateform/{id}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;getTaskUpdateForm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Methods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;//Update Task&lt;/span&gt;
    &lt;span class="n"&gt;gRouter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/tasks/{id}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;updateTask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Methods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PUT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;//Delete Task&lt;/span&gt;
    &lt;span class="n"&gt;gRouter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/tasks/{id}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;deleteTask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Methods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DELETE"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":4000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gRouter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Homepage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"home.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;fetchTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;getTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;//fmt.Println(todos)&lt;/span&gt;

    &lt;span class="c"&gt;//If you used "define" to define the template, use the name you gave it here, not the filename&lt;/span&gt;
    &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"todoList"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;getTaskForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"addTaskForm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;addTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"task"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"INSERT INTO tasks (task, done) VALUES (?, ?)"&lt;/span&gt;

    &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;executeErr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;executeErr&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;executeErr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Return a new list of Todos&lt;/span&gt;
    &lt;span class="n"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;getTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;//You can also just send back the single task and append it&lt;/span&gt;
    &lt;span class="c"&gt;//I like returning the whole list just to get everything fresh, but this might not be the best strategy&lt;/span&gt;
    &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"todoList"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;getTaskUpdateForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;vars&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Vars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;//Convert string id from URL to integer&lt;/span&gt;
    &lt;span class="n"&gt;taskId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vars&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;getTaskByID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;taskId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"updateTaskForm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;updateTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;vars&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Vars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;taskItem&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"task"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;//taskStatus, _ := strconv.ParseBool(r.FormValue("done"))&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;taskStatus&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"done"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="c"&gt;//Check the string value of the checkbox&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"done"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"yes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"on"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;taskStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"no"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"off"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;taskStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;taskStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;taskId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vars&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;taskId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;taskItem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;taskStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;updateErr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;updateTaskById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;updateErr&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;updateErr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;//Refresh all Tasks&lt;/span&gt;
    &lt;span class="n"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;getTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"todoList"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;deleteTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;vars&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Vars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;taskId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vars&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;deleTaskWithID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;taskId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;//Return list&lt;/span&gt;
    &lt;span class="n"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;getTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"todoList"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;getTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dbPointer&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"SELECT id, task, done FROM tasks"&lt;/span&gt;

    &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;dbPointer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;

        &lt;span class="n"&gt;rowErr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;rowErr&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;getTaskByID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dbPointer&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"SELECT id, task, done FROM tasks WHERE id = ?"&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;

    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;dbPointer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryRow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrNoRows&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No task was found with task %d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;updateTaskById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dbPointer&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"UPDATE tasks SET task = ?, done = ? WHERE id = ?"&lt;/span&gt;

    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;dbPointer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;rowsAffected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RowsAffected&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;rowsAffected&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No rows updated"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%d row(s) updated&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rowsAffected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;deleTaskWithID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dbPointer&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"DELETE FROM tasks WHERE id = ?"&lt;/span&gt;

    &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;dbPointer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;rowsAffected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RowsAffected&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;rowsAffected&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"no task found with id %d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Deleted %d task(s)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rowsAffected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yeah, that was alot of code. Don’t worry, we will take it from the very top and walk down&lt;/p&gt;

&lt;p&gt;So first we import all our necessary packages. The MySQL driver and Gorilla Mux router we installed, and a bunch of packages from the Go standard library that will be useful in our code operations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"database/sql"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"html/template"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"strconv"&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="s"&gt;"github.com/go-sql-driver/mysql"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/gorilla/mux"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we create a &lt;code&gt;tmpl&lt;/code&gt; variable that will be used to hold our loaded templates and a &lt;code&gt;db&lt;/code&gt; variable that will be a pointer to our database connection for running database tasks. We then create a custom &lt;code&gt;Task&lt;/code&gt; struct that defines a task type.&lt;/p&gt;

&lt;p&gt;Inside the &lt;code&gt;init()&lt;/code&gt; function, we load all our templates from a &lt;code&gt;templates&lt;/code&gt; folder. All our templates are expected to have the &lt;code&gt;.html&lt;/code&gt; extension as since HTMX expects us to return HTML, this makes a ton of sense.&lt;/p&gt;

&lt;p&gt;Go ahead and create the &lt;code&gt;templates&lt;/code&gt; folder at the root of the project so that we can begin loading all our templates from there.&lt;/p&gt;

&lt;p&gt;We also have an &lt;code&gt;initDB()&lt;/code&gt; function that takes care of setting up our connection to the database and returns a pointer reference to our database. Ensure to change the connection string to match that of your database (credentials, host, port, database name etc)&lt;/p&gt;

&lt;p&gt;Inside the &lt;code&gt;main&lt;/code&gt; function, we initialize our router and call our &lt;code&gt;initDB()&lt;/code&gt; database function to initialize our database. This is then followed by all our routes and route handlers and finally, we listen on port &lt;code&gt;4000&lt;/code&gt; which is where we will be serving the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Routes and Handlers
&lt;/h2&gt;

&lt;p&gt;Now let’s begin breaking down our routes and their respective handlers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The &lt;code&gt;GET /&lt;/code&gt; Base Route:&lt;/strong&gt; This is our base route and loads the home page of the application. The handler, &lt;code&gt;Hompage&lt;/code&gt; returns the &lt;code&gt;home.html&lt;/code&gt; file to the client.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The &lt;code&gt;GET /tasks&lt;/code&gt; Route:&lt;/strong&gt; This route uses the &lt;code&gt;fetchTasks&lt;/code&gt; handler to get all our tasks from our database and return them in an HTML list to the client using a &lt;code&gt;todoList&lt;/code&gt; template.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The &lt;code&gt;GET /newtaskform&lt;/code&gt; Route:&lt;/strong&gt; This route will load a new task form from the server each time a user wants to create a new task or clicks a &lt;strong&gt;Add New Task&lt;/strong&gt; button. It uses a &lt;code&gt;addTaskForm&lt;/code&gt; template to display a new HTML form for adding a new task&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The &lt;code&gt;POST /tasks&lt;/code&gt; Route:&lt;/strong&gt; This route calls the &lt;code&gt;addTask&lt;/code&gt; handler to add a new task to the database and return an updated list of all tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The &lt;code&gt;GET /gettaskupdateform/{id}&lt;/code&gt; Route:&lt;/strong&gt; Uses the &lt;code&gt;Id&lt;/code&gt; of a task to load the task into an update form with the &lt;code&gt;updateTaskForm&lt;/code&gt; template and returns this form to the client when the user clicks the &lt;strong&gt;Edit&lt;/strong&gt; button.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The &lt;code&gt;PUT/POST /tasks/{id}&lt;/code&gt; Route:&lt;/strong&gt; Takes the &lt;code&gt;Id&lt;/code&gt; of a task to be updated and updates it using the &lt;code&gt;updateTask&lt;/code&gt; handler. After the update operation, the most recent version of the list is returned as HTML.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The &lt;code&gt;DELETE /tasks/{id}&lt;/code&gt; Route:&lt;/strong&gt; Uses the &lt;code&gt;deleteTask&lt;/code&gt; handler and a task &lt;code&gt;Id&lt;/code&gt; to delete a specific task. Once the task is deleted, an updated list of tasks is returned back to the client.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that’s all the routes and handlers used in this application. &lt;/p&gt;

&lt;p&gt;You may have noticed some other functions asides the route handlers also defined in our &lt;code&gt;main.go&lt;/code&gt; file. These are functions for performing database operations for fetching tasks (&lt;code&gt;getTasks&lt;/code&gt;), getting a single task using its &lt;code&gt;Id&lt;/code&gt; (&lt;code&gt;getTaskByID&lt;/code&gt;), updating a task using its &lt;code&gt;Id&lt;/code&gt; (&lt;code&gt;updateTaskById&lt;/code&gt;), and deleting a task using the tasks’ &lt;code&gt;Id&lt;/code&gt; (&lt;code&gt;deleTaskWithID&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;These helper functions are used within our route handlers to facilitate database operations and keep the handlers lean.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating Our Templates
&lt;/h2&gt;

&lt;p&gt;Now that we are familiar with our Hypermedia API, let’s begin creating the HTML templates that will be retuned in the response to our API calls.&lt;/p&gt;

&lt;p&gt;First, we create &lt;code&gt;home.html&lt;/code&gt; file in the &lt;code&gt;templates&lt;/code&gt; folder. This will load the home page of our task management application. Add the following code to the file after creating it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"X-UA-Compatible"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"IE=edge"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;integrity=&lt;/span&gt;&lt;span class="s"&gt;"sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"&lt;/span&gt; &lt;span class="na"&gt;crossorigin=&lt;/span&gt;&lt;span class="s"&gt;"anonymous"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/htmx.org@1.9.12"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;To Do App&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Tasks&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;

            &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;"/newtaskform"&lt;/span&gt; &lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"#addTaskForm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Add New Item&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"taskList"&lt;/span&gt; &lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;"/tasks"&lt;/span&gt; &lt;span class="na"&gt;hx-trigger=&lt;/span&gt;&lt;span class="s"&gt;"load"&lt;/span&gt; &lt;span class="na"&gt;hx-swap=&lt;/span&gt;&lt;span class="s"&gt;"innerHTML"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- &amp;lt;div class="col"&amp;gt;

        &amp;lt;/div&amp;gt; --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Add New Task&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;

            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"addTaskForm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                {{template "addTaskForm"}}
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This templates forms the shell and layout of the entire application. We have the boilerplate HTML structure and I have also added the &lt;a href="https://getbootstrap.com/" rel="noopener noreferrer"&gt;Bootstrap CSS library&lt;/a&gt; for some basic styling. The &lt;a href="https://htmx.org/" rel="noopener noreferrer"&gt;HTMX library&lt;/a&gt; has also been included through a CDN link.&lt;/p&gt;

&lt;p&gt;The application layout contains two sections. One section for displaying tasks and the other for showing the new task and task update forms.&lt;/p&gt;

&lt;p&gt;The first section contains a button for requesting a new task form from the hypermedia API. Once the form is returned, we then use &lt;code&gt;hx-target&lt;/code&gt; to load the form into the &lt;code&gt;div&lt;/code&gt; with an &lt;code&gt;id&lt;/code&gt; of &lt;code&gt;addTaskForm&lt;/code&gt; in the forms section of the page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;"/newtaskform"&lt;/span&gt; &lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"#addTaskForm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Add New Item&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next component in the first section is the &lt;code&gt;div&lt;/code&gt; where our tasks will be loaded into. This &lt;code&gt;div&lt;/code&gt; uses &lt;code&gt;hx-trigger&lt;/code&gt; to initiate a &lt;code&gt;GET&lt;/code&gt; request to the &lt;code&gt;/tasks&lt;/code&gt; route once the page loads, thus immediately loading the tasks into the page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"taskList"&lt;/span&gt; &lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;"/tasks"&lt;/span&gt; &lt;span class="na"&gt;hx-trigger=&lt;/span&gt;&lt;span class="s"&gt;"load"&lt;/span&gt; &lt;span class="na"&gt;hx-swap=&lt;/span&gt;&lt;span class="s"&gt;"innerHTML"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the second section, as mentioned earlier, we have a &lt;code&gt;div&lt;/code&gt; with an &lt;strong&gt;id&lt;/strong&gt; of &lt;code&gt;addTaskForm&lt;/code&gt; for loading both our new task and update forms. We have also preloaded the form for adding a new task into this &lt;code&gt;div&lt;/code&gt; using Go template import syntax so as to have a default form in place.&lt;/p&gt;

&lt;p&gt;Now let’s create the form for adding a new task next. Inside the &lt;code&gt;templates&lt;/code&gt; folder, create the file &lt;code&gt;addTaskForm.html&lt;/code&gt; and add the following code inside it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{{define "addTaskForm"}}
&lt;span class="nt"&gt;&amp;lt;form&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-control"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"task"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mt-2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-primary"&lt;/span&gt; &lt;span class="na"&gt;hx-post=&lt;/span&gt;&lt;span class="s"&gt;"/tasks"&lt;/span&gt; &lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"#taskList"&lt;/span&gt; &lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"innerHTML"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            Save
        &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
{{end}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This templates loads a fresh form in the UI for adding a new task. When the submit button is clicked, it uses HTMX to send a &lt;code&gt;POST&lt;/code&gt; request to the &lt;code&gt;/tasks&lt;/code&gt; route to add a new task. When the operation is done, it uses HTMX once again to load the response, an updated list of tasks, into the &lt;code&gt;div&lt;/code&gt; with an &lt;strong&gt;id&lt;/strong&gt; of &lt;code&gt;taskList&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next is our update form template. Inside the &lt;code&gt;templates&lt;/code&gt; folder, create the file &lt;code&gt;updateTaskForm.html&lt;/code&gt; and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{{define "updateTaskForm"}}
&lt;span class="nt"&gt;&amp;lt;form&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-control"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"task"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"{{.Task}}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"done"&lt;/span&gt; &lt;span class="err"&gt;{{&lt;/span&gt;&lt;span class="na"&gt;if&lt;/span&gt; &lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Done&lt;/span&gt;&lt;span class="err"&gt;}}&lt;/span&gt; &lt;span class="na"&gt;checked&lt;/span&gt; &lt;span class="err"&gt;{{&lt;/span&gt;&lt;span class="na"&gt;end&lt;/span&gt;&lt;span class="err"&gt;}}&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mt-2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-primary"&lt;/span&gt; &lt;span class="na"&gt;hx-put=&lt;/span&gt;&lt;span class="s"&gt;"/tasks/{{.Id}}"&lt;/span&gt; &lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"#taskList"&lt;/span&gt; &lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"innerHTML"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            Update Task
        &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
{{end}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This template takes in a task to be updated and uses it to pre-populate the update form so that the user can see the previous state of the task to be updated.&lt;/p&gt;

&lt;p&gt;When the &lt;strong&gt;Update Task&lt;/strong&gt; button is clicked, it will send the updated values to the hypermedia API for the task to be updated. Once updated, it loads the updated list into the page.&lt;/p&gt;

&lt;p&gt;Finally, we create the template the returns our list of task items. Inside the &lt;code&gt;templates&lt;/code&gt; folder, create the file &lt;code&gt;todoList.html&lt;/code&gt; and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{{define "todoList"}}
&lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
    {{range .}}
        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="err"&gt;{{&lt;/span&gt;&lt;span class="na"&gt;if&lt;/span&gt; &lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Done&lt;/span&gt;&lt;span class="err"&gt;}}&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"text-decoration:line-through"&lt;/span&gt; &lt;span class="err"&gt;{{&lt;/span&gt;&lt;span class="na"&gt;end&lt;/span&gt;&lt;span class="err"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{.Task}}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
            [&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;"/gettaskupdateform/{{.Id}}"&lt;/span&gt; &lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"#addTaskForm"&lt;/span&gt; &lt;span class="na"&gt;hx-swap=&lt;/span&gt;&lt;span class="s"&gt;"innerHTML"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Edit&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;] | 
            &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;hx-delete=&lt;/span&gt;&lt;span class="s"&gt;"/tasks/{{.Id}}"&lt;/span&gt; 
                        &lt;span class="na"&gt;hx-confirm=&lt;/span&gt;&lt;span class="s"&gt;"Are you sure you want to Delete this Task?"&lt;/span&gt;
                        &lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"#taskList"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;[Delete]&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    {{end}}
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;

{{end}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yeah, a lot is going on in this template, so let’s break it down.&lt;/p&gt;

&lt;p&gt;First, the template takes in a Go &lt;code&gt;slice&lt;/code&gt; of &lt;code&gt;Task&lt;/code&gt; types and loops over it using the &lt;code&gt;range&lt;/code&gt; function to create an HTML list of unordered items.&lt;/p&gt;

&lt;p&gt;The task it displayed in each list item and the &lt;code&gt;Done&lt;/code&gt; property is used to check if the task is completed. If so, we use CSS to strike the task as being completed.&lt;/p&gt;

&lt;p&gt;Just after the task text, we have an &lt;strong&gt;Edit&lt;/strong&gt; button. This button calls the &lt;code&gt;/gettaskupdateform&lt;/code&gt; endpoint to load an update form using the id of the specific task that was clicked. The user can then update the task and get an updated list of task items.&lt;/p&gt;

&lt;p&gt;After the &lt;strong&gt;Edit&lt;/strong&gt; button, we have a Delete button that uses &lt;code&gt;hx-delete&lt;/code&gt; to call the &lt;code&gt;DELETE /tasks/{id}&lt;/code&gt; endpoint so that we can delete the task. But before we can send the delete request, we use &lt;code&gt;hx-confirm&lt;/code&gt; to display a confirmation dialog to the user so that they can confirm if they really want to delete this task item. Once deleted, a new updated list is returned and the task will be gone.&lt;/p&gt;

&lt;p&gt;And with that we wrap up our application, so let’s move on to the fun part, checking it out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running the Application
&lt;/h2&gt;

&lt;p&gt;With all the code in place, now let’s test our application.&lt;/p&gt;

&lt;p&gt;Ensure that all files are saved and run the following command at the root of your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now go to your browser and load the application page at &lt;code&gt;http://localhost:4000&lt;/code&gt;. If you have used a different port, ensure that you’re using that port to load the app.&lt;/p&gt;

&lt;p&gt;Now you should see your application as displayed below. See below as we add a new task, update an existing task and delete a task from our task list&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbgv5u945hjtnoscqimow.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbgv5u945hjtnoscqimow.gif" alt="todo-demo-ezgif.com-crop.gif" width="525" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If you have enjoyed this article, and will like to learn more about building projects with HTMX,  I’ll like you to check out &lt;a href="https://www.udemy.com/course/htmx-go-build-fullstack-applications-with-golang-and-htmx/?couponCode=F92B5F6CD6297B66643D" rel="noopener noreferrer"&gt;&lt;strong&gt;HTMX + Go: Build Fullstack Applications with Golang and HTMX&lt;/strong&gt;&lt;/a&gt;, and &lt;a href="https://www.udemy.com/course/the-complete-htmx-course/?couponCode=E3B0B3DBAC2964EE2079" rel="noopener noreferrer"&gt;&lt;strong&gt;The Complete HTMX Course: Zero to Pro with HTMX&lt;/strong&gt;&lt;/a&gt; to further expand your knowledge on building hypermedia-driven applications with HTMX.&lt;/p&gt;

&lt;p&gt;Happy Coding :)&lt;/p&gt;

</description>
      <category>htmx</category>
      <category>go</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
