<?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: Jason Huang</title>
    <description>The latest articles on DEV Community by Jason Huang (@jason_huang_cat).</description>
    <link>https://dev.to/jason_huang_cat</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3938019%2F53ba58ff-624d-4842-9bf7-af6f3fc4e554.jpg</url>
      <title>DEV Community: Jason Huang</title>
      <link>https://dev.to/jason_huang_cat</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jason_huang_cat"/>
    <language>en</language>
    <item>
      <title>Building an AI Agent in Go: What I Learned</title>
      <dc:creator>Jason Huang</dc:creator>
      <pubDate>Mon, 18 May 2026 12:25:11 +0000</pubDate>
      <link>https://dev.to/jason_huang_cat/building-an-ai-agent-in-go-what-i-learned-2nh1</link>
      <guid>https://dev.to/jason_huang_cat/building-an-ai-agent-in-go-what-i-learned-2nh1</guid>
      <description>&lt;p&gt;Hey DEV community! 👋&lt;/p&gt;

&lt;p&gt;I'm an undergraduate developer who recently shipped &lt;strong&gt;OpenAgent&lt;/strong&gt; — a local AI Agent that runs as a single binary. No dependencies, no Docker, just download and double-click.&lt;/p&gt;

&lt;p&gt;This post isn't about marketing. It's about the technical decisions, mistakes, and lessons from building an AI Agent in a language most people don't associate with AI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project:&lt;/strong&gt; &lt;a href="https://github.com/the-open-agent/openagent" rel="noopener noreferrer"&gt;github.com/the-open-agent/openagent&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Go for an AI Agent?
&lt;/h2&gt;

&lt;p&gt;The obvious question: &lt;em&gt;"Isn't AI Python's territory?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's what I realized: &lt;strong&gt;AI Agents spend 90% of their time waiting on LLM APIs, not crunching numbers.&lt;/strong&gt; The bottleneck isn't language performance — it's architecture. How you orchestrate tools, manage state, handle concurrency, and ship to users.&lt;/p&gt;

&lt;p&gt;Go excels at exactly those things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Static compilation&lt;/strong&gt; → single distributable binary&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Goroutines&lt;/strong&gt; → handle concurrent tool calls without memory explosion&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-platform&lt;/strong&gt; → Windows/Mac/Linux from one codebase&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero runtime dependencies&lt;/strong&gt; → users don't install anything&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a "download and run" experience, these trade-offs beat Python's ecosystem richness.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lesson 1: Embedding Frontend into a Go Binary
&lt;/h2&gt;

&lt;p&gt;I wanted a web UI without shipping separate static files. Go 1.16+ makes this trivial with the &lt;code&gt;embed&lt;/code&gt; package:&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="s"&gt;"embed"&lt;/span&gt;

&lt;span class="c"&gt;//go:embed all:dist&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;distFS&lt;/span&gt; &lt;span class="n"&gt;embed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FS&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="c"&gt;// Serve React build directly from binary&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;Handle&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;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileServer&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;FS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;distFS&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;":14000"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What I learned:&lt;/strong&gt; The &lt;code&gt;all:&lt;/code&gt; prefix is crucial. Without it, files starting with &lt;code&gt;_&lt;/code&gt; or &lt;code&gt;.&lt;/code&gt; get skipped, and your React build might mysteriously break.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build process:&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;&lt;span class="c"&gt;# Build React app&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;frontend &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run build

&lt;span class="c"&gt;# Go embeds the dist folder automatically&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; .. &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; go build &lt;span class="nt"&gt;-o&lt;/span&gt; openagent &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One file. Frontend and backend. No path resolution bugs, no "where did my assets go" issues.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lesson 2: Shell Access Without Footguns
&lt;/h2&gt;

&lt;p&gt;Giving an AI Agent shell access is powerful but dangerous. I spent significant time on safety boundaries in &lt;code&gt;tool/shell.go&lt;/code&gt;:&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;type&lt;/span&gt; &lt;span class="n"&gt;ShellConfig&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;DefaultTimeout&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt; &lt;span class="c"&gt;// 30s default&lt;/span&gt;
    &lt;span class="n"&gt;MaxTimeout&lt;/span&gt;     &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt; &lt;span class="c"&gt;// 300s hard limit&lt;/span&gt;
    &lt;span class="n"&gt;EnablePTY&lt;/span&gt;      &lt;span class="kt"&gt;bool&lt;/span&gt;          &lt;span class="c"&gt;// Interactive mode&lt;/span&gt;
    &lt;span class="n"&gt;AuditLog&lt;/span&gt;       &lt;span class="kt"&gt;bool&lt;/span&gt;          &lt;span class="c"&gt;// Log every command&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ShellSession&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;string&lt;/span&gt;
    &lt;span class="n"&gt;State&lt;/span&gt;   &lt;span class="n"&gt;SessionState&lt;/span&gt; &lt;span class="c"&gt;// idle | running | waiting_input&lt;/span&gt;
    &lt;span class="n"&gt;Timeout&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Time&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key design decisions:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Session-based flow&lt;/strong&gt; — &lt;code&gt;poll/write/submit&lt;/code&gt; pattern instead of streaming stdout&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timeouts at two levels&lt;/strong&gt; — default prevents runaways, max prevents abuse&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optional PTY&lt;/strong&gt; — interactive programs work, but only when explicitly enabled&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit logging&lt;/strong&gt; — every command logged with timestamp and output hash&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;What I learned:&lt;/strong&gt; Users will accidentally run &lt;code&gt;rm -rf /&lt;/code&gt; or fork bombs. Design for the worst case, not the happy path.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lesson 3: Memory-Conscious Concurrency
&lt;/h2&gt;

&lt;p&gt;I ran a stress test: 80 concurrent health checks. Memory grew by &lt;strong&gt;10 MB&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here's why Go's model works for Agents:&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="c"&gt;// Each tool call gets its own goroutine&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ExecuteTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&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;tool&lt;/span&gt; &lt;span class="n"&gt;Tool&lt;/span&gt;&lt;span class="p"&gt;)&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="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;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Timeout&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;cancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;resultChan&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;resultChan&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;resultChan&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ctx&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="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&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;ctx&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="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;&lt;strong&gt;What I learned:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Goroutines are cheap (~2KB stack), but channels need buffering to prevent leaks&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;context.Context&lt;/code&gt; is your friend for cancellation and timeouts&lt;/li&gt;
&lt;li&gt;Always &lt;code&gt;defer cancel()&lt;/code&gt; — goroutine leaks are subtle and painful to debug&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compare to Node.js: each concurrent operation holds the entire event loop. Memory grows with concurrency. Go's model scales horizontally.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lesson 4: Streaming LLM Responses
&lt;/h2&gt;

&lt;p&gt;Users expect typing effects, not wall-of-text responses. Implementing SSE (Server-Sent Events) with Go:&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;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ChatStream&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;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"text/event-stream"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cache-Control"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"no-cache"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Connection"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"keep-alive"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;flusher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&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;Flusher&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&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="s"&gt;"Streaming not supported"&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="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChatStream&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;Context&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;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;stream&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;Fprintf&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;"data: %s&lt;/span&gt;&lt;span class="se"&gt;\n\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;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;flusher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Flush&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What I learned:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;http.Flusher&lt;/code&gt; interface is required — not all ResponseWriters support it&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;\n\n&lt;/code&gt; after &lt;code&gt;data:&lt;/code&gt; is mandatory per SSE spec&lt;/li&gt;
&lt;li&gt;Always handle client disconnects — &lt;code&gt;r.Context()&lt;/code&gt; cancels when they close the tab&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Lesson 5: Tool Calling Architecture
&lt;/h2&gt;

&lt;p&gt;The heart of an Agent is deciding &lt;em&gt;which&lt;/em&gt; tool to use and &lt;em&gt;when&lt;/em&gt;. I settled on this interface:&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;type&lt;/span&gt; &lt;span class="n"&gt;Tool&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RawMessage&lt;/span&gt; &lt;span class="c"&gt;// JSON Schema for LLM&lt;/span&gt;
    &lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&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;input&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RawMessage&lt;/span&gt;&lt;span class="p"&gt;)&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="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="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Agent&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;tools&lt;/span&gt;   &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;Tool&lt;/span&gt;
    &lt;span class="n"&gt;llm&lt;/span&gt;     &lt;span class="n"&gt;LLMClient&lt;/span&gt;
    &lt;span class="n"&gt;history&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="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&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;userInput&lt;/span&gt; &lt;span class="kt"&gt;string&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="c"&gt;// 1. Add user message to history&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;history&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;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UserMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userInput&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// 2. Ask LLM what to do&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Complete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;availableTools&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="c"&gt;// 3. If LLM wants to use a tool&lt;/span&gt;
        &lt;span class="k"&gt;if&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;ToolCall&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;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;executeTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&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;ToolCall&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;history&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;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ToolMessage&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;continue&lt;/span&gt; &lt;span class="c"&gt;// Loop back for next decision&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c"&gt;// 4. Final answer&lt;/span&gt;
        &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;history&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;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AssistantMessage&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;Content&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What I learned:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The loop pattern (LLM decides → tool executes → LLM decides again) is surprisingly robust&lt;/li&gt;
&lt;li&gt;Tool schemas must be precise — vague descriptions lead to wrong tool selection&lt;/li&gt;
&lt;li&gt;History management is critical — context windows fill up fast&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Lesson 6: Error Handling in Distributed Systems
&lt;/h2&gt;

&lt;p&gt;An Agent is essentially a distributed system: LLM API, local tools, browser automation, file I/O. Things fail constantly.&lt;/p&gt;

&lt;p&gt;My error taxonomy:&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;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ErrToolTimeout&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tool execution timed out"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ErrToolNotFound&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tool not found"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ErrLLMRateLimit&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"LLM rate limited"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ErrLLMContextLimit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"context window exceeded"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ErrUserCancel&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user cancelled"&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;executeWithRetry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&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;tool&lt;/span&gt; &lt;span class="n"&gt;Tool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RawMessage&lt;/span&gt;&lt;span class="p"&gt;)&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="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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;attempt&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;attempt&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="o"&gt;++&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;tool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input&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;result&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="c"&gt;// Don't retry user cancellations&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Is&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;ErrUserCancel&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="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="p"&gt;}&lt;/span&gt;

        &lt;span class="c"&gt;// Exponential backoff for rate limits&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Is&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;ErrLLMRateLimit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c"&gt;// Non-retryable error&lt;/span&gt;
        &lt;span class="k"&gt;return&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="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&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;ErrMaxRetriesExceeded&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What I learned:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;errors.Is()&lt;/code&gt; and &lt;code&gt;errors.As()&lt;/code&gt; are essential for error classification&lt;/li&gt;
&lt;li&gt;Not all errors are retryable — know when to fail fast&lt;/li&gt;
&lt;li&gt;Context cancellation should propagate immediately, not retry&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Lesson 7: Testing Agents is Hard
&lt;/h2&gt;

&lt;p&gt;How do you test something that calls external LLMs? My approach:&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="c"&gt;// Mock LLM for deterministic tests&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;MockLLM&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;Responses&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;LLMResponse&lt;/span&gt;
    &lt;span class="n"&gt;CallCount&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;MockLLM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Complete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&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;history&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;tools&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Tool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LLMResponse&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CallCount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&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;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Responses&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="n"&gt;LLMResponse&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"unexpected LLM call"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Responses&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CallCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CallCount&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;resp&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;TestAgentToolLoop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mock&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;MockLLM&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Responses&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;LLMResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ToolCall&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ToolCall&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"calculator"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;`{"expr": "2+2"}`&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"The answer is 4"&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="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Tool&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;CalculatorTool&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;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"What's 2+2?"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NoError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&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;assert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CallCount&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;&lt;strong&gt;What I learned:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mock the LLM, test the orchestration logic&lt;/li&gt;
&lt;li&gt;Integration tests with real LLMs are flaky and slow — keep them minimal&lt;/li&gt;
&lt;li&gt;Record/replay patterns work well for regression testing&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What I'd Do Differently
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Start with the binary constraint&lt;/strong&gt;&lt;br&gt;
I initially prototyped in Python, then rewrote in Go. Waste of time. If the constraint is "single binary," start with Go (or Rust).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Design state management earlier&lt;/strong&gt;&lt;br&gt;
I underestimated how complex conversation state gets. Tool results, errors, user corrections, context window management — it piles up fast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Invest in observability from day one&lt;/strong&gt;&lt;br&gt;
Debugging an Agent is like debugging a distributed system blindfolded. Structured logging and tracing are non-negotiable.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Building an AI Agent in Go was the right call for this project. The language's strengths (static binaries, concurrency, simplicity) aligned perfectly with the goal of "download and run."&lt;/p&gt;

&lt;p&gt;Is Go the right choice for every AI project? No. If you're training models or doing heavy data science, Python's ecosystem is unmatched. But for shipping a tool that &lt;em&gt;uses&lt;/em&gt; AI? Go is surprisingly effective.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you're curious, check out the code:&lt;/strong&gt; &lt;a href="https://github.com/the-open-agent/openagent" rel="noopener noreferrer"&gt;github.com/the-open-agent/openagent&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'd love to hear your thoughts — especially if you've built Agents in other languages. What worked? What didn't?&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with Go, excessive amounts of coffee, and the stubborn belief that software should just work.&lt;/em&gt; ☕&lt;/p&gt;

</description>
      <category>ai</category>
      <category>discuss</category>
      <category>productivity</category>
      <category>llm</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Jason Huang</dc:creator>
      <pubDate>Mon, 18 May 2026 12:20:45 +0000</pubDate>
      <link>https://dev.to/jason_huang_cat/-5dj8</link>
      <guid>https://dev.to/jason_huang_cat/-5dj8</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/jason_huang_cat/just-download-and-run-openagent-launches-possibly-the-most-hassle-free-local-ai-agent-4b09" class="crayons-story__hidden-navigation-link"&gt;Just Download and Run: OpenAgent Launches, Possibly the Most Hassle-Free Local AI Agent&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/jason_huang_cat" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F3938019%2F53ba58ff-624d-4842-9bf7-af6f3fc4e554.jpg" alt="jason_huang_cat profile" class="crayons-avatar__image" width="800" height="792"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/jason_huang_cat" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Jason Huang
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Jason Huang
                
              
              &lt;div id="story-author-preview-content-3693377" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/jason_huang_cat" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F3938019%2F53ba58ff-624d-4842-9bf7-af6f3fc4e554.jpg" class="crayons-avatar__image" alt="" width="800" height="792"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Jason Huang&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/jason_huang_cat/just-download-and-run-openagent-launches-possibly-the-most-hassle-free-local-ai-agent-4b09" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 18&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/jason_huang_cat/just-download-and-run-openagent-launches-possibly-the-most-hassle-free-local-ai-agent-4b09" id="article-link-3693377"&gt;
          Just Download and Run: OpenAgent Launches, Possibly the Most Hassle-Free Local AI Agent
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/productivity"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;productivity&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/security"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;security&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/jason_huang_cat/just-download-and-run-openagent-launches-possibly-the-most-hassle-free-local-ai-agent-4b09" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;5&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/jason_huang_cat/just-download-and-run-openagent-launches-possibly-the-most-hassle-free-local-ai-agent-4b09#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              1&lt;span class="hidden s:inline"&gt; comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            6 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>I Built a Single-File AI Agent in Go — Zero Dependencies, Double-Click to Run</title>
      <dc:creator>Jason Huang</dc:creator>
      <pubDate>Mon, 18 May 2026 12:20:08 +0000</pubDate>
      <link>https://dev.to/jason_huang_cat/i-built-a-single-file-ai-agent-in-go-zero-dependencies-double-click-to-run-4g9b</link>
      <guid>https://dev.to/jason_huang_cat/i-built-a-single-file-ai-agent-in-go-zero-dependencies-double-click-to-run-4g9b</guid>
      <description>&lt;p&gt;Hey DEV community! 👋&lt;/p&gt;

&lt;p&gt;I'm an undergrad developer who spent the last few months hacking on something I'm excited to share: &lt;strong&gt;OpenAgent&lt;/strong&gt; — a local AI Agent that ships as a single binary. No Docker. No Node.js. No Python environments. Just download the &lt;code&gt;.exe&lt;/code&gt; and double-click.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/the-open-agent/openagent" rel="noopener noreferrer"&gt;github.com/the-open-agent/openagent&lt;/a&gt; ⭐&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem I Was Trying to Solve
&lt;/h2&gt;

&lt;p&gt;Like many of you, I've been experimenting with AI Agents for everything from code generation to automating tedious tasks. But I kept hitting the same friction:&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="c"&gt;# Typical "getting started" experience&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; some-agent
&lt;span class="c"&gt;# 847 packages installed...&lt;/span&gt;
&lt;span class="c"&gt;# Oh, you need Python 3.9+ too&lt;/span&gt;
pip &lt;span class="nb"&gt;install&lt;/span&gt; ...
&lt;span class="c"&gt;# Also Docker for the vector DB&lt;/span&gt;
docker-compose up
&lt;span class="c"&gt;# 12 minutes later...&lt;/span&gt;
&lt;span class="c"&gt;# Wait, why is this 400MB?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sound familiar? I wanted something that felt more like:&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="c"&gt;# Download openagent.exe (23MB)&lt;/span&gt;
&lt;span class="c"&gt;# Double-click&lt;/span&gt;
&lt;span class="c"&gt;# Done ✅&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So I built it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Makes OpenAgent Different
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Single Binary, Zero Runtime Dependencies
&lt;/h3&gt;

&lt;p&gt;I wrote OpenAgent in &lt;strong&gt;Go&lt;/strong&gt; with a specific constraint: everything must compile into one executable. The React frontend gets embedded at build time. The backend is pure Go. One process, one port (14000), one file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The result:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;23 MB&lt;/strong&gt; executable (vs 400MB+ for typical setups)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;~2.7s&lt;/strong&gt; cold start (vs 30s for alternatives)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;~110 MB&lt;/strong&gt; idle memory&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  It's Not Just "Hello World"
&lt;/h3&gt;

&lt;p&gt;Despite being a single file, OpenAgent packs real capabilities:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Details&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🤖 &lt;strong&gt;Models&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;30+ providers: OpenAI, Claude, DeepSeek, Gemini, Mistral, Grok...&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🌐 &lt;strong&gt;Browser&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Real browser automation (navigation, clicks, forms, screenshots)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🖥️ &lt;strong&gt;Shell&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Local command execution with PTY support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📄 &lt;strong&gt;Office&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Read/write Word, Excel, PowerPoint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔗 &lt;strong&gt;MCP&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Plug-and-play with any MCP-compatible server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📚 &lt;strong&gt;RAG&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;PDF/Word/Excel → automatic chunking, embedding, indexing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⚡ &lt;strong&gt;Workflows&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;BPMN-style visual orchestration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📊 &lt;strong&gt;Dashboard&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Token usage, activity logs, tool management&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Why Go Instead of Python?
&lt;/h2&gt;

&lt;p&gt;"But isn't AI/ML Python's domain?"&lt;/p&gt;

&lt;p&gt;Here's the thing: &lt;strong&gt;Agent performance is bottlenecked by LLM API calls, not language execution speed.&lt;/strong&gt; The magic happens in the &lt;em&gt;architecture&lt;/em&gt; — how you orchestrate tools, manage state, handle concurrency.&lt;/p&gt;

&lt;p&gt;Go gives me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Static compilation&lt;/strong&gt; → single distributable binary&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Goroutines&lt;/strong&gt; → efficient concurrency without the memory bloat&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-platform&lt;/strong&gt; → Windows/Mac/Linux from one codebase&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No runtime&lt;/strong&gt; → users don't install anything&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a "personal local Agent," these trade-offs beat Python's dynamic flexibility.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Windows (easiest):&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download &lt;code&gt;openagent_Windows_x86_64.exe&lt;/code&gt; from &lt;a href="https://github.com/the-open-agent/openagent/releases" rel="noopener noreferrer"&gt;Releases&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Double-click&lt;/li&gt;
&lt;li&gt;Open &lt;a href="http://localhost:14000" rel="noopener noreferrer"&gt;http://localhost:14000&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;macOS/Linux:&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;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/the-open-agent/openagent/master/scripts/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Configure your model:&lt;/strong&gt;&lt;br&gt;
The UI has a one-click setup for OpenAI, Claude, DeepSeek, or any OpenRouter-compatible provider.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Engineering Decisions I'm Proud Of
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Shell with Guardrails
&lt;/h3&gt;

&lt;p&gt;Shell access is powerful but dangerous. In &lt;code&gt;tool/shell.go&lt;/code&gt;, I built in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Default 30s timeout (max 300s)&lt;/li&gt;
&lt;li&gt;Session-based &lt;code&gt;poll/write/submit&lt;/code&gt; flow&lt;/li&gt;
&lt;li&gt;Optional PTY for interactive programs&lt;/li&gt;
&lt;li&gt;Audit logging for every command&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's designed as a &lt;strong&gt;production tool&lt;/strong&gt;, not a foot-gun.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Memory-Conscious Concurrency
&lt;/h3&gt;

&lt;p&gt;I ran an 80-concurrent health check stress test. Memory grew by &lt;strong&gt;10 MB&lt;/strong&gt;. Go's goroutine + channel model makes this trivial compared to the memory curves I've seen in Node.js-based agents.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Frontend Embedded, Not Served
&lt;/h3&gt;

&lt;p&gt;The React build gets embedded into the binary with Go's &lt;code&gt;embed&lt;/code&gt; package. No separate static files to manage, no path resolution issues, no "where did my assets go" bugs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real Talk: What's Not Perfect
&lt;/h2&gt;

&lt;p&gt;I want to be transparent about where we stand:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;OpenAgent&lt;/th&gt;
&lt;th&gt;OpenClaw&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Lighthouse Score&lt;/td&gt;
&lt;td&gt;45&lt;/td&gt;
&lt;td&gt;87&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Health Check P50&lt;/td&gt;
&lt;td&gt;~33ms&lt;/td&gt;
&lt;td&gt;~20ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Our frontend loading needs work. The Lighthouse gap is real — we're optimizing it. The health check difference is milliseconds, but still.&lt;/p&gt;

&lt;p&gt;If you find cases where we're slower or more expensive, &lt;strong&gt;file an issue&lt;/strong&gt;. I genuinely want to know.&lt;/p&gt;




&lt;h2&gt;
  
  
  Who This Is For
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Developers&lt;/strong&gt; who want a Claude Code alternative that runs locally with their own API keys&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy-conscious users&lt;/strong&gt; who don't want data leaving their machine&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource-limited setups&lt;/strong&gt; where running multiple agents used to be impossible&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security folks&lt;/strong&gt; who need audit trails and controlled shell access&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Get Involved
&lt;/h2&gt;

&lt;p&gt;OpenAgent is Apache 2.0 licensed. The code is on GitHub, and I review issues/PRs within 12 hours.&lt;/p&gt;

&lt;p&gt;If the project helps you, a ⭐ means a lot. If you want to contribute, there are plenty of &lt;code&gt;good first issue&lt;/code&gt; labels waiting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/the-open-agent/openagent" rel="noopener noreferrer"&gt;github.com/the-open-agent/openagent&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Discord:&lt;/strong&gt; &lt;a href="https://discord.gg/5rPsrAzK7S" rel="noopener noreferrer"&gt;discord.gg/5rPsrAzK7S&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bigger Picture
&lt;/h2&gt;

&lt;p&gt;I believe personal AI Agents should be &lt;strong&gt;lighter, not heavier&lt;/strong&gt;. One file. Double-click. Done.&lt;/p&gt;

&lt;p&gt;No 400MB installs. No dependency hell. No "it works on my machine."&lt;/p&gt;

&lt;p&gt;Just an Agent that does the job and gets out of your way.&lt;/p&gt;

&lt;p&gt;That's OpenAgent.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with Go, caffeine, and the stubborn belief that software should just work.&lt;/em&gt; ☕&lt;/p&gt;

</description>
      <category>ai</category>
      <category>go</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
    <item>
      <title>OpenAgent - My Journey Building a Zero-Config Local AI Agent</title>
      <dc:creator>Jason Huang</dc:creator>
      <pubDate>Mon, 18 May 2026 12:13:55 +0000</pubDate>
      <link>https://dev.to/jason_huang_cat/openagent-my-journey-building-a-zero-config-local-ai-agent-411n</link>
      <guid>https://dev.to/jason_huang_cat/openagent-my-journey-building-a-zero-config-local-ai-agent-411n</guid>
      <description>&lt;p&gt;Hi everyone! I'm an undergraduate student and a developer on the OpenAgent open-source team.&lt;/p&gt;

&lt;p&gt;We spent two months building a truly zero-configuration, zero-dependency, double-click-to-run personal local single-file Agent 🦞 with Go. It truly works out of the box, and it has garnered significant attention in the community.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenAgent&lt;/strong&gt; is an open-source local AI Agent for individual developers and tech enthusiasts. Similar to OpenClaw and Hermes in the "personal local assistant" space, but we've taken a completely different approach: written in Go as a single binary executable — download the .exe, double-click to run, zero configuration out of the box.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project:&lt;/strong&gt; &lt;a href="https://github.com/the-open-agent/openagent" rel="noopener noreferrer"&gt;https://github.com/the-open-agent/openagent&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If this project's features or architecture help you, we'd appreciate a star ⭐&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Why We Built This
&lt;/h2&gt;

&lt;p&gt;More and more people are using AI to get work done — not just coding, but creating presentations, running scripts, researching, organizing documents. But after using these tools for a while, most people hit the same wall: &lt;strong&gt;deployment costs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Many well-known Agents are structural dependency monsters — a complete environment requires Node.js, Python, Docker, WSL, nested layer by layer. The problem usually isn't the model itself, but the Agent's delivery format: dependency bloat, tens of thousands of scattered files, complex configuration, difficult migration. Each layer drains user patience, and the monthly bill delivers the final lesson.&lt;/p&gt;

&lt;p&gt;OpenAgent's trade-offs were clear from day one: &lt;strong&gt;make "single-file zero-config" a top-level design goal&lt;/strong&gt;, not an afterthought patch. We chose a harder path — rewriting from scratch in Go as a single binary, with no runtime dependencies, no installer, no Docker. The frontend React is embedded directly into the binary, the backend is pure Go, one process listening on port 14000.&lt;/p&gt;

&lt;p&gt;This is OpenAgent today.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. More Than Lightweight — A Complete Agent Work Platform
&lt;/h2&gt;

&lt;p&gt;OpenAgent isn't just a fast single-file executable. It comes with a full suite of capabilities for daily workflows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;🤖 30+ Model Providers&lt;/strong&gt;: OpenAI, Claude, DeepSeek, Gemini, Mistral, Grok... Switch anytime without code changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🌐 Browser-Use&lt;/strong&gt;: Drive real browsers for navigation, clicking, form filling, screenshots&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🖥️ Shell Execution&lt;/strong&gt;: Local command execution with PTY interactive session support&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;📄 Office Automation&lt;/strong&gt;: Read and write Word, Excel, PowerPoint&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🔗 MCP Integration&lt;/strong&gt;: Any MCP-compatible server, plug and play&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;📚 RAG Knowledge Base&lt;/strong&gt;: Automatic slicing, embedding, and indexing of PDF/Word/Excel&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;⚡ Workflow Orchestration&lt;/strong&gt;: BPMN-style visual drag-and-drop orchestration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;📊 Admin Dashboard&lt;/strong&gt;: Token usage statistics, activity monitoring, tool management, request logs&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Why Better Performance and Lower Latency — 3 Engineering Decisions
&lt;/h2&gt;

&lt;p&gt;Not "cutting features for performance" — every layer made the right choice.&lt;/p&gt;

&lt;h3&gt;
  
  
  ① Single Binary: One File, Zero Dependencies
&lt;/h3&gt;

&lt;p&gt;Go static compilation, frontend React build embedded directly into the binary. Windows users download the .exe and double-click to run — no WSL, no Docker, no Node.js. Mac/Linux one-command install. This is what a "personal local Agent" delivery should look like.&lt;/p&gt;

&lt;h3&gt;
  
  
  ② Shell Execution with Boundaries, Safe and Controllable
&lt;/h3&gt;

&lt;p&gt;At the source code level, &lt;code&gt;tool/shell.go&lt;/code&gt; defines default timeout 30 seconds, max 300 seconds, optional PTY, session-based &lt;code&gt;poll/write/submit&lt;/code&gt; mechanisms. Shell capability is &lt;strong&gt;strongly constrained production-grade tooling&lt;/strong&gt; by default, not unlimited remote execution. Also supports audit logs, SSO, request logs, and enterprise-grade observability.&lt;/p&gt;

&lt;h3&gt;
  
  
  ③ Go Native Concurrency, Memory Controllable
&lt;/h3&gt;

&lt;p&gt;Go's goroutine + channel model keeps memory growth very restrained in high-concurrency scenarios. 80-concurrent health stress test, memory grew only 10 MB. Compare to Node.js memory curves — this is a structural advantage at the language level.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. About the Go Rewrite
&lt;/h2&gt;

&lt;p&gt;Some might ask: Isn't AI Agent Python's territory? Why Go?&lt;/p&gt;

&lt;p&gt;Agent bottlenecks are in &lt;strong&gt;LLM calls, not language performance&lt;/strong&gt; — what makes an Agent run well is Harness-layer architecture design, not underlying language execution speed. Go's advantages: &lt;strong&gt;static compilation single file, controllable memory, clean concurrency model, native cross-platform support&lt;/strong&gt;. These characteristics matter more than Python's dynamic flexibility for the "personal local Agent" use case.&lt;/p&gt;

&lt;p&gt;We wrote in Go for three months, from zero to one, building this core.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Finally
&lt;/h2&gt;

&lt;p&gt;OpenAgent is an Apache 2.0 open-source project, all code on GitHub, welcome to review, Star, and file issues.&lt;/p&gt;

&lt;p&gt;We firmly believe: &lt;strong&gt;The future of personal local Agents isn't getting heavier, it's getting lighter.&lt;/strong&gt; One file, double-click to run — that's what users really want.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/the-open-agent/openagent" rel="noopener noreferrer"&gt;https://github.com/the-open-agent/openagent&lt;/a&gt; ⭐&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>programming</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Just Download and Run: OpenAgent Launches, Possibly the Most Hassle-Free Local AI Agent</title>
      <dc:creator>Jason Huang</dc:creator>
      <pubDate>Mon, 18 May 2026 12:07:15 +0000</pubDate>
      <link>https://dev.to/jason_huang_cat/just-download-and-run-openagent-launches-possibly-the-most-hassle-free-local-ai-agent-4b09</link>
      <guid>https://dev.to/jason_huang_cat/just-download-and-run-openagent-launches-possibly-the-most-hassle-free-local-ai-agent-4b09</guid>
      <description>&lt;p&gt;Hi DEV community, I'm a developer from the OpenAgent team and a long-time lurker here.&lt;/p&gt;

&lt;p&gt;Today, I want to introduce a project we've been refining for quite some time — &lt;strong&gt;OpenAgent&lt;/strong&gt;, an open-source local AI Agent for individual developers and tech enthusiasts. Similar to OpenClaw and Hermes in the "personal local assistant" space, but we've taken a completely different approach: &lt;strong&gt;written in Go as a single binary executable — download the .exe, double-click to run, zero configuration out of the box.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One-liner positioning: A ready-to-use single-file local Agent with better stability, lower latency, and minimal resource footprint.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/the-open-agent/openagent" rel="noopener noreferrer"&gt;github.com/the-open-agent/openagent&lt;/a&gt; (Stars appreciated ⭐)&lt;/p&gt;

&lt;p&gt;Official Website: &lt;a href="https://www.openagentai.org" rel="noopener noreferrer"&gt;openagentai.org&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Why We Built This
&lt;/h2&gt;

&lt;p&gt;More and more people are using AI to get work done — not just coding, but creating presentations, running scripts, researching, organizing documents, even security scanning. But after using these tools for a while, most people hit the same wall: &lt;strong&gt;deployment costs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Many "well-known" Agents are structural dependency monsters — a complete environment requires Node.js, Python, Docker, WSL, nested layer by layer. The problem usually isn't the model itself, but the Agent's delivery format: &lt;strong&gt;dependency bloat, tens of thousands of scattered files, complex configuration, difficult migration&lt;/strong&gt;. Each layer drains user patience, and the monthly bill delivers the final lesson.&lt;/p&gt;

&lt;p&gt;OpenAgent's trade-offs were clear from day one: &lt;strong&gt;make "single-file zero-config" a top-level design goal&lt;/strong&gt;, not an afterthought patch. We chose a harder path — &lt;strong&gt;rewriting from scratch in Go as a single binary&lt;/strong&gt;, with no runtime dependencies, no installer, no Docker. The frontend React is embedded directly into the binary, the backend is pure Go, one process listening on port 14000.&lt;/p&gt;

&lt;p&gt;This is OpenAgent today.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. More Than Lightweight — A Complete Agent Work Platform
&lt;/h2&gt;

&lt;p&gt;OpenAgent isn't just a fast single-file executable. It comes with a full suite of capabilities for daily workflows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;🤖 30+ Model Providers&lt;/strong&gt;: OpenAI, Claude, DeepSeek, Gemini, Mistral, Grok... Switch anytime without code changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🌐 Browser-Use&lt;/strong&gt;: Drive real browsers for navigation, clicking, form filling, screenshots&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🖥️ Shell Execution&lt;/strong&gt;: Local command execution with PTY interactive session support&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;📄 Office Automation&lt;/strong&gt;: Read and write Word, Excel, PowerPoint&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🔗 MCP Integration&lt;/strong&gt;: Any MCP-compatible server, plug and play&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;📚 RAG Knowledge Base&lt;/strong&gt;: Automatic slicing, embedding, and indexing of PDF/Word/Excel&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;⚡ Workflow Orchestration&lt;/strong&gt;: BPMN-style visual drag-and-drop orchestration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;📊 Admin Dashboard&lt;/strong&gt;: Token usage statistics, activity monitoring, tool management, request logs&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Let's Look at the Data: Performance and Latency Benchmarks vs OpenClaw
&lt;/h2&gt;

&lt;p&gt;Architecture done — but how does it actually perform? We spent over ten days on horizontal benchmarking, putting OpenAgent and OpenClaw on the same starting line. &lt;strong&gt;Both use deepseek/deepseek-v4-flash as the underlying model&lt;/strong&gt;, currently the most cost-effective model that best exposes the true capabilities of each Agent Harness.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 Agent Tool Invocation Benchmark (Core Performance)
&lt;/h3&gt;

&lt;p&gt;12 tasks × 3 rounds = 36 scoring runs, same model, same prompt:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;OpenAgent&lt;/th&gt;
&lt;th&gt;OpenClaw&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Success Rate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;83.33%&lt;/strong&gt; (30/36)&lt;/td&gt;
&lt;td&gt;61.11% (22/36)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Avg. Time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;14,183 ms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;26,128 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Avg. Tokens&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1,312&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2,362&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compliance Rate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;90.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;76.67&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Coverage Rate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;97.5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;91.67&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Overall Score&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;91.14&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;78.41&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;One-sentence summary&lt;/strong&gt;: Higher success rate, faster speed, fewer tokens. OpenAgent averages ~11.9 seconds less per round, with ~1,050 fewer tokens consumed. 36 real execution rounds, scored by automated scripts, zero human intervention.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2 Conversation Scenario Performance
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;OpenAgent&lt;/th&gt;
&lt;th&gt;OpenClaw&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Completion Rate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;95%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Format Accuracy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;82.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Factual Accuracy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;92.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Avg. Latency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3,991 ms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;26,781 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;OpenAgent achieves 100% completion rate, format accuracy, and factual accuracy in conversation scenarios, with average latency around 4 seconds; OpenClaw averages around 26.8 seconds.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.3 Project Performance
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;OpenAgent&lt;/th&gt;
&lt;th&gt;OpenClaw&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cold Start Ready&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~2.7 s&lt;/td&gt;
&lt;td&gt;~29.2 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Resident Memory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~110 MB&lt;/td&gt;
&lt;td&gt;~215–307 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Install Size&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;exe ~23 MB&lt;/td&gt;
&lt;td&gt;~382 MB / 42,000+ files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TTFT (Time to First Token)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~23 ms&lt;/td&gt;
&lt;td&gt;~44 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Cold Start&lt;/strong&gt;: OpenAgent median 2.7 seconds to pass health check and return HTTP 200, OpenClaw needs 29.2 seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Size&lt;/strong&gt;: OpenAgent single file ~23 MB, OpenClaw entire directory ~382 MB, over 40,000 files. This isn't "trading features for size" — it's the architectural advantage of Go static compilation + frontend embedding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory&lt;/strong&gt;: Idle OpenAgent ~110 MB, OpenClaw ~215–245 MB. Under load testing OpenAgent ~120 MB, OpenClaw ~307 MB.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Why Better Performance and Lower Latency — 3 Engineering Decisions
&lt;/h2&gt;

&lt;p&gt;Not "cutting features for performance" — every layer made the right choice.&lt;/p&gt;

&lt;h3&gt;
  
  
  ① Single Binary: One File, Zero Dependencies
&lt;/h3&gt;

&lt;p&gt;Go static compilation, frontend React build embedded directly into the binary. Windows users download the .exe and double-click to run — no WSL, no Docker, no Node.js. Mac/Linux one-command install. This is what a "personal local Agent" delivery should look like.&lt;/p&gt;

&lt;h3&gt;
  
  
  ② Shell Execution with Boundaries, Safe and Controllable
&lt;/h3&gt;

&lt;p&gt;At the source code level, &lt;code&gt;tool/shell.go&lt;/code&gt; defines default timeout 30 seconds, max 300 seconds, optional PTY, session-based &lt;code&gt;poll/write/submit&lt;/code&gt; mechanisms. Shell capability is &lt;strong&gt;strongly constrained production-grade tooling&lt;/strong&gt; by default, not unlimited remote execution. Also supports audit logs, SSO, request logs, and enterprise-grade observability.&lt;/p&gt;

&lt;h3&gt;
  
  
  ③ Go Native Concurrency, Memory Controllable
&lt;/h3&gt;

&lt;p&gt;Go's goroutine + channel model keeps memory growth very restrained in high-concurrency scenarios. 80-concurrent health stress test, memory grew only 10 MB. Compare to Node.js memory curves — this is a structural advantage at the language level.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Let's Be Honest, Challenges Welcome
&lt;/h2&gt;

&lt;p&gt;How far from "perfect"? Let's be clear about a few things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Lighthouse Overall Score&lt;/strong&gt;: OpenClaw 87, we're at 45. This is frontend loading performance — we used Lighthouse 11, OpenClaw's test version may differ, scores shouldn't be compared across versions. But it does indicate our frontend has optimization room.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sequential Health P50&lt;/strong&gt;: OpenClaw ~20 ms, we're ~33 ms. Millisecond-level difference, limited reference value for personal local Agents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration Prerequisites&lt;/strong&gt;: Chat API requires &lt;code&gt;Authorization: Bearer &amp;lt;provider_key&amp;gt;&lt;/code&gt;, not "completely zero steps". But compared to installing Node.js, configuring Docker, pulling tens of thousands of files, our friction is already minimal.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;We Welcome Your Challenge&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download OpenAgent, use your own OpenRouter Key&lt;/li&gt;
&lt;li&gt;Run the same prompts, compare the bills&lt;/li&gt;
&lt;li&gt;Beat us on speed/efficiency? PRs welcome. Find us more expensive? File an issue and we'll fix it.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6. About the Go Rewrite
&lt;/h2&gt;

&lt;p&gt;Some might ask: Isn't AI Agent Python's territory? Why Go?&lt;/p&gt;

&lt;p&gt;Agent bottlenecks are in &lt;strong&gt;LLM calls, not language performance&lt;/strong&gt; — what makes an Agent run well is Harness-layer architecture design, not underlying language execution speed. Go's advantages: &lt;strong&gt;static compilation single file, controllable memory, clean concurrency model, native cross-platform support&lt;/strong&gt;. These characteristics matter more than Python's dynamic flexibility for the "personal local Agent" use case.&lt;/p&gt;

&lt;p&gt;We wrote in Go for three months, from zero to one, building this core.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Who Benefits — Typical Use Cases
&lt;/h2&gt;

&lt;p&gt;🔧 &lt;strong&gt;Programmers / Developers&lt;/strong&gt;: CLI form directly replaces Claude Code, BYOK with your own Key, local Shell, Browser, Office tools one-click invocation.&lt;/p&gt;

&lt;p&gt;🏠 &lt;strong&gt;Individual Users / Enthusiasts&lt;/strong&gt;: Same machine specs, where running one Agent used to cause lag, now easily run multiple — memory footprint less than half the competition.&lt;/p&gt;

&lt;p&gt;💼 &lt;strong&gt;Freelancers / One-Person Companies&lt;/strong&gt;: Client proposals, consulting reports, competitive analysis, document organization — run locally, data never leaves your machine, the savings are peace of mind.&lt;/p&gt;

&lt;p&gt;🔒 &lt;strong&gt;Security Professionals&lt;/strong&gt;: Shell tool supports nmap, subfinder, httpx and other security CLI calls (requires local installation), with audit logs for traceable attack/defense exercises.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Getting Started
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Windows (Easiest, Recommended)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download &lt;code&gt;openagent_Windows_x86_64.exe&lt;/code&gt; from GitHub Releases&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Double-click to run&lt;/strong&gt;, environment/dependencies auto-configured&lt;/li&gt;
&lt;li&gt;Open &lt;a href="http://localhost:14000" rel="noopener noreferrer"&gt;http://localhost:14000&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;macOS / Linux / WSL&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;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/the-open-agent/openagent/master/scripts/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Windows PowerShell&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;irm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://raw.githubusercontent.com/the-open-agent/openagent/master/scripts/install.ps1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Model Integration&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One-click configuration in the project startup frontend interface, supports almost all mainstream LLMs, including locally deployed models.&lt;/li&gt;
&lt;li&gt;Download and docs: &lt;a href="https://www.openagentai.org" rel="noopener noreferrer"&gt;openagentai.org&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  9. Finally
&lt;/h2&gt;

&lt;p&gt;OpenAgent is an Apache 2.0 open-source project, all code on GitHub, welcome to review, Star, and file issues.&lt;/p&gt;

&lt;p&gt;We firmly believe: &lt;strong&gt;The future of personal local Agents isn't getting heavier, it's getting lighter.&lt;/strong&gt; One file, double-click to run — that's what users really want.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/the-open-agent/openagent" rel="noopener noreferrer"&gt;github.com/the-open-agent/openagent&lt;/a&gt; ⭐&lt;/p&gt;

&lt;p&gt;Discord: &lt;a href="https://discord.gg/5rPsrAzK7S" rel="noopener noreferrer"&gt;discord.gg/5rPsrAzK7S&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>opensource</category>
      <category>security</category>
    </item>
  </channel>
</rss>
