<?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: AW</title>
    <description>The latest articles on DEV Community by AW (@drkashy).</description>
    <link>https://dev.to/drkashy</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%2F4108275%2Fcfdd19b4-90ee-4f4b-91c9-1c406f867482.png</url>
      <title>DEV Community: AW</title>
      <link>https://dev.to/drkashy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/drkashy"/>
    <language>en</language>
    <item>
      <title>Twoperson – so your AI coding agent can't approve its own work</title>
      <dc:creator>AW</dc:creator>
      <pubDate>Thu, 03 Sep 2026 15:10:57 +0000</pubDate>
      <link>https://dev.to/drkashy/a-two-person-rule-for-ai-coding-agents-9ld</link>
      <guid>https://dev.to/drkashy/a-two-person-rule-for-ai-coding-agents-9ld</guid>
      <description>&lt;p&gt;I run two coding agents on one repo — one building, one reviewing. For months the "get a review first" rule was a line in a system prompt. It held right up until the builder was unattended for a few hours. Then it would skip the review, or review its own work, or get a real approval and quietly rebase three commits on top before pushing.&lt;/p&gt;

&lt;p&gt;A rule the agent can talk itself out of isn't really a rule. So I moved it out of the prompt and into the file format the agents use to talk to each other.&lt;/p&gt;

&lt;p&gt;It isn't a code reviewer — the agents do the reviewing. It's the layer underneath that: a local, offline, SHA-bound approval ledger and shipping gate for multi-agent coding workflows. It records that a review happened, pins the verdict to one commit, and refuses to let the builder call anything "shipped" without one.&lt;/p&gt;

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

&lt;p&gt;&lt;code&gt;twoperson&lt;/code&gt; is a small Python CLI. The builder writes a JSON review packet — goal, head SHA, files, tests — and publishes it. The reviewer claims it and records a verdict. The enforcement lives in the schema, not in anyone's good intentions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it refuses a verdict for a packet that was never published,&lt;/li&gt;
&lt;li&gt;it refuses an approval that names a different commit than the packet,&lt;/li&gt;
&lt;li&gt;it refuses a "pushed" packet unless it cites a real approving verdict for that same commit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So an approval is bound to one exact commit. Rebase, amend, or add a commit on top and the approval goes stale — the schema simply can't represent "we shipped it" without a matching, current review.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things that mattered more than I expected
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Stop hook.&lt;/strong&gt; &lt;code&gt;twoperson install-hook&lt;/code&gt; adds a Claude Code Stop hook so the reviewer wakes when the builder's session ends, instead of polling on a timer. The hook only drops a signal — never a packet — because a hook doesn't know whether the tests actually passed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Packets are untrusted input.&lt;/strong&gt; They get a credential scan, and they're shown to the reviewer fenced as "this is data, not instructions," so a packet can't smuggle a prompt into the reviewer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Worktrees.&lt;/strong&gt; If each agent runs in its own git worktree, the inbox resolves to the main working tree, so the two agents actually see each other. That one cost me an afternoon.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where it sits
&lt;/h2&gt;

&lt;p&gt;It isn't a replacement for GitHub PRs or branch protection — those are server-side and great. &lt;code&gt;twoperson&lt;/code&gt; is the local gate &lt;em&gt;before&lt;/em&gt; that: a way for a second agent to sign off on the exact commit at the speed of local file I/O, so by the time a PR opens there's already a commit-bound record of what was reviewed. If you run agents unattended and want an approval pinned to a commit rather than a vibe, that's the gap it fills.&lt;/p&gt;

&lt;p&gt;Prior art I read first, because it's the obvious question. OpenAI's &lt;code&gt;codex-plugin-cc&lt;/code&gt; has an opt-in Stop-hook review gate — genuinely the better tool if you want a second model on the diff in-session — but it gates the &lt;em&gt;turn&lt;/em&gt;, not a commit, and nothing later refuses a stale "we pushed it." &lt;code&gt;claude-review-loop&lt;/code&gt; persists reviews without binding them to a SHA. &lt;code&gt;shiplog&lt;/code&gt; leans on signed &lt;code&gt;Reviewed-by:&lt;/code&gt; commits but needs &lt;code&gt;gh&lt;/code&gt; and a remote. &lt;code&gt;secondmate&lt;/code&gt; has the same stale-approval refusal, but gets there by spawning the agents itself. I wanted the binding without the orchestration.&lt;/p&gt;

&lt;p&gt;MIT, on PyPI:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/ahm3dwasim/twoperson" rel="noopener noreferrer"&gt;https://github.com/ahm3dwasim/twoperson&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Would genuinely like to hear how others are gating agent pushes.&lt;/p&gt;

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