<?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: Batty</title>
    <description>The latest articles on DEV Community by Batty (@battyterm).</description>
    <link>https://dev.to/battyterm</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3837762%2F1ac153b9-5261-4e4f-9eea-84cdf31f4d5a.png</url>
      <title>DEV Community: Batty</title>
      <link>https://dev.to/battyterm</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/battyterm"/>
    <language>en</language>
    <item>
      <title>I Built a Chess Engine with 5 AI Agents — Here's What Surprised Me</title>
      <dc:creator>Batty</dc:creator>
      <pubDate>Sun, 05 Apr 2026 14:18:36 +0000</pubDate>
      <link>https://dev.to/battyterm/i-built-a-chess-engine-with-5-ai-agents-heres-what-surprised-me-1g16</link>
      <guid>https://dev.to/battyterm/i-built-a-chess-engine-with-5-ai-agents-heres-what-surprised-me-1g16</guid>
      <description>&lt;p&gt;I gave five AI coding agents a task: build a chess engine from scratch. One planned the architecture. Three built components in parallel. One supervised everything.&lt;/p&gt;

&lt;p&gt;No external chess libraries. No internet lookups. Just agents, a test suite, and a goal: beat Stockfish at 1200 ELO at least 50% of the time.&lt;/p&gt;

&lt;p&gt;The engine works. But what surprised me wasn't the output — it was what I learned about supervised AI agent execution along the way.&lt;/p&gt;

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

&lt;p&gt;The team looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;roles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;architect&lt;/span&gt;
    &lt;span class="na"&gt;role_type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;architect&lt;/span&gt;
    &lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;claude&lt;/span&gt;
    &lt;span class="na"&gt;instances&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;talks_to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;manager&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;manager&lt;/span&gt;
    &lt;span class="na"&gt;role_type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;manager&lt;/span&gt;
    &lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;claude&lt;/span&gt;
    &lt;span class="na"&gt;instances&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;talks_to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;architect&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;engineer&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;engineer&lt;/span&gt;
    &lt;span class="na"&gt;role_type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;engineer&lt;/span&gt;
    &lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;claude&lt;/span&gt;
    &lt;span class="na"&gt;instances&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
    &lt;span class="na"&gt;use_worktrees&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;talks_to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;manager&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Five agents. One architect running Opus for planning. Three engineers running Sonnet for implementation. One manager routing work between them. Each engineer got its own git worktree — its own branch, its own directory, completely isolated from the others.&lt;/p&gt;

&lt;p&gt;The task board was a Markdown file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## To Do&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Implement board representation (bitboard)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Implement move generation (legal moves)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Implement position evaluation (material + position tables)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Implement search (alpha-beta with iterative deepening)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Implement UCI protocol interface
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Write integration tests against known positions

&lt;span class="gu"&gt;## In Progress&lt;/span&gt;

&lt;span class="gu"&gt;## Done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I typed &lt;code&gt;batty start --attach&lt;/code&gt; and watched.&lt;/p&gt;

&lt;h2&gt;
  
  
  Surprise 1: The Architect Was 10x More Important Than Any Engineer
&lt;/h2&gt;

&lt;p&gt;This was the biggest lesson. I initially thought the engineers — the agents writing actual code — were the bottleneck. They weren't.&lt;/p&gt;

&lt;p&gt;The architect was.&lt;/p&gt;

&lt;p&gt;A good architecture plan meant engineers could work independently. Board representation, move generation, and evaluation are naturally isolated — they touch different files, use different data structures, and can be tested independently. The architect saw this and decomposed the work accordingly.&lt;/p&gt;

&lt;p&gt;When I ran an earlier version with a weaker architecture plan, engineers kept blocking each other. The evaluation agent needed the board representation agent to finish first. The search agent needed both. Three agents, but only one could work at any given time. Parallel in theory, sequential in practice.&lt;/p&gt;

&lt;p&gt;The fix was spending more time — and more expensive tokens — on the planning phase. I ran the architect on Opus (the most capable model) and gave it explicit instructions: "Decompose the work so that each engineer can start immediately without waiting for another engineer's output. Define interfaces upfront."&lt;/p&gt;

&lt;p&gt;The architect produced a plan with clear module boundaries, shared type definitions in a common &lt;code&gt;types.rs&lt;/code&gt; file, and stub implementations that each engineer could code against. All three engineers started within seconds of each other.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson: In supervised AI agent execution, the quality of task decomposition determines everything. A great architect with mediocre engineers outperforms mediocre architecture with great engineers.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Surprise 2: Test Gating Caught Things I Would Have Missed
&lt;/h2&gt;

&lt;p&gt;Every engineer's branch had to pass &lt;code&gt;cargo test&lt;/code&gt; before merging. No exceptions. The agent says "done" — the supervisor runs the tests. Exit code 0 means done. Anything else means try again.&lt;/p&gt;

&lt;p&gt;Here's what the test gate caught that I wouldn't have noticed in code review:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Off-by-one in move generation.&lt;/strong&gt; Engineer 2 implemented pawn moves. The code looked correct — clean, well-structured, proper handling of en passant and promotion. But the test suite included known positions from the &lt;a href="https://www.chessprogramming.org/Perft_Results" rel="noopener noreferrer"&gt;Perft test suite&lt;/a&gt; — positions where the exact number of legal moves is known. Engineer 2's implementation generated 19 moves in a position that should have 20. A missing edge case in castling rights after a rook capture. The kind of bug that passes code review because the logic &lt;em&gt;reads&lt;/em&gt; correctly.&lt;/p&gt;

&lt;p&gt;The test gate caught it. The agent got the failure output, saw exactly which position failed and by how many moves, and fixed it in the retry.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Type mismatch in evaluation scores.&lt;/strong&gt; Engineer 3 implemented position evaluation using centipawn scores. The search module expected scores in a different range. Both modules compiled independently. Both had passing unit tests. The integration test — which ran the full engine against a known position — produced moves that were legal but strategically terrible. The engine was maximizing the wrong scale.&lt;/p&gt;

&lt;p&gt;Without the test gate, this would have merged. I would have spent an hour debugging "why does the engine sacrifice its queen for no reason" before finding the score scaling issue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson: Test gates don't just catch bugs. They catch the class of bugs that look correct in isolation but break at integration boundaries. This is exactly where multi-agent systems fail — each agent's work is locally correct but globally broken.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Surprise 3: Five Agents Was the Sweet Spot
&lt;/h2&gt;

&lt;p&gt;I tried three configurations:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Config&lt;/th&gt;
&lt;th&gt;Agents&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pair&lt;/td&gt;
&lt;td&gt;1 architect + 1 engineer&lt;/td&gt;
&lt;td&gt;Works but sequential. ~45 minutes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Team&lt;/td&gt;
&lt;td&gt;1 architect + 3 engineers + 1 manager&lt;/td&gt;
&lt;td&gt;Parallel execution. ~18 minutes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Squad&lt;/td&gt;
&lt;td&gt;1 architect + 5 engineers + 1 manager&lt;/td&gt;
&lt;td&gt;Merge complexity killed the gains. ~22 minutes.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Going from 1 to 3 engineers was a clear win. Each engineer worked on a different module. Merges were clean because worktree isolation prevented file conflicts, and the architect's decomposition kept modules independent.&lt;/p&gt;

&lt;p&gt;Going from 3 to 5 engineers actually slowed things down.&lt;/p&gt;

&lt;p&gt;Why? Two reasons:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Merge serialization.&lt;/strong&gt; Batty merges branches sequentially with a file lock. With 3 engineers finishing around the same time, merges queue briefly but resolve quickly. With 5, the queue backs up. Each merge triggers a test run in the target branch, and later merges sometimes conflict with earlier ones because the codebase has changed underneath them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task granularity.&lt;/strong&gt; A chess engine has about 5-6 natural modules. With 3 engineers, each gets a substantial chunk of work. With 5, you're splitting modules into smaller pieces that have tighter coupling. Engineer 4 needs to implement the UCI protocol, but it depends on the search module (Engineer 3) and the board representation (Engineer 1). The independence that made 3 agents work breaks down at 5.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson: More agents isn't always better. The optimal team size depends on how many truly independent tasks exist. If you have to create artificial boundaries to give agents work, you've gone too far.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Surprise 4: Token Costs Weren't What I Expected
&lt;/h2&gt;

&lt;p&gt;The naive assumption: 5 agents = 5x the cost. The reality was closer to 2x.&lt;/p&gt;

&lt;p&gt;Here's why:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scoped context.&lt;/strong&gt; Each engineer only loaded the files relevant to its module. Engineer 1 (board representation) never saw the evaluation code. Engineer 3 (evaluation) never saw the UCI protocol. A strict &lt;code&gt;.claudeignore&lt;/code&gt; file kept each agent's context to ~25K tokens instead of the full ~80K project context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Session resets.&lt;/strong&gt; After each task, the agent got a fresh session. No accumulated conversation history from previous tasks. Clean context = fewer tokens per completion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Model mixing.&lt;/strong&gt; The architect ran on Opus (~15x more expensive per token than Sonnet). The engineers ran on Sonnet. Since engineers do 80% of the token-consuming work, the blended cost was much lower than running everything on Opus.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cost Component&lt;/th&gt;
&lt;th&gt;Tokens&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Architect (Opus)&lt;/td&gt;
&lt;td&gt;~40K&lt;/td&gt;
&lt;td&gt;~$1.20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Engineer 1 (Sonnet)&lt;/td&gt;
&lt;td&gt;~60K&lt;/td&gt;
&lt;td&gt;~$0.36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Engineer 2 (Sonnet)&lt;/td&gt;
&lt;td&gt;~55K&lt;/td&gt;
&lt;td&gt;~$0.33&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Engineer 3 (Sonnet)&lt;/td&gt;
&lt;td&gt;~65K&lt;/td&gt;
&lt;td&gt;~$0.39&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manager (Sonnet)&lt;/td&gt;
&lt;td&gt;~15K&lt;/td&gt;
&lt;td&gt;~$0.09&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~235K&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~$2.37&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A single agent doing the same work sequentially would use ~180K tokens on Opus (~$5.40) because it carries the full context throughout. The multi-agent approach was both faster and cheaper.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson: Multi-agent execution is a cost optimization strategy, not just a speed optimization. Scoped tasks + model mixing + session resets cut costs more than you'd expect.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Engine Looks Like
&lt;/h2&gt;

&lt;p&gt;The result: &lt;a href="https://github.com/Zedmor/chess_test" rel="noopener noreferrer"&gt;chess_test&lt;/a&gt;. A Rust chess engine built entirely by AI agents under supervision.&lt;/p&gt;

&lt;p&gt;It's not going to beat Stockfish at full strength. But against Stockfish at 1200 ELO, it wins consistently. The architecture is clean — separate modules for board representation, move generation, evaluation, search, and UCI protocol. Each module has its own test suite.&lt;/p&gt;

&lt;p&gt;The interesting thing isn't the engine itself. It's that the development process — supervised AI agent execution with worktree isolation, test gating, and hierarchical task dispatch — produced a codebase that's more modular and better-tested than what I typically get from a single long agent session.&lt;/p&gt;

&lt;p&gt;When one agent does everything, it tends to take shortcuts. Shared mutable state. Implicit dependencies. Tests that pass but don't cover edge cases. When multiple agents work in isolation with hard boundaries, the code is forced to be modular because agents literally can't access each other's files.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Try This
&lt;/h2&gt;

&lt;p&gt;If you want to run a similar experiment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo &lt;span class="nb"&gt;install &lt;/span&gt;batty-cli
&lt;span class="nb"&gt;cd &lt;/span&gt;your-project
batty init &lt;span class="nt"&gt;--template&lt;/span&gt; team  &lt;span class="c"&gt;# architect + 3 engineers + manager&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Edit &lt;code&gt;.batty/team_config/team.yaml&lt;/code&gt; to configure agents, roles, and the test command. Add tasks to the kanban board. Run &lt;code&gt;batty start --attach&lt;/code&gt; and watch agents work in adjacent tmux panes.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://youtube.com/watch?v=2wmBcUnq0vw" rel="noopener noreferrer"&gt;demo video&lt;/a&gt; shows the chess engine build from start to finish — architect planning, engineers implementing in parallel, test gates catching bugs, branches merging.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source:&lt;/strong&gt; &lt;a href="https://github.com/battysh/batty?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=chess-engine" rel="noopener noreferrer"&gt;github.com/battysh/batty&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Supervised AI agent execution isn't about making agents faster. It's about making their output trustworthy.&lt;/p&gt;

&lt;p&gt;Five agents building a chess engine taught me:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Invest in the architect.&lt;/strong&gt; Task decomposition quality &amp;gt; agent count. Use your best model for planning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test gates are non-negotiable.&lt;/strong&gt; Agents produce confident, plausible, broken code. Exit code 0 is the cheapest reviewer you'll ever hire.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More agents ≠ better.&lt;/strong&gt; Match team size to the number of naturally independent tasks. Stop at the boundary where you'd have to create artificial splits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-agent is a cost play.&lt;/strong&gt; Scoped context + model mixing + session resets = faster AND cheaper than one expensive agent doing everything sequentially.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The agents didn't surprise me with their code quality. They surprised me with how much the &lt;em&gt;supervision layer&lt;/em&gt; — task decomposition, isolation, test gating — determined the outcome.&lt;/p&gt;

&lt;p&gt;The code wrote itself. The architecture didn't.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What's the most agents you've run on a single project? Where did the coordination break down? I'm curious whether the 5-agent ceiling holds for other codebases or if it's specific to this kind of project.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rust</category>
      <category>opensource</category>
      <category>programming</category>
    </item>
    <item>
      <title>Why a Markdown File Beats a Message Bus</title>
      <dc:creator>Batty</dc:creator>
      <pubDate>Sun, 05 Apr 2026 14:18:09 +0000</pubDate>
      <link>https://dev.to/battyterm/why-a-markdown-file-beats-a-message-bus-4p4o</link>
      <guid>https://dev.to/battyterm/why-a-markdown-file-beats-a-message-bus-4p4o</guid>
      <description>&lt;p&gt;You have five AI coding agents. They need to know what to work on, what's already taken, and what's done. How do you coordinate them?&lt;/p&gt;

&lt;p&gt;The popular answer is a message bus. Agents publish and subscribe. They negotiate tasks, share context, broadcast status. It's the architecture you'd find in CrewAI, AutoGen, or any framework with "multi-agent" in the tagline.&lt;/p&gt;

&lt;p&gt;I tried that approach. Then I replaced it with a directory of markdown files — kanban-driven task dispatch for AI agents, using the filesystem instead of a broker. It's been six months, and I haven't looked back.&lt;/p&gt;

&lt;h2&gt;
  
  
  The O(n²) problem with message buses
&lt;/h2&gt;

&lt;p&gt;When agents coordinate through messages, every agent potentially talks to every other agent. Agent A finishes a task and broadcasts "task 27 done." Agents B, C, D, and E all receive it. Agent B claims the next task and broadcasts "I'm taking task 28." Now everyone else needs to hear that, update their state, and avoid claiming the same task.&lt;/p&gt;

&lt;p&gt;With 5 agents, that's manageable. With 10, it's 90 potential message pairs. With 20, it's 380. The communication overhead grows as O(n²), and every message is a chance for race conditions, stale state, or lost updates.&lt;/p&gt;

&lt;p&gt;Worse: you can't see what's happening. The coordination state lives in flight — in message queues, in-memory buffers, agent context windows. When something goes wrong, you're debugging invisible state.&lt;/p&gt;

&lt;h2&gt;
  
  
  The O(1) alternative: read a file
&lt;/h2&gt;

&lt;p&gt;Here's how &lt;a href="https://github.com/battysh/batty?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=kanban-dispatch" rel="noopener noreferrer"&gt;Batty&lt;/a&gt; dispatches tasks instead. Every task is a markdown file in a directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.batty/board/tasks/
├── 027-add-jwt-auth.md          # status: in-progress, claimed_by: eng-1
├── 028-user-registration.md     # status: todo
├── 029-add-rate-limiting.md     # status: backlog
└── 030-fix-dashboard-css.md     # status: done
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each file has YAML frontmatter for machine-readable fields and a markdown body for the task description:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;id: 28
title: User registration endpoint
status: todo
priority: high
depends_on: [27]
claimed_by:
tags: [api, auth]

&lt;span class="gh"&gt;# User registration endpoint&lt;/span&gt;

Add POST /api/register with email validation,
password hashing, and duplicate detection.

&lt;span class="gu"&gt;## Done when&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Endpoint returns 201 with user object
&lt;span class="p"&gt;-&lt;/span&gt; Duplicate email returns 409
&lt;span class="p"&gt;-&lt;/span&gt; Tests cover happy path and validation errors
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An agent doesn't subscribe to a topic or negotiate with peers. It reads a file. One file, one read, one task. O(1).&lt;/p&gt;

&lt;h2&gt;
  
  
  How kanban-driven dispatch actually works
&lt;/h2&gt;

&lt;p&gt;Batty's daemon runs a polling loop — every 10 seconds, it reads the board and makes decisions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Scan the task directory
2. Find idle agents (no active task)
3. For each idle agent, find the highest-priority task that is:
   - status: backlog or todo
   - not claimed by anyone
   - not blocked
   - dependencies resolved (all depends_on tasks are done)
4. Update the task file: status → in-progress, claimed_by → eng-1
5. Launch the agent with the task context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the entire dispatch algorithm. Priority sorting is deterministic: critical tasks dispatch before high, high before medium. Ties break by task ID, so the oldest unblocked task wins. The board is always consistent because the daemon updates the file &lt;em&gt;before&lt;/em&gt; launching the agent — if the launch fails, the task stays claimed and the daemon retries next cycle.&lt;/p&gt;

&lt;p&gt;No message broker. No pub/sub. No consensus protocol. The filesystem is the coordination layer, and &lt;code&gt;grep&lt;/code&gt; is your monitoring tool:&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;# What's in progress right now?&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-rl&lt;/span&gt; &lt;span class="s2"&gt;"status: in-progress"&lt;/span&gt; .batty/board/tasks/

&lt;span class="c"&gt;# Who's working on what?&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-rn&lt;/span&gt; &lt;span class="s2"&gt;"claimed_by:"&lt;/span&gt; .batty/board/tasks/&lt;span class="k"&gt;*&lt;/span&gt;.md

&lt;span class="c"&gt;# How many tasks in each status?&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-rh&lt;/span&gt; &lt;span class="s2"&gt;"^status:"&lt;/span&gt; .batty/board/tasks/ | &lt;span class="nb"&gt;sort&lt;/span&gt; | &lt;span class="nb"&gt;uniq&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try doing that with a message bus.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why agents understand markdown natively
&lt;/h2&gt;

&lt;p&gt;This is the insight that makes the whole approach work: LLMs already know markdown. It's the dominant format in their training data — README files, GitHub issues, documentation, Stack Overflow posts. When you hand an AI coding agent a markdown task file, it reads the title, parses the acceptance criteria, and starts working. No serialization format to teach it. No API client to configure.&lt;/p&gt;

&lt;p&gt;Compare this to handing an agent a message from a coordination bus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"task_assignment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"payload"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"User registration endpoint"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"priority"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"high"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"depends_on"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"auth"&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Add POST /api/register..."&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent can parse this, but the format carries no information about the task. It's overhead. The markdown version is the task description — the agent reads it the same way a human developer would read a ticket.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happens when things go wrong
&lt;/h2&gt;

&lt;p&gt;Message buses need sophisticated error handling. What if a message is lost? What if two agents claim the same task? What if an agent crashes mid-task?&lt;/p&gt;

&lt;p&gt;With file-based dispatch, the answers are simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lost updates:&lt;/strong&gt; Can't happen. The file is on disk. If the daemon crashes mid-write, the file is either updated or it isn't. On restart, the daemon reads the board and picks up where it left off.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Double claims:&lt;/strong&gt; The daemon is the only writer for dispatch operations. It claims the task (updates &lt;code&gt;claimed_by&lt;/code&gt; in the file) &lt;em&gt;before&lt;/em&gt; launching the agent. If the launch fails, the claim is already on the board — the daemon retries or escalates. No two agents race for the same task.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Crashed agents:&lt;/strong&gt; Every poll cycle, the daemon reconciles. If an agent is idle but has an in-progress task, the daemon re-assigns it. If a task is claimed by an agent that no longer exists, it gets unclaimed and returned to the queue. Orphaned state is impossible because the board is always the source of truth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dependency violations:&lt;/strong&gt; Before dispatching task 28, the daemon checks that all tasks in &lt;code&gt;depends_on: [27]&lt;/code&gt; have &lt;code&gt;status: done&lt;/code&gt;. If task 27 is still in progress, task 28 stays in the queue. No message ordering to worry about — just a field comparison.&lt;/p&gt;

&lt;h2&gt;
  
  
  What humans can do that message buses can't
&lt;/h2&gt;

&lt;p&gt;Your kanban board is a directory of text files. This means:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reprioritize on the fly.&lt;/strong&gt; Open &lt;code&gt;029-add-rate-limiting.md&lt;/code&gt;, change &lt;code&gt;priority: medium&lt;/code&gt; to &lt;code&gt;priority: critical&lt;/code&gt;. Next dispatch cycle, it jumps the queue. No API call, no admin panel, no "drag the card."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add context mid-task.&lt;/strong&gt; An agent is working on task 28, and you realize it needs additional context. Edit the markdown file — add a note, clarify an acceptance criterion, paste a code snippet. The agent reads the updated file on its next reference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Debug with &lt;code&gt;cat&lt;/code&gt;.&lt;/strong&gt; When something goes wrong at 11pm, the difference between "open a file" and "connect to a monitoring dashboard and reconstruct message flow" is the difference between fixing the problem and going to bed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Block a task instantly.&lt;/strong&gt; Add &lt;code&gt;blocked: "waiting on API key from vendor"&lt;/code&gt; to the frontmatter. The daemon skips it on every dispatch cycle until you remove the field. No "pause" button to find, no workflow to trigger.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Version-control everything.&lt;/strong&gt; &lt;code&gt;git log -- .batty/board/tasks/&lt;/code&gt; shows every task creation, status change, and priority shift. &lt;code&gt;git diff&lt;/code&gt; shows exactly what changed. &lt;code&gt;git blame&lt;/code&gt; shows who changed it. Your project management history is in the same repo as your code, with the same tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  When this doesn't work
&lt;/h2&gt;

&lt;p&gt;Honest limitations:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-time collaboration.&lt;/strong&gt; If you need agents to share intermediate results — "I just changed the API schema, everyone update your types" — file polling with a 10-second interval isn't fast enough. You need something push-based.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;High agent counts.&lt;/strong&gt; At 50+ agents, scanning a directory of task files every 10 seconds starts to matter. Batty is built for teams of 3-10 agents, not swarms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-project coordination.&lt;/strong&gt; If agents span multiple repositories or machines, a shared filesystem isn't available. You'd need a networked coordination layer.&lt;/p&gt;

&lt;p&gt;For the typical use case — a developer running 3-8 AI coding agents on a single project — a directory of markdown files handles dispatch better than any message bus I've tried. It's simpler to operate, simpler to debug, and agents read it as naturally as you read a README.&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;cargo &lt;span class="nb"&gt;install &lt;/span&gt;batty-cli
batty init
batty up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Define tasks as markdown files. Batty dispatches them to your agents, gates on tests, and moves them through the board. No message bus required.&lt;/p&gt;

&lt;p&gt;How does your multi-agent setup handle task coordination? I'm curious whether anyone else has landed on file-based approaches — or if there's a message bus setup that's actually simple to debug.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/battysh/batty?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=kanban-dispatch" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; | &lt;a href="https://youtube.com/watch?v=2wmBcUnq0vw" rel="noopener noreferrer"&gt;Demo&lt;/a&gt; | &lt;a href="https://battysh.github.io/batty" rel="noopener noreferrer"&gt;Docs&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devtools</category>
      <category>opensource</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How I Run a Team of AI Coding Agents in Parallel</title>
      <dc:creator>Batty</dc:creator>
      <pubDate>Sun, 05 Apr 2026 10:56:25 +0000</pubDate>
      <link>https://dev.to/battyterm/how-i-run-a-team-of-ai-coding-agents-in-parallel-p7c</link>
      <guid>https://dev.to/battyterm/how-i-run-a-team-of-ai-coding-agents-in-parallel-p7c</guid>
      <description>&lt;p&gt;Running one AI coding agent is productive. Running five in parallel is chaos.&lt;/p&gt;

&lt;p&gt;I've been using Claude Code daily for months. It's great — until you realize there are four other tasks sitting idle while you wait for one agent to finish refactoring a module. So you open more terminal tabs, spin up more sessions, and now you're the bottleneck. You're context-switching between agents, resolving merge conflicts they created, and manually checking if anything still compiles.&lt;/p&gt;

&lt;p&gt;I spent a week in this mode before I decided there had to be a better way.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Multi-Agent Problem
&lt;/h2&gt;

&lt;p&gt;Here's what goes wrong when you naively run multiple AI coding agents on the same repo:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;They stomp on each other's files.&lt;/strong&gt; Agent A edits &lt;code&gt;src/auth.rs&lt;/code&gt; while Agent B is also editing &lt;code&gt;src/auth.rs&lt;/code&gt;. Someone loses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nobody checks the tests.&lt;/strong&gt; An agent says "Done!" but the test suite is failing. You don't find out until three more tasks are stacked on top of the broken one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You become the dispatcher.&lt;/strong&gt; Which agent is working on what? Is anyone idle? Did that task actually get assigned? You're doing more coordination than coding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;There's no shared context.&lt;/strong&gt; Agent A doesn't know Agent B just changed the API interface it depends on. Chaos.&lt;/p&gt;

&lt;p&gt;Sound familiar? If you're using Claude Code, Codex, or Aider, and you've ever wanted to run more than one at a time — this is the wall you hit.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Solved It
&lt;/h2&gt;

&lt;p&gt;I built &lt;a href="https://github.com/battysh/batty" rel="noopener noreferrer"&gt;Batty&lt;/a&gt; — a terminal-native supervisor that turns multiple AI coding agents into a coordinated team. No web UI. No servers. Just your terminal and tmux.&lt;/p&gt;

&lt;p&gt;The core idea: instead of a flat pool of agents, you define a &lt;strong&gt;hierarchy&lt;/strong&gt;. An architect agent plans the work. A manager breaks it into tasks. Engineers execute in isolated environments. A kanban board tracks everything. Tests gate completion.&lt;/p&gt;

&lt;p&gt;Here's the minimal setup — an architect and three engineers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .batty/team_config/team.yaml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-project&lt;/span&gt;
&lt;span class="na"&gt;board&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;rotation_threshold&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
&lt;span class="na"&gt;standup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;interval_secs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;600&lt;/span&gt;
  &lt;span class="na"&gt;output_lines&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;40&lt;/span&gt;
&lt;span class="na"&gt;roles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;architect&lt;/span&gt;
    &lt;span class="na"&gt;role_type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;architect&lt;/span&gt;
    &lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;claude&lt;/span&gt;
    &lt;span class="na"&gt;instances&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;architect.md&lt;/span&gt;
    &lt;span class="na"&gt;talks_to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;manager&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;manager&lt;/span&gt;
    &lt;span class="na"&gt;role_type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;manager&lt;/span&gt;
    &lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;claude&lt;/span&gt;
    &lt;span class="na"&gt;instances&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;manager.md&lt;/span&gt;
    &lt;span class="na"&gt;talks_to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;architect&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;engineer&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;engineer&lt;/span&gt;
    &lt;span class="na"&gt;role_type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;engineer&lt;/span&gt;
    &lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;claude&lt;/span&gt;
    &lt;span class="na"&gt;instances&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
    &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;engineer.md&lt;/span&gt;
    &lt;span class="na"&gt;talks_to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;manager&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;use_worktrees&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three lines that matter:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;talks_to&lt;/code&gt;&lt;/strong&gt; — Agents can only communicate with their defined contacts. No free-for-all. The architect talks to the manager, the manager talks to engineers. This prevents the message chaos that kills multi-agent setups.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;instances: 3&lt;/code&gt;&lt;/strong&gt; — Three engineer agents, each in its own tmux pane. Batty names them &lt;code&gt;eng-1-1&lt;/code&gt;, &lt;code&gt;eng-1-2&lt;/code&gt;, &lt;code&gt;eng-1-3&lt;/code&gt; and manages them independently.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;use_worktrees: true&lt;/code&gt;&lt;/strong&gt; — Each engineer works in an isolated git worktree. Their own branch, their own working directory. No merge conflicts during active work.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Workflow
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo &lt;span class="nb"&gt;install &lt;/span&gt;kanban-md &lt;span class="nt"&gt;--locked&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cargo &lt;span class="nb"&gt;install &lt;/span&gt;batty-cli
&lt;span class="nb"&gt;cd &lt;/span&gt;my-project
batty init &lt;span class="nt"&gt;--template&lt;/span&gt; simple
batty start &lt;span class="nt"&gt;--attach&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This launches a tmux session. Each agent gets its own pane — you can watch them all work simultaneously, or detach and come back later.&lt;/p&gt;

&lt;p&gt;Then you send a task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;batty send architect &lt;span class="s2"&gt;"Build a REST API with JWT auth and user registration"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what happens:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;strong&gt;architect&lt;/strong&gt; analyzes the request and breaks it into subtasks&lt;/li&gt;
&lt;li&gt;Tasks land on the &lt;strong&gt;kanban board&lt;/strong&gt; (a Markdown file — yes, you can &lt;code&gt;cat&lt;/code&gt; it)&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;manager&lt;/strong&gt; dispatches tasks to available engineers&lt;/li&gt;
&lt;li&gt;Each &lt;strong&gt;engineer&lt;/strong&gt; picks up a task, creates a branch in its worktree, and starts coding&lt;/li&gt;
&lt;li&gt;When an engineer says it's done, Batty runs the &lt;strong&gt;test suite&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;If tests pass, the work is ready to merge. If not, the task goes back to the engineer.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The whole thing is file-based. YAML config, Markdown kanban, Maildir-style inboxes, JSONL event logs. You can &lt;code&gt;git diff&lt;/code&gt; your team's entire state.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned Running This Setup
&lt;/h2&gt;

&lt;p&gt;After a few weeks of daily use, here's what surprised me:&lt;/p&gt;

&lt;h3&gt;
  
  
  Five parallel agents is the sweet spot
&lt;/h3&gt;

&lt;p&gt;For most repos, 3-5 engineers is ideal. Beyond that, you start hitting genuine merge complexity even with worktree isolation. The agents aren't the bottleneck — the codebase's ability to absorb parallel changes is.&lt;/p&gt;

&lt;h3&gt;
  
  
  The architect matters more than the engineers
&lt;/h3&gt;

&lt;p&gt;Task decomposition quality is everything. A good architect agent that breaks "Build auth system" into well-scoped, independent subtasks will outperform six engineers working on poorly defined work. I spent more time refining my &lt;code&gt;architect.md&lt;/code&gt; prompt than any other part of the setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test gating is non-negotiable
&lt;/h3&gt;

&lt;p&gt;Before Batty, I'd have agents "complete" tasks that broke everything downstream. Now, a task isn't done until tests pass. Period. This single constraint eliminated most of the chaos.&lt;/p&gt;

&lt;p&gt;It sounds obvious. But when you're watching five agents work in parallel and one of them says "Done!", the temptation to just accept it and move on is strong. Don't.&lt;/p&gt;

&lt;h3&gt;
  
  
  You still need to supervise
&lt;/h3&gt;

&lt;p&gt;Batty is not "fire and forget." It's closer to managing a junior dev team than doing the work yourself. You review architecture decisions, redirect when an agent goes off-track, and unblock when someone gets stuck. But you're supervising five workstreams instead of doing one — that's the leverage.&lt;/p&gt;

&lt;h3&gt;
  
  
  The tmux-native approach just works
&lt;/h3&gt;

&lt;p&gt;I tried web-based dashboards. I tried custom UIs. Nothing beat having the agents in tmux panes where I already work. I can split, resize, scroll back through an agent's history, or detach the whole session and come back from my phone via SSH.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Real Example
&lt;/h2&gt;

&lt;p&gt;I used Batty to build &lt;a href="https://github.com/Zedmor/chess_test" rel="noopener noreferrer"&gt;chess_test&lt;/a&gt; — a chess engine built entirely by a team of AI agents. The challenge: build an engine that can beat Stockfish at 1200 ELO at least 50% of the time. No external libraries. No internet lookups.&lt;/p&gt;

&lt;p&gt;The team had an architect planning the engine architecture, a manager coordinating the work, and multiple engineers implementing different components in parallel — move generation, evaluation, search algorithms. Each working in their own worktree, each gated on tests.&lt;/p&gt;

&lt;p&gt;It's the kind of project that would take one agent days of sequential work. With a coordinated team, the parallel execution compressed the timeline dramatically.&lt;/p&gt;

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

&lt;p&gt;Batty works with the AI coding agents you already use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Claude Code&lt;/strong&gt; — First-class support, built-in templates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codex&lt;/strong&gt; — Works as an engineer agent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aider&lt;/strong&gt; — Works as an engineer agent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom&lt;/strong&gt; — Any CLI tool that accepts stdin
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install&lt;/span&gt;
cargo &lt;span class="nb"&gt;install &lt;/span&gt;kanban-md &lt;span class="nt"&gt;--locked&lt;/span&gt;
cargo &lt;span class="nb"&gt;install &lt;/span&gt;batty-cli

&lt;span class="c"&gt;# Initialize in your project&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;your-project
batty init &lt;span class="nt"&gt;--template&lt;/span&gt; pair  &lt;span class="c"&gt;# start small: 1 architect + 1 engineer&lt;/span&gt;

&lt;span class="c"&gt;# Launch&lt;/span&gt;
batty start &lt;span class="nt"&gt;--attach&lt;/span&gt;

&lt;span class="c"&gt;# Send a task&lt;/span&gt;
batty send architect &lt;span class="s2"&gt;"Implement user authentication with JWT"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eight built-in templates range from &lt;code&gt;solo&lt;/code&gt; (one agent, no hierarchy) to &lt;code&gt;large&lt;/code&gt; (19 agents with three management layers). Start with &lt;code&gt;pair&lt;/code&gt; or &lt;code&gt;simple&lt;/code&gt; and scale up as you get comfortable.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Batty Is Not
&lt;/h2&gt;

&lt;p&gt;I want to be honest about limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It's early.&lt;/strong&gt; Version 0.1.0. The core loop is solid, but the API is still settling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's not magic.&lt;/strong&gt; You still need good prompts and good task decomposition. Batty orchestrates — it doesn't think for you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It requires tmux.&lt;/strong&gt; If you don't use a terminal-based workflow, this isn't your tool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's not a framework.&lt;/strong&gt; You can't embed it in your app. It's a CLI supervisor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want a GUI, check out vibe-kanban. If you want a single-agent experience, Claude Code alone is excellent. Batty fills the gap between "one great agent" and "a coordinated team."&lt;/p&gt;

&lt;p&gt;Batty is open source, built in Rust, and published on crates.io.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/battysh/batty" rel="noopener noreferrer"&gt;github.com/battysh/batty&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Demo video:&lt;/strong&gt; &lt;a href="https://youtube.com/watch?v=2wmBcUnq0vw" rel="noopener noreferrer"&gt;2-minute walkthrough&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Docs:&lt;/strong&gt; &lt;a href="https://battysh.github.io/batty" rel="noopener noreferrer"&gt;battysh.github.io/batty&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're already running multiple AI agents and feeling the coordination pain, give it a try. And if you have ideas or feedback — issues and PRs are welcome.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>rust</category>
      <category>codingagents</category>
    </item>
    <item>
      <title>Choosing an AI Agent Orchestrator in 2026: A Practical Comparison</title>
      <dc:creator>Batty</dc:creator>
      <pubDate>Sun, 05 Apr 2026 05:13:20 +0000</pubDate>
      <link>https://dev.to/battyterm/choosing-an-ai-agent-orchestrator-in-2026-a-practical-comparison-cdl</link>
      <guid>https://dev.to/battyterm/choosing-an-ai-agent-orchestrator-in-2026-a-practical-comparison-cdl</guid>
      <description>&lt;p&gt;Running one AI coding agent is easy. Running three in parallel on the same codebase is where things get interesting — and where you need to make a tooling choice.&lt;/p&gt;

&lt;p&gt;There's no "best" orchestrator. There's the right one for your workflow. Here's an honest comparison of five approaches, with the tradeoffs I've seen after months of running multi-agent setups.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Options
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Raw tmux Scripts
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; Shell scripts that launch agents in tmux panes. DIY orchestration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zero dependencies beyond tmux&lt;/li&gt;
&lt;li&gt;Full control over every detail&lt;/li&gt;
&lt;li&gt;No abstractions to fight&lt;/li&gt;
&lt;li&gt;You already know how it works&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No state management — you track everything manually&lt;/li&gt;
&lt;li&gt;No message routing between agents&lt;/li&gt;
&lt;li&gt;No test gating — agents declare "done" without verification&lt;/li&gt;
&lt;li&gt;Breaks when agents crash or hit context limits&lt;/li&gt;
&lt;li&gt;You become the orchestrator&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; One-off tasks where you need 2-3 agents for an afternoon. If your coordination needs fit in a 50-line script, use the script.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not for:&lt;/strong&gt; Repeatable workflows, overnight sessions, or anything where "walk away and come back to merged PRs" matters.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. CrewAI
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; Python framework for building multi-agent systems with role-based collaboration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rich agent definition (role, goal, backstory, tools)&lt;/li&gt;
&lt;li&gt;Built-in task delegation and sequential/parallel execution&lt;/li&gt;
&lt;li&gt;Large ecosystem of tools and integrations&lt;/li&gt;
&lt;li&gt;Active community, good documentation&lt;/li&gt;
&lt;li&gt;Supports multiple LLM providers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Framework, not a tool — you write Python to configure agents&lt;/li&gt;
&lt;li&gt;Agents are CrewAI agents, not existing CLI tools (Claude Code, Codex)&lt;/li&gt;
&lt;li&gt;No terminal visibility — agents run as Python processes&lt;/li&gt;
&lt;li&gt;Learning curve for the framework concepts&lt;/li&gt;
&lt;li&gt;Token costs can be high with verbose agent interactions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Building custom multi-agent applications in Python. Research, analysis, content generation workflows where you want programmatic control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not for:&lt;/strong&gt; Orchestrating existing CLI coding agents. If you already use Claude Code or Codex and want to run multiples in parallel, CrewAI means rebuilding your agent setup in Python.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. AutoGen
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; Microsoft's framework for multi-agent conversation and collaboration. &lt;strong&gt;Note (April 2026):&lt;/strong&gt; Microsoft has announced AutoGen is entering maintenance phase, replaced by the new Microsoft Agent Framework. AutoGen will still receive bug fixes and security updates, but no new features. Worth considering if you're starting fresh.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sophisticated conversation patterns between agents&lt;/li&gt;
&lt;li&gt;Strong research backing (Microsoft Research)&lt;/li&gt;
&lt;li&gt;Group chat, nested conversations, teachable agents&lt;/li&gt;
&lt;li&gt;Good for complex reasoning chains&lt;/li&gt;
&lt;li&gt;Human-in-the-loop support&lt;/li&gt;
&lt;li&gt;Large community (56K+ GitHub stars)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Entering maintenance mode — Microsoft recommends migrating to Agent Framework&lt;/li&gt;
&lt;li&gt;Heavy framework — significant setup for simple use cases&lt;/li&gt;
&lt;li&gt;Python and .NET only&lt;/li&gt;
&lt;li&gt;Designed for conversational agents, not coding workflows&lt;/li&gt;
&lt;li&gt;No git integration, no worktree isolation&lt;/li&gt;
&lt;li&gt;Overkill for "run 3 coding agents in parallel"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Existing projects already built on AutoGen. Complex multi-step reasoning and agent conversations in research settings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not for:&lt;/strong&gt; New projects (consider Microsoft Agent Framework instead). Parallel code execution — AutoGen excels at agent conversations, not at managing git branches and test suites.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. vibe-kanban
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; Web-based kanban board for AI agent task management. Built in Rust with a TypeScript frontend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Visual interface — see all agents and tasks at a glance&lt;/li&gt;
&lt;li&gt;Drag-and-drop task management with real-time agent log streaming&lt;/li&gt;
&lt;li&gt;Git worktree isolation per agent — same isolation concept as Batty, different interface&lt;/li&gt;
&lt;li&gt;Built-in diff review UI for checking agent output before merging&lt;/li&gt;
&lt;li&gt;MCP integration (both client and server) — agents can manage the board programmatically&lt;/li&gt;
&lt;li&gt;Works with Claude Code, Codex, Gemini CLI, and other coding agents&lt;/li&gt;
&lt;li&gt;Large community (24K+ GitHub stars)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web UI means leaving your terminal&lt;/li&gt;
&lt;li&gt;No test gating — review is manual through the diff UI&lt;/li&gt;
&lt;li&gt;Requires a running web server&lt;/li&gt;
&lt;li&gt;Different mental model from terminal-native workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Teams that prefer visual interfaces. Developers who want to see diffs and review agent work in a browser. Workflows where drag-and-drop task management and visual oversight are features, not overhead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not for:&lt;/strong&gt; Developers who live in tmux and want everything in the terminal. If Alt-Tab to a browser feels like context switching, vibe-kanban adds friction your workflow doesn't need.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Batty
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; Terminal-native Rust CLI that supervises AI coding agents in tmux.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each agent runs in a real tmux pane — your keybindings, SSH attach, pipe-pane all work&lt;/li&gt;
&lt;li&gt;Git worktree isolation per agent — no file conflicts&lt;/li&gt;
&lt;li&gt;Test gating — nothing merges until tests pass&lt;/li&gt;
&lt;li&gt;Markdown kanban for task dispatch — &lt;code&gt;cat&lt;/code&gt; the board, &lt;code&gt;git diff&lt;/code&gt; the state&lt;/li&gt;
&lt;li&gt;File-based everything — YAML config, Maildir inboxes, JSONL logs&lt;/li&gt;
&lt;li&gt;Single binary (&lt;code&gt;cargo install batty-cli&lt;/code&gt;), no runtime dependencies&lt;/li&gt;
&lt;li&gt;Works with existing CLI agents (Claude Code, Codex, Aider)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tmux is a hard dependency — doesn't work on Windows without WSL&lt;/li&gt;
&lt;li&gt;No web UI — if you want a visual dashboard, look elsewhere&lt;/li&gt;
&lt;li&gt;Early stage (v0.1.0) — API still settling&lt;/li&gt;
&lt;li&gt;Rust contributor barrier — harder for casual contributions than a Python tool&lt;/li&gt;
&lt;li&gt;Smaller community than framework-based alternatives&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Developers who already live in tmux and want to scale from one agent to many without leaving the terminal. Teams that care about test gating and code quality gates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not for:&lt;/strong&gt; Non-terminal users. Windows-primary developers. People who want to build custom agent systems from scratch (use CrewAI/AutoGen instead).&lt;/p&gt;




&lt;h2&gt;
  
  
  Decision Matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Need&lt;/th&gt;
&lt;th&gt;Best Choice&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Quick one-off parallel tasks&lt;/td&gt;
&lt;td&gt;Raw tmux scripts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom multi-agent Python app&lt;/td&gt;
&lt;td&gt;CrewAI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complex agent reasoning/debate&lt;/td&gt;
&lt;td&gt;AutoGen (or Microsoft Agent Framework)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Visual task management with diff review&lt;/td&gt;
&lt;td&gt;vibe-kanban&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Terminal-native with test gating&lt;/td&gt;
&lt;td&gt;Batty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows-only environment&lt;/td&gt;
&lt;td&gt;CrewAI or vibe-kanban&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Orchestrate existing CLI agents&lt;/td&gt;
&lt;td&gt;Batty, vibe-kanban, or tmux scripts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The Question That Matters
&lt;/h2&gt;

&lt;p&gt;Before picking a tool, ask: &lt;strong&gt;am I building an agent system or coordinating existing agents?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're building from scratch — defining agent behaviors, tool access, conversation patterns — you want a framework. CrewAI and AutoGen give you the building blocks.&lt;/p&gt;

&lt;p&gt;If you're already using Claude Code, Codex, or Aider and want to run multiples in parallel — you want a supervisor. Batty, vibe-kanban, and tmux scripts operate at this layer, each with different tradeoffs: vibe-kanban gives you a visual board with diff review, Batty gives you terminal-native supervision with test gating, and tmux scripts give you full control with no abstractions.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Honest Take
&lt;/h2&gt;

&lt;p&gt;I built &lt;a href="https://github.com/battysh/batty" rel="noopener noreferrer"&gt;Batty&lt;/a&gt;, so I'm biased. But I built it because the other options didn't fit my workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CrewAI and AutoGen are frameworks — I didn't want to rewrite my agent setup in Python when Claude Code already works well&lt;/li&gt;
&lt;li&gt;vibe-kanban is web-based — I wanted to stay in tmux&lt;/li&gt;
&lt;li&gt;Raw scripts broke when agents crashed or I needed to walk away&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Batty fills a specific niche: terminal-native supervision with test gating for people who already use CLI coding agents. If that's you, try it. If it's not, the other tools are genuinely good at what they do.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Try Batty:&lt;/strong&gt; &lt;code&gt;cargo install batty-cli&lt;/code&gt; — &lt;a href="https://github.com/battysh/batty" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; | &lt;a href="https://youtube.com/watch?v=2wmBcUnq0vw" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try the alternatives:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/crewAIInc/crewAI" rel="noopener noreferrer"&gt;CrewAI&lt;/a&gt; — Python multi-agent framework&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/microsoft/autogen" rel="noopener noreferrer"&gt;AutoGen&lt;/a&gt; — Microsoft's agent conversation framework (entering maintenance phase)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/BloopAI/vibe-kanban" rel="noopener noreferrer"&gt;vibe-kanban&lt;/a&gt; — Visual AI agent kanban&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>devtools</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Get Your Open Source Project into Awesome Lists (and Why It's Worth the Effort)</title>
      <dc:creator>Batty</dc:creator>
      <pubDate>Sun, 05 Apr 2026 05:12:13 +0000</pubDate>
      <link>https://dev.to/battyterm/how-to-get-your-open-source-project-into-awesome-lists-and-why-its-worth-the-effort-5h45</link>
      <guid>https://dev.to/battyterm/how-to-get-your-open-source-project-into-awesome-lists-and-why-its-worth-the-effort-5h45</guid>
      <description>&lt;p&gt;You shipped your open source project. You wrote the README. You posted on Reddit. Now what?&lt;/p&gt;

&lt;p&gt;One of the most underrated distribution channels for open source is &lt;strong&gt;awesome lists&lt;/strong&gt; — those curated &lt;code&gt;awesome-*&lt;/code&gt; repositories on GitHub. There are thousands of them, many with tens of thousands of stars. Getting your project listed means a permanent, dofollow backlink from a high-authority GitHub page.&lt;/p&gt;

&lt;p&gt;I recently submitted our Rust CLI tool to seven awesome lists. Here's what I learned about the process — and what I wish someone had told me before I started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Awesome Lists Matter
&lt;/h2&gt;

&lt;p&gt;The obvious benefit is visibility. Someone browsing &lt;code&gt;awesome-rust&lt;/code&gt; (40k+ stars) looking for developer tools might discover your project.&lt;/p&gt;

&lt;p&gt;But the bigger win is &lt;strong&gt;SEO&lt;/strong&gt;. Each awesome list that merges your PR gives you a dofollow backlink from a page with high domain authority. GitHub pages rank well in search engines. A single listing on a popular awesome list can outperform weeks of blog posts for driving organic search traffic to your repo.&lt;/p&gt;

&lt;p&gt;For a project with under 100 stars, getting listed on 3-4 relevant awesome lists can be the difference between showing up on page 1 or page 5 of Google results for your target keywords.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Find the Right Lists
&lt;/h2&gt;

&lt;p&gt;Don't just search GitHub for "awesome" + your language. Think about your project from multiple angles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Language ecosystem&lt;/strong&gt;: &lt;code&gt;awesome-rust&lt;/code&gt;, &lt;code&gt;awesome-python&lt;/code&gt;, &lt;code&gt;awesome-go&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool category&lt;/strong&gt;: &lt;code&gt;awesome-cli-apps&lt;/code&gt;, &lt;code&gt;awesome-devops&lt;/code&gt;, &lt;code&gt;awesome-selfhosted&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain&lt;/strong&gt;: &lt;code&gt;awesome-ai-agents&lt;/code&gt;, &lt;code&gt;awesome-tmux&lt;/code&gt;, &lt;code&gt;awesome-shell&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Meta-lists&lt;/strong&gt;: &lt;a href="https://github.com/sindresorhus/awesome" rel="noopener noreferrer"&gt;awesome&lt;/a&gt; is the list of lists — search it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I found seven relevant lists for a single Rust CLI tool by thinking about it as (1) a Rust project, (2) a CLI app, (3) a DevOps tool, (4) a tmux plugin, (5) a shell utility, (6) an AI agent tool, and (7) a self-hosted application. Each angle pointed to a different list.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; Check how recently the list was updated. A list with no merges in 6 months probably has an inactive maintainer. You'll be waiting a long time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Read the Contribution Guidelines (Seriously)
&lt;/h2&gt;

&lt;p&gt;Every awesome list has different rules. Some are strict. Here's what varies:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Star minimums.&lt;/strong&gt; &lt;code&gt;awesome-rust&lt;/code&gt; requires 50+ stars. &lt;code&gt;awesome-cli-apps&lt;/code&gt; requires 20+. Many lists have no minimum. Check before you invest time in a PR.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Age requirements.&lt;/strong&gt; &lt;code&gt;awesome-cli-apps&lt;/code&gt; requires your first release to be 90+ days old. &lt;code&gt;awesome-selfhosted&lt;/code&gt; requires 4+ months. Don't submit a week-old project to a list with age gates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Entry format.&lt;/strong&gt; Some lists use &lt;code&gt;*&lt;/code&gt; bullets, others use &lt;code&gt;-&lt;/code&gt;. Some want badges, some don't. Some use YAML data files instead of Markdown (awesome-selfhosted does this). Copy the exact format — maintainers reject PRs over formatting alone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sort order.&lt;/strong&gt; Most lists are alphabetical within sections. Submit to the right position. This is the most common fixable mistake in awesome list PRs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Section choice.&lt;/strong&gt; Pick the section that fits best. If your project could go in multiple sections, pick one. Don't submit to three sections in the same PR.&lt;/p&gt;

&lt;p&gt;Here's a real example of how formats differ between two lists:&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;awesome-rust&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;user/repo&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://github.com/user/repo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;[crate&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;(https://crates.io/crates/crate)] - Description &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;![build badge&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;badge-url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;](actions-url)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For &lt;code&gt;awesome-cli-apps&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;app-name&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://github.com/user/repo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; - Description.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same project. Completely different entry format.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Write the PR
&lt;/h2&gt;

&lt;p&gt;Keep it simple. The PR should include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;One commit.&lt;/strong&gt; Don't restructure the list. Just add your entry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A clear title.&lt;/strong&gt; "Add ProjectName" or "Add user/project to Section Name"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A brief body.&lt;/strong&gt; One sentence about what the project does. Link to the repo. That's it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Don't write a sales pitch. Maintainers are curating, not buying. They want to know: what is it, does it belong here, does it meet the requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common mistakes that get PRs rejected:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adding your project to the wrong section&lt;/li&gt;
&lt;li&gt;Not following alphabetical ordering&lt;/li&gt;
&lt;li&gt;Including promotional language ("the best", "revolutionary")&lt;/li&gt;
&lt;li&gt;Submitting to multiple sections in one PR&lt;/li&gt;
&lt;li&gt;Missing required badges or format elements&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 4: Wait (Then Follow Up Politely)
&lt;/h2&gt;

&lt;p&gt;Here's the part nobody tells you: &lt;strong&gt;awesome list PRs sit for weeks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Maintainers are volunteers. Most popular awesome lists get dozens of PRs. Your submission is competing for attention with spam, low-quality projects, and other legitimate submissions.&lt;/p&gt;

&lt;p&gt;From my experience across seven submissions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One PR was acknowledged within 24 hours&lt;/li&gt;
&lt;li&gt;Two have been sitting for 14+ days with no response&lt;/li&gt;
&lt;li&gt;One has been open for 40 days&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Follow-up etiquette:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wait at least 7 days before your first nudge&lt;/li&gt;
&lt;li&gt;Keep it short and friendly: "Just checking in — happy to make any adjustments if needed"&lt;/li&gt;
&lt;li&gt;If your project has improved since submission, mention specific updates&lt;/li&gt;
&lt;li&gt;One follow-up comment is fine. Two is the max. After that, the maintainer has either seen it or the list is inactive.&lt;/li&gt;
&lt;li&gt;Never close and re-open the same PR to bump it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a PR sits for 60+ days with zero maintainer activity, it's probably not getting merged. That's OK. Close it cleanly and move on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Track Your Backlinks
&lt;/h2&gt;

&lt;p&gt;Once PRs start getting merged, track the SEO impact:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google Search Console&lt;/strong&gt; shows when new backlinks appear and how they affect your search rankings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub traffic analytics&lt;/strong&gt; (Insights &amp;gt; Traffic) shows referring sites — awesome lists show up here&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Star history&lt;/strong&gt; often shows small bumps after awesome list merges&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a project in the 10-50 star range, a single awesome-list merge from a popular list can drive 5-20 new visitors per week, indefinitely. That compounds.&lt;/p&gt;

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

&lt;p&gt;Awesome lists are one piece of an open source distribution strategy. They work best alongside:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dev.to / Hashnode articles (more backlinks, different audience)&lt;/li&gt;
&lt;li&gt;Reddit posts in relevant subreddits&lt;/li&gt;
&lt;li&gt;GitHub Topics (free discovery via &lt;code&gt;github.com/topics/your-keyword&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The effort per submission is small — 15 minutes to read guidelines, 5 minutes to write the PR. Even if only half get merged, the permanent backlinks and discovery are worth it.&lt;/p&gt;

&lt;p&gt;Start with the list that fits your project best. Read the CONTRIBUTING.md. Format your entry correctly. Submit. Follow up once. Move on to the next one.&lt;/p&gt;

&lt;p&gt;Your future self (and your search rankings) will thank you.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm building &lt;a href="https://github.com/battysh/batty" rel="noopener noreferrer"&gt;Batty&lt;/a&gt;, a tmux-native supervisor for AI coding agents. Currently going through this exact process — 7 awesome list submissions, results pending. Follow along for more lessons from the open source trenches.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>github</category>
      <category>seo</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Git Worktrees: The Secret Weapon You're Not Using</title>
      <dc:creator>Batty</dc:creator>
      <pubDate>Sun, 05 Apr 2026 04:31:32 +0000</pubDate>
      <link>https://dev.to/battyterm/git-worktrees-the-secret-weapon-youre-not-using-3pdc</link>
      <guid>https://dev.to/battyterm/git-worktrees-the-secret-weapon-youre-not-using-3pdc</guid>
      <description>&lt;p&gt;You're deep in a feature branch. A bug report comes in. You need to check main, reproduce the bug, fix it, push — then get back to your feature.&lt;/p&gt;

&lt;p&gt;Most developers do one of these:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;git stash&lt;/code&gt; → switch branch → work → switch back → &lt;code&gt;git stash pop&lt;/code&gt; → hope nothing broke&lt;/li&gt;
&lt;li&gt;Clone the repo again into a second directory&lt;/li&gt;
&lt;li&gt;Commit half-finished work with a "WIP" message&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All three are bad. There's a better way, and it's been in git since 2015.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are Git Worktrees?
&lt;/h2&gt;

&lt;p&gt;A git worktree is a &lt;strong&gt;linked working directory&lt;/strong&gt; that shares the same &lt;code&gt;.git&lt;/code&gt; repository. Each worktree checks out a different branch, and they coexist on disk simultaneously.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-project/              ← main branch (your primary worktree)
my-project-hotfix/       ← hotfix branch (linked worktree)
my-project-experiment/   ← experiment branch (linked worktree)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three directories. Three branches. One repository. One &lt;code&gt;.git&lt;/code&gt; history.&lt;/p&gt;

&lt;p&gt;You can edit files in each directory independently, run tests in each, even have different editors open. No stashing. No switching. No WIP commits.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Create a worktree
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# From your main checkout&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;my-project

&lt;span class="c"&gt;# Create a worktree for an existing branch&lt;/span&gt;
git worktree add ../my-project-hotfix hotfix/login-bug

&lt;span class="c"&gt;# Create a worktree with a new branch&lt;/span&gt;
git worktree add &lt;span class="nt"&gt;-b&lt;/span&gt; feature/new-api ../my-project-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. &lt;code&gt;../my-project-hotfix&lt;/code&gt; is now a fully functional checkout of &lt;code&gt;hotfix/login-bug&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  List worktrees
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git worktree list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/home/dev/my-project           abc1234 [main]
/home/dev/my-project-hotfix    def5678 [hotfix/login-bug]
/home/dev/my-project-api       789abcd [feature/new-api]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Remove a worktree
&lt;/h3&gt;

&lt;p&gt;When you're done with the branch:&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;# Delete the directory&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ../my-project-hotfix

&lt;span class="c"&gt;# Clean up the worktree reference&lt;/span&gt;
git worktree prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or in one step (git 2.17+):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git worktree remove ../my-project-hotfix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real-World Use Cases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Bug fixes without context switching
&lt;/h3&gt;

&lt;p&gt;You're mid-feature. A P0 bug comes in.&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;# Create a worktree for the fix (30 seconds)&lt;/span&gt;
git worktree add &lt;span class="nt"&gt;-b&lt;/span&gt; hotfix/p0-crash ../hotfix main

&lt;span class="c"&gt;# Fix the bug in the other directory&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ../hotfix
&lt;span class="c"&gt;# edit, test, commit, push&lt;/span&gt;

&lt;span class="c"&gt;# Switch back — your feature branch is untouched&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ../my-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your feature branch never moved. No stash. No WIP commit. No mental overhead of remembering where you were.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Running tests on one branch while working on another
&lt;/h3&gt;

&lt;p&gt;Long test suite? Run it in the background on the worktree while you keep coding in the primary.&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;# In terminal 1 (worktree)&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ../my-project-hotfix
cargo &lt;span class="nb"&gt;test&lt;/span&gt;

&lt;span class="c"&gt;# In terminal 2 (primary)&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ../my-project
&lt;span class="c"&gt;# keep working on your feature&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Comparing behavior across branches
&lt;/h3&gt;

&lt;p&gt;Need to check how the app behaves on main vs. your branch?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git worktree add ../my-project-main main

&lt;span class="c"&gt;# Terminal 1: run the app on main&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ../my-project-main &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cargo run

&lt;span class="c"&gt;# Terminal 2: run your branch&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ../my-project &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cargo run

&lt;span class="c"&gt;# Compare side by side&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Code review with full context
&lt;/h3&gt;

&lt;p&gt;Reviewing a PR? Check it out in a worktree instead of switching your primary branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git worktree add ../review-pr-42 origin/feature/pr-42
&lt;span class="nb"&gt;cd&lt;/span&gt; ../review-pr-42
&lt;span class="c"&gt;# run tests, explore code, check behavior&lt;/span&gt;
&lt;span class="c"&gt;# when done:&lt;/span&gt;
git worktree remove ../review-pr-42
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Parallel CI-like workflows
&lt;/h3&gt;

&lt;p&gt;Running linters, type checkers, and tests simultaneously across branches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git worktree add ../wt-lint main
git worktree add ../wt-test feature/new-api

&lt;span class="c"&gt;# Parallel execution&lt;/span&gt;
&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ../wt-lint &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run lint&lt;span class="o"&gt;)&lt;/span&gt; &amp;amp;
&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ../wt-test &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;test&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &amp;amp;
&lt;span class="nb"&gt;wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How It Works Under the Hood
&lt;/h2&gt;

&lt;p&gt;When you clone a repo, git creates a &lt;code&gt;.git&lt;/code&gt; directory that stores all objects, refs, and history. Your working directory is just one view into that data.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git worktree add&lt;/code&gt; creates another view — a new directory with its own &lt;code&gt;HEAD&lt;/code&gt;, index, and working tree, but sharing the same &lt;code&gt;.git/objects&lt;/code&gt; store.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.git/                    ← shared object store
  objects/               ← all commits, blobs, trees (shared)
  refs/                  ← all branches and tags (shared)
  worktrees/
    my-project-hotfix/   ← per-worktree HEAD and index
    my-project-api/      ← per-worktree HEAD and index
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Disk usage is minimal.&lt;/strong&gt; Worktrees share all git objects. Only the checked-out files are duplicated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commits are immediately visible&lt;/strong&gt; across worktrees. Push from one, pull from another.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Branches are locked.&lt;/strong&gt; You can't check out the same branch in two worktrees simultaneously. Git prevents this to avoid conflicting edits.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Common Pitfalls
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Branch locking
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git worktree add ../wt-main main
&lt;span class="c"&gt;# Later, in primary:&lt;/span&gt;
git checkout main
&lt;span class="c"&gt;# fatal: 'main' is already checked out at '../wt-main'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is by design. Remove the worktree first, or work on a different branch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Forgetting to prune
&lt;/h3&gt;

&lt;p&gt;Deleted a worktree directory manually? Run &lt;code&gt;git worktree prune&lt;/code&gt; to clean up stale references. Otherwise git still thinks the worktree exists and won't let you check out that branch elsewhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  Submodules
&lt;/h3&gt;

&lt;p&gt;Worktrees and submodules interact poorly in older git versions. If you use submodules, test with your git version first. Git 2.36+ handles this better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Worktrees vs. Alternatives
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Disk cost&lt;/th&gt;
&lt;th&gt;Speed&lt;/th&gt;
&lt;th&gt;Risk&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git stash&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;td&gt;Stash conflicts, forgotten stashes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Second clone&lt;/td&gt;
&lt;td&gt;Full repo&lt;/td&gt;
&lt;td&gt;Slow&lt;/td&gt;
&lt;td&gt;Divergent histories, double fetch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WIP commits&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;td&gt;Polluted history, rebase headaches&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Worktrees&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Minimal&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Fast&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Branch lock (by design)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Worktrees win on every dimension except one: they require you to know they exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Reference
&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;# Create worktree (existing branch)&lt;/span&gt;
git worktree add &amp;lt;path&amp;gt; &amp;lt;branch&amp;gt;

&lt;span class="c"&gt;# Create worktree (new branch from current HEAD)&lt;/span&gt;
git worktree add &lt;span class="nt"&gt;-b&lt;/span&gt; &amp;lt;new-branch&amp;gt; &amp;lt;path&amp;gt;

&lt;span class="c"&gt;# Create worktree (new branch from specific base)&lt;/span&gt;
git worktree add &lt;span class="nt"&gt;-b&lt;/span&gt; &amp;lt;new-branch&amp;gt; &amp;lt;path&amp;gt; &amp;lt;base&amp;gt;

&lt;span class="c"&gt;# List all worktrees&lt;/span&gt;
git worktree list

&lt;span class="c"&gt;# Remove a worktree&lt;/span&gt;
git worktree remove &amp;lt;path&amp;gt;

&lt;span class="c"&gt;# Clean up stale worktree references&lt;/span&gt;
git worktree prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Beyond Manual Use: Worktrees for Automation
&lt;/h2&gt;

&lt;p&gt;Worktrees aren't just for humans. Any workflow that needs parallel access to multiple branches benefits: CI scripts, deployment pipelines, automated testing — or AI coding agents that need isolated working directories.&lt;/p&gt;

&lt;p&gt;If you're running multiple AI agents on the same repo, worktrees give each agent its own checkout without the overhead of full clones. Each agent edits files independently, and conflicts only surface at merge time — which is when you want them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it:&lt;/strong&gt; &lt;code&gt;cargo install batty-cli&lt;/code&gt; — &lt;a href="https://github.com/battysh/batty" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; | &lt;a href="https://youtube.com/watch?v=2wmBcUnq0vw" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Git worktrees have been stable since git 2.5 (2015). If you're using any modern git version, they just work.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>tutorial</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>Git Worktrees Explained: The Secret Weapon You're Not Using</title>
      <dc:creator>Batty</dc:creator>
      <pubDate>Sun, 05 Apr 2026 04:31:00 +0000</pubDate>
      <link>https://dev.to/battyterm/git-worktrees-explained-the-secret-weapon-youre-not-using-3708</link>
      <guid>https://dev.to/battyterm/git-worktrees-explained-the-secret-weapon-youre-not-using-3708</guid>
      <description>&lt;p&gt;You're deep in a feature branch. A bug report comes in. You need to check main, reproduce the bug, fix it, push — then get back to your feature.&lt;/p&gt;

&lt;p&gt;Most developers do one of these:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;git stash&lt;/code&gt; → switch branch → work → switch back → &lt;code&gt;git stash pop&lt;/code&gt; → hope nothing broke&lt;/li&gt;
&lt;li&gt;Clone the repo again into a second directory&lt;/li&gt;
&lt;li&gt;Commit half-finished work with a "WIP" message&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All three are bad. There's a better way, and it's been in git since 2015.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are Git Worktrees?
&lt;/h2&gt;

&lt;p&gt;A git worktree is a &lt;strong&gt;linked working directory&lt;/strong&gt; that shares the same &lt;code&gt;.git&lt;/code&gt; repository. Each worktree checks out a different branch, and they coexist on disk simultaneously.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-project/              ← main branch (your primary worktree)
my-project-hotfix/       ← hotfix branch (linked worktree)
my-project-experiment/   ← experiment branch (linked worktree)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three directories. Three branches. One repository. One &lt;code&gt;.git&lt;/code&gt; history.&lt;/p&gt;

&lt;p&gt;You can edit files in each directory independently, run tests in each, even have different editors open. No stashing. No switching. No WIP commits.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Create a worktree
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# From your main checkout&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;my-project

&lt;span class="c"&gt;# Create a worktree for an existing branch&lt;/span&gt;
git worktree add ../my-project-hotfix hotfix/login-bug

&lt;span class="c"&gt;# Create a worktree with a new branch&lt;/span&gt;
git worktree add &lt;span class="nt"&gt;-b&lt;/span&gt; feature/new-api ../my-project-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. &lt;code&gt;../my-project-hotfix&lt;/code&gt; is now a fully functional checkout of &lt;code&gt;hotfix/login-bug&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  List worktrees
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git worktree list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/home/dev/my-project           abc1234 [main]
/home/dev/my-project-hotfix    def5678 [hotfix/login-bug]
/home/dev/my-project-api       789abcd [feature/new-api]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Remove a worktree
&lt;/h3&gt;

&lt;p&gt;When you're done with the branch:&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;# Delete the directory&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ../my-project-hotfix

&lt;span class="c"&gt;# Clean up the worktree reference&lt;/span&gt;
git worktree prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or in one step (git 2.17+):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git worktree remove ../my-project-hotfix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real-World Use Cases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Bug fixes without context switching
&lt;/h3&gt;

&lt;p&gt;You're mid-feature. A P0 bug comes in.&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;# Create a worktree for the fix (30 seconds)&lt;/span&gt;
git worktree add &lt;span class="nt"&gt;-b&lt;/span&gt; hotfix/p0-crash ../hotfix main

&lt;span class="c"&gt;# Fix the bug in the other directory&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ../hotfix
&lt;span class="c"&gt;# edit, test, commit, push&lt;/span&gt;

&lt;span class="c"&gt;# Switch back — your feature branch is untouched&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ../my-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your feature branch never moved. No stash. No WIP commit. No mental overhead of remembering where you were.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Running tests on one branch while working on another
&lt;/h3&gt;

&lt;p&gt;Long test suite? Run it in the background on the worktree while you keep coding in the primary.&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;# In terminal 1 (worktree)&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ../my-project-hotfix
cargo &lt;span class="nb"&gt;test&lt;/span&gt;

&lt;span class="c"&gt;# In terminal 2 (primary)&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ../my-project
&lt;span class="c"&gt;# keep working on your feature&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Comparing behavior across branches
&lt;/h3&gt;

&lt;p&gt;Need to check how the app behaves on main vs. your branch?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git worktree add ../my-project-main main

&lt;span class="c"&gt;# Terminal 1: run the app on main&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ../my-project-main &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cargo run

&lt;span class="c"&gt;# Terminal 2: run your branch&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ../my-project &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cargo run

&lt;span class="c"&gt;# Compare side by side&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Code review with full context
&lt;/h3&gt;

&lt;p&gt;Reviewing a PR? Check it out in a worktree instead of switching your primary branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git worktree add ../review-pr-42 origin/feature/pr-42
&lt;span class="nb"&gt;cd&lt;/span&gt; ../review-pr-42
&lt;span class="c"&gt;# run tests, explore code, check behavior&lt;/span&gt;
&lt;span class="c"&gt;# when done:&lt;/span&gt;
git worktree remove ../review-pr-42
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Parallel CI-like workflows
&lt;/h3&gt;

&lt;p&gt;Running linters, type checkers, and tests simultaneously across branches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git worktree add ../wt-lint main
git worktree add ../wt-test feature/new-api

&lt;span class="c"&gt;# Parallel execution&lt;/span&gt;
&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ../wt-lint &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run lint&lt;span class="o"&gt;)&lt;/span&gt; &amp;amp;
&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ../wt-test &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;test&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &amp;amp;
&lt;span class="nb"&gt;wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How It Works Under the Hood
&lt;/h2&gt;

&lt;p&gt;When you clone a repo, git creates a &lt;code&gt;.git&lt;/code&gt; directory that stores all objects, refs, and history. Your working directory is just one view into that data.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git worktree add&lt;/code&gt; creates another view — a new directory with its own &lt;code&gt;HEAD&lt;/code&gt;, index, and working tree, but sharing the same &lt;code&gt;.git/objects&lt;/code&gt; store.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.git/                    ← shared object store
  objects/               ← all commits, blobs, trees (shared)
  refs/                  ← all branches and tags (shared)
  worktrees/
    my-project-hotfix/   ← per-worktree HEAD and index
    my-project-api/      ← per-worktree HEAD and index
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Disk usage is minimal.&lt;/strong&gt; Worktrees share all git objects. Only the checked-out files are duplicated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commits are immediately visible&lt;/strong&gt; across worktrees. Push from one, pull from another.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Branches are locked.&lt;/strong&gt; You can't check out the same branch in two worktrees simultaneously. Git prevents this to avoid conflicting edits.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Common Pitfalls
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Branch locking
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git worktree add ../wt-main main
&lt;span class="c"&gt;# Later, in primary:&lt;/span&gt;
git checkout main
&lt;span class="c"&gt;# fatal: 'main' is already checked out at '../wt-main'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is by design. Remove the worktree first, or work on a different branch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Forgetting to prune
&lt;/h3&gt;

&lt;p&gt;Deleted a worktree directory manually? Run &lt;code&gt;git worktree prune&lt;/code&gt; to clean up stale references. Otherwise git still thinks the worktree exists and won't let you check out that branch elsewhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  Submodules
&lt;/h3&gt;

&lt;p&gt;Worktrees and submodules interact poorly in older git versions. If you use submodules, test with your git version first. Git 2.36+ handles this better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Worktrees vs. Alternatives
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Disk cost&lt;/th&gt;
&lt;th&gt;Speed&lt;/th&gt;
&lt;th&gt;Risk&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git stash&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;td&gt;Stash conflicts, forgotten stashes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Second clone&lt;/td&gt;
&lt;td&gt;Full repo&lt;/td&gt;
&lt;td&gt;Slow&lt;/td&gt;
&lt;td&gt;Divergent histories, double fetch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WIP commits&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;td&gt;Polluted history, rebase headaches&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Worktrees&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Minimal&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Fast&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Branch lock (by design)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Worktrees win on every dimension except one: they require you to know they exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Reference
&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;# Create worktree (existing branch)&lt;/span&gt;
git worktree add &amp;lt;path&amp;gt; &amp;lt;branch&amp;gt;

&lt;span class="c"&gt;# Create worktree (new branch from current HEAD)&lt;/span&gt;
git worktree add &lt;span class="nt"&gt;-b&lt;/span&gt; &amp;lt;new-branch&amp;gt; &amp;lt;path&amp;gt;

&lt;span class="c"&gt;# Create worktree (new branch from specific base)&lt;/span&gt;
git worktree add &lt;span class="nt"&gt;-b&lt;/span&gt; &amp;lt;new-branch&amp;gt; &amp;lt;path&amp;gt; &amp;lt;base&amp;gt;

&lt;span class="c"&gt;# List all worktrees&lt;/span&gt;
git worktree list

&lt;span class="c"&gt;# Remove a worktree&lt;/span&gt;
git worktree remove &amp;lt;path&amp;gt;

&lt;span class="c"&gt;# Clean up stale worktree references&lt;/span&gt;
git worktree prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Beyond Manual Use: Worktrees for Automation
&lt;/h2&gt;

&lt;p&gt;Worktrees aren't just for humans. Any workflow that needs parallel access to multiple branches benefits: CI scripts, deployment pipelines, automated testing — or AI coding agents that need isolated working directories.&lt;/p&gt;

&lt;p&gt;If you're running multiple AI agents on the same repo, worktrees give each agent its own checkout without the overhead of full clones. Each agent edits files independently, and conflicts only surface at merge time — which is when you want them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it:&lt;/strong&gt; &lt;code&gt;cargo install batty-cli&lt;/code&gt; — &lt;a href="https://github.com/battysh/batty" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; | &lt;a href="https://youtube.com/watch?v=2wmBcUnq0vw" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Git worktrees have been stable since git 2.5 (2015). If you're using any modern git version, they just work.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>tutorial</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>What I Learned Supervising 5 AI Agents on a Real Project</title>
      <dc:creator>Batty</dc:creator>
      <pubDate>Sun, 05 Apr 2026 00:58:58 +0000</pubDate>
      <link>https://dev.to/battyterm/what-i-learned-supervising-5-ai-agents-on-a-real-project-cl8</link>
      <guid>https://dev.to/battyterm/what-i-learned-supervising-5-ai-agents-on-a-real-project-cl8</guid>
      <description>&lt;p&gt;I ran 5 AI coding agents in parallel on a real Rust project for a week. Not a demo. Not a toy. A 51K-line codebase with real users.&lt;/p&gt;

&lt;p&gt;Here's what happened — with actual numbers.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Project:&lt;/strong&gt; A Rust CLI tool with a daemon, tmux integration, message routing, and a kanban board parser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Team configuration:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 architect (Claude Opus) — plans and decomposes work&lt;/li&gt;
&lt;li&gt;1 manager (Claude Opus) — dispatches tasks, handles escalations&lt;/li&gt;
&lt;li&gt;3 engineers (Codex) — parallel execution in isolated worktrees&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Duration:&lt;/strong&gt; 5 working days, ~6 hours per day supervised.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tasks:&lt;/strong&gt; Backlog of features, refactors, and bug fixes that had been accumulating for weeks.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Numbers
&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;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tasks completed&lt;/td&gt;
&lt;td&gt;47&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tasks failed and reassigned&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test gate catches (merge blocked)&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context exhaustions&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Merge conflicts&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lines changed&lt;/td&gt;
&lt;td&gt;~8,200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total time supervised&lt;/td&gt;
&lt;td&gt;~30 hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Estimated sequential time&lt;/td&gt;
&lt;td&gt;~120 hours&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;47 tasks in 30 hours of supervision. The same work would have taken me roughly 120 hours doing it sequentially — 4x compression.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Worked
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Task decomposition was the multiplier
&lt;/h3&gt;

&lt;p&gt;The architect agent spent the first 30 minutes of each day reading the backlog and decomposing features into independent, testable tasks. This planning phase was the single most valuable step.&lt;/p&gt;

&lt;p&gt;Bad decomposition: "Refactor the message routing system." Three engineers attempted overlapping changes and every merge conflicted.&lt;/p&gt;

&lt;p&gt;Good decomposition: "Extract delivery retry logic into its own module." "Add timeout configuration to message delivery." "Write tests for Maildir atomic rename." Three independent tasks, zero conflicts.&lt;/p&gt;

&lt;p&gt;The quality of the architect's output determined whether the day went smoothly or devolved into conflict resolution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test gating prevented 12 bad merges
&lt;/h3&gt;

&lt;p&gt;12 times, an engineer declared a task complete but the test suite failed. Without test gating, those 12 broken branches would have merged to main, creating cascading failures.&lt;/p&gt;

&lt;p&gt;The pattern: engineer produces code that compiles, looks correct, and handles the happy path. But it misses an edge case, breaks an existing test, or introduces a subtle regression. The test gate catches it, sends the failure output back, and the engineer fixes it — usually on the first retry.&lt;/p&gt;

&lt;p&gt;Three of those 12 catches were serious: a race condition in merge locking, a missing null check in config parsing, and a test that passed locally but failed because of a hardcoded path. Without the gate, any of these would have cost hours to debug in main.&lt;/p&gt;

&lt;h3&gt;
  
  
  Worktree isolation eliminated file conflicts (mostly)
&lt;/h3&gt;

&lt;p&gt;Each engineer worked in its own git worktree on its own branch. During active work, there were zero file conflicts. Engineers could edit the same files simultaneously without knowing about each other.&lt;/p&gt;

&lt;p&gt;Conflicts only appeared at merge time — 4 total across 47 tasks. All were straightforward to resolve because only one branch was being merged at a time (serialized with a file lock).&lt;/p&gt;

&lt;h2&gt;
  
  
  What Broke
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Context exhaustion on complex tasks
&lt;/h3&gt;

&lt;p&gt;Three times, an engineer hit the context window limit mid-task. Each time, the pattern was the same: a task that seemed simple but required reading many files to understand the full picture.&lt;/p&gt;

&lt;p&gt;The worst case: "Update the error handling to use typed errors throughout." The engineer started reading error types, then the modules that used them, then the modules that called those modules. By the time it understood the scope, the context window was nearly full and the actual changes were shallow and incomplete.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Break broad refactors into per-module tasks. "Add typed errors to the delivery module" fits in one context window. "Add typed errors everywhere" does not.&lt;/p&gt;

&lt;h3&gt;
  
  
  The architect occasionally over-decomposed
&lt;/h3&gt;

&lt;p&gt;On day 3, the architect broke a single feature into 11 tasks. Three of the tasks were trivial one-liners that took more effort to dispatch, execute, test, and merge than they would have taken to do manually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Set a minimum complexity threshold. If a task takes less than 5 minutes for a human, it's not worth the orchestration overhead. Batch trivial changes into a single "cleanup" task.&lt;/p&gt;

&lt;h3&gt;
  
  
  One engineer got stuck in a retry loop
&lt;/h3&gt;

&lt;p&gt;An engineer hit a failing test, attempted to fix it, introduced a new failure, attempted to fix that, and looped for 40 minutes. The test gate correctly blocked the merge each time, but the agent didn't know how to step back and reconsider its approach.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; After 2 failed retries, escalate to the manager instead of letting the engineer continue. The manager can provide fresh perspective or reassign the task. Batty now enforces this automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Surprised Me
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The 3-5 engineer sweet spot is real
&lt;/h3&gt;

&lt;p&gt;With 3 engineers, merge conflicts were rare and supervision was comfortable. With 5, conflicts increased and I spent more time watching for stuck agents. The codebase — not the tooling — was the bottleneck. Too many concurrent changes in a tightly-coupled codebase created interference even with worktree isolation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Supervision isn't passive
&lt;/h3&gt;

&lt;p&gt;I expected to kick off tasks and check back later. In reality, I checked agent status every 10-15 minutes during the first two hours, then relaxed to every 30 minutes once the pattern was established. The supervision was lightweight but continuous — closer to managing a team than running a batch job.&lt;/p&gt;

&lt;h3&gt;
  
  
  The architect agent was the best investment
&lt;/h3&gt;

&lt;p&gt;If I had to choose between 1 architect + 2 engineers or 0 architects + 5 engineers, I'd take the architect every time. Well-decomposed tasks with clear acceptance criteria produced better results than throwing more engineers at vague objectives.&lt;/p&gt;

&lt;h3&gt;
  
  
  Token costs were reasonable
&lt;/h3&gt;

&lt;p&gt;Total token cost for the week: approximately $45. Sequential work on the same tasks would have cost roughly $30 (fewer context loads). The 50% cost increase bought a 4x time compression. At any reasonable hourly rate, this is an obvious trade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Would I Do It Again?
&lt;/h2&gt;

&lt;p&gt;Yes, with two changes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Minimum task complexity threshold.&lt;/strong&gt; Don't orchestrate tasks that take less than 5 minutes manually.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stricter retry limits from day 1.&lt;/strong&gt; Two retries, then escalate. No exceptions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The 4x compression was real, the test gating prevented real damage, and the supervision overhead was manageable. Multi-agent development isn't fire-and-forget, but it's a genuine productivity multiplier for anyone willing to supervise.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Try it:&lt;/strong&gt; &lt;code&gt;cargo install batty-cli&lt;/code&gt; — &lt;a href="https://github.com/battysh/batty" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; | &lt;a href="https://youtube.com/watch?v=2wmBcUnq0vw" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devtools</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>How File-Based Architecture Makes AI Agents Debuggable</title>
      <dc:creator>Batty</dc:creator>
      <pubDate>Sun, 05 Apr 2026 00:45:29 +0000</pubDate>
      <link>https://dev.to/battyterm/how-file-based-architecture-makes-ai-agents-debuggable-4e4i</link>
      <guid>https://dev.to/battyterm/how-file-based-architecture-makes-ai-agents-debuggable-4e4i</guid>
      <description>&lt;p&gt;When an AI agent does something wrong — and it will — you need to answer two questions fast: what happened, and why?&lt;/p&gt;

&lt;p&gt;If your agent state lives in a database, the answer requires a SQL client, the right query, and knowledge of the schema. If it lives in an API, you need auth tokens, endpoint documentation, and a way to correlate events across services.&lt;/p&gt;

&lt;p&gt;If it lives in files, the answer is &lt;code&gt;ls&lt;/code&gt; and &lt;code&gt;cat&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;Every layer of abstraction between you and the agent's state is a debugging tax. Each layer adds latency to your investigation:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Architecture&lt;/th&gt;
&lt;th&gt;To see what happened&lt;/th&gt;
&lt;th&gt;Time to first insight&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Database (SQLite/Postgres)&lt;/td&gt;
&lt;td&gt;Open client, write query, parse results&lt;/td&gt;
&lt;td&gt;2-5 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API-based state&lt;/td&gt;
&lt;td&gt;Authenticate, find endpoint, decode response&lt;/td&gt;
&lt;td&gt;3-10 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File-based state&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ls .batty/inboxes/eng-1-1/new/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;At 2am when an agent has been looping for an hour, those minutes matter. File-based state gives you instant visibility with tools you already know.&lt;/p&gt;

&lt;h2&gt;
  
  
  What File-Based Looks Like
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/battysh/batty" rel="noopener noreferrer"&gt;Batty&lt;/a&gt; stores every piece of agent state as a file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.batty/
  team_config/
    team.yaml              # Who does what, who talks to whom
    prompts/               # Per-role instruction files
  kanban/
    board/tasks/           # Each task is a Markdown file
  inboxes/
    eng-1-1/
      new/                 # Undelivered messages
      cur/                 # Delivered messages
      tmp/                 # Atomic write staging
    architect/
      new/
      cur/
  worktrees/
    eng-1-1/               # Full git worktree per engineer
  logs/
    events.jsonl           # Every event, one JSON object per line
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No database. No hidden state. Every piece of the system is a file you can read with standard Unix tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four Formats, Four Purposes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  YAML Config — Who Does What
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;roles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;engineer&lt;/span&gt;
    &lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;claude&lt;/span&gt;
    &lt;span class="na"&gt;instances&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
    &lt;span class="na"&gt;talks_to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;manager&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;use_worktrees&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;YAML is human-readable configuration. You edit it in your editor, validate it at startup, and &lt;code&gt;git diff&lt;/code&gt; it to see what changed. Configuration doesn't change during a session — it's the rules, not the state.&lt;/p&gt;

&lt;h3&gt;
  
  
  Markdown Kanban — What's Happening
&lt;/h3&gt;

&lt;p&gt;Each task is a Markdown file with YAML frontmatter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;27&lt;/span&gt;
&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;in-progress&lt;/span&gt;
&lt;span class="na"&gt;assigned_to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;eng-1-1&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="gh"&gt;# Add JWT authentication&lt;/span&gt;
Implement JWT middleware for protected routes.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Want to see all in-progress tasks? &lt;code&gt;grep -l "status: in-progress" board/tasks/*.md&lt;/code&gt;. Want to see what changed? &lt;code&gt;git diff board/&lt;/code&gt;. Want to edit a task while the daemon is running? Open the file in vim.&lt;/p&gt;

&lt;h3&gt;
  
  
  Maildir Inboxes — Who Said What
&lt;/h3&gt;

&lt;p&gt;Messages between agents use the Maildir protocol — the same format email servers have used since 1995:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;inboxes/eng-1-1/new/   → Messages waiting to be delivered
inboxes/eng-1-1/cur/   → Messages already delivered
inboxes/eng-1-1/tmp/   → Messages being written (atomic staging)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each message is a JSON file: sender, recipient, body, timestamp. Delivery is atomic — write to &lt;code&gt;tmp/&lt;/code&gt;, rename to &lt;code&gt;new/&lt;/code&gt;. No partial writes, no corruption, no WAL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Debugging a delivery failure:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# What messages are stuck?&lt;/span&gt;
&lt;span class="nb"&gt;ls &lt;/span&gt;inboxes/eng-1-1/new/

&lt;span class="c"&gt;# What does the stuck message say?&lt;/span&gt;
&lt;span class="nb"&gt;cat &lt;/span&gt;inboxes/eng-1-1/new/1711108200.msg

&lt;span class="c"&gt;# Who sent it?&lt;/span&gt;
&lt;span class="nb"&gt;cat &lt;/span&gt;inboxes/eng-1-1/new/1711108200.msg | jq .from
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare this to debugging a message queue: connect to the broker, navigate the admin UI, find the right queue, decode the message format. With Maildir, it's &lt;code&gt;cat&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  JSONL Logs — What Happened When
&lt;/h3&gt;

&lt;p&gt;Every significant event is appended to &lt;code&gt;events.jsonl&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;{"ts":1711108200,"event":"task_assigned","engineer":"eng-1-1","task_id":27}
{"ts":1711108890,"event":"test_executed","task_id":27,"passed":false}
{"ts":1711108950,"event":"message_delivered","from":"batty","to":"eng-1-1"}
{"ts":1711109400,"event":"test_executed","task_id":27,"passed":true}
{"ts":1711109405,"event":"merge","source":"eng-1-1/task-27","target":"main"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One JSON object per line. Append-only. &lt;code&gt;grep&lt;/code&gt;-able. &lt;code&gt;jq&lt;/code&gt;-able.&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;# Which tasks failed tests?&lt;/span&gt;
&lt;span class="nb"&gt;cat &lt;/span&gt;events.jsonl | jq &lt;span class="s1"&gt;'select(.event == "test_executed" and .passed == false)'&lt;/span&gt;

&lt;span class="c"&gt;# Average time from assignment to completion?&lt;/span&gt;
&lt;span class="nb"&gt;cat &lt;/span&gt;events.jsonl | jq &lt;span class="s1"&gt;'select(.event == "task_assigned" or .event == "task_completed")'&lt;/span&gt;

&lt;span class="c"&gt;# Which engineer fails tests most often?&lt;/span&gt;
&lt;span class="nb"&gt;cat &lt;/span&gt;events.jsonl | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'select(.event == "test_executed" and .passed == false) | .engineer'&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; | &lt;span class="nb"&gt;uniq&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No Grafana dashboard. No log aggregation service. Just &lt;code&gt;jq&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Not a Database?
&lt;/h2&gt;

&lt;p&gt;SQLite would work. It's fast, embedded, and well-understood. But it adds three problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Opaque state.&lt;/strong&gt; You can't &lt;code&gt;cat&lt;/code&gt; a SQLite database. You need a client and a query. When something breaks, the first step is figuring out how to inspect the state — not inspecting it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Merge complexity.&lt;/strong&gt; Git can't meaningfully diff a binary database file. With file-based state, &lt;code&gt;git diff&lt;/code&gt; shows you exactly what changed between two points in time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Recovery complexity.&lt;/strong&gt; If the daemon crashes mid-write, a database might need WAL recovery. With Maildir, the atomic rename protocol means messages are either fully written or not written at all. No recovery logic needed.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The tradeoff: files don't scale to millions of records. But an agent supervisor manages 5-20 agents with 50-100 tasks. At that scale, files are faster to inspect and equally fast to read.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Compound Effect
&lt;/h2&gt;

&lt;p&gt;When everything is a file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Backups&lt;/strong&gt; are &lt;code&gt;cp -r .batty/ /backup/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version control&lt;/strong&gt; is &lt;code&gt;git add .batty/ &amp;amp;&amp;amp; git commit&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging&lt;/strong&gt; is &lt;code&gt;ls&lt;/code&gt; and &lt;code&gt;cat&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring&lt;/strong&gt; is &lt;code&gt;watch ls inboxes/*/new/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Migration&lt;/strong&gt; is copying a directory&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing&lt;/strong&gt; is seeding files and checking results&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No client libraries. No connection strings. No schema migrations. No ORM. The filesystem is the API.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Files Don't Work
&lt;/h2&gt;

&lt;p&gt;File-based architecture has real limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Concurrent writes from multiple machines&lt;/strong&gt; — files assume a single host. For distributed agents, you need a coordination layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complex queries&lt;/strong&gt; — "show me all tasks assigned to eng-1-1 that failed tests in the last hour" is easier in SQL than with &lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;jq&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-volume events&lt;/strong&gt; — JSONL works for hundreds of events per session. For millions, you need a proper time-series database.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a single-host agent supervisor managing 5-20 agents? Files are the right abstraction. They're not clever. They're debuggable.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Try it:&lt;/strong&gt; &lt;code&gt;cargo install batty-cli&lt;/code&gt; — &lt;a href="https://github.com/battysh/batty" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; | &lt;a href="https://youtube.com/watch?v=2wmBcUnq0vw" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>devtools</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building an AI Agent Supervisor: Series Index</title>
      <dc:creator>Batty</dc:creator>
      <pubDate>Sun, 05 Apr 2026 00:06:06 +0000</pubDate>
      <link>https://dev.to/battyterm/building-an-ai-agent-supervisor-series-index-m4p</link>
      <guid>https://dev.to/battyterm/building-an-ai-agent-supervisor-series-index-m4p</guid>
      <description>&lt;p&gt;This series documents the architecture, decisions, and lessons from building Batty — a Rust CLI that supervises teams of AI coding agents in tmux.&lt;/p&gt;

&lt;p&gt;Each post covers a specific subsystem or challenge. Start anywhere — they're designed to be useful independently.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://dev.to/battyterm/how-i-run-a-team-of-ai-coding-agents-in-parallel"&gt;How I Run a Team of AI Coding Agents in Parallel&lt;/a&gt;&lt;/strong&gt; — The problem and the solution. Why running multiple agents on the same repo breaks without coordination.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://dev.to/battyterm/building-a-tmux-native-agent-supervisor-in-rust-5hek"&gt;Building a tmux-native agent supervisor in Rust&lt;/a&gt;&lt;/strong&gt; — Deep dive into the Rust implementation. Crate choices, architecture decisions, what I'd do differently.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://dev.to/battyterm/why-i-chose-a-synchronous-poll-loop-over-async-for-my-rust-daemon-1416"&gt;Why I Chose a Synchronous Poll Loop Over Async&lt;/a&gt;&lt;/strong&gt; — I ripped out tokio after two weeks. Here's why sleep(5) was the right call.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://dev.to/battyterm/how-tmux-became-the-runtime-for-ai-agent-teams-gmi"&gt;How tmux Became the Runtime&lt;/a&gt;&lt;/strong&gt; — Why tmux, not Docker or a custom TUI, is the perfect agent runtime.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Patterns
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://dev.to/battyterm/how-to-use-git-worktrees-to-run-multiple-ai-agents-on-the-same-repo-1on8"&gt;Git Worktrees for AI Agent Isolation&lt;/a&gt;&lt;/strong&gt; — Step-by-step tutorial for parallel agent work without file conflicts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://dev.to/battyterm/the-case-for-markdown-as-your-agents-task-format-6mp"&gt;The Case for Markdown as Your Agent's Task Format&lt;/a&gt;&lt;/strong&gt; — Why Markdown beats JSON for agent task management.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://dev.to/battyterm/context-rotation-for-ai-coding-agents-what-happens-when-they-run-out-of-memory-17f6"&gt;Context Rotation: When Agents Run Out of Memory&lt;/a&gt;&lt;/strong&gt; — Detection, rotation patterns, and scoping tasks to fit context windows.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://dev.to/battyterm/your-ai-agent-says-done-how-do-you-know-it-actually-worked-3mfc"&gt;Your AI Agent Says Done — How Do You Know?&lt;/a&gt;&lt;/strong&gt; — Test gating as the quality gate. Exit code 0 means done.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Practice
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://dev.to/battyterm/5-lessons-from-running-ai-coding-agents-in-parallel-53on"&gt;5 Lessons from Running AI Agents in Parallel&lt;/a&gt;&lt;/strong&gt; — Task decomposition, test gating, worktree isolation, supervision vs autonomy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://dev.to/battyterm/from-solo-agent-to-agent-team-a-migration-guide-474c"&gt;From Solo Agent to Agent Team: A Migration Guide&lt;/a&gt;&lt;/strong&gt; — Progressive 6-stage path from one agent to full automation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://dev.to/battyterm/the-real-cost-of-running-5-ai-coding-agents-in-parallel-1lo"&gt;The Real Cost of Running 5 Agents in Parallel&lt;/a&gt;&lt;/strong&gt; — Token math, cost reduction tactics. 1.5-2x not 5x.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://dev.to/battyterm/choosing-an-ai-agent-orchestrator-in-2026-a-practical-comparison-i0k"&gt;Choosing an AI Agent Orchestrator in 2026&lt;/a&gt;&lt;/strong&gt; — Honest comparison: Batty vs vibe-kanban vs CrewAI vs AutoGen vs tmux scripts.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;The tool:&lt;/strong&gt; &lt;a href="https://github.com/battysh/batty" rel="noopener noreferrer"&gt;github.com/battysh/batty&lt;/a&gt; — open source, MIT licensed, built in Rust.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rust</category>
      <category>devtools</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Open Source Marketing with Zero Budget: How We Got 14 Stars in 4 Weeks</title>
      <dc:creator>Batty</dc:creator>
      <pubDate>Sat, 04 Apr 2026 23:21:22 +0000</pubDate>
      <link>https://dev.to/battyterm/open-source-marketing-with-zero-budget-how-we-got-14-stars-in-4-weeks-45m2</link>
      <guid>https://dev.to/battyterm/open-source-marketing-with-zero-budget-how-we-got-14-stars-in-4-weeks-45m2</guid>
      <description>&lt;p&gt;Four weeks ago, &lt;a href="https://github.com/battysh/batty" rel="noopener noreferrer"&gt;Batty&lt;/a&gt; didn't exist as far as the internet was concerned. No stars. No downloads. No articles. No social presence.&lt;/p&gt;

&lt;p&gt;Today: 14 stars, 76 crate downloads, 241 cloners, 293 GitHub views, 25+ articles indexed by Google, and 68 X replies that built a recognized presence in the AI coding space.&lt;/p&gt;

&lt;p&gt;Total marketing budget: $0.&lt;/p&gt;

&lt;p&gt;Here's exactly what we did, what worked, what failed, and what we'd do differently.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Strategy: Content as Infrastructure
&lt;/h2&gt;

&lt;p&gt;Most open-source projects treat marketing as an event — a launch day, a Show HN, a Product Hunt post. We treated it as infrastructure. Every article is a permanent search discovery path. Every X reply is a conversation that surfaces our profile. The goal wasn't a traffic spike. It was steady compounding.&lt;/p&gt;

&lt;p&gt;The strategy has three pillars:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;SEO content on Dev.to&lt;/strong&gt; — articles targeting specific keyword clusters&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;X engagement&lt;/strong&gt; — quality replies in relevant threads, not broadcasting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Directory submissions&lt;/strong&gt; — backlinks from high-authority platforms&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. No paid ads, no influencer outreach, no growth hacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Worked
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Dev.to Articles (Highest ROI)
&lt;/h3&gt;

&lt;p&gt;25+ articles published across Dev.to and Hashnode. Each targets a different keyword cluster:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Keyword Cluster&lt;/th&gt;
&lt;th&gt;Article&lt;/th&gt;
&lt;th&gt;Why It Works&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;"git worktrees AI agents"&lt;/td&gt;
&lt;td&gt;How to Use Git Worktrees...&lt;/td&gt;
&lt;td&gt;Tutorial, actionable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"sync vs async Rust daemon"&lt;/td&gt;
&lt;td&gt;Why I Chose Sync Over Async...&lt;/td&gt;
&lt;td&gt;Contrarian, Rust community bait&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"AI agent orchestrator 2026"&lt;/td&gt;
&lt;td&gt;Choosing an AI Agent Orchestrator...&lt;/td&gt;
&lt;td&gt;Comparison, high-intent search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"AI agent task management"&lt;/td&gt;
&lt;td&gt;The Case for Markdown...&lt;/td&gt;
&lt;td&gt;Opinionated, practical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"tmux AI agents"&lt;/td&gt;
&lt;td&gt;How tmux Became the Runtime...&lt;/td&gt;
&lt;td&gt;Narrative, niche keyword&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"running multiple AI agents"&lt;/td&gt;
&lt;td&gt;5 Lessons from Running AI Agents...&lt;/td&gt;
&lt;td&gt;Listicle, shareable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"AI agent cost"&lt;/td&gt;
&lt;td&gt;The Real Cost of Running 5 Agents...&lt;/td&gt;
&lt;td&gt;Addresses #1 objection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"solo to agent team"&lt;/td&gt;
&lt;td&gt;From Solo Agent to Agent Team&lt;/td&gt;
&lt;td&gt;Migration guide, widest audience&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Key insight: article quantity compounds faster than quality.&lt;/strong&gt; Each article is a permanent Google entry point. A mediocre article that ranks for a long-tail keyword drives more lasting traffic than a perfect article that nobody finds. We'd rather publish 25 good articles than 5 great ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The 5-article threshold.&lt;/strong&gt; After our first 5 articles, Google started treating our Dev.to profile as authoritative for multi-agent coding topics. Articles 6-25 indexed faster and ranked higher. The first 5 were investment; the rest are compounding returns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-posting to Hashnode&lt;/strong&gt; added a second indexed domain with canonical URLs pointing back to Dev.to. Zero extra writing — same content, different discovery path.&lt;/p&gt;

&lt;h3&gt;
  
  
  X Engagement (Highest Quality Traffic)
&lt;/h3&gt;

&lt;p&gt;68 replies across 23 rounds. Strategy: find high-engagement threads about AI coding agents, Rust CLI tools, or developer workflows. Add a genuinely helpful reply. Never promote.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The math:&lt;/strong&gt; replies to threads from accounts with 10K+ followers appear under their post, visible to their entire audience. A single reply on a 20K-view thread drives more targeted traffic than a standalone post with 100 impressions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What we actually said:&lt;/strong&gt; technical observations about multi-agent coordination, token cost management, sync vs async tradeoffs. Things only someone who's actually built an agent supervisor would know. The replies built credibility before anyone clicked through to our profile.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quality signal:&lt;/strong&gt; X drove nearly 1:1 visitor-to-unique ratio. When someone clicks through from a quality reply, they're genuinely interested. Most other channels have much higher bounce rates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We never said "check out Batty"&lt;/strong&gt; in a reply. Not once across 68 replies. The profile link in our bio does the conversion. Forcing it kills credibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Directory Submissions (Backlinks)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SaaSHub&lt;/strong&gt; (DR 77) — submitted, pending approval&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;awesome-tmux, awesome-ai-tools, awesome-ai-agents&lt;/strong&gt; — PRs open&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;This Week in Rust&lt;/strong&gt; — PR submitted&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rust Users Forum&lt;/strong&gt; — post submitted (pending mod approval)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Search Console&lt;/strong&gt; — verified, data incoming&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each approved submission is a permanent dofollow backlink from a high-authority domain. These take weeks to process but compound permanently.&lt;/p&gt;

&lt;h3&gt;
  
  
  YouTube Comments (Permanent Discovery)
&lt;/h3&gt;

&lt;p&gt;3 comments on major Claude Code tutorial videos. YouTube comments are permanently visible, Google-indexed, and contextually placed — they appear exactly where someone is learning about the problem Batty solves.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Failed
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Show HN (Dead on Arrival)
&lt;/h3&gt;

&lt;p&gt;Our Show HN was posted with a solid title, a strong first comment, and architecture details. The author's HN account got flagged for AI-generated comments (unrelated to the Show HN). Post died at 1 point with zero engagement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; HN is a single point of failure. If your account has any issues, the entire launch is wasted. We'd invested weeks in karma building and response templates — all for nothing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reddit (Near Zero Engagement)
&lt;/h3&gt;

&lt;p&gt;Three posts across r/commandline, r/rust, and the r/rust weekly thread. Total community engagement: approximately zero. The posts exist and are indexed, but Reddit's algorithm buried them without early upvote velocity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Reddit rewards participation in existing discussions, not announcements. We should have spent those hours commenting helpfully in other threads instead of creating our own posts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bluesky (Blocked by Logistics)
&lt;/h3&gt;

&lt;p&gt;We had a Bluesky account but couldn't activate it — email verification issues, app password problems, browser automation incompatibility. 4 unique visitors from near-zero effort suggests potential, but we never got to test it properly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Set up all accounts and verify everything before you need them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Numbers Nobody Shows You
&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;Reality&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Articles published&lt;/td&gt;
&lt;td&gt;25+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X replies sent&lt;/td&gt;
&lt;td&gt;68&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total marketing hours&lt;/td&gt;
&lt;td&gt;~40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stars earned&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost per star&lt;/td&gt;
&lt;td&gt;$0 (but ~3 hours of work)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Viral moments&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Articles that "went viral"&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Steady daily growth&lt;/td&gt;
&lt;td&gt;2-3 visitors/day&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No single piece of content drove our growth. It was the accumulation of 25 articles, 68 replies, and consistent presence over 4 weeks. The growth is invisible day-to-day but obvious week-to-week.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Skip Reddit posts, do Reddit comments.&lt;/strong&gt; Reply to "what tools do you use" threads instead of creating our own announcement posts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Set up all accounts on day 1.&lt;/strong&gt; Bluesky, Discord, AlternativeTo — every platform that needs verification should be ready before you need it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Start with the comparison article.&lt;/strong&gt; "Choosing an AI Agent Orchestrator in 2026" is our highest-intent search target. We should have published it first, not fifteenth.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Don't invest in HN.&lt;/strong&gt; It's high risk, single point of failure, and doesn't compound. The same hours spent on Dev.to articles produce permanently indexed content.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Publish daily from day 1.&lt;/strong&gt; The 5-article threshold means the first week is pure investment. Starting earlier means reaching the compounding phase sooner.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Playbook (Steal This)
&lt;/h2&gt;

&lt;p&gt;If you're marketing an open-source tool with zero budget:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Write 5 articles in week 1&lt;/strong&gt; targeting different keyword clusters. Dev.to + Hashnode cross-post.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reply to 3 threads daily on X.&lt;/strong&gt; Technically specific, never promotional. Your bio link does the conversion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Submit to directories&lt;/strong&gt; — SaaSHub, awesome-lists, This Week in Rust (or your language's equivalent). Free backlinks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leave YouTube comments&lt;/strong&gt; on tutorial videos about the problem you solve. Permanent and contextual.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't launch.&lt;/strong&gt; Build presence continuously instead of betting on a single launch day.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The boring answer is the correct answer: show up every day, write something useful, engage genuinely, and let search do the compounding.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;The tool:&lt;/strong&gt; &lt;a href="https://github.com/battysh/batty" rel="noopener noreferrer"&gt;github.com/battysh/batty&lt;/a&gt; — supervised agent execution for software teams.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you're marketing an open-source project with zero budget, I'd love to compare playbooks. What's working for you?&lt;/em&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>buildinpublic</category>
      <category>marketing</category>
      <category>devtools</category>
    </item>
    <item>
      <title>From Solo Agent to Agent Team: A Migration Guide</title>
      <dc:creator>Batty</dc:creator>
      <pubDate>Sat, 04 Apr 2026 22:26:40 +0000</pubDate>
      <link>https://dev.to/battyterm/from-solo-agent-to-agent-team-a-migration-guide-474c</link>
      <guid>https://dev.to/battyterm/from-solo-agent-to-agent-team-a-migration-guide-474c</guid>
      <description>&lt;p&gt;You're already using an AI coding agent. Claude Code, Codex, Aider — pick one. It works. You give it a task, it writes code, you review it. Simple.&lt;/p&gt;

&lt;p&gt;But you have a backlog. Five tasks that could run in parallel. You open three terminal tabs, paste prompts, and immediately discover why "just run more agents" doesn't scale.&lt;/p&gt;

&lt;p&gt;Here's the progressive path from one agent to a supervised team. Each step adds capability without requiring you to rethink everything at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 0: Where You Are Now
&lt;/h2&gt;

&lt;p&gt;One agent. One terminal. Sequential tasks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude-code
&lt;span class="c"&gt;# "Add JWT authentication"&lt;/span&gt;
&lt;span class="c"&gt;# Wait 15 minutes&lt;/span&gt;
&lt;span class="c"&gt;# Review, iterate&lt;/span&gt;
&lt;span class="c"&gt;# "Now write the API tests"&lt;/span&gt;
&lt;span class="c"&gt;# Wait 10 minutes&lt;/span&gt;
&lt;span class="c"&gt;# Review, iterate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works. The limitation is time — you're processing tasks sequentially when many of them could run in parallel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to move past this:&lt;/strong&gt; You regularly have 3+ independent tasks queued, and you're spending more time waiting for agents than reviewing their output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 1: Two Agents in Parallel
&lt;/h2&gt;

&lt;p&gt;The simplest upgrade. Two terminal tabs, two agents, two tasks.&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;# Terminal 1&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; .agents/agent-1
git worktree add .agents/agent-1 &lt;span class="nt"&gt;-b&lt;/span&gt; agent-1/task-auth
&lt;span class="nb"&gt;cd&lt;/span&gt; .agents/agent-1
claude-code
&lt;span class="c"&gt;# "Add JWT authentication"&lt;/span&gt;

&lt;span class="c"&gt;# Terminal 2&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; .agents/agent-2
git worktree add .agents/agent-2 &lt;span class="nt"&gt;-b&lt;/span&gt; agent-2/task-tests
&lt;span class="nb"&gt;cd&lt;/span&gt; .agents/agent-2
codex
&lt;span class="c"&gt;# "Write integration tests for the user API"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key change:&lt;/strong&gt; Git worktrees. Each agent gets its own directory on its own branch. Without this, they overwrite each other's files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What you manage manually:&lt;/strong&gt; Checking when each agent finishes. Running tests. Merging branches one at a time. Resolving conflicts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to move past this:&lt;/strong&gt; You're running 2 agents reliably, but the manual merge/test/check cycle is eating your supervision time. You find yourself asking "is agent 2 still working or stuck?"&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 2: Add tmux and Basic Monitoring
&lt;/h2&gt;

&lt;p&gt;Replace terminal tabs with tmux. Now you can see both agents simultaneously and detach without killing them.&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;# Create a session with two panes&lt;/span&gt;
tmux new-session &lt;span class="nt"&gt;-s&lt;/span&gt; agents &lt;span class="nt"&gt;-d&lt;/span&gt;
tmux split-window &lt;span class="nt"&gt;-h&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; agents

&lt;span class="c"&gt;# Launch agents in their worktrees&lt;/span&gt;
tmux send-keys &lt;span class="nt"&gt;-t&lt;/span&gt; agents:0.0 &lt;span class="s1"&gt;'cd .agents/agent-1 &amp;amp;&amp;amp; claude-code'&lt;/span&gt; Enter
tmux send-keys &lt;span class="nt"&gt;-t&lt;/span&gt; agents:0.1 &lt;span class="s1"&gt;'cd .agents/agent-2 &amp;amp;&amp;amp; codex'&lt;/span&gt; Enter

&lt;span class="c"&gt;# Attach and watch both&lt;/span&gt;
tmux attach &lt;span class="nt"&gt;-t&lt;/span&gt; agents
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key change:&lt;/strong&gt; Visibility and persistence. You can see both agents working side by side. Close your laptop, SSH back in later, &lt;code&gt;tmux attach&lt;/code&gt; — they're still running.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What you still manage manually:&lt;/strong&gt; Everything from Stage 1, plus you're now building up tmux muscle memory for pane navigation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to move past this:&lt;/strong&gt; You want 3+ agents, automated test checking, or the ability to walk away and come back to merged results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 3: Add Test Gating
&lt;/h2&gt;

&lt;p&gt;Before this stage, "done" means the agent said it's done. After this stage, "done" means tests pass.&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;# After agent-1 says it's finished:&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; .agents/agent-1
cargo &lt;span class="nb"&gt;test&lt;/span&gt;          &lt;span class="c"&gt;# or npm test, pytest&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt;             &lt;span class="c"&gt;# 0 = merge, non-zero = send back&lt;/span&gt;

&lt;span class="c"&gt;# If tests pass:&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; /project
git merge agent-1/task-auth

&lt;span class="c"&gt;# If tests fail:&lt;/span&gt;
&lt;span class="c"&gt;# Copy the failure output back to the agent&lt;/span&gt;
&lt;span class="c"&gt;# "Tests failed: thread 'test_jwt_auth' panicked..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key change:&lt;/strong&gt; Quality gate. This single check reduces "agent broke something" incidents by roughly 80%. The remaining 20% are gaps in test coverage, not agent failures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What you still manage manually:&lt;/strong&gt; Running the test command, reading the output, deciding whether to merge or send feedback.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to move past this:&lt;/strong&gt; You're doing the test-run-merge cycle manually for every task and want it automated. You want an architect that decomposes features before engineers execute.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 4: Add an Architect
&lt;/h2&gt;

&lt;p&gt;Separate planning from execution. One agent decomposes work; others execute.&lt;/p&gt;

&lt;p&gt;Until now, you've been the architect — deciding what each agent works on. An architect agent takes a high-level objective and breaks it into specific, testable tasks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You → "Build user authentication with JWT"

Architect → Creates tasks:
  1. Add JWT middleware to protected routes
  2. Implement login endpoint with token generation
  3. Implement token refresh endpoint
  4. Write integration tests for auth flow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each task is independent, specific, and has clear completion criteria. The difference in output quality between "build auth" and four decomposed tasks is dramatic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key change:&lt;/strong&gt; Task decomposition quality. A good architect prompt produces better results than adding more engineers with vague tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 5: Automate with Batty
&lt;/h2&gt;

&lt;p&gt;Every step above is something you can do manually. &lt;a href="https://github.com/battysh/batty" rel="noopener noreferrer"&gt;Batty&lt;/a&gt; automates the full loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .batty/team_config/team.yaml&lt;/span&gt;
&lt;span class="na"&gt;roles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;architect&lt;/span&gt;
    &lt;span class="na"&gt;role_type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;architect&lt;/span&gt;
    &lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;claude&lt;/span&gt;
    &lt;span class="na"&gt;instances&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;talks_to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;manager&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;manager&lt;/span&gt;
    &lt;span class="na"&gt;role_type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;manager&lt;/span&gt;
    &lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;claude&lt;/span&gt;
    &lt;span class="na"&gt;instances&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;talks_to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;architect&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;engineer&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;engineer&lt;/span&gt;
    &lt;span class="na"&gt;role_type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;engineer&lt;/span&gt;
    &lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;codex&lt;/span&gt;
    &lt;span class="na"&gt;instances&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
    &lt;span class="na"&gt;use_worktrees&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;talks_to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;manager&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo &lt;span class="nb"&gt;install &lt;/span&gt;batty-cli
batty init &lt;span class="nt"&gt;--template&lt;/span&gt; standard
batty start &lt;span class="nt"&gt;--attach&lt;/span&gt;
batty send architect &lt;span class="s2"&gt;"Build user authentication with JWT"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What Batty automates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Worktree creation:&lt;/strong&gt; persistent per-engineer, fresh branch per task&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test gating:&lt;/strong&gt; runs your test command before allowing merges&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Merge serialization:&lt;/strong&gt; file lock prevents concurrent merge conflicts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Task dispatch:&lt;/strong&gt; Markdown kanban board with auto-assignment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Message routing:&lt;/strong&gt; Maildir inboxes with &lt;code&gt;talks_to&lt;/code&gt; constraints&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idle detection:&lt;/strong&gt; 4-layer system (output hashing, session files, context exhaustion, completion packets)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent lifecycle:&lt;/strong&gt; spawn, monitor, restart on crash or context exhaustion&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You supervise the team instead of operating the machinery.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which Stage Are You?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;You're ready when...&lt;/th&gt;
&lt;th&gt;Time to set up&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0 → 1&lt;/td&gt;
&lt;td&gt;You have 2+ independent tasks&lt;/td&gt;
&lt;td&gt;5 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1 → 2&lt;/td&gt;
&lt;td&gt;You want to see agents side by side&lt;/td&gt;
&lt;td&gt;10 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2 → 3&lt;/td&gt;
&lt;td&gt;You want quality gates before merging&lt;/td&gt;
&lt;td&gt;5 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3 → 4&lt;/td&gt;
&lt;td&gt;You want better task decomposition&lt;/td&gt;
&lt;td&gt;15 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4 → 5&lt;/td&gt;
&lt;td&gt;You want the full loop automated&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cargo install batty-cli&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Start where you are. Each stage adds capability without requiring you to rebuild your workflow from scratch. Most developers find Stage 1 (worktrees) delivers immediate value — you can stay there for weeks before needing more.&lt;/p&gt;

&lt;p&gt;The important thing isn't the tool. It's the progression: isolate work, gate on tests, decompose tasks, then automate.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Start here:&lt;/strong&gt; &lt;code&gt;cargo install batty-cli&lt;/code&gt; — &lt;a href="https://github.com/battysh/batty" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; | &lt;a href="https://youtube.com/watch?v=2wmBcUnq0vw" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>tutorial</category>
      <category>devtools</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
