<?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: solemness</title>
    <description>The latest articles on DEV Community by solemness (@solemness).</description>
    <link>https://dev.to/solemness</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%2F4011450%2F7a082dd6-1487-422b-b996-96811b257648.png</url>
      <title>DEV Community: solemness</title>
      <link>https://dev.to/solemness</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/solemness"/>
    <language>en</language>
    <item>
      <title>Claude Code hooks are the seatbelt nobody buckles — here's the 10-hook setup that makes agent disasters impossible</title>
      <dc:creator>solemness</dc:creator>
      <pubDate>Wed, 01 Jul 2026 22:42:47 +0000</pubDate>
      <link>https://dev.to/solemness/claude-code-hooks-are-the-seatbelt-nobody-buckles-heres-the-10-hook-setup-that-makes-agent-4p7m</link>
      <guid>https://dev.to/solemness/claude-code-hooks-are-the-seatbelt-nobody-buckles-heres-the-10-hook-setup-that-makes-agent-4p7m</guid>
      <description>&lt;p&gt;Every Claude Code power user has a story: the force-pushed main, the "helpfully" rewritten .env, the API key committed at 2am. The fix has been sitting in the docs the whole time — &lt;strong&gt;hooks&lt;/strong&gt;: shell scripts that run on every tool call, &lt;em&gt;outside&lt;/em&gt; the model, so they hold even when the model has a bad day.&lt;/p&gt;

&lt;p&gt;Almost nobody sets them up. Writing defensive hook scripts is genuinely fiddly. Here's what I learned building a full 10-hook guard-rail set, including the parts the docs make you discover the hard way.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three mechanics that matter
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Exit code 2 is the magic word.&lt;/strong&gt; A PreToolUse hook that exits 2 blocks the tool call, and everything you wrote to stderr is fed back to Claude as the reason. Claude then &lt;em&gt;adapts&lt;/em&gt; — tell it "force-push to main refused, use a feature branch" and it does exactly that. Exit 0 allows; other codes just log.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. JSON decisions beat exit codes for nuance.&lt;/strong&gt; Printing &lt;code&gt;{"decision":"block","reason":"..."}&lt;/code&gt; on stdout does the same job and works for PostToolUse feedback loops too — that's how you pipe lint errors straight back to the model so it fixes its own warnings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Stop hooks can refuse "done".&lt;/strong&gt; A Stop hook that runs your test suite and blocks on red means the agent literally cannot declare victory with failing tests. Guard against infinite loops by checking &lt;code&gt;stop_hook_active&lt;/code&gt; in the payload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design rules for hooks you'll trust
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fail open.&lt;/strong&gt; If jq is missing or your script errors, allow the action. A guard rail that bricks your session gets uninstalled by lunchtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Block with instructions, not just "no".&lt;/strong&gt; The stderr message is a prompt — tell the model what to do instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make every hook a no-op switch away.&lt;/strong&gt; &lt;code&gt;REPO_ARMOR_DANGER_OFF=1&lt;/code&gt; beats editing settings.json mid-incident.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Match narrowly.&lt;/strong&gt; A Bash matcher that blocks &lt;code&gt;rm -rf /&lt;/code&gt; must still allow &lt;code&gt;rm -f build/tmp.txt&lt;/code&gt;, or you'll drown in false positives and turn it all off.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The full set worth having
&lt;/h2&gt;

&lt;p&gt;Secret-leak blocker, dangerous-command guard, protected-file guard, main-branch commit guard, test-on-stop, format-on-edit, lint feedback loop, desktop notifications, JSONL audit log, and a context guard that injects a warning when your prompt mentions "production".&lt;/p&gt;

&lt;p&gt;I packaged all 10 (bash + jq, zero network, fail-open, 52 self-tests) with a one-command installer as &lt;strong&gt;repo-armor&lt;/strong&gt; — it's $5 on Gumroad: &lt;a href="https://solemness.gumroad.com/l/repo-armor" rel="noopener noreferrer"&gt;https://solemness.gumroad.com/l/repo-armor&lt;/a&gt;. Or build your own from the mechanics above; either way, buckle the seatbelt before the next long unattended session.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claudecode</category>
      <category>productivity</category>
      <category>bash</category>
    </item>
  </channel>
</rss>
