<?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: Don Karter</title>
    <description>The latest articles on DEV Community by Don Karter (@donk8r).</description>
    <link>https://dev.to/donk8r</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%2F3868460%2F00d65e09-1e87-48db-8634-1af15e5f7438.jpeg</url>
      <title>DEV Community: Don Karter</title>
      <link>https://dev.to/donk8r</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/donk8r"/>
    <language>en</language>
    <item>
      <title>Waiting Is Not a Tool Call: Making an MCP Server's Shell Event-Driven</title>
      <dc:creator>Don Karter</dc:creator>
      <pubDate>Wed, 02 Sep 2026 12:37:56 +0000</pubDate>
      <link>https://dev.to/donk8r/waiting-is-not-a-tool-call-making-an-mcp-servers-shell-event-driven-3nag</link>
      <guid>https://dev.to/donk8r/waiting-is-not-a-tool-call-making-an-mcp-servers-shell-event-driven-3nag</guid>
      <description>&lt;p&gt;One of our agents ran a test suite. The suite takes four minutes. The MCP client's idle timeout is sixty seconds.&lt;/p&gt;

&lt;p&gt;You can see where this is going. At second sixty the client cancelled the call. The process kept running — nobody told it to stop — while the model, holding a cancellation where its test results should be, did the reasonable thing and ran the suite again. Two test suites, same directory, racing each other over the same build artifacts. The second one failed with a locking error, the model reported the tests as broken, and the tests were fine.&lt;/p&gt;

&lt;p&gt;In another session the same model, burned before, developed a workaround: run the build, then call &lt;code&gt;sleep 240&lt;/code&gt;, then look. A tool call that does nothing, held open for four minutes, so that a different tool call might have something to show. The model had reinvented polling, badly, because we hadn't given it anything better.&lt;/p&gt;

&lt;p&gt;I build &lt;a href="https://github.com/Muvon/octofs" rel="noopener noreferrer"&gt;octofs&lt;/a&gt;, an open-source MCP filesystem server, and this incident set the agenda for eleven releases in two weeks (0.10.1 through 0.14.1). The principle behind them is one I keep coming back to: an MCP server's real interface is every string it hands back to the model. These releases apply it to the slowest string of all — the one the model waits for. The shell is now event-driven. Commands start in the foreground, move to the background on their own if they outlast ten seconds, and the client gets a notification when they finish. Nothing blocks, nothing gets killed, nothing runs twice.&lt;/p&gt;

&lt;h2&gt;
  
  
  First fix: prove the call is alive
&lt;/h2&gt;

&lt;p&gt;The sixty-second cancellation had a shallow cause and a deep one. The shallow one: a shell call is silent by nature. A build that's compiling says nothing on the wire for minutes, and to an MCP client silence is indistinguishable from a hung server. So 0.10.2 added liveness heartbeats — while a command runs in the foreground, octofs emits a progress notification every ten seconds, well below any sane idle timeout, so a single missed beat can't cancel the call.&lt;/p&gt;

&lt;p&gt;That stopped the killings. It did not touch the deep problem: the call still blocked. A four-minute test suite still cost four minutes of session time in which the model could do nothing — not read the failing file, not prepare the next edit, not think. Heartbeats make waiting survivable. They don't make it useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Second fix: background jobs — and the flag we had to delete
&lt;/h2&gt;

&lt;p&gt;0.11.0 introduced background execution: run a command as a job, get a handle back immediately, collect the output later. Each job is an MCP resource with a URI like &lt;code&gt;octofs://jobs/17342-1&lt;/code&gt;, readable at any time for its status and output.&lt;/p&gt;

&lt;p&gt;It shipped with a background flag on the shell tool, and that flag was a mistake we recognize in hindsight as a familiar one. In 0.9.0 we deleted a &lt;code&gt;--line-mode&lt;/code&gt; switch because safety that ships behind a flag is safety most people never turn on. The background flag was the same bug in a different costume: it asked the model to predict the duration of a command before running it. Models are bad at this in exactly the way you'd expect — &lt;code&gt;cargo build&lt;/code&gt; is instant on a warm cache and takes six minutes cold, and the flag turned that unknowable fact into a required decision. Guess background for a fast command and you've added a pointless round trip. Guess foreground for a slow one and you're back to the blocked call we started with.&lt;/p&gt;

&lt;p&gt;So 0.13.0 deleted the flag and replaced the prediction with a measurement. Every command starts in the foreground. If it's still running at ten seconds, it is automatically promoted to a background job — the same process, not killed, not restarted. Output capture is durable from the first byte, so crossing the deadline loses nothing: whatever the command printed in its foreground life is sitting in the job's log when you read it later.&lt;/p&gt;

&lt;p&gt;The tool call returns immediately at promotion, with a resource link carrying the command as its name — so a client can render "make test … still running" without re-deriving what the job was, even after a context compaction. When the process exits, octofs emits &lt;code&gt;notifications/resources/updated&lt;/code&gt; for the job's URI. The client reads the resource once and gets the exit code and the output tail. No polling, no held-open call, no orphaned process.&lt;/p&gt;

&lt;p&gt;Two details in that flow earned their place the hard way:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The tail, not the head.&lt;/strong&gt; A resource read returns at most the last 30 KB of output. Build logs run long, and the verdict — the error, the final test summary — lives at the end. Feeding a model the first 30 KB of a log whose last line says FAILED is how you get a confident report that everything passed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two delivery paths.&lt;/strong&gt; Clients on the 2026-07-28 MCP revision that opened a subscription stream get the completion on it; older clients get the unsolicited push the earlier spec allowed. And since 0.13.0, a client that subscribes late — after the job already exited — gets the completion replayed instead of waiting forever on a notification that fired before anyone was listening.&lt;/p&gt;

&lt;p&gt;The foreground window also shrank from thirty seconds to ten in 0.13.0, and that's the auto-promotion paying for itself: when crossing the boundary costs nothing — same process, durable output, a notification at the end — there's no reason to hold the session hostage for half a minute just in case the command finishes at second twenty-five.&lt;/p&gt;

&lt;h2&gt;
  
  
  Third fix: let jobs run next to each other
&lt;/h2&gt;

&lt;p&gt;0.11.0 was conservative: one job per directory, full stop. Safe, and too blunt — it serialized a build and a log tail that had no business waiting on each other.&lt;/p&gt;

&lt;p&gt;0.14.0 narrowed the guard to the one case that's actually a bug: the identical command already running in the same directory. That's not concurrency, that's the double-fired test suite from the opening story, and instead of racing it, octofs rejects it and tells the model precisely what to do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The same shell command is already running as background job
octofs://jobs/17342-1 (`cargo test`). Wait for its completion — you will
get a resources/updated notification with its output — instead of
starting a duplicate. Independent commands may run concurrently in this
directory.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Distinct commands run side by side. The duplicate gets an error that is, once again, the recovery instruction.&lt;/p&gt;

&lt;h2&gt;
  
  
  A hard line under all of it
&lt;/h2&gt;

&lt;p&gt;With the server doing the waiting, a model burning a tool call on &lt;code&gt;sleep 240&lt;/code&gt; stopped being a clever workaround and became pure waste. So 0.10.4 added it to the shell misuse list, next to &lt;code&gt;watch&lt;/code&gt; and &lt;code&gt;top&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Waiting with a bare `sleep` is forbidden — it burns the whole tool call
doing nothing.

  To wait for a condition, poll it in a loop (sleep inside a loop body
  is allowed):
    until &amp;lt;check&amp;gt;; do sleep 2; done
  To wait for a command you started, run it normally; long-running
  commands automatically move to the background and notify you when
  they finish.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same policy as 0.9.0's grep rejection: don't hint, fail — and put the correct move in the error. Octofs rejects a bare &lt;code&gt;sleep&lt;/code&gt;; a &lt;code&gt;sleep&lt;/code&gt; inside an &lt;code&gt;until&lt;/code&gt; loop is a legitimate condition poll and passes. &lt;code&gt;watch&lt;/code&gt; and &lt;code&gt;top&lt;/code&gt; get rejected because they never exit, which in an event-driven shell means they'd hold a promotion slot forever and never deliver a completion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fewer places to hallucinate
&lt;/h2&gt;

&lt;p&gt;Around the shell work, five smaller releases kept pulling the 0.9.0 thread — closing gaps where a model could mistake silence or ambiguity for information.&lt;/p&gt;

&lt;p&gt;Empty search results say so out loud. A model handed an empty string doesn't reliably conclude "no matches." Sometimes it concludes "the tool failed" and retries; sometimes, worse, it fills the silence with what it expected to find and proceeds as if it had. So the no-match case is a sentence stating what was searched and that zero matches exist.&lt;/p&gt;

&lt;p&gt;Tool schemas dropped their null variants (0.10.3). Optional-as-nullable in a JSON schema reads fine to a human and is an attractive nuisance to a model — &lt;code&gt;"path": null&lt;/code&gt; is a call that validates nowhere good. Optional now means absent.&lt;/p&gt;

&lt;p&gt;Stale line IDs report better (0.10.5). Listing and search got faster (0.10.1) — newline counting on raw bytes, file types from the directory walker, a whole-buffer prefilter. Latency in a tool the model calls hundreds of times per session is a tax on everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  The remote box, without ceremony
&lt;/h2&gt;

&lt;p&gt;Octofs has spoken SSH/SFTP since 0.8.0 — point a tool at &lt;code&gt;ssh://user@host/path&lt;/code&gt; and the agent gets the same verified filesystem on a remote machine. 0.14.0 resolves targets through &lt;code&gt;~/.ssh/config&lt;/code&gt;. Host aliases, a ProxyJump bastion, IdentityFile, IdentityAgent, per-host users and ports — the configuration you already wrote for your own fingers now applies to the agent's connections. The test is simple: if plain &lt;code&gt;ssh box&lt;/code&gt; works in your terminal, &lt;code&gt;ssh://box/path&lt;/code&gt; works in octofs, bastion and all. (One hop, honestly: we reject multi-hop ProxyJump chains and ProxyCommand with a clear error rather than half-supporting them.)&lt;/p&gt;

&lt;p&gt;0.14.1 made misuse detection read inside ssh commands. The grep-rejection story had a remote-shaped hole: &lt;code&gt;ssh box 'grep -r TODO src/'&lt;/code&gt; sailed past a detector that respected quotes too politely to look inside them. It now parses the remote command through SSH's options and nesting and applies the same rules. Pipelines stay allowed, interactive SSH stays untouched.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means for your MCP server
&lt;/h2&gt;

&lt;p&gt;If you build MCP tools, the takeaways transfer directly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A blocked tool call is a liability, not a wait. Return a handle and notify on completion.&lt;/li&gt;
&lt;li&gt;Don't make the model predict durations — measure them. Auto-promotion beat a flag.&lt;/li&gt;
&lt;li&gt;Errors should contain the recovery instruction, not just the failure.&lt;/li&gt;
&lt;li&gt;Silence is ambiguous — say "nothing found" out loud.&lt;/li&gt;
&lt;li&gt;Safety behind a flag is safety nobody turns on. Delete the flag and make the right behavior the only behavior.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Nothing in octofs depends on our agent runtime, by the way. The job resources, the links, the notifications are all plain MCP — any client that follows the protocol gets the event-driven shell for free.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Homebrew&lt;/span&gt;
brew upgrade muvon/tap/octofs

&lt;span class="c"&gt;# Cargo&lt;/span&gt;
cargo &lt;span class="nb"&gt;install &lt;/span&gt;octofs &lt;span class="nt"&gt;--version&lt;/span&gt; 0.14.1

&lt;span class="c"&gt;# npm&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @muvon/octofs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No config changes required. One behavioral note: if your prompts or client code passed a background flag to the shell tool, remove it — the flag is gone and promotion is automatic.&lt;/p&gt;

&lt;p&gt;Octofs is open source (Apache 2.0) at &lt;a href="https://github.com/Muvon/octofs" rel="noopener noreferrer"&gt;github.com/Muvon/octofs&lt;/a&gt;. The full write-up lives on the Muvon blog: &lt;a href="https://muvon.io/blog/octofs-0-14-waiting-is-not-a-tool-call" rel="noopener noreferrer"&gt;Waiting Is Not a Tool Call&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>ai</category>
      <category>mcp</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Most tools strip your image and answer anyway. I built mine to refuse.</title>
      <dc:creator>Don Karter</dc:creator>
      <pubDate>Tue, 01 Sep 2026 08:24:13 +0000</pubDate>
      <link>https://dev.to/donk8r/most-tools-strip-your-image-and-answer-anyway-i-built-mine-to-refuse-1e6k</link>
      <guid>https://dev.to/donk8r/most-tools-strip-your-image-and-answer-anyway-i-built-mine-to-refuse-1e6k</guid>
      <description>&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%2Fdgfoxxftt2954refk49c.jpeg" 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%2Fdgfoxxftt2954refk49c.jpeg" alt=" " width="800" height="447"&gt;&lt;/a&gt;Attach an image to a model that can't see.&lt;/p&gt;

&lt;p&gt;The industry-standard behavior is to remove it and answer anyway. You get a confident reply to a question the model never received.&lt;/p&gt;

&lt;p&gt;I hate that. So octomind refuses instead. By name. Before the machine wakes and before anything is charged.&lt;/p&gt;

&lt;p&gt;That's the whole stance behind what I just shipped: images and voice, live. Attach or paste a screenshot and the agent looks at it. Hold the mic and talk instead of typing. Send a photo or a voice note from Telegram, Slack, or WhatsApp and it lands in the same session your browser has open.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nothing gets silently dropped
&lt;/h2&gt;

&lt;p&gt;This is the part I care most about. Because it's where every other product fails.&lt;/p&gt;

&lt;p&gt;If your model can't see, the attach button is already disabled. The tooltip names one that works.&lt;/p&gt;

&lt;p&gt;If your machine is running an older image that predates attachments, the turn is refused too. Never sent and hoped for. Because an older agent would accept the frame, drop the picture, and reply as though nothing were missing.&lt;/p&gt;

&lt;p&gt;Your upload stays valid through all of it. So retrying after a model switch never costs a second upload.&lt;/p&gt;

&lt;p&gt;Refusing feels harsh. Silently dropping feels fine, right up until you're acting on an answer to a question that was never asked. I'd rather be the tool that says no up front.&lt;/p&gt;

&lt;h2&gt;
  
  
  Same session, same machine
&lt;/h2&gt;

&lt;p&gt;Nothing here is a separate mode. That's the point.&lt;/p&gt;

&lt;p&gt;A screenshot pasted at your desk at 09:14 and a voice note sent from your phone at 12:40 are the same session. On the same machine. With the same files. Open the tab again at six and all of it is still there.&lt;/p&gt;

&lt;p&gt;Not a phone app that syncs to a web app that syncs to a bot. One session. One machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Voice you can fix before it sends
&lt;/h2&gt;

&lt;p&gt;Speak, and the words arrive in the composer as text you can still edit. Nothing sends until you press send.&lt;/p&gt;

&lt;p&gt;Transcription is very good and not perfect. The failure mode of auto-send is that a misheard word becomes an instruction. So I put guards in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recording stops itself after 15 seconds of silence.&lt;/li&gt;
&lt;li&gt;It hard-stops at two minutes.&lt;/li&gt;
&lt;li&gt;A recording that comes out shorter than three words never wakes a machine.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You talk. You read it back. You fix it. Then it goes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Replies can talk back
&lt;/h2&gt;

&lt;p&gt;Replies can come back spoken in Telegram and WhatsApp, where a voice message is a real thing you can play with the phone in your pocket.&lt;/p&gt;

&lt;p&gt;I don't read markdown out loud. A fenced block is announced as "a 12-line code block," not as a mouthful of backticks.&lt;/p&gt;

&lt;p&gt;Spoken replies are off until you switch them on in Settings. And the text always comes too. Never instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it costs
&lt;/h2&gt;

&lt;p&gt;Images are on every plan, at no extra cost. No per-attachment charge. No storage charge. The disk is already part of your machine. Images cap at 5 MB, audio at 8 MB, four attachments to a message.&lt;/p&gt;

&lt;p&gt;Voice is on paid plans. $0.010 a minute to listen. $0.025 a minute to speak. On top of the model, in the same spend view as everything else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Routines from your chat apps
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;/routines&lt;/code&gt; now lists your routines, runs one immediately, pauses and resumes — from Telegram, Slack, or WhatsApp.&lt;/p&gt;

&lt;p&gt;Completed runs deliver the full report into the chat rather than a bare "done." Long output is clamped to fit the platform instead of cut at a byte boundary. Times render in the routine's own timezone, not ours.&lt;/p&gt;

&lt;p&gt;Each routine carries its own notification preference now. So an hourly check and a weekly report don't have to shout equally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Machines are on octomind 0.47.0
&lt;/h2&gt;

&lt;p&gt;0.46 was a deletion release. Verifier recovery tracking and mutation outcome contracts in. A net −1,884 lines of supervisor surface out. The benchmark said those mechanics weren't paying for themselves, so they went.&lt;/p&gt;

&lt;p&gt;0.47 is the release that carries attachments on the wire.&lt;/p&gt;

&lt;p&gt;Config format moves 5 → 7 → 8 across the two. The CLI migrates an existing machine's config on first run. There's nothing for you to edit.&lt;/p&gt;

&lt;p&gt;New machines are on 0.47.0 now. Existing ones pick it up on their next rebuild, with files, sessions, and settings untouched. Voice doesn't wait on the upgrade at all. Transcription runs on my side, so the machine only ever receives text.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixed
&lt;/h2&gt;

&lt;p&gt;A routine whose turn never started could settle early and report a run that hadn't happened. Endpoint routing also tightened how it validates domains.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I want argued
&lt;/h2&gt;

&lt;p&gt;The refusal thing is the hill I'll die on. Every tool that strips your image and answers anyway is training you to distrust it. You can't tell it dropped anything. You just get a smooth, confident, wrong-shaped reply.&lt;/p&gt;

&lt;p&gt;Refusing by name costs me a little friction up front. It buys you the one thing a silent drop never can: knowing your input actually arrived.&lt;/p&gt;

&lt;p&gt;Full write-up: &lt;a href="https://octomind.run/blog/images-and-voice" rel="noopener noreferrer"&gt;https://octomind.run/blog/images-and-voice&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>automation</category>
      <category>voice</category>
    </item>
    <item>
      <title>The 11-Day Silence: What Scheduled Agents Taught Me About Building Routines That Don't Die</title>
      <dc:creator>Don Karter</dc:creator>
      <pubDate>Fri, 28 Aug 2026 06:23:32 +0000</pubDate>
      <link>https://dev.to/donk8r/the-11-day-silence-what-scheduled-agents-taught-me-about-building-routines-that-dont-die-3gjj</link>
      <guid>https://dev.to/donk8r/the-11-day-silence-what-scheduled-agents-taught-me-about-building-routines-that-dont-die-3gjj</guid>
      <description>&lt;p&gt;There is a specific kind of disappointment that comes from scheduled agents, and it always arrives the same way. You set one up. It works when you test it. Three weeks later you notice it hasn't done anything in eleven days, and there's nowhere to look to find out why.&lt;/p&gt;

&lt;p&gt;That experience — the eleven-day silence — is why I built Routines into Octomind the way I did.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Shipped
&lt;/h2&gt;

&lt;p&gt;A routine is a standing instruction with a trigger attached. Pick an agent, pick when, and it wakes a computer in the cloud, does the work, and tells you what came of it. Nothing of yours has to be switched on.&lt;/p&gt;

&lt;p&gt;That's the elevator pitch. The engineering reality is messier, because scheduled systems have four failure modes documented in the original post.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Four Ways Scheduled Agents Fail
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. It didn't run and nobody said so.&lt;/strong&gt; The config file says what should run and has no opinion about what is running. Claude Cowork has an open issue where tasks skip on a timezone offset and simply don't appear. You don't know it failed. You just notice the silence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. It ran, spent money, produced nothing.&lt;/strong&gt; Silent failure. No crash, no signal, just a charge. Telerik has a taxonomy of agents returning status: ok having done nothing useful. Your credit card gets charged. Your problem stays unsolved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Cost runs away.&lt;/strong&gt; An agent loop costs roughly 3.2× a chatbot turn at five steps and over 30× at fifty, and a polling schedule pays full price on every run where nothing happened. Context accumulation is the dominant cost driver, and it compounds silently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Time is the only trigger.&lt;/strong&gt; If something breaks at 15:00 and your check runs at 23:00, you find out at 23:00. You're at the mercy of the schedule you set.&lt;/p&gt;

&lt;p&gt;Routines is designed to fail differently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scheduling Is a Sentence You Complete
&lt;/h2&gt;

&lt;p&gt;The scheduling UX is a sentence you complete: "Every weekday at eight." There's a cron option with plain-English readback, because the failure mode of a cron field is not rejection, it's silently scheduling something else.&lt;/p&gt;

&lt;p&gt;Times are stored with an IANA timezone, never an offset, and the next fire is recomputed after each run rather than incremented. That is the whole reason daylight saving doesn't drift: a local time that doesn't exist in spring fires at the next real instant, and a local time that happens twice in autumn fires once, on the first. Both are pinned by tests with fixed clocks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pick Who Does It
&lt;/h2&gt;

&lt;p&gt;Routines run as specialist agents — same roster as tasks. Assistant picks if you don't want to choose. The point is: you know what's running your job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Every Non-Run Is a Row
&lt;/h2&gt;

&lt;p&gt;This matters more than it sounds. Refusals — routine off, out of budget, cold storage, previous run still going — become run rows with status. "Didn't run — machine was in cold storage." "Hit its cost cap."&lt;/p&gt;

&lt;p&gt;Header totals show: "7 runs · $0.63 · typically 3m 8s". It's a heartbeat list view, one tick per run coloured by outcome. And after five consecutive failures, a routine disables itself and tells you, because a broken routine must not bill forever.&lt;/p&gt;

&lt;p&gt;Silence is the bug we're building against.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost Controls That Actually Work
&lt;/h2&gt;

&lt;p&gt;Fresh conversation each run by default. There's a checkbox for long conversation labelled honestly: "keeps context between runs, costs more over time". No marketing spin, just the truth.&lt;/p&gt;

&lt;p&gt;Optional zero-token check command — shell runs first, non-zero exit = "nothing to do" with no model call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git fetch &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git log &lt;span class="nt"&gt;--oneline&lt;/span&gt; @..@&lt;span class="o"&gt;{&lt;/span&gt;u&lt;span class="o"&gt;}&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We deliberately did not make this a natural-language condition: an LLM condition costs a model call to decide whether to make model calls. That's backwards.&lt;/p&gt;

&lt;p&gt;Per-run cost cap. Always.&lt;/p&gt;

&lt;h2&gt;
  
  
  State Is a File, Not a Black Box
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;~/routines//&lt;/code&gt; with state.md. Read state.md before you start, write what the next run needs to know before you finish. Persistent disk, openable in Files or terminal, edit to correct memory, delete to reset.&lt;/p&gt;

&lt;p&gt;State is a file, not a vendor black box. You can touch it. You can fix it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run It Now
&lt;/h2&gt;

&lt;p&gt;There's a button that fires the real queue, the real runner, the real billing lane. Not a preview. A routine you have never watched run is a routine you cannot trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  Machine Sleep
&lt;/h2&gt;

&lt;p&gt;Free machines suspend after 5 idle minutes, Pro after 15. Your computer sleeps, costs nothing, and gets up when the routine says so. Wake goes through the same admission door; refusal = visible skip with reason, never an overdraft. Machines with enabled routines are exempt from cold storage.&lt;/p&gt;

&lt;h2&gt;
  
  
  /schedule vs Routines
&lt;/h2&gt;

&lt;p&gt;Agent-internal timers die with the session. A schedule living inside the box cannot wake the box. Routines fire from outside and start the machine. That's the architectural difference.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PRODUCERS (timer, webhook, connector, workflow)
    ↓
QUEUE (routine_fires, dedup/claim)
    ↓
RoutineRunner
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing in the runner knows what caused a run. Timer + manual ship today. Webhook, connector, and workflow land without migrations — the queue and seam are built, the part that's expensive to retrofit is the trigger sources themselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Notifications
&lt;/h2&gt;

&lt;p&gt;Panel bell plus Telegram, Slack, or WhatsApp mirror. Default notify-on-change. Failures always ring. Silence is the bug we're building against.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plans
&lt;/h2&gt;

&lt;p&gt;Free: 1 routine, once a day.&lt;br&gt;
Pro: 10 routines, down to every 15 min.&lt;br&gt;
Max/Team: 30 routines, down to every 5 min.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Not There (Yet)
&lt;/h2&gt;

&lt;p&gt;Webhook triggers aren't built yet. The queue and seam are ready, but the part that's expensive to retrofit is the trigger sources. Timeouts and cost caps end our turn rather than killing the agent mid-thought, which is a real limit we'd rather name than paper over.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Advice I'd Give Myself
&lt;/h2&gt;

&lt;p&gt;Open Routines and start with one. Watch it run once before you schedule it — that's the whole advice.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This is a personal retelling of the Routines launch post. The original company-voice version is at &lt;a href="https://octomind.run/blog/routines-scheduled-agents" rel="noopener noreferrer"&gt;octomind.run/blog/routines-scheduled-agents&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>devops</category>
      <category>cloud</category>
    </item>
    <item>
      <title>From Chat to Pipeline: Running Octomind Non-Interactively in CI and Scripts</title>
      <dc:creator>Don Karter</dc:creator>
      <pubDate>Mon, 24 Aug 2026 16:33:59 +0000</pubDate>
      <link>https://dev.to/donk8r/from-chat-to-pipeline-running-octomind-non-interactively-in-ci-and-scripts-93</link>
      <guid>https://dev.to/donk8r/from-chat-to-pipeline-running-octomind-non-interactively-in-ci-and-scripts-93</guid>
      <description>&lt;p&gt;How to take an AI agent out of the terminal and into automation – non-interactive runs, JSON Lines output, structured output with JSON Schema, and multi-step workflows. A practical guide to Octomind in CI, cron jobs, and scripts.&lt;/p&gt;

&lt;p&gt;An AI agent that only works when you're typing at it is a tool. An AI agent that works inside a pipeline is infrastructure. Octomind is built to run non-interactively from day one, but pinning the right capabilities is what keeps your CI job from flaking.&lt;/p&gt;

&lt;p&gt;I've put Octomind into CI checks, cron jobs, and deploy scripts. This is what I wish I'd known the first time, from the basic "run it without a terminal" up to structured output you can pipe into other tools. Sharing this here because the dev.to community asked practical questions about agent automation, and these patterns might save you a few CI failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Idea: Pipe In, Read Out
&lt;/h2&gt;

&lt;p&gt;Interactively, you type and Octomind answers in a styled terminal. Non-interactively, you give it the prompt on stdin and it runs once and exits. The switch is the --format flag:&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;echo&lt;/span&gt; &lt;span class="s2"&gt;"Review the changes in this PR and flag anything risky"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | octomind run developer:general &lt;span class="nt"&gt;--format&lt;/span&gt; plain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pass a --format value, or pipe stdin instead of attaching a terminal, and the session runs once, reads its input from stdin, and exits when done. That's the whole non-interactive contract. plain keeps the human-readable, terminal-decorated output; for anything a machine consumes, you want jsonl.&lt;/p&gt;

&lt;h2&gt;
  
  
  JSON Lines: Output a Pipeline Can Parse
&lt;/h2&gt;

&lt;p&gt;--format jsonl emits structured JSON Lines regardless of whether a terminal is attached. One object per event, easy to parse, stable to depend on:&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;echo&lt;/span&gt; &lt;span class="s2"&gt;"List the three highest-risk files in this diff"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | octomind run developer:general &lt;span class="nt"&gt;--format&lt;/span&gt; jsonl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use this format in CI. Pipe it into jq, grep it for the events you care about, store it as a build artifact. Every line carries a type – assistant, tool_use, tool_result, cost, status, and so on – so the model's answer is one filter away: &lt;code&gt;jq -r 'select(.type == "assistant") | .content'&lt;/code&gt;. Because each line is a complete JSON object, you can stream and process it as the run goes rather than waiting for the end.&lt;/p&gt;

&lt;p&gt;A reliability note that has bitten me: pin down the environment the agent runs in. In CI you want deterministic behavior, not whatever tools happen to match your prompt. Octomind normally loads capabilities on demand by matching your message – great interactively, slightly unpredictable in a pipeline. Force-load the tools you need at boot instead:&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;echo&lt;/span&gt; &lt;span class="s2"&gt;"Audit src/ for hardcoded secrets"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nv"&gt;OCTOMIND_CAPABILITIES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;codesearch-semantic,filesystem-read &lt;span class="se"&gt;\&lt;/span&gt;
    octomind run developer:general &lt;span class="nt"&gt;--format&lt;/span&gt; jsonl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything in that list is loaded before the first turn, regardless of what the automatic matching thinks of your prompt. Matching still runs on top of it, though – if you want the surface to be exactly that list and nothing else, also set auto_capabilities = false in your config. Same tools on every run is exactly what you want when a green check depends on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structured Output: Make the Agent Return Data, Not Prose
&lt;/h2&gt;

&lt;p&gt;Structured output turns an agent into a pipeline stage. Pass --schema with a JSON Schema file and the model's output is constrained to match it. Instead of a paragraph you have to parse with fragile regex, you get clean, typed JSON:&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;echo&lt;/span&gt; &lt;span class="s2"&gt;"List the top 3 TODOs in this codebase"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | octomind run developer:general &lt;span class="nt"&gt;--format&lt;/span&gt; jsonl &lt;span class="nt"&gt;--schema&lt;/span&gt; todos.schema.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every assistant reply for that run conforms to your schema, while tool calls still flow normally underneath – only the final text is constrained. This is how you wire an agent into a larger system: have it emit &lt;code&gt;{ "issues": [...] }&lt;/code&gt; and feed that straight into the next step, no scraping required. A ready-to-use example ships in the repo at config-templates/todos.schema.json.&lt;/p&gt;

&lt;p&gt;Structured output needs a model that supports it. Most providers do – OpenAI, Google, xAI, DeepSeek, Groq, OpenRouter, and more. Anthropic models don't, and the run fails fast with a clear message if you pick one that can't. Like --model, the schema is a runtime override that isn't persisted, so pass it again on each run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-Step Workflows
&lt;/h2&gt;

&lt;p&gt;For multi-step flows, use octomind workflow. It runs a TOML-defined pipeline, reading input from stdin:&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;echo&lt;/span&gt; &lt;span class="s2"&gt;"Build a JSON-to-CSV CLI in Rust"&lt;/span&gt; | octomind workflow build-flow.toml &lt;span class="nt"&gt;--format&lt;/span&gt; jsonl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With --format jsonl it emits one assistant event per step as it completes, each tagged with a step field (the last one is the final result), followed by a single aggregated cost event. Per-step progress and cost stay on stderr for a human to watch, so stdout is clean for your parser. Use --dry-run first to print the execution plan and validate the flow without spending a token.&lt;/p&gt;

&lt;h2&gt;
  
  
  Guardrails Are Even More Important Here
&lt;/h2&gt;

&lt;p&gt;When a human is watching, a wrong move gets caught. In an unattended pipeline, nobody's watching – which makes guardrails and the sandbox mandatory, not optional. For any automated run I do two things by reflex:&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;# restrict writes to the working directory — OS-enforced (Landlock on Linux, Seatbelt on macOS)&lt;/span&gt;
octomind run developer:general &lt;span class="nt"&gt;--sandbox&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt; jsonl &amp;lt; prompt.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also set spending limits in config so a runaway loop can't run up a bill while I'm asleep:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;max_session_spending_threshold&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;
&lt;span class="py"&gt;max_request_spending_threshold&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Interactively the session cap asks before continuing; in a pipeline there's nobody to ask, so it stops the run. A pipeline that can't write outside its directory and can't spend more than two dollars is a pipeline you can actually trust to run on a schedule. When a guardrail fires it shows up in the JSONL stream as an injected event with source_kind set to guardrail_hook or guardrail_validator, so you can assert in CI that a rule fired (or didn't) as part of your test.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Real CI Shape
&lt;/h2&gt;

&lt;p&gt;Put together, a PR-review check looks like this:&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;#!/bin/sh&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;
git diff origin/main... &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/diff.txt

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Review the diff in /tmp/diff.txt. Return findings as JSON matching the schema."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nv"&gt;OCTOMIND_CAPABILITIES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;filesystem-read &lt;span class="se"&gt;\&lt;/span&gt;
    octomind run developer:general &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;--sandbox&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt; jsonl &lt;span class="nt"&gt;--schema&lt;/span&gt; review.schema.json &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;tee &lt;/span&gt;review.jsonl

&lt;span class="c"&gt;# downstream: parse review.jsonl, post comments, fail the build on severity &amp;gt;= high&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deterministic tools, sandboxed, structured output, cost-capped. The agent does the judgment; your script does the plumbing. (If you specifically want code review on every GitHub PR, we package this exact pattern as a ready-made Action so you don't have to assemble it yourself.)&lt;/p&gt;

&lt;h2&gt;
  
  
  What Changes When Nobody's Watching
&lt;/h2&gt;

&lt;p&gt;Once an agent runs cleanly without a terminal, you stop thinking of it as a thing you use and start thinking of it as a thing you deploy. Cron jobs that triage issues overnight. CI checks that flag risky diffs. Scripts that summarize a day's commits. Same binary, same models – just pointed at stdin instead of a keyboard, emitting JSON instead of prose.&lt;/p&gt;

&lt;p&gt;Start with one &lt;code&gt;echo ... | octomind run --format jsonl&lt;/code&gt;. Add a schema when you need structured data, a sandbox and spending cap when it runs unattended, and a workflow when one prompt isn't enough. The same binary that answers in your terminal can run your pipeline at 3 AM. That's the difference between a tool and infrastructure.&lt;/p&gt;

&lt;p&gt;Get Octomind – and put your agent on the pipeline.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>ci</category>
      <category>automation</category>
    </item>
    <item>
      <title>Octomind 0.44.2: I Removed the Agent's Ability to Grade Its Own Homework</title>
      <dc:creator>Don Karter</dc:creator>
      <pubDate>Thu, 20 Aug 2026 08:55:00 +0000</pubDate>
      <link>https://dev.to/donk8r/octomind-0442-i-removed-the-agents-ability-to-grade-its-own-homework-97l</link>
      <guid>https://dev.to/donk8r/octomind-0442-i-removed-the-agents-ability-to-grade-its-own-homework-97l</guid>
      <description>&lt;h2&gt;
  
  
  The Lie That Bugged Me
&lt;/h2&gt;

&lt;p&gt;I was building a feature last month when Octomind told me it was done. Five files needed editing based on the task I gave it. I checked – three were changed, two were untouched. The agent had marked the task complete anyway.&lt;/p&gt;

&lt;p&gt;Worse, I caught it verifying its own work by reading back the edit it just made and essentially admiring it. The model was saying "the code looks correct" because it had written the code itself. That isn't verification. It's the model grading its own homework.&lt;/p&gt;

&lt;p&gt;I got tired of my own tool lying to me. So in 0.44.2, I removed that ability entirely.&lt;/p&gt;

&lt;p&gt;This isn't a minor tweak. It's a philosophical shift about what an AI coding agent should actually do. I'm choosing honesty over the appearance of competence. An agent that says "I couldn't do this" is more useful than one that says "done!" and leaves you to find the gaps.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Changed
&lt;/h2&gt;

&lt;p&gt;Three pillars. All of them aimed at making the agent honest about what it's done and what it hasn't.&lt;/p&gt;

&lt;h3&gt;
  
  
  Per-Condition Verification
&lt;/h3&gt;

&lt;p&gt;The verify gate no longer accepts a holistic "looks good" verdict. Every task derives evidence conditions. The verifier must address each one. An unmatched condition beats a holistic PASS, every time.&lt;/p&gt;

&lt;p&gt;Before, the model could say "yeah, this looks solid" and move on. Now it has to prove each condition is met. If your task requires "function X exists" and "test Y passes", both get checked individually. One fails, the gate stays closed. No hand-waving.&lt;/p&gt;

&lt;p&gt;This came from watching the agent skip over edge cases. It would verify the happy path and call the task done. Now every condition you specify – or that the planner derives – gets its own verification moment. The verifier can't gloss over gaps.&lt;/p&gt;

&lt;h3&gt;
  
  
  External Planning
&lt;/h3&gt;

&lt;p&gt;Planning left the model's hands entirely. The model-callable plan tool is gone. An external plan manager – running its own cheap model – owns the checklist now.&lt;/p&gt;

&lt;p&gt;This matters because the main model was using planning as procrastination. It would generate a plan, call it done, and treat the plan like the work. Finishing paperwork isn't doing the work. I'd see tasks where the agent spent tokens generating a detailed plan but hadn't actually touched the code.&lt;/p&gt;

&lt;p&gt;The external planner is cheaper, faster, and doesn't confuse bureaucracy with progress. It's a separate model that only does planning – no code writing, no verification. Just the checklist. This separation means the main model can't hide behind a plan and pretend it made progress.&lt;/p&gt;

&lt;h3&gt;
  
  
  Persisted Verification Policy
&lt;/h3&gt;

&lt;p&gt;Verification policy persists with the session and survives restarts. It's folded into the governance hash.&lt;/p&gt;

&lt;p&gt;I was losing my verification rules every time I restarted my session. That's fixed. Your policy travels with the session now, encoded into the governance hash that tracks the session's integrity. Restart your terminal, restart your machine – your verification rules come back.&lt;/p&gt;

&lt;p&gt;This sounds minor until you've had to re-specify your verification standards for the fifth time. It's not minor. It's the difference between a tool that remembers your standards and one that makes you retrain it constantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You'll Notice Day-to-Day
&lt;/h2&gt;

&lt;p&gt;You'll see fewer false positives. The agent will tell you "I couldn't verify condition 3" instead of "done!" when it's not. That might feel slower, but it's actually honest. You're getting accurate status instead of premature completion.&lt;/p&gt;

&lt;p&gt;The model can't grade its own homework anymore. When verification runs, it runs with no fallback model. If verification fails, the gate stays closed. No silent downgrade to a weaker check.&lt;/p&gt;

&lt;p&gt;This was a hard call. I could've let verification fail over to a cheaper model when the primary verifier struggled. That would've kept the gate moving. But it would've also meant weaker verification on the hard cases – exactly when you need it most. Now, if verification fails, you know. The gate stays closed. You get notified. You decide what's next.&lt;/p&gt;

&lt;p&gt;You'll also notice the planner is snappier. That's because it's a separate, cheaper model doing only planning – not trying to write code and plan at the same time. The separation of concerns actually shows up in latency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upgrade Notes
&lt;/h2&gt;

&lt;p&gt;This one's not entirely smooth. A few things to know before you upgrade:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Config auto-migrates to version 5 with backup.&lt;/strong&gt; Your existing config will be migrated automatically on first run, and the old version is backed up. You won't lose anything. The migration handles the structural changes required by the new verification and planning architecture. If something goes wrong, your backup is there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The plan MCP tool is gone.&lt;/strong&gt; This is breaking for embedders who called &lt;code&gt;plan(command=...)&lt;/code&gt;. If you built something on top of that tool, you'll need to adjust. I know – breaking changes suck. I'd rather ship this now than live with the debt. The tool was enabling the wrong behavior – letting external code trigger planning in ways that bypassed the new external plan manager. If you're an embedder, reach out. I can help you migrate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tap and schedule moved to a new orchestration server.&lt;/strong&gt; If you use scheduled runs or tap functionality, they're now handled by a separate orchestration layer. Functionally the same from your end, just cleaner under the hood. The orchestration server is purpose-built for timing and coordination, which means the main agent process doesn't carry that weight anymore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;If you're on macOS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;muvon/tap/octomind
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fresh install or upgrade, you'll get 0.44.2. The config migration happens on first run. Check the backup it creates – it'll be in your config directory with a timestamp.&lt;/p&gt;

&lt;p&gt;On other platforms, pull the latest from the repo. The release tags are up to date.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I'm Writing This
&lt;/h2&gt;

&lt;p&gt;I could've just shipped it with a changelog. But these aren't minor tweaks – they're philosophical shifts about what an AI agent should be.&lt;/p&gt;

&lt;p&gt;The old behavior felt like progress. The agent moved fast, checked boxes, told me it was done. But I was doing the actual verification myself, which meant the agent wasn't earning its keep. I was just paying for automation that still required my full attention.&lt;/p&gt;

&lt;p&gt;These changes came from me getting burned by the old behavior, not from a roadmap meeting. Your agent should tell you the truth, even when the truth is "I didn't finish."&lt;/p&gt;

&lt;p&gt;The full technical breakdown is in &lt;a href="https://octomind.run/blog/octomind-0-44-2-release" rel="noopener noreferrer"&gt;the release post on the Octomind blog&lt;/a&gt; if you want the deeper dive on governance hashes and the orchestration split.&lt;/p&gt;

&lt;p&gt;I use Octomind on my own projects every day. These changes make it more honest, more useful, and ultimately more trustworthy. That's the release. Install it, break it, let me know what else needs fixing.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>rust</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I wrote a browser in 25k lines of Rust because every AI browser is lying to you</title>
      <dc:creator>Don Karter</dc:creator>
      <pubDate>Tue, 18 Aug 2026 08:50:55 +0000</pubDate>
      <link>https://dev.to/donk8r/i-wrote-a-browser-in-25k-lines-of-rust-because-every-ai-browser-is-lying-to-you-1pho</link>
      <guid>https://dev.to/donk8r/i-wrote-a-browser-in-25k-lines-of-rust-because-every-ai-browser-is-lying-to-you-1pho</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This post originally appeared on the &lt;a href="https://muvon.io/blog/introducing-octoweb-keyboard-first-ai-browser" rel="noopener noreferrer"&gt;Muvon blog&lt;/a&gt;. I'm cross-posting it here because the dev.to crowd is exactly who I built this for.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Every browser suddenly has AI in it. And every one of them did it the same way: take Chrome, bolt a chat panel onto the side, call it an AI browser. The browser doesn't know the agent exists. The agent can't touch the browser. Two strangers sharing a window.&lt;/p&gt;

&lt;p&gt;I spent this year building agents — a runtime, memory, code search, a filesystem layer — and at some point the question became unavoidable: what would a browser look like if it were designed for AI from the first commit? Not AI added. AI as a citizen — in both directions. The agent lives in the browser and can see what you see. And the browser is a tool the agent can pick up and use.&lt;/p&gt;

&lt;p&gt;So I built it. Octoweb is a WebKit browser written in Rust — no Electron, no Chromium, about 25,000 lines — made for two overlapping audiences: people who live on the keyboard, and people who work with agents all day. I'm both, and five months later it's the browser I start every morning in: reading docs, debugging my own web apps, handing the boring browser chores to Octomind while I keep reading.&lt;/p&gt;

&lt;p&gt;It just hit 0.10.0, and I figured the dev.to crowd would care about the engineering decisions more than the product announcement. So here's the build story.&lt;/p&gt;

&lt;h2&gt;
  
  
  First, the geek part: no mouse required
&lt;/h2&gt;

&lt;p&gt;Before the AI does anything, Octoweb has to earn its place as a browser for people who think in keystrokes. The design rule was simple: every action has a shortcut, nothing requires a click.&lt;/p&gt;

&lt;p&gt;The center of it is the command palette (&lt;code&gt;⌘⇧P&lt;/code&gt;) — type a URL, a search query, or any fragment of a page you've visited, and it fuzzy-matches across open tabs and history, ranked by match quality and visit frequency. One more keystroke opens, switches, or searches. And because muscle memory is sacred, the palette speaks readline: &lt;code&gt;⌃A&lt;/code&gt;/&lt;code&gt;⌃E&lt;/code&gt; to jump, &lt;code&gt;⌃K&lt;/code&gt;/&lt;code&gt;⌃U&lt;/code&gt; to kill, &lt;code&gt;⌃N&lt;/code&gt;/&lt;code&gt;⌃P&lt;/code&gt; to move. If your fingers know Emacs or a shell, they already know Octoweb.&lt;/p&gt;

&lt;p&gt;The rest of the vocabulary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fast-access slots&lt;/strong&gt; — &lt;code&gt;⌘⇧1&lt;/code&gt;–&lt;code&gt;⌘⇧0&lt;/code&gt; pins the current page to a numbered slot; &lt;code&gt;⌘1&lt;/code&gt;–&lt;code&gt;⌘0&lt;/code&gt; jumps back from anywhere. Ten pages, one keystroke each, persisted across restarts. It's the browser equivalent of Vim marks. New in 0.10.0: &lt;code&gt;⌘⇧N&lt;/code&gt; pins the current page to the first free slot — and unpins it if it's already there.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MRU tab cycling&lt;/strong&gt; — &lt;code&gt;⌃N&lt;/code&gt;/&lt;code&gt;⌃P&lt;/code&gt; walks tabs in most-recently-used order, the way you actually switch between two pages, not the order they happen to sit in the tab bar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vim-style scrolling&lt;/strong&gt; — &lt;code&gt;⌃D&lt;/code&gt;/&lt;code&gt;⌃U&lt;/code&gt; for half pages, &lt;code&gt;⌃T&lt;/code&gt;/&lt;code&gt;⌃B&lt;/code&gt; for top and bottom.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Screenshots to clipboard&lt;/strong&gt; — &lt;code&gt;⌘S&lt;/code&gt; viewport, &lt;code&gt;⌘⇧S&lt;/code&gt; full page. No save dialog, no file to clean up later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;⌃R&lt;/code&gt; in the AI prompt box&lt;/strong&gt; — reverse incremental search through your prompt history. Yes: I put readline's history search in the browser's AI input, because once you've had it in a shell you want it everywhere.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Global shortcuts run through CGEventTap, macOS-native and configurable. And here's why Octoweb is macOS-only for now — it leans on the platform (WKWebView, AppKit, CGEventTap) instead of shipping a second operating system in a zip file. That's also why the whole browser is a single lean binary instead of a 300 MB Electron app.&lt;/p&gt;

&lt;h2&gt;
  
  
  The agent in the sidebar — running on Octomind
&lt;/h2&gt;

&lt;p&gt;Press &lt;code&gt;⌘⇧A&lt;/code&gt; and an agent slides in over the page. Not an iframe with a chat website in it — a real agent process, running locally, connected over the Agent Client Protocol.&lt;/p&gt;

&lt;p&gt;The agent is Octomind, my plug-and-play agent runtime — the same one that powers my terminal sessions and CI reviews. And here's the part you don't do: start it. Octoweb launches &lt;code&gt;octomind acp octoweb:assistant&lt;/code&gt; itself — a sandboxed subprocess per session, restarted if it dies, resumed with your conversation intact on the next launch. Install Octomind once, and the sidebar takes it from there.&lt;/p&gt;

&lt;p&gt;That &lt;code&gt;octoweb:assistant&lt;/code&gt; tag is a manifest from the community tap registry: model, system prompt, and tools, fetched and assembled automatically. Zero config files written by hand. From then on you can ask about the page you're reading, get code on it explained, or summarize a thread you don't have time for — with responses streaming in, sessions that persist and resume, and slash commands with rich output cards.&lt;/p&gt;

&lt;p&gt;And because it's a real agent, the sidebar isn't a chat box with opinions — it works. Swap the tag to &lt;code&gt;developer:rust&lt;/code&gt; and you can code from the browser: the agent edits files in its sandboxed workspace, tool calls show up as clickable rows with live status, and when it wants to show you something richer than prose — a form, a table, a small interactive UI — it renders an A2UI surface right in the sidebar. I've fixed bugs in Octoweb, from Octoweb, while the failing page sat in the next tab.&lt;/p&gt;

&lt;p&gt;Three details I sweated:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The agent tag is editable.&lt;/strong&gt; The sidebar header shows &lt;code&gt;octoweb:assistant&lt;/code&gt; by default, but type any tag your Octomind knows — &lt;code&gt;developer:rust&lt;/code&gt;, your own custom agent — and the sidebar reconnects to it on the spot. The browser doesn't care which brain it's talking to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The browser never calls an AI provider.&lt;/strong&gt; Every model call is made by Octomind, outside the browser process, with the agent's filesystem access sandboxed to its workspace. No data leaves your machine unless your agent sends it somewhere — and which agent that is, with which provider, is entirely your call.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The session is a two-way street.&lt;/strong&gt; Since 0.10.0, messages injected by the Octomind runtime — a specialist replying from the tap, a scheduled job finishing, a webhook firing — arrive in the sidebar as their own labeled bubbles, mid-conversation. Your browser becomes the place where your agents report back.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's also a smaller door: select text on any page, press &lt;code&gt;⌘⇧E&lt;/code&gt;, and an inline edit modal transforms the selection — rewrite, summarize, translate. It runs its own dedicated agent from the same tap — &lt;code&gt;octoweb:editor&lt;/code&gt; — with its own prompt history, &lt;code&gt;⌃R&lt;/code&gt; and all.&lt;/p&gt;

&lt;h2&gt;
  
  
  The browser as a tool: MCP from the inside
&lt;/h2&gt;

&lt;p&gt;This is the direction nobody else builds, and it's my favorite part. Octoweb runs an MCP server inside the browser — &lt;code&gt;localhost:3434/mcp&lt;/code&gt;. Any MCP client — Claude Desktop, an Octomind session, your own script — can connect and drive it: twenty-six tools covering navigation, tabs, clicking, typing, scrolling, screenshots, content extraction, console output, and network activity.&lt;/p&gt;

&lt;p&gt;You've seen browser automation before. The difference here is that the agent isn't driving a headless Chromium in a datacenter with no cookies and a bot-detection target on its back. It's driving your browser — your sessions, your logins, your tabs — while you watch. And the tool design takes "while you watch" seriously:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Navigation never steals focus.&lt;/strong&gt; &lt;code&gt;browser_navigate&lt;/code&gt; always opens in the background. Exactly one tool — &lt;code&gt;browser_switch_tab&lt;/code&gt; — is allowed to change what you're looking at. An agent can research in ten tabs behind your back without ever yanking the page out from under your cursor. It browses beside you, not instead of you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clicks that don't lie.&lt;/strong&gt; &lt;code&gt;browser_click&lt;/code&gt; retries until the element is present, stable, and unobstructed — and if something is covering it, the error says what. &lt;code&gt;browser_snapshot&lt;/code&gt; returns a map of interactive elements with stable &lt;code&gt;@N&lt;/code&gt; refs that pierces iframes, shadow DOM, and listener-only clickables. &lt;code&gt;browser_wait&lt;/code&gt; knows about SPA readiness, not just page load.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eyes included.&lt;/strong&gt; &lt;code&gt;browser_console_messages&lt;/code&gt; and &lt;code&gt;browser_network_requests&lt;/code&gt; give the agent the page's console errors and fetch/XHR activity with statuses and timings — the two things you'd open DevTools for, as tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guard rails at the boundary.&lt;/strong&gt; Text that flows out through snapshots and page content passes a sanitizer — card numbers get redacted before they ever reach a prompt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tokens are the budget.&lt;/strong&gt; Every tool answer is shaped for a model, not for a debugger: &lt;code&gt;browser_snapshot&lt;/code&gt; returns a compact element map instead of raw HTML (I deleted the &lt;code&gt;get_html&lt;/code&gt; tool on purpose), console and network logs come capped and filterable, and &lt;code&gt;@N&lt;/code&gt; refs mean the agent never burns half a context window guessing CSS selectors. An agent's turn is priced in tokens; the browser respects that.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And if your agent runtime is Octomind, wiring it up is one line inside a session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/mcp add octoweb http://localhost:3434/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The agent you were already talking to can now open docs, read them, fill forms, and check what a page's console is screaming about — mid-conversation, no restart. This is how browser chores leave my to-do list: the agent reproduces a bug in a background tab, reads the console, and comes back with the failing request; it walks an admin panel I didn't feel like clicking through; it checks that a deploy actually rendered — in my logged-in browser, with my sessions, while I keep reading in the foreground tab.&lt;/p&gt;
&lt;h2&gt;
  
  
  The browser that learns with you
&lt;/h2&gt;

&lt;p&gt;One more experiment: proactive learning. On an interval — 30 minutes by default — Octoweb wakes a second, fully independent agent, the &lt;code&gt;octoweb:learning&lt;/code&gt; tag, which looks at your open tabs and recent history and distills what you're working on into Octomind's memory. Next session, the sidebar assistant already knows the docs you've been circling for three days.&lt;/p&gt;

&lt;p&gt;It's on by default — one toggle in Settings turns it off — it's local, the interval is yours to set, and the two agents are fully independent: run either without the other. I think ambient memory is where browser AI actually gets interesting, and I'd rather ship the honest v1 of it than a demo.&lt;/p&gt;
&lt;h2&gt;
  
  
  Yes, it's also just a good browser
&lt;/h2&gt;

&lt;p&gt;None of this matters if the browsing is worse than what you left. The fundamentals are there, and a few are better than there:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Smart tab hibernation&lt;/strong&gt; — background tabs freeze under memory pressure, with RAM-aware thresholds. Fifty tabs is a lifestyle, not a leak. And since 0.10.0 there's a cap on open tabs (500 by default, configurable) that quietly closes the least-recently-used ones past it — an airbag for tab hoarders.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content blocking built in&lt;/strong&gt; — trackers and ads via WebKit's native content rule lists, no extension needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cold starts stay cold&lt;/strong&gt; — favicons are cached as data-URIs, so launching the browser makes zero network requests until you do.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Session restore, WebAuthn passkeys, PDF and DOCX viewing, find-in-page on the CSS Custom Highlight API, native fullscreen, proper popup-window handling.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What about extensions? Honest status: the Safari Web Extensions integration (for 1Password, Bitwarden, and friends) is fully implemented in the code — and blocked on Apple's &lt;code&gt;com.apple.developer.web-browser&lt;/code&gt; entitlement, an approval only Apple can grant. Until it lands, content scripts don't inject. I'd rather tell you that than pretend extensions are a roadmap item.&lt;/p&gt;
&lt;h2&gt;
  
  
  Five months, 0.1.0 to 0.10.0
&lt;/h2&gt;

&lt;p&gt;Octoweb started in late March as an experiment: could a keyboard browser with an ACP sidebar be usable in a week? By 0.6.0 it had tab hibernation and the first MCP automation tools. 0.7.0 brought persistent chat sessions, passkeys, and slash commands. 0.8.0 was the big one — the actionability harness, the e2e suite that tests the browser through its own MCP server, agent sandboxing, configurable keybindings, A2UI surfaces. 0.9.0, cut in late July, moved to ACP v1.2.0 with account authentication and a long tail of stability work. And today's 0.10.0 is what daily use does to a roadmap: pinned tabs, the open-tab cap, account quota status that refreshes itself, specialist messages landing in the sidebar — plus fixes for a memory leak and orphaned agent processes, the kind of thing you only find by leaving it running for weeks.&lt;/p&gt;

&lt;p&gt;What started as an experiment is now the browser I actually live in. It won't replace my main browser this year — it might become the one I reach for when I want to think.&lt;/p&gt;
&lt;h2&gt;
  
  
  Get it
&lt;/h2&gt;

&lt;p&gt;One line on any Mac, Apple Silicon or Intel:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--cask&lt;/span&gt; muvon/tap/octoweb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Or grab a prebuilt archive from &lt;a href="https://github.com/muvon/octoweb/releases" rel="noopener noreferrer"&gt;GitHub Releases&lt;/a&gt;, or build from source with a Rust toolchain:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/muvon/octoweb
&lt;span class="nb"&gt;cd &lt;/span&gt;octoweb
./build.sh &lt;span class="nt"&gt;--dev&lt;/span&gt;        &lt;span class="c"&gt;# ad-hoc signed, no cert needed&lt;/span&gt;
open dist/Octoweb.app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For the sidebar, install Octomind and sign in:&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/muvon/octomind/master/install.sh | bash
octomind login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;octomind login&lt;/code&gt; is a device-code sign-in to Octomind Cloud — the subscription includes model access, so there's nothing else to configure, and the sidebar shows your account and quota status. Prefer your own keys? Skip the login and export any provider key instead (&lt;code&gt;OPENROUTER_API_KEY&lt;/code&gt;, &lt;code&gt;ANTHROPIC_API_KEY&lt;/code&gt;, …) — BYOK is a first-class path. Either way, that's the whole setup: launch Octoweb, press &lt;code&gt;⌘⇧A&lt;/code&gt;, and say hello — the browser starts and manages the agent process itself. Config is one TOML file at &lt;code&gt;~/Library/Application Support/octoweb/config.toml&lt;/code&gt;; Settings is &lt;code&gt;⌘,&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Octoweb is on GitHub under Apache-2.0, like everything else I ship. If you live on the keyboard, or your agents deserve a real browser instead of a headless one — try it, and tell me what's missing. The features requested by early users are the reason 0.10.0 looks nothing like 0.1.0.&lt;/p&gt;

&lt;p&gt;— Don&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Muvon" rel="noopener noreferrer"&gt;
        Muvon
      &lt;/a&gt; / &lt;a href="https://github.com/Muvon/octoweb" rel="noopener noreferrer"&gt;
        octoweb
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Dead simple AI-loaded browser for geeks
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Octoweb — the keyboard-first AI browser for macOS&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://github.com/muvon/octoweb/releases" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9e919fc10d7ba6ddc98407c53ddbcbc95a9547787d6d8f2a818e648795b2af9d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f76657273696f6e2d302e392e302d626c75652e737667" alt="Version"&gt;&lt;/a&gt;
&lt;a href="https://github.com/muvon/octoweb/releases" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c9cbcc6cb408dcb296c9b6c8a65cb4ad58e794b84e4e3cd247a2fc454e7ece5e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f706c6174666f726d2d6d61634f532d626c61636b2e737667" alt="Platform"&gt;&lt;/a&gt;
&lt;a href="https://github.com/Muvon/octoweb/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/48c3918479c6ea40d65216332adbf6c7a89400e32b69faf50a750b905d214b76/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d417061636865253230322e302d677265656e2e737667" alt="License"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The browser you reach for when you want to think. macOS only, by design.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Built on WebKit and Rust. No Electron. No Chrome. No mouse required.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why Octoweb?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Most browsers are built around the mouse. Octoweb is built around the keyboard — and around the idea that your browser should amplify your thinking, not interrupt it. Every action has a shortcut. The AI assistant lives in a sidebar, not a tab. And your AI tools can drive the browser directly via MCP. No extensions. No config. Just open it and go.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Three things it does differently:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Keyboard-first navigation&lt;/strong&gt; — Every action has a shortcut. Nothing requires a click. The command palette (&lt;code&gt;⌘⇧P&lt;/code&gt;) fuzzy-searches tabs and history. Pin any page to a fast-access slot with &lt;code&gt;⌘⇧1&lt;/code&gt;–&lt;code&gt;⌘⇧0&lt;/code&gt; and jump back with &lt;code&gt;⌘1&lt;/code&gt;–&lt;code&gt;⌘0&lt;/code&gt; from anywhere.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;AI assistant built in&lt;/strong&gt;…&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Muvon/octoweb" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;(Octoweb is open source under Apache-2.0, developed by Muvon Un Limited. It runs on Octomind, my plug-and-play AI agent runtime.)&lt;/p&gt;

</description>
      <category>rust</category>
      <category>opensource</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>DeepSeek V4 Flash on 50 Real Pull Requests: Two Harnesses, One Ceiling</title>
      <dc:creator>Don Karter</dc:creator>
      <pubDate>Sat, 15 Aug 2026 08:16:05 +0000</pubDate>
      <link>https://dev.to/donk8r/deepseek-v4-flash-on-50-real-pull-requests-two-harnesses-one-ceiling-38be</link>
      <guid>https://dev.to/donk8r/deepseek-v4-flash-on-50-real-pull-requests-two-harnesses-one-ceiling-38be</guid>
      <description>&lt;p&gt;Two harnesses. Same model. Two tasks apart.&lt;/p&gt;

&lt;p&gt;We ran deepseek-v4-flash through octomind and opencode on 50 real-PR tasks — same model, same prompt, sealed network. 45/50 vs 43/50, three judge points apart, three cents a task either way. The model is strong enough to be harness-neutral; what separates clients now is who finishes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Model Won't Make It Dramatic
&lt;/h2&gt;

&lt;p&gt;Two weeks ago we published a same-model A/B where the harness decided everything: 24 of 25 tasks solved in octomind, 19 of 25 in opencode, at double the cost. We just re-ran that experiment with DeepSeek V4 Flash, on a stricter benchmark, twice the tasks – and the model refused to make it dramatic. 45 versus 43.&lt;/p&gt;

&lt;p&gt;On 50 real pull requests harvested from merged fixes across C++, JavaScript, PHP, Python and Rust, deepseek-v4-flash solved 45/50 in octomind and 43/50 in opencode – same model, same system prompt, sealed network, about three cents a task either way. The model is strong enough to be harness-neutral. What's left for a harness to prove is how often it finishes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Ran: Real Bugs, Not Puzzles
&lt;/h2&gt;

&lt;p&gt;octobench cases aren't synthetic puzzles. Each one is a real bug or feature that a maintainer actually merged, replayed at the parent commit, and graded by the project's own held-out tests plus a judge panel scoring 0–100. Fifty cases, ten per language.&lt;/p&gt;

&lt;p&gt;Since the glm-5.2 run, we rebuilt the methodology, because the first version had a hole you could drive a truck through: the bench is built from merged PRs, and nothing stopped an agent from going and reading the merged PR. In early rounds opencode fetched the upstream fix from raw.githubusercontent.com in 13 of 49 cases and copied it. octomind's stock role was subtler but worse in spirit – it ordered the agent to websearch the upstream issue and "mirror its approach and API contracts EXACTLY." On a benchmark made of merged PRs, that's an instruction to read the answer key.&lt;/p&gt;

&lt;p&gt;So this campaign runs clean: One shared system prompt for both harnesses, distilled from octomind's role with the client-specific parts stripped. A sync script fails the build if they drift. No route to the answer. Web search and web fetch disabled in both clients; GitHub unreachable from the agent's container once setup finishes. Same model, same endpoint – official deepseek-v4-flash on api.deepseek.com, deepseek:deepseek-v4-flash in octomind, deepseek/deepseek-v4-flash in opencode. One measurement note that changed our read of things: we started on a third-party token-plan endpoint and switched to the official API mid-campaign. The official endpoint is roughly 3× faster per request. A chunk of what we'd previously logged as "slow client" turned out to be slow provider.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Scoreboard
&lt;/h2&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;octomind&lt;/th&gt;
&lt;th&gt;opencode&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Solved&lt;/td&gt;
&lt;td&gt;45/50 (90.0%)&lt;/td&gt;
&lt;td&gt;43/50 (86.0%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Judge average&lt;/td&gt;
&lt;td&gt;88.59&lt;/td&gt;
&lt;td&gt;85.59&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total cost&lt;/td&gt;
&lt;td&gt;≈$1.59 ($0.032/case)&lt;/td&gt;
&lt;td&gt;≈$1.53 ($0.031/case)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent runtime&lt;/td&gt;
&lt;td&gt;10.4h (12.5m/case)&lt;/td&gt;
&lt;td&gt;8.7h (10.4m/case)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tokens&lt;/td&gt;
&lt;td&gt;4.4M (1.9M in / 1.5M out / 1.0M thinking)&lt;/td&gt;
&lt;td&gt;4.0M (2.1M in / 573K out / 1.3M thinking)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache read&lt;/td&gt;
&lt;td&gt;224.2M&lt;/td&gt;
&lt;td&gt;254.3M&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two tasks and three judge points apart. For calibration: our measured judge noise on this suite is about 1.7 points, so the gap is real but roughly double the noise floor – not the five-task blowout the glm run produced. Costs are a coin flip.&lt;/p&gt;

&lt;h2&gt;
  
  
  The New Flash in Numbers
&lt;/h2&gt;

&lt;p&gt;The official V4 Flash went live July 31, and the release is the real thing: DeepSeek's own GA numbers have it beating the V4 Pro preview on agentic benchmarks – Terminal Bench 2.1 at 82.7, DeepSWE at 54.4, Toolathlon verified at 70.3 – from a Mixture-of-Experts with 284B total and 13B activated parameters and a 1M-token context window. What that translates to on real-PR work: twelve minutes and three cents per landed fix, a ~94 judge average on cases it passes, in either harness. No babysitting, no mystery timeouts. For the routine 90% of maintainer work, this model at flash pricing is simply a solved problem.&lt;/p&gt;

&lt;p&gt;And here's the interesting part – it's harness-neutral. The glm-5.2 run showed a five-task gap between the same model in two harnesses. V4 Flash lands two tasks apart. Two. Part of that is the model carrying more of its own discipline: fewer wasted reads, fewer early victory laps, less need for a supervisor to keep it honest. Part of it is that this benchmark is stricter with both clients – we sealed the answer key, and that cut against octomind's stock role as much as anyone's web access. We made the test harder for ourselves and the gap narrowed anyway. Both things are true.&lt;/p&gt;

&lt;h2&gt;
  
  
  One Ceiling, Five Walls
&lt;/h2&gt;

&lt;p&gt;The five cases octomind fails are the same five opencode fails: yaml-cpp's binary emit styles, pino-pretty's control stripping, commonmark's fence tabs, rustls's misplaced extensions, and React's hidden hydration hang. Identical walls across harnesses is what a model blind spot looks like – not a harness artifact. These are the composition-heavy fixes where the model keeps missing a sibling path or a per-message rule no matter how it's prompted. Four instrumented reruns of pino-pretty all missed the same sibling. That's the model, not the steering. The honest read of the 86–90% band: the last 10% is where model quality ends and everything else begins.&lt;/p&gt;

&lt;p&gt;What the harness still decides is the finish: octomind has zero unique failures. opencode's two extra losses are both finishes that never landed: Guzzle's cookie prefixes, where opencode spent 17 minutes and failed while octomind passed in 4; Monolog's trace length, where opencode bailed in 3 minutes with a judge score of 36 while octomind landed a 94.67 in 2.&lt;/p&gt;

&lt;p&gt;The React case is the same story at maximum volume. It's a hang-by-design bug – every wrong attempt blocks instead of failing – on a giant repo. opencode stopped at 63 minutes and 394 steps, scoring 36.67. octomind ground for 271 minutes and 1,322 steps – for the same $0.32 – to a fix that passes 66 of 67 hidden tests. We record it as a failure, because it is one, but the judge scored the near-miss at 41.67. (One run died at minute 213 on a provider quota error and was resumed from a restored session to finish at all.)&lt;/p&gt;

&lt;p&gt;That's finalization: not better luck, more refusal to stop early. Strip the React outlier and octomind also averages about 7 minutes a case to opencode's 9.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Token Tax
&lt;/h2&gt;

&lt;p&gt;The tax is real, though. octomind wrote 2.6× the output tokens – 1.5M versus 573K. It talks more. And on the React-sized repos its fine-grained tool loop against a fat per-call context is a genuine speed ceiling; coarser steps and context slimming are next on our own list. A harness that finishes everything will still cost you in words.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Ceiling and Floor Thesis
&lt;/h2&gt;

&lt;p&gt;The model sets the ceiling. The harness sets the floor. After the glm run we wrote that model quality is table stakes and the harness is where the edge is. V4 Flash tightens that into something more precise: a model this good raises the ceiling for everyone – pick the model you like, the ceiling barely moves between harnesses. What the harness decides is how often you actually reach it, and whether the last five percent lands or gets declared done at minute 63.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next: GLM-5.3
&lt;/h2&gt;

&lt;p&gt;glm-5.3 just dropped. Same bench, next question. Yesterday Zhipu released GLM-5.3: same base model as 5.2, with the gains coming from post-training alone. Zhipu claims a 50% coding improvement over 5.2 and calls it the strongest open-weights coding model. It's live through their coding plan now. Open weights are promised in about two weeks, behind a safety review. This matters to us more than most releases, because glm-5.2 is the model that started this story. In the first run, glm-5.2 in octomind beat Claude Code running claude-opus-5 (24/25 solved against 23/25, $63 against $82, 3.6 hours against 6.7) – while paying full freight: that run went through an endpoint with no prompt caching, so every turn re-bought its whole context at list price. So the next campaign writes itself. glm-5.3 versus glm-5.2 on the same sealed 50-case bench, in both harnesses, answer key locked. A claimed 50% post-training jump is exactly the kind of number vendor benchmarks love and real pull requests interrogate. And there's a sharper question underneath: V4 Flash just showed that a strong model narrows the harness gap to two tasks. If 5.3 really is that much better than a model already beating Opus, does the floor rise with the ceiling – or does the last 10% stay exactly right where it was? Worth finding out.&lt;/p&gt;

&lt;p&gt;Reproduction steps and the raw per-case artifacts are pinned at the commit this post describes. GLM-5.3 versus 5.2 is next on the calendar, with Claude Code and Codex columns on the same sealed bench right behind it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>machinelearning</category>
      <category>devops</category>
    </item>
    <item>
      <title>Benchmarking AI Coding Agents on Real Pull Requests</title>
      <dc:creator>Don Karter</dc:creator>
      <pubDate>Sat, 01 Aug 2026 17:25:42 +0000</pubDate>
      <link>https://dev.to/donk8r/benchmarking-ai-coding-agents-on-real-pull-requests-22k9</link>
      <guid>https://dev.to/donk8r/benchmarking-ai-coding-agents-on-real-pull-requests-22k9</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;No synthetic puzzles, no contaminated suites: 25 tasks harvested from PRs merged in 2026 across five languages, graded by each project's own held-out tests. Four agents at stock settings. octomind with an open model solved 24/25 - ahead of Claude Code with Opus - while the same model in another harness solved 19 at double the cost. Here's how we built the benchmark and what it taught us.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We wanted one number we could actually trust: if you hand a coding agent the kind of task a maintainer faces on a normal Tuesday - a real bug, a real feature request, in a real codebase - how often does it deliver a fix the project's own test suite accepts?&lt;/p&gt;

&lt;p&gt;None of the public benchmarks could give us that number, so we built octobench. This post is the story of how, what broke along the way, and what the scoreboard says.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not an existing benchmark
&lt;/h2&gt;

&lt;p&gt;Two problems kept biting us with the popular suites.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contamination.&lt;/strong&gt; The well-known benchmarks are old enough that frontier models have seen the fixes - sometimes literally, commit by commit - in training data. At one point we caught a model running git show on a commit hash it had no business knowing about. Whatever that measures, it isn't problem-solving.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Taste-grading.&lt;/strong&gt; Many benchmark tasks are graded by tests that assert an implementer's arbitrary choices: an internal variable name, the exact wording of an error message. An agent can write a maintainer-grade fix and fail because it phrased an error differently than the original author. That measures mimicry, not engineering.&lt;/p&gt;

&lt;p&gt;So the design goals were: real tasks, fresh tasks, fair grading.&lt;/p&gt;

&lt;h2&gt;
  
  
  25 tasks, 5 languages, mostly newer than the models
&lt;/h2&gt;

&lt;p&gt;We harvested every task from a real, recently-merged pull request in a respected open-source project: werkzeug, click, anyio, pydantic, twig, carbon, symfony, guzzle, commonmark, uuid, rayon, chrono, bytes, serde-json, fmt, yaml-cpp, catch2, spdlog, eslint, fastify, undici, pino, pino-pretty.&lt;/p&gt;

&lt;p&gt;That list is deliberate on two axes. &lt;strong&gt;Languages:&lt;/strong&gt; five of them - python, php, rust, c++, js - because an agent that's great at python and lost in a CMake build is not a general coding agent. &lt;strong&gt;Freshness:&lt;/strong&gt; every fix was merged in 2026, mostly after current model training cutoffs - several within days of harvesting. One case, chrono's reversed date iterators, was merged the same morning we picked it. A benchmark you can re-harvest as cutoffs advance is a benchmark that can't go stale.&lt;/p&gt;

&lt;p&gt;The scenario mix runs from one-line crash fixes to multi-file features, and each case reconstructs the moment before the fix existed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;setup.sh&lt;/strong&gt; checks out the repository at the commit before the fix - as a single-commit shallow clone, so the answer isn't hiding in the git object store - prepares the toolchain, and removes the git remote so the agent can't just fetch the upstream fix.&lt;/li&gt;
&lt;li&gt;The agent gets a task prompt and works in the repo like a hired contractor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;validate.sh&lt;/strong&gt; runs after the agent finishes: it fetches the merged fix's test files - which the agent has never seen - overwrites whatever the agent may have done to the test suite, and runs exactly those tests. The project's own tests, written by the project's own maintainers, decide pass or fail.&lt;/li&gt;
&lt;li&gt;An LLM judge separately grades work quality from the diff and logs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before any case entered the benchmark it had to prove itself fail-to-pass: held-out tests must fail on the pre-fix code and pass with the real merged fix applied. No proof, no case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing prompts that don't cheat - in either direction
&lt;/h2&gt;

&lt;p&gt;For 20 tasks we ran a dedicated agent (octomind's developer:reverse-spec) over each merged commit to reconstruct the request that plausibly produced it, then curated by hand with one rule - the derivability rule: everything the hidden tests assert must be derivable from the prompt. Bug fixes got a short informal prompt, because any correct fix passes. Features whose tests pin public API names or exact output formats got a spec-tight version, because a real requester would state a wire format.&lt;/p&gt;

&lt;p&gt;For the other 5 - one per language - we used the actual GitHub issue text, verbatim, trimmed only of fix-leaking sections (one author had helpfully written "I have a PR ready that does X"). That tests something different: turning a user-shaped bug report, sometimes with a screenshot instead of expected output, into a maintainer-grade fix.&lt;/p&gt;

&lt;p&gt;A few favorites, by the skill they isolate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;anyio's cancel-scope spin&lt;/strong&gt; - a 4-line fix that requires understanding why an asyncio event loop pins a CPU core. Tiny diff, deep async reasoning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;guzzle's cookie prefixes&lt;/strong&gt; - 27 lines with three independent traps; the naive startsWith("__Secure-") &amp;amp;&amp;amp; !secure fix fails half the tests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;commonmark's fenced-code tabs&lt;/strong&gt; - a user reported "code blocks sometimes lose their first character" with a screenshot. The held-out fixtures include cases the issue never mentions - only a true root-cause fix passes, a symptom-patch fails.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pino-pretty's control characters&lt;/strong&gt; - two hidden tests exist purely to punish over-broad sanitizing: they pass on the broken code and fail any fix that doesn't respect the trust boundary.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Eating our own dogfood
&lt;/h2&gt;

&lt;p&gt;Before the final run, three reviewers read every held-out assertion against every prompt. The audit caught real problems - in our benchmark, not the agents. One case's tests asserted the exact prose of an error message the issue never quoted; two frontier agents produced perfect fixes (one even picked the same error-code number as the maintainer) and both failed on wording. We replaced the case. Another case's hidden tests contradicted its own issue text. A third had its held-out tests inside a source file, so restoring gold tests wholesale would silently revert a correct fix.&lt;/p&gt;

&lt;p&gt;The meta-lesson: benchmark infrastructure fails in ways that look exactly like model failures. Every anomaly we chased - a judge scoring 0 on a passing run, a "solved" case with an empty diff - deserved a real root-cause, and about half were ours.&lt;/p&gt;

&lt;h2&gt;
  
  
  The scoreboard
&lt;/h2&gt;

&lt;p&gt;Four agents, each at its stock, out-of-the-box single-agent invocation. No tuning, no custom prompts.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Agent&lt;/th&gt;
&lt;th&gt;Solved&lt;/th&gt;
&lt;th&gt;Judge Σ / 2500&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;th&gt;Wall Time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;octomind + glm-5.2&lt;/td&gt;
&lt;td&gt;24/25&lt;/td&gt;
&lt;td&gt;2264&lt;/td&gt;
&lt;td&gt;$63.43&lt;/td&gt;
&lt;td&gt;3.6h&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;claude code + claude-opus-5&lt;/td&gt;
&lt;td&gt;23/25&lt;/td&gt;
&lt;td&gt;2262&lt;/td&gt;
&lt;td&gt;$81.79&lt;/td&gt;
&lt;td&gt;6.7h&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;codex + gpt-5.6-sol&lt;/td&gt;
&lt;td&gt;21/25&lt;/td&gt;
&lt;td&gt;2127&lt;/td&gt;
&lt;td&gt;$14.86&lt;/td&gt;
&lt;td&gt;1.0h&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;opencode + glm-5.2&lt;/td&gt;
&lt;td&gt;19/25&lt;/td&gt;
&lt;td&gt;2093&lt;/td&gt;
&lt;td&gt;$129.54&lt;/td&gt;
&lt;td&gt;3.3h&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Four things the table says:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The harness matters as much as the model.&lt;/strong&gt; octomind and opencode ran the same model on the same endpoint at the same prices - a pure harness A/B. octomind solved 24, opencode 19, at half the cost. The difference is context discipline (opencode pushed 30M input tokens through one task where octomind needed 8M) and supervision: the cases opencode dropped are exactly the deep-root-cause, multi-trap ones where an unsupervised agent declares victory too early.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;An open model beat Opus while paying full price for every token.&lt;/strong&gt; glm-5.2 ran via Ollama cloud, which has no prompt caching - every agent turn re-bought its full context at list price. Opus, meanwhile, billed ~97% of its context re-reads at 1/10 cache rates. glm's dollar figure is its worst case, and it still came out ahead on solves, cost, and time. On any cache-enabled endpoint the cost gap becomes a chasm.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Speed has a thoroughness tax.&lt;/strong&gt; Codex is remarkable - 2-4 minutes per case, $0.59 median - but all four of its failures are cases that punish not checking one more caller, one more surface, one more trap.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No task was impossible.&lt;/strong&gt; Every case was solved by at least one agent, and the failure classes were clean: the trust-boundary case caught opus, codex, and opencode; the deep root-cause parser case caught everyone except octomind; and the one case both glm harnesses failed identically is a genuine model blind spot, not a harness artifact.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Where the harness edge comes from
&lt;/h2&gt;

&lt;p&gt;A big share of "context discipline" is simply how the agent finds code. Stock claude code, codex, and opencode navigate a repository the same way: grep, read the file, grep again, read more - and every re-read is context the model pays for on every subsequent turn. octomind's developer:general ships with octocode out of the box: structural search that finds the exact symbol, signature, or code pattern directly, so the agent jumps to the three functions that matter instead of paging through files that don't. Enable semantic indexing and it also searches the codebase by meaning - "where is cookie validation handled" as a query, not a grep pattern. Fewer wrong files read is fewer tokens re-bought, and that compounds into the 8M-vs-30M input-token gap the A/B exposed.&lt;/p&gt;

&lt;p&gt;The other share is supervision. During dry runs an agent once "finished" a task by announcing "Now let me create a plan and implement the fix" - and stopping, with a zero diff. In a non-interactive run a text-only turn ends the session, so octomind added a deterministic guard: if a turn ends with no action while the agent's self-reported status is still in progress, it gets sent back to work. In the final run that failure mode was gone - and the cases opencode dropped are precisely the ones where nothing questioned an early declaration of victory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reproduce it
&lt;/h2&gt;

&lt;p&gt;Everything is public and pinned: the full per-case table and reproduction guide at the exact commit of this run, per-case agent traces and judge verdicts in the run artifacts, and the case-harvesting pipeline - the reverse-spec agent, the derivability rules, the fail-to-pass verifier - documented so the set keeps growing as training cutoffs advance.&lt;/p&gt;

&lt;p&gt;The result we care most about isn't the ranking. It's the A/B: same model, same endpoint, five more tasks solved at half the cost. Model quality is table stakes now - the harness is where the leverage is. That's the thesis octomind is built on, and now we have the number.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>coding</category>
      <category>benchmark</category>
      <category>programming</category>
    </item>
    <item>
      <title>Workflows Come to the Cloud: Running Multi-Agent Pipelines from the Browser</title>
      <dc:creator>Don Karter</dc:creator>
      <pubDate>Wed, 29 Jul 2026 08:22:38 +0000</pubDate>
      <link>https://dev.to/donk8r/workflows-come-to-the-cloud-running-multi-agent-pipelines-from-the-browser-4lg</link>
      <guid>https://dev.to/donk8r/workflows-come-to-the-cloud-running-multi-agent-pipelines-from-the-browser-4lg</guid>
      <description>&lt;h1&gt;
  
  
  Workflows Come to the Cloud: Running Multi-Agent Pipelines from the Browser
&lt;/h1&gt;

&lt;p&gt;I've been building AI tools for three years now. Here's what I keep running into: most real work isn't a conversation – it's a contract.&lt;/p&gt;

&lt;p&gt;You have the input (an article, a diff, a pile of CSV data). You know what the output should be (social drafts, a review verdict, a readable report). What you want in between isn't chat. It's a pipeline: specialists doing their parts, handing off to each other, with an auditor gating the result before it reaches you.&lt;/p&gt;

&lt;p&gt;That's the core idea behind workflows in &lt;a href="https://github.com/muvon/octomind" rel="noopener noreferrer"&gt;Octomind&lt;/a&gt; – our session-first, multi-provider AI agent runtime. And as of this week, those workflows now run in the cloud panel, not just the CLI.&lt;/p&gt;

&lt;p&gt;Same pipelines. Same tap library. New surface.&lt;/p&gt;

&lt;p&gt;If you've been running &lt;code&gt;octomind workflow&lt;/code&gt; from your terminal, nothing changed – you just got a second way to do the same thing. If you haven't tried workflows yet, here's what I built and why I built it this way.&lt;/p&gt;

&lt;h2&gt;
  
  
  A workflow is a team with a contract
&lt;/h2&gt;

&lt;p&gt;Every workflow in Octomind is a declared pipeline of steps. Each step is a full agent run with its own role. Steps can be sequential, parallel, conditional – or loops, which is where it gets interesting.&lt;/p&gt;

&lt;p&gt;Take the &lt;code&gt;promote&lt;/code&gt; workflow. You feed it an article. It turns that article into platform-native social drafts. Here's what actually happens:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A researcher grounds the article in its source material&lt;/li&gt;
&lt;li&gt;A writer drafts per platform (Twitter, LinkedIn, whatever)&lt;/li&gt;
&lt;li&gt;An auditor checks each draft against quality gates&lt;/li&gt;
&lt;li&gt;If the audit fails, the draft loops back for re-editing&lt;/li&gt;
&lt;li&gt;The pipeline halts rather than shipping something the auditor rejected&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Or &lt;code&gt;review&lt;/code&gt; – it takes your unstaged diff and produces an independently verified verdict. Or &lt;code&gt;report&lt;/code&gt; – it turns raw data into a decision-ready document where every number is computed, never invented.&lt;/p&gt;

&lt;p&gt;There are fourteen of these in the public tap today. They're the same whether you run them from a terminal or a browser.&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;# CLI still works exactly the same&lt;/span&gt;
&lt;span class="nb"&gt;cat &lt;/span&gt;article.md | octomind workflow promote
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The full input goes in at the start – the whole brief, up to 256 KB of it – and the finished result comes out at the end. No steering mid-flight, no drip-feeding context. That's not a limitation; it's the point. You're not chatting with a team, you're commissioning one.&lt;/p&gt;

&lt;h2&gt;
  
  
  From library to running pipeline
&lt;/h2&gt;

&lt;p&gt;In the cloud panel, the Library tab shows the catalog. Pick a workflow and the new-run screen asks for exactly two things: which machine, and your input.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Dry run&lt;/strong&gt; button is the part I'd point at first. It validates the workflow on the machine itself and renders the resolved pipeline – every step, every role, the loop caps – without spawning anything or reading your input.&lt;/p&gt;

&lt;p&gt;It's free. It takes a couple of seconds. And it means a broken pipeline fails before a single token burns.&lt;/p&gt;

&lt;p&gt;Starting a real run performs the same validation again on its own, so the button is a preview, not a chore. But I use it anyway. There's something useful about seeing the full pipeline shape before you commit to running it.&lt;/p&gt;

&lt;p&gt;Then the run page becomes the thing worth watching: the whole chain renders immediately from the validated plan, and steps light up as the stream comes in. A checkmark when a step completes. A spinner on the one running. A pass counter on loops as the auditor sends drafts back.&lt;/p&gt;

&lt;p&gt;You can close the tab and come back. The run belongs to the machine, not to your browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Artifacts: when output is a file, not text
&lt;/h2&gt;

&lt;p&gt;Under the result there's a detail we're calling artifacts. Workflow deliverables are often files – &lt;code&gt;promote&lt;/code&gt; writes drafts, &lt;code&gt;report&lt;/code&gt; renders a document – and the final message names the paths.&lt;/p&gt;

&lt;p&gt;The panel picks those mentions out and turns each one into a download chip, with inline previews for images and text. Nothing is fetched until you click – the mention is just a string until you ask for the file.&lt;/p&gt;

&lt;p&gt;This is also the security posture: text can name a path, but only you can fetch one. Sessions got the same mechanic: when an agent in a chat says it saved something, the file is right there to grab.&lt;/p&gt;

&lt;p&gt;Everything the run printed is kept, verbatim. The collapsible full log holds the validated plan, the machine-readable event stream, and the human progress view – downloadable, nothing summarized away. Step outputs get their own friendly view too, so you can read what each specialist handed to the next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest one-shots: why there's no retry button
&lt;/h2&gt;

&lt;p&gt;Here's a design decision I want to be explicit about: a workflow run has five states – queued, running, done, failed, canceled – and the last three are final.&lt;/p&gt;

&lt;p&gt;There is no resume. No retry-in-place. No "continue from step 3".&lt;/p&gt;

&lt;p&gt;The CLI has no such mode, and we didn't fake one in the UI. Partial re-execution of a pipeline whose earlier steps fed later ones is a good way to get confidently wrong output. If step 2 consumed step 1's output and step 5 consumed step 4's output, you can't just rerun step 3 without invalidating everything downstream.&lt;/p&gt;

&lt;p&gt;So a failed run tells you plainly what went wrong – the actual stderr tail, not a shrug – keeps every completed step's output visible (that spend was real, and the work is often still useful), and offers exactly one recovery: &lt;strong&gt;Run again&lt;/strong&gt;, which pre-fills a fresh run with the same workflow and input.&lt;/p&gt;

&lt;p&gt;Your runs list is history you can trust: what ran, what it cost, what came out.&lt;/p&gt;

&lt;p&gt;I'd rather give you a clean slate than a half-broken retry mechanism that produces garbage output.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it costs: nothing new
&lt;/h2&gt;

&lt;p&gt;There's no workflow fee and no new meter. A run's model calls flow through your account's hub key exactly like a session's – plan caps and credits decide, per published prices – and the machine bills per second while it works, like always.&lt;/p&gt;

&lt;p&gt;The run page shows the aggregated cost the pipeline reported, so you can see what a &lt;code&gt;promote&lt;/code&gt; actually costs you end to end. On the open models, it's typically cents.&lt;/p&gt;

&lt;p&gt;Dry runs are free. And workflows are on every plan, free tier included – the free tier's one-at-a-time model calls just serialize the steps, which makes runs slower, not smaller.&lt;/p&gt;

&lt;h2&gt;
  
  
  Same contract as the CLI
&lt;/h2&gt;

&lt;p&gt;If you already run workflows from the terminal, nothing changed and everything got a second surface. The panel drives the same &lt;code&gt;octomind workflow&lt;/code&gt; binary on your machine, with the same tap resolution and the same machine-readable output contract the CLI exposes via &lt;code&gt;--format jsonl&lt;/code&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;# Machine-readable output&lt;/span&gt;
&lt;span class="nb"&gt;cat &lt;/span&gt;article.md | octomind workflow promote &lt;span class="nt"&gt;--format&lt;/span&gt; jsonl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One event per completed step. One aggregated cost at the end. A pipeline you tested locally behaves identically in the cloud, because it is identical.&lt;/p&gt;

&lt;p&gt;That's also the direction this is headed. Today the library is the public tap. The plan is for every account to get its own tap – personal workflows, edited in the panel with the same dry-run validation, distributed to your machines through the exact mechanism tap content already uses.&lt;/p&gt;

&lt;p&gt;One distribution system, not two.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why pipelines beat chat for production work
&lt;/h2&gt;

&lt;p&gt;I want to zoom out for a second. Why build this at all?&lt;/p&gt;

&lt;p&gt;Chat is great for exploratory work. You don't know what you're looking for. You want to poke around, ask follow-ups, change direction mid-conversation. A session – a conversation where you steer turn by turn – is exactly right for that.&lt;/p&gt;

&lt;p&gt;But production work is different. You have a contract. Input in, output out. You want repeatability. You want auditability. You want to know that if you run the same thing tomorrow, you get the same result.&lt;/p&gt;

&lt;p&gt;Workflows give you that. They're not better than sessions – they're different. And for a whole class of problems, they're the right tool.&lt;/p&gt;

&lt;p&gt;Here's what I mean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Chat&lt;/strong&gt;: "Help me figure out what's wrong with this code"&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Workflow&lt;/strong&gt;: "Review this diff and tell me if it's safe to merge"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Chat&lt;/strong&gt;: "What should I post about this article?"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Workflow&lt;/strong&gt;: "Turn this article into Twitter, LinkedIn, and Mastodon drafts"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Chat&lt;/strong&gt;: "Help me analyze this data"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Workflow&lt;/strong&gt;: "Turn this CSV into a decision-ready report with computed metrics"&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The chat version is open-ended. The workflow version has a contract. Both are useful. I use both. But they're not the same thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The technical bit: how the pipeline actually runs
&lt;/h2&gt;

&lt;p&gt;Under the hood, a workflow run is a state machine. Each step is an agent invocation with its own context, role, and constraints. The pipeline orchestrates these invocations, passing outputs between steps, handling loops, and aggregating costs.&lt;/p&gt;

&lt;p&gt;The event stream is the key. Every step completion emits an event. The panel subscribes to that stream and renders it live. That's how you see steps light up, how loop counters increment, how the final cost gets computed.&lt;/p&gt;

&lt;p&gt;Here's what a simplified event stream looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{"event": "step_start", "step": "research", "role": "researcher"}
{"event": "step_complete", "step": "research", "output": "...", "cost": 0.002}
{"event": "step_start", "step": "write", "role": "writer"}
{"event": "step_complete", "step": "write", "output": "...", "cost": 0.004}
{"event": "step_start", "step": "audit", "role": "auditor"}
{"event": "audit_failed", "step": "audit", "reason": "..."}
{"event": "loop_iteration", "step": "write", "iteration": 2}
{"event": "step_complete", "step": "audit", "passed": true, "cost": 0.001}
{"event": "workflow_complete", "total_cost": 0.015, "artifacts": ["drafts/twitter.md", "drafts/linkedin.md"]}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CLI and the panel both consume this same stream. That's why they behave identically – they're two different UIs over the same underlying contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;If you haven't tried the cloud yet, it's open to everyone – no card, no invite. Create a machine, open Workflows, feed &lt;code&gt;promote&lt;/code&gt; a blog post you like, and watch a team you didn't have five minutes ago argue itself into shippable drafts.&lt;/p&gt;

&lt;p&gt;And if you're already running workflows from the CLI: nothing broke. Your taps still work. Your machines still work. You just got a browser option now.&lt;/p&gt;

&lt;p&gt;The repo is at &lt;a href="https://github.com/muvon/octomind" rel="noopener noreferrer"&gt;github.com/muvon/octomind&lt;/a&gt;. Apache-2.0, like everything we build. Pull it, run it, tell me what breaks.&lt;/p&gt;

&lt;p&gt;This is the original article: &lt;a href="https://octomind.run/blog/workflows-in-the-cloud" rel="noopener noreferrer"&gt;Workflows Come to the Cloud&lt;/a&gt;&lt;/p&gt;

</description>
      <category>octomind</category>
      <category>devops</category>
      <category>ai</category>
      <category>cloud</category>
    </item>
    <item>
      <title>We Built an Invite System. We Deleted It Three Days Later.</title>
      <dc:creator>Don Karter</dc:creator>
      <pubDate>Sun, 26 Jul 2026 15:18:29 +0000</pubDate>
      <link>https://dev.to/donk8r/we-built-an-invite-system-we-deleted-it-three-days-later-48p9</link>
      <guid>https://dev.to/donk8r/we-built-an-invite-system-we-deleted-it-three-days-later-48p9</guid>
      <description>&lt;p&gt;Three days after launch, we killed the invite gate on Octomind Cloud machines.&lt;/p&gt;

&lt;p&gt;Not paused. Not "temporarily opened." Deleted.&lt;/p&gt;

&lt;p&gt;Here's what happened, why it was wrong, and what changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Confession
&lt;/h2&gt;

&lt;p&gt;At launch, machines were invite-only. We're bootstrapped – no investors – and hardware gets bought with revenue, not term sheets. A gate felt responsible. Don't let everyone in if you can't handle them.&lt;/p&gt;

&lt;p&gt;Three days of production taught us the gate was solving a problem we didn't have yet, and creating one we definitely did.&lt;/p&gt;

&lt;p&gt;Fleet had headroom. Bottleneck wasn't capacity – it was new users hitting a locked door and leaving before seeing what a machine actually is.&lt;/p&gt;

&lt;p&gt;So we removed it. The invite system is gone from the product. Fewer moving parts, one honest answer to "can I try it?": yes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Octomind Cloud Is (Briefly)
&lt;/h2&gt;

&lt;p&gt;Octomind Cloud is an agent runtime. Persistent Linux machines from $0.05/hr, real Docker inside, a hub of 21 models behind one key at published per-token prices, one wallet with caps.&lt;/p&gt;

&lt;p&gt;Free tier: $0, $0.15/day usage, 1 Tiny machine, no card required.&lt;/p&gt;

&lt;p&gt;The agent runs on these cloud machines, not your laptop. Sessions survive you closing the tab – keep running, full transcript when you come back.&lt;/p&gt;

&lt;p&gt;Whole stack is open source Apache-2.0: octomind, octocode, octobrain, octohub.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Three Days Taught Us
&lt;/h2&gt;

&lt;p&gt;Day one: invites felt prudent. Don't oversubscribe a fleet you're funding yourself.&lt;/p&gt;

&lt;p&gt;Day three: the prudent thing was creating friction for people who just wanted to see what this does.&lt;/p&gt;

&lt;p&gt;We watched the funnel. Signups were fine. Activation dropped at the invite wall. People weren't hitting capacity limits – they were hitting a locked door and bouncing.&lt;/p&gt;

&lt;p&gt;The invite system wasn't protecting us from overload. It was protecting us from users.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  What Changed
&lt;/h2&gt;

&lt;p&gt;As of today, every Octomind account – free tier included – can create a machine and have it running in under a minute. No codes, no waitlist, no earning your way in.&lt;/p&gt;

&lt;p&gt;Sign up, click, it's yours.&lt;/p&gt;

&lt;p&gt;What this means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New users sign up, create a machine – real Linux box, whole agent toolchain, web terminal, Docker inside – in under a minute&lt;/li&gt;
&lt;li&gt;Free tier, no card&lt;/li&gt;
&lt;li&gt;Unredeemed codes are moot&lt;/li&gt;
&lt;li&gt;Referral program still alive (both earn storage and credit bonuses)&lt;/li&gt;
&lt;li&gt;Paid plans still buy bigger everything (caps, sizes, slots) – just no longer buy a key to a door that's now open&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We're still bootstrapped. Fleet grows as subscriptions fund hardware. If demand outruns capacity, machine creation says so plainly rather than silently degrading.&lt;/p&gt;

&lt;p&gt;Honesty over optics.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;Open the panel, sign up free (no card), create a machine. Pick a name, pick a size, done – boots in seconds. Open a session and put the agent to work.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/muvon/octomind" rel="noopener noreferrer"&gt;https://github.com/muvon/octomind&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Full post: &lt;a href="https://octomind.run/blog/cloud-invites-removed" rel="noopener noreferrer"&gt;https://octomind.run/blog/cloud-invites-removed&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>cloud</category>
      <category>opensource</category>
      <category>startup</category>
    </item>
    <item>
      <title>We Taught Our Code Search to Think — Here's What Broke (and What Fixed It)</title>
      <dc:creator>Don Karter</dc:creator>
      <pubDate>Sun, 26 Jul 2026 08:14:36 +0000</pubDate>
      <link>https://dev.to/donk8r/we-taught-our-code-search-to-think-heres-what-broke-and-what-fixed-it-47ao</link>
      <guid>https://dev.to/donk8r/we-taught-our-code-search-to-think-heres-what-broke-and-what-fixed-it-47ao</guid>
      <description>&lt;p&gt;Octocode is our open source semantic code search engine built in Rust (Apache-2.0). It's the code-search layer behind Octomind, and you can grab it at &lt;a href="https://github.com/muvon/octocode" rel="noopener noreferrer"&gt;https://github.com/muvon/octocode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Last month we added an LLM reasoning step to the retrieval pipeline. The first version made things worse.&lt;/p&gt;

&lt;p&gt;Hit@10 dropped 7 points. Recall@10 dropped 7.5 points. The model was pruning away true positives because it thought they weren't relevant.&lt;/p&gt;

&lt;p&gt;Here's what we learned, what we shipped, and why "add contextual retrieval" is not the universal win everyone claims.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Similarity Is Not Relevance
&lt;/h2&gt;

&lt;p&gt;Octocode uses hybrid retrieval — vector search plus keyword overlap. Works well. But there's a gap: the snippet that shares the most tokens with your query is often not the code that answers it.&lt;/p&gt;

&lt;p&gt;Ask "where do we decide a request is retryable" and the similarity ranker hands you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The retry config struct&lt;/li&gt;
&lt;li&gt;The retry constant
&lt;/li&gt;
&lt;li&gt;The test that names the word four times&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The actual function that makes the call? Rank seven.&lt;/p&gt;

&lt;p&gt;Vector search ranks by similarity. Hybrid adds keyword matching. But neither reads the code. Neither knows what the code &lt;em&gt;does&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  First Attempt: Pure LLM Reranking
&lt;/h2&gt;

&lt;p&gt;We added an LLM reasoning step after hybrid retrieval. The model reads the candidate code bodies and re-ranks by whether they actually answer the query. No new index, no reindexing — just a reranker sitting between retrieval and results.&lt;/p&gt;

&lt;p&gt;Tested on 127 queries. Here's what happened:&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;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;th&gt;Change&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MRR&lt;/td&gt;
&lt;td&gt;0.595&lt;/td&gt;
&lt;td&gt;0.752&lt;/td&gt;
&lt;td&gt;+0.157&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NDCG@10&lt;/td&gt;
&lt;td&gt;0.658&lt;/td&gt;
&lt;td&gt;0.758&lt;/td&gt;
&lt;td&gt;+0.100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hit@10&lt;/td&gt;
&lt;td&gt;0.913&lt;/td&gt;
&lt;td&gt;0.843&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;−0.071&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recall@10&lt;/td&gt;
&lt;td&gt;0.886&lt;/td&gt;
&lt;td&gt;0.811&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;−0.075&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;MRR and NDCG went up. The ranking quality improved. But Hit@10 and Recall@10 &lt;em&gt;dropped&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The LLM was being too aggressive. It returned only what it judged relevant and quietly discarded true positives at ranks 6–10. Better ranking head, worse recall floor.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fix: Fuse, Don't Replace
&lt;/h2&gt;

&lt;p&gt;Don't let the LLM replace the ranking — fuse it with the hybrid ranking via Reciprocal Rank Fusion (RRF).&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;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;hybrid_rank&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;reasoning_weight&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;reasoning_rank&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hybrid rank always contributes — that's your recall floor. Reasoning rank drives the head.&lt;/p&gt;

&lt;p&gt;Final fused results on the same 127 queries:&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;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;th&gt;Change&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MRR&lt;/td&gt;
&lt;td&gt;0.595&lt;/td&gt;
&lt;td&gt;0.809&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+36%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NDCG@10&lt;/td&gt;
&lt;td&gt;0.658&lt;/td&gt;
&lt;td&gt;0.833&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+27%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hit@5&lt;/td&gt;
&lt;td&gt;0.827&lt;/td&gt;
&lt;td&gt;0.953&lt;/td&gt;
&lt;td&gt;+0.126&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hit@10&lt;/td&gt;
&lt;td&gt;0.913&lt;/td&gt;
&lt;td&gt;0.969&lt;/td&gt;
&lt;td&gt;+0.056&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recall@5&lt;/td&gt;
&lt;td&gt;0.777&lt;/td&gt;
&lt;td&gt;0.924&lt;/td&gt;
&lt;td&gt;+0.147&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recall@10&lt;/td&gt;
&lt;td&gt;0.886&lt;/td&gt;
&lt;td&gt;0.944&lt;/td&gt;
&lt;td&gt;+0.058&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every metric up. Hit@5 at 0.953 means nineteen times out of twenty the answer is in the top five.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Tuned (and What Didn't Matter)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Reasoning weight:&lt;/strong&gt; Best at 2.0. Weight 5 buys nothing and costs recall.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Candidates:&lt;/strong&gt; 25 is the sweet spot. We tried 40 — worse across the board.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context level:&lt;/strong&gt; Full code bodies win by a lot. Signatures-only was the worst performer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LLM temperature:&lt;/strong&gt; 1.0 beat 0.3 and 0.0. Counterintuitive, but the model reasons better with normal sampling. Stiff decoding made it dumber.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Did NOT Work: Contextual Retrieval
&lt;/h2&gt;

&lt;p&gt;Anthropic's contextual retrieval approach — adding descriptions at index time — gets recommended everywhere. We tested it.&lt;/p&gt;

&lt;p&gt;Hit@5: −0.008&lt;br&gt;&lt;br&gt;
Recall@10: −0.019&lt;/p&gt;

&lt;p&gt;It trades recall for ranking. On code, that's a net loss. "Add contextual retrieval" is cargo-culted advice — not a universal win. We didn't ship it.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to Turn It On
&lt;/h2&gt;

&lt;p&gt;The feature is in Octocode's master branch now (not yet released — landing soon). Off by default, one config flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[search.reasoning]&lt;/span&gt;
&lt;span class="py"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"deepseek:deepseek-v4-flash"&lt;/span&gt;
&lt;span class="py"&gt;max_candidates&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;
&lt;span class="py"&gt;context_level&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"full"&lt;/span&gt;
&lt;span class="py"&gt;reasoning_weight&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;
&lt;span class="py"&gt;final_top_k&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or swap in any other provider:model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[search.reasoning]&lt;/span&gt;
&lt;span class="py"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"openai:gpt-4o-mini"&lt;/span&gt;
&lt;span class="py"&gt;max_candidates&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;
&lt;span class="py"&gt;context_level&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"full"&lt;/span&gt;
&lt;span class="py"&gt;reasoning_weight&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;
&lt;span class="py"&gt;final_top_k&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any provider:model works. One LLM call per semantic search. &lt;code&gt;structural_search&lt;/code&gt; stays pure grep. No reindex needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;LLM reranking works – but only if you keep the hybrid ranking as a floor. Fusion beats replacement. And don't cargo-cult "best practices" without testing them on your actual workload.&lt;/p&gt;

&lt;p&gt;Octocode is open source under Apache-2.0. The benchmark suite, ground truth dataset, and raw results are all in the repo: &lt;a href="https://github.com/muvon/octocode" rel="noopener noreferrer"&gt;https://github.com/muvon/octocode&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This feature is merged to master now, not yet released – landing soon.&lt;/p&gt;

&lt;p&gt;Full writeup with all the numbers and tuning details: &lt;a href="https://muvon.io/blog/reasoning-retrieval-code-search" rel="noopener noreferrer"&gt;https://muvon.io/blog/reasoning-retrieval-code-search&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>codesearch</category>
      <category>llm</category>
      <category>opensource</category>
    </item>
    <item>
      <title>The Tap Registry Grew Beyond Code: 108 Agents, 27 Domains, and Workflows That Verify Their Own Work</title>
      <dc:creator>Don Karter</dc:creator>
      <pubDate>Fri, 24 Jul 2026 10:30:00 +0000</pubDate>
      <link>https://dev.to/donk8r/the-tap-registry-grew-beyond-code-108-agents-27-domains-and-workflows-that-verify-their-own-work-4lc6</link>
      <guid>https://dev.to/donk8r/the-tap-registry-grew-beyond-code-108-agents-27-domains-and-workflows-that-verify-their-own-work-4lc6</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This post originally appeared on &lt;a href="https://octomind.run/blog/octomind-tap-registry-expansion" rel="noopener noreferrer"&gt;octomind.run/blog/octomind-tap-registry-expansion&lt;/a&gt;. Cross-posted to dev.to.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;The cloud launch got the attention this week. But something quieter happened alongside it — the tap registry went through its biggest expansion since taps were first introduced, and it's worth a closer look if you're building with agents.&lt;/p&gt;

&lt;p&gt;The default registry now ships &lt;strong&gt;108 agents across 27 domains&lt;/strong&gt;, 71 capabilities, and 18 workflows. All available with one command. No downloads, no marketplace accounts, no setup.&lt;/p&gt;

&lt;p&gt;Here's what changed and why it matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a tap actually is
&lt;/h2&gt;

&lt;p&gt;If you haven't used taps before, the mental model is simple: a tap is a &lt;strong&gt;git-hosted registry of TOML manifests&lt;/strong&gt;. Each manifest defines one agent — its system prompt, model, tools, MCP servers. Octomind fetches the manifest at runtime and merges it into your config.&lt;/p&gt;

&lt;p&gt;Nothing gets installed. There's no global state to rot.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;octomind run developer:rust      &lt;span class="c"&gt;# a Rust specialist&lt;/span&gt;
octomind run lawyer:immigration  &lt;span class="c"&gt;# an immigration-law explainer&lt;/span&gt;
octomind workflow harden         &lt;span class="c"&gt;# a multi-step security audit pipeline&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tag format is &lt;code&gt;domain:spec&lt;/code&gt;. The official &lt;code&gt;muvon/octomind-tap&lt;/code&gt; ships as the default registry. You can browse it on the site, and adding your own registry is a single &lt;code&gt;octomind tap&lt;/code&gt; away.&lt;/p&gt;

&lt;p&gt;The point: agents should be distributed like code — reviewable in a diff, not installed like apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  The registry isn't just for developers anymore
&lt;/h2&gt;

&lt;p&gt;This is the biggest shift. The tap registry started as a developer toolbox, but most problems people bring to an agent aren't code problems.&lt;/p&gt;

&lt;p&gt;This week added 17 new agents across domains you wouldn't expect in a dev tool:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Family&lt;/strong&gt; — &lt;code&gt;family:parenting&lt;/code&gt;, &lt;code&gt;family:eldercare&lt;/code&gt;, &lt;code&gt;family:bereavement&lt;/code&gt; (an agent for the paperwork and decisions that arrive at the worst possible time, written with the gravity that moment deserves)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Finance&lt;/strong&gt; — &lt;code&gt;finance:tax&lt;/code&gt;, &lt;code&gt;finance:retirement&lt;/code&gt;, &lt;code&gt;finance:insurance&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Health &amp;amp; wellbeing&lt;/strong&gt; — &lt;code&gt;doctor:sleep&lt;/code&gt;, &lt;code&gt;coach:wellbeing&lt;/code&gt;, &lt;code&gt;coach:negotiation&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Life&lt;/strong&gt; — &lt;code&gt;lawyer:immigration&lt;/code&gt;, &lt;code&gt;home:realty&lt;/code&gt;, &lt;code&gt;vet:general&lt;/code&gt;, &lt;code&gt;vet:behavior&lt;/code&gt;, &lt;code&gt;vehicle:mechanic&lt;/code&gt;, &lt;code&gt;tutor:coding&lt;/code&gt;, &lt;code&gt;content:fiction&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These aren't replacements for licensed professionals. They're structured, well-prompted assistants that help you prepare, organize, and understand. The value is that the preparation — which is honestly 80% of the work — no longer starts from a blank page.&lt;/p&gt;

&lt;p&gt;There's also &lt;code&gt;assistant:concierge&lt;/code&gt;, which routes across the whole ecosystem. A bare &lt;code&gt;octomind run&lt;/code&gt; discovers matching specialists by intent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four new workflows that close the loop
&lt;/h2&gt;

&lt;p&gt;Workflows are multi-step TOML pipelines. Each step gets its own agent, model, and toolset, with validate scripts acting as deterministic quality gates between steps.&lt;/p&gt;

&lt;p&gt;The shared pattern across all four new workflows: &lt;strong&gt;don't stop at the first answer — loop until the check passes.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  harden
&lt;/h3&gt;

&lt;p&gt;An OWASP-lens security audit of your current repo, then a fix ⇄ re-audit loop that runs until findings are resolved and your project's own checks stay green.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;octomind workflow harden
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  upgrade
&lt;/h3&gt;

&lt;p&gt;Dependency bumps — named packages, or safe patch/minor by default — running in a bump ⇄ verify loop until your build is green.&lt;/p&gt;

&lt;h3&gt;
  
  
  scout
&lt;/h3&gt;

&lt;p&gt;This one's interesting. It's the phase &lt;em&gt;before&lt;/em&gt; anyone has an idea: take a field or market, mine it for real evidenced pain through three blind parallel sweeps, and come back with vetted opportunities instead of vibes.&lt;/p&gt;

&lt;h3&gt;
  
  
  learn
&lt;/h3&gt;

&lt;p&gt;Bootstraps a project knowledge base. Reads the codebase, extracts durable facts, promotes them into &lt;code&gt;.box/&lt;/code&gt; where they're indexed and readable by every agent that works on the project afterward.&lt;/p&gt;

&lt;p&gt;All four run the same way as everything else — &lt;code&gt;octomind workflow&lt;/code&gt; — reading from stdin, writing to stdout, scriptable by construction. That brings the registry to 18 workflows total.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agents that remember the project
&lt;/h2&gt;

&lt;p&gt;A new &lt;code&gt;octobrain&lt;/code&gt;-backed knowledge capability gives agents durable project memory. &lt;code&gt;assistant:knowledge&lt;/code&gt; curates it, the &lt;code&gt;learn&lt;/code&gt; workflow seeds it from the codebase.&lt;/p&gt;

&lt;p&gt;Facts get extracted once, stored in the repo's &lt;code&gt;.box/&lt;/code&gt; directory, and become available to every specialist that touches the project afterward. You run &lt;code&gt;learn&lt;/code&gt; once. Every agent after that starts with context instead of zero.&lt;/p&gt;

&lt;h2&gt;
  
  
  The unglamorous fixes that actually matter
&lt;/h2&gt;

&lt;p&gt;Two things that don't make headlines but fix real pain:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dependency installs now work in containers and CI.&lt;/strong&gt; Tap agents bootstrap their own tooling (Node for MCP servers), and those scripts assumed &lt;code&gt;sudo&lt;/code&gt; exists. Root containers — Docker, CI images — don't have it. Every dep script now escalates through a helper that runs bare as root, uses &lt;code&gt;sudo&lt;/code&gt; when present, and tells you exactly what's missing otherwise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Web search needs no API key.&lt;/strong&gt; The &lt;code&gt;websearch&lt;/code&gt; capability defaults to DuckDuckGo now. One less credential between a fresh install and a working researcher agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use it anywhere
&lt;/h2&gt;

&lt;p&gt;Everything works on a local Octomind install (one curl command) and comes preloaded on cloud machines. Models route through the hub with &lt;code&gt;octohub:auto&lt;/code&gt; routing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Browse the full registry&lt;/strong&gt; at &lt;a href="https://octomind.run/tap" rel="noopener noreferrer"&gt;octomind.run/tap&lt;/a&gt; — see what's available before you build something from scratch&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read the manifests&lt;/strong&gt; at &lt;a href="https://github.com/Muvon/octomind-tap" rel="noopener noreferrer"&gt;github.com/Muvon/octomind-tap&lt;/a&gt; — they're TOML files, fully reviewable, and contributions are open&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Try a workflow&lt;/strong&gt; — &lt;code&gt;octomind workflow harden&lt;/code&gt; on a repo you care about and see the loop-until-green pattern in action&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If there's a specialist you keep wishing existed, it's one manifest away. And if you build one, we'd genuinely like to see it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>devtools</category>
      <category>agents</category>
    </item>
  </channel>
</rss>
