<?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: Ahmad Shawar</title>
    <description>The latest articles on DEV Community by Ahmad Shawar (@ahmad_shawar_de8d35d546cf).</description>
    <link>https://dev.to/ahmad_shawar_de8d35d546cf</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4209564%2F53e87819-0ac9-43b4-ac5d-9f2d1d1462cc.jpg</url>
      <title>DEV Community: Ahmad Shawar</title>
      <link>https://dev.to/ahmad_shawar_de8d35d546cf</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ahmad_shawar_de8d35d546cf"/>
    <language>en</language>
    <item>
      <title>Why markdown plans break when you run multiple AI agents</title>
      <dc:creator>Ahmad Shawar</dc:creator>
      <pubDate>Tue, 27 Oct 2026 21:55:01 +0000</pubDate>
      <link>https://dev.to/ahmad_shawar_de8d35d546cf/why-markdown-plans-break-when-you-run-multiple-ai-agents-h11</link>
      <guid>https://dev.to/ahmad_shawar_de8d35d546cf/why-markdown-plans-break-when-you-run-multiple-ai-agents-h11</guid>
      <description>&lt;p&gt;Most of us coordinate AI coding agents the same way: a markdown file in the repo with a checklist. The agent reads it, picks an item, does the work, ticks the box and commits. For one agent in one session, it works well.&lt;/p&gt;

&lt;p&gt;Then you start a second session. And a third.&lt;/p&gt;

&lt;h2&gt;
  
  
  What goes wrong
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Two agents pick the same item.&lt;/strong&gt; Nothing in a markdown file stops two readers from choosing the same line at the same moment. You find out when both open a PR for the same fix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An agent dies mid-task.&lt;/strong&gt; The session times out, the laptop sleeps, the context runs out. The item stays marked "in progress" and no other agent will touch it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Edits race each other.&lt;/strong&gt; Two agents update the plan at once, and one change is lost or turns into a merge conflict an agent then "resolves" badly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;History lives in git diffs.&lt;/strong&gt; Who claimed what, when, and why it was rejected is buried in commit history, if it was recorded at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nobody can see it.&lt;/strong&gt; You can't tell at a glance which agent is on what, or what has been stuck for an hour.&lt;/p&gt;

&lt;p&gt;None of these are agent problems. They're the classic problems of shared mutable state, and a file is the wrong place for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a fix needs
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Atomic claims.&lt;/strong&gt; Two claimers can never get the same item.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expiry.&lt;/strong&gt; A claim that isn't refreshed goes back to the pool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Legal transitions only&lt;/strong&gt;, with an error that tells the model what is allowed instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review as a step&lt;/strong&gt;, not an afterthought: approve, send back, or escalate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An append-only history&lt;/strong&gt; of every change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visibility&lt;/strong&gt;: a live view for people, and updates where the team already looks, without making agents wait on GitHub or Slack.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How workstream-mcp does it
&lt;/h2&gt;

&lt;p&gt;I built &lt;a href="https://github.com/ahmad-codex/workstream-mcp" rel="noopener noreferrer"&gt;workstream-mcp&lt;/a&gt; to cover that list. It's an MCP server, so agents use it through ordinary tool calls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claims&lt;/strong&gt; run in one Postgres transaction with &lt;code&gt;SELECT ... FOR UPDATE SKIP LOCKED&lt;/code&gt;. Concurrent claimers skip rows that are already locked instead of waiting on them, so 32 agents claiming at once each get a different task, and none of them block. A test suite runs exactly that. Each claim has a TTL. If an agent stops refreshing it, the task returns to the pool. A plan can also cap how long a claim lives and refuse refreshes when the holder hasn't recorded any progress, so an agent stuck in a loop that keeps its heartbeat going still lets go.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dependencies decide what can run in parallel.&lt;/strong&gt; When the orchestrator breaks work into tasks, it declares which ones depend on which, typically because they touch the same module. &lt;code&gt;claim_next_task&lt;/code&gt; skips a task until its dependencies are done, so two agents never work the same code at once, and tasks that don't overlap run side by side.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The state machine is data.&lt;/strong&gt; Each plan type stores its statuses, transitions, allowed roles and retry caps in a JSON graph. If an agent tries an illegal move, the tool returns &lt;code&gt;illegal_transition&lt;/code&gt; along with &lt;code&gt;allowed_next&lt;/code&gt;. In practice the model reads that and corrects itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reviews are part of the flow.&lt;/strong&gt; A developer agent submits an attempt; a reviewer approves it or sends it back to the pool for another pass. After the retry cap, the task goes to a human.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every change writes an event.&lt;/strong&gt; Database triggers block updates and deletes on the event log, so the history can't be rewritten after the fact.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub and Slack go through an outbox.&lt;/strong&gt; The change and its notification commit in the same transaction, and a background worker delivers it with retries. A GitHub outage never fails an agent's tool call.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The dashboard&lt;/strong&gt; shows each plan as a board: who holds each task, how long their claim has left, what is waiting on what, and what is stuck. It reads through the same tools the agents call.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1puqh9p4nxo99cai33ck.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1puqh9p4nxo99cai33ck.png" alt="Dashboard" width="800" height="450"&gt;&lt;/a&gt;&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;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 127.0.0.1:8080:8080 &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;WORKSTREAM_ADMIN_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;local-admin &lt;span class="se"&gt;\&lt;/span&gt;
  ghcr.io/ahmad-codex/workstream-mcp:demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;a href="http://localhost:8080/demo-insecure-token/ui/" rel="noopener noreferrer"&gt;http://localhost:8080/demo-insecure-token/ui/&lt;/a&gt;. From a clone of the repo, &lt;code&gt;WORKSTREAM_ADMIN_TOKEN=local-admin node scripts/simulate-agents.mjs&lt;/code&gt; runs two developer agents and a reviewer against a ten-task plan, so you can watch claims move across the board.&lt;/p&gt;

&lt;p&gt;To connect your own agent: &lt;code&gt;claude mcp add --transport http workstream-demo http://localhost:8080/demo-insecure-token/mcp&lt;/code&gt;, then ask it to claim the next task.&lt;/p&gt;

&lt;p&gt;For a real setup, clone the repo, open Claude Code in it and paste the setup prompt from the README.&lt;/p&gt;

&lt;p&gt;It's MIT licensed. The &lt;a href="https://github.com/ahmad-codex/workstream-mcp/blob/master/ROADMAP.md" rel="noopener noreferrer"&gt;roadmap&lt;/a&gt; is public, with good first issues for webhooks, connectors and SDKs. Several of these details came straight from the first Reddit thread: the outbox transaction and the refresh limits both shipped within a day of someone pointing at them. I'd especially like to hear how you coordinate multiple agents today, and what breaks.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>automation</category>
      <category>softwaredevelopment</category>
    </item>
  </channel>
</rss>
