<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Configure Claude |</title><link>https://haobin-tan.netlify.app/doc/claude/claude-code-in-action/01-configure-claude/</link><atom:link href="https://haobin-tan.netlify.app/doc/claude/claude-code-in-action/01-configure-claude/index.xml" rel="self" type="application/rss+xml"/><description>Configure Claude</description><generator>HugoBlox Kit (https://hugoblox.com)</generator><language>en</language><lastBuildDate>Sat, 03 Oct 2026 00:00:00 +0000</lastBuildDate><image><url>https://haobin-tan.netlify.app/media/icon_hu_eee4a95885829ab2.png</url><title>Configure Claude</title><link>https://haobin-tan.netlify.app/doc/claude/claude-code-in-action/01-configure-claude/</link></image><item><title>A CLAUDE.md That Follows</title><link>https://haobin-tan.netlify.app/doc/claude/claude-code-in-action/01-configure-claude/a_claude_md_that_follows/</link><pubDate>Sat, 03 Oct 2026 00:00:00 +0000</pubDate><guid>https://haobin-tan.netlify.app/doc/claude/claude-code-in-action/01-configure-claude/a_claude_md_that_follows/</guid><description>
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-blue-100 dark:bg-blue-900 border-blue-500"
data-callout="note"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-blue-600 dark:text-blue-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m16.862 4.487l1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8l.8-2.685a4.5 4.5 0 0 1 1.13-1.897zm0 0L19.5 7.125"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;Note&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;h3 id="tldr"&gt;TL;DR&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Main idea: The leaner the CLAUDE.md, the more of it Claude follows.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Treat your CLAUDE.md like production code. If you can&amp;rsquo;t justify a line, delete it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Keep CLAUDE.md lean and followable&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Move hard rules to hooks, where they&amp;rsquo;re actually enforced.&lt;/li&gt;
&lt;li&gt;Organize long files with imports&lt;/li&gt;
&lt;li&gt;Make every rule specific and checkable, and name the replacement.&lt;/li&gt;
&lt;li&gt;Spend your emphasis budget on the few rules that matter most.&lt;/li&gt;
&lt;li&gt;Keep revising the file whenever Claude gets something wrong.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="first-ask-if-claudemd-is-even-the-right-tool"&gt;First, Ask if CLAUDE.md Is Even the Right Tool&lt;/h2&gt;
&lt;p&gt;Before you write a rule, ask whether it belongs in CLAUDE.md at all:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Some rules are guidance / softer conventions. -&amp;gt; Can go to CLAUDE.md.&lt;/li&gt;
&lt;li&gt;Some rules are hard lines that must never be crossed, e.g., &amp;ldquo;never push to main.&amp;rdquo;. A hard rule like that belongs in a pre-tool-use &lt;strong&gt;hook&lt;/strong&gt; instead.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-four-locations"&gt;The Four Locations&lt;/h2&gt;
&lt;p&gt;There are &lt;strong&gt;four&lt;/strong&gt; places CLAUDE.md can live, and Claude loads all of them together at launch. Nothing gets dropped, and they stack.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Managed policy&lt;/strong&gt; — the org-level file your platform team controls. You can&amp;rsquo;t exclude it, so org policy is always in play.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User&lt;/strong&gt; — your personal preferences that follow you across every project on your machine.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Project&lt;/strong&gt; — the file shared with your team, checked into the repo.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Local&lt;/strong&gt; — ignored by git. Your personal notes for this one repository only.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="split-up-a-big-file-with-imports"&gt;Split up a Big File with Imports&lt;/h2&gt;
&lt;p&gt;When your project file starts getting long, you can break it into pieces using the &lt;strong&gt;path-to-file import&lt;/strong&gt; syntax. This is great for organizing.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@.claude/conventions/code-style.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@.claude/conventions/testing.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@.claude/conventions/workflow.md
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;!-- text: required trigger text; content is inserted from clipboard --&gt;
&lt;details class="spoiler " id="spoiler-0"&gt;
&lt;summary class="cursor-pointer"&gt;Use imports to organize, not to shrink the load.&lt;/summary&gt;
&lt;div class="rounded-lg bg-neutral-50 dark:bg-neutral-800 p-2"&gt;
When Claude launches, it expands those imported files inline, right where you referenced them. So imports help you keep things tidy, but &lt;strong&gt;everything still loads up front. They do not reduce the amount of context Claude has to read.&lt;/strong&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;h2 id="phrasing-is-what-makes-rules-stick"&gt;Phrasing Is What Makes Rules Stick&lt;/h2&gt;
&lt;h3 id="be-specific-and-checkable"&gt;Be specific and checkable&lt;/h3&gt;
&lt;p&gt;If you can&amp;rsquo;t check whether it was followed, neither can Claude.&lt;/p&gt;
&lt;!-- text: required trigger text; content is inserted from clipboard --&gt;
&lt;details class="spoiler " id="spoiler-1"&gt;
&lt;summary class="cursor-pointer"&gt;Example&lt;/summary&gt;
&lt;div class="rounded-lg bg-neutral-50 dark:bg-neutral-800 p-2"&gt;
&lt;p&gt;Compare these two:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vague: &amp;ldquo;Follow best practices for API routes.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Specific: &amp;ldquo;Put new API routes in src/api/handlers, one per file.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The second one is explicit and clear.&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;h3 id="name-the-replacement-dont-just-ban-something"&gt;Name the replacement, don&amp;rsquo;t just ban something&lt;/h3&gt;
&lt;p&gt;When you tell Claude not to do something, say what to do instead. Otherwise you&amp;rsquo;ve left the door open.&lt;/p&gt;
&lt;!-- text: required trigger text; content is inserted from clipboard --&gt;
&lt;details class="spoiler " id="spoiler-2"&gt;
&lt;summary class="cursor-pointer"&gt;Example&lt;/summary&gt;
&lt;div class="rounded-lg bg-neutral-50 dark:bg-neutral-800 p-2"&gt;
&lt;ul&gt;
&lt;li&gt;Leaves it open: &amp;ldquo;Don&amp;rsquo;t use default exports.&amp;rdquo; Okay, but then what?&lt;/li&gt;
&lt;li&gt;Closes it: &amp;ldquo;Use named exports, not default exports.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The second version names the replacement, so there&amp;rsquo;s nothing left to misinterpret.&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;h3 id="emphasis-is-a-budget"&gt;Emphasis is a budget&lt;/h3&gt;
&lt;p&gt;Words like &amp;ldquo;IMPORTANT&amp;rdquo; and &amp;ldquo;YOU MUST&amp;rdquo; do raise a rule&amp;rsquo;s priority. But only relative to everything quieter around it. If every rule shouts, then nothing stands out and the emphasis means nothing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Treat emphasis like a budget. Spend it on the two or three rules that really hurt when they get broken, and let the rest sit at normal volume.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="keep-the-file-under-revision"&gt;Keep the File Under Revision&lt;/h2&gt;
&lt;p&gt;Your CLAUDE.md file is &lt;em&gt;never&lt;/em&gt; finished. Treat it like &lt;strong&gt;living code that keeps getting edited&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;When Claude does the wrong thing, don&amp;rsquo;t just fix it by hand. Treat it as a bug report against your CLAUDE.md file. You can even tell Claude directly: &amp;ldquo;add that to the CLAUDE.md file,&amp;rdquo; and it&amp;rsquo;ll write the rule for you.&lt;/p&gt;
&lt;p&gt;-&amp;gt; That way the file gets better every time something goes wrong.&lt;/p&gt;</description></item><item><title>Verification Skills</title><link>https://haobin-tan.netlify.app/doc/claude/claude-code-in-action/01-configure-claude/verification_skills/</link><pubDate>Sat, 03 Oct 2026 00:00:00 +0000</pubDate><guid>https://haobin-tan.netlify.app/doc/claude/claude-code-in-action/01-configure-claude/verification_skills/</guid><description>
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-blue-100 dark:bg-blue-900 border-blue-500"
data-callout="note"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-blue-600 dark:text-blue-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m16.862 4.487l1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8l.8-2.685a4.5 4.5 0 0 1 1.13-1.897zm0 0L19.5 7.125"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;Note&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;h3 id="tldr"&gt;TL;DR&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;A skill is a folder with a SKILL.md inside it: a name, a description that triggers it, and the procedure itself.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;If you&amp;rsquo;ve typed the same multi-step instruction twice, that&amp;rsquo;s a skill.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The rule of thumb: &lt;strong&gt;If you&amp;rsquo;ve typed the same multi-step instruction twice, that&amp;rsquo;s a skill.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="skill-folder"&gt;Skill Folder&lt;/h2&gt;
&lt;p&gt;A skill isn&amp;rsquo;t just a single &lt;code&gt;SKILL.md&lt;/code&gt; file. The folder around it can carry other things.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Drop a &lt;code&gt;reference.md&lt;/code&gt; next to &lt;code&gt;SKILL.md&lt;/code&gt; for detailed material, then link to it from &lt;code&gt;SKILL.md&lt;/code&gt;. Claude reads it only when it needs that depth. Your main file stays short.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Put scripts in the folder too. Claude executes them rather than loading their contents into context. That means a skill can carry its own tooling, like a &lt;code&gt;check.sh&lt;/code&gt; that runs all the gates.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-emerald-100 dark:bg-emerald-900 border-emerald-500"
data-callout="tip"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-emerald-600 dark:text-emerald-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 18v-5.25m0 0a6 6 0 0 0 1.5-.189m-1.5.189a6 6 0 0 1-1.5-.189m3.75 7.478a12.1 12.1 0 0 1-4.5 0m3.75 2.383a14.4 14.4 0 0 1-3 0M14.25 18v-.192c0-.983.658-1.823 1.508-2.316a7.5 7.5 0 1 0-7.517 0c.85.493 1.509 1.333 1.509 2.316V18"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;Tip&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;p&gt;keep SKILL.md itself &lt;strong&gt;lean&lt;/strong&gt;. Push the heavy material (the long explanations and the executable scripts) into side files.&lt;/p&gt;
&lt;p&gt;The lean file describes what to do. The side files hold the depth and the tools.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="which-instruction-surface-owns-which-rule"&gt;Which Instruction Surface Owns Which Rule&lt;/h2&gt;
&lt;p&gt;
&lt;figure &gt;
&lt;div class="flex justify-center "&gt;
&lt;div class="w-full" &gt;&lt;img src="https://raw.githubusercontent.com/EckoTan0804/upic-repo/master/uPic/%E6%88%AA%E5%B1%8F2026-10-07%2011.00.14.png" alt="instruction surface" loading="lazy" data-zoomable /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Owns&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt; file&lt;/td&gt;
&lt;td&gt;Conventions that apply all the time, things like naming rules or where files go.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skill&lt;/td&gt;
&lt;td&gt;Procedures and reference material tied to a particular kind of task belong in a skill.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hook&lt;/td&gt;
&lt;td&gt;A rule that Claude &lt;strong&gt;must not&lt;/strong&gt; be able to skip.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</description></item><item><title>Permission Modes</title><link>https://haobin-tan.netlify.app/doc/claude/claude-code-in-action/01-configure-claude/permission_modes/</link><pubDate>Sat, 03 Oct 2026 00:00:00 +0000</pubDate><guid>https://haobin-tan.netlify.app/doc/claude/claude-code-in-action/01-configure-claude/permission_modes/</guid><description>&lt;p&gt;
&lt;figure &gt;
&lt;div class="flex justify-center "&gt;
&lt;div class="w-full" &gt;&lt;img src="https://raw.githubusercontent.com/EckoTan0804/upic-repo/master/uPic/%E6%88%AA%E5%B1%8F2026-10-07%2011.58.47.png" alt="permission modes" loading="lazy" data-zoomable /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;Reads only, without prompting. Everything else asks first.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accept edits&lt;/td&gt;
&lt;td&gt;Runs reads, file edits, and common file system bash commands without asking. This is for iterating on code that you review after the fact.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plan&lt;/td&gt;
&lt;td&gt;Researches and proposes changes without editing anything. Reads run freely, and when auto mode is available, auto&amp;rsquo;s classifier reviews the commands Claude runs to explore and lets the approved ones run without a prompt.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto&lt;/td&gt;
&lt;td&gt;Accepts everything, with a separate classifier model reviewing each action before it runs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Don&amp;rsquo;t ask&lt;/td&gt;
&lt;td&gt;Allows only pre-approved tools. Everything else is auto-denied with no prompt.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bypass permissions&lt;/td&gt;
&lt;td&gt;Kips all checks. This is the equivalent of the dangerously-skip-permissions flag. &lt;strong&gt;Only run it inside an isolated container or virtual machine!&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="cycling-with-shift-tab"&gt;Cycling with shift-tab&lt;/h2&gt;
&lt;p&gt;Press &lt;strong&gt;shift-tab&lt;/strong&gt; to cycle through the everyday ones: manual, accept edits, plan, and auto.&lt;/p&gt;
&lt;p&gt;The status bar at the bottom always shows which mode you&amp;rsquo;re currently in, so you can glance down and know exactly what Claude is allowed to do.&lt;/p&gt;
&lt;h2 id="how-auto-mode-works"&gt;How &lt;code&gt;auto&lt;/code&gt; Mode Works&lt;/h2&gt;
&lt;p&gt;Auto is the &lt;strong&gt;hands-off&lt;/strong&gt; mode. Claude runs on its own, but &lt;strong&gt;before each action executes, a separate classifier model reviews it&lt;/strong&gt;. The classifier guards intent. It&amp;rsquo;s watching for moves that escalate beyond what you actually asked for.&lt;/p&gt;
&lt;p&gt;The kind of thing it&amp;rsquo;s designed to block:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Production deploys and migrations&lt;/li&gt;
&lt;li&gt;Force pushing, or piping downloaded code straight into a shell&lt;/li&gt;
&lt;li&gt;Sending sensitive data to external endpoints&lt;/li&gt;
&lt;li&gt;Irreversibly destroying files that existed before the session&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What the classifier can&amp;rsquo;t do: The classifier &lt;strong&gt;checks intent, not correctness&lt;/strong&gt;. It won&amp;rsquo;t catch whether the code actually works.&lt;/p&gt;
&lt;!-- text: required trigger text; content is inserted from clipboard --&gt;
&lt;details class="spoiler " id="spoiler-0"&gt;
&lt;summary class="cursor-pointer"&gt;Example&lt;/summary&gt;
&lt;div class="rounded-lg bg-neutral-50 dark:bg-neutral-800 p-2"&gt;
&lt;p&gt;If you ask Claude to refactor authentication and it writes broken authentication, the classifier waves it through, because broken isn&amp;rsquo;t dangerous.&lt;/p&gt;
&lt;p&gt;In this case, you should pair auto mode with a stop hook that runs your tests. The two work together:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Auto mode watches what Claude is &lt;em&gt;trying&lt;/em&gt; to do while it runs.&lt;/li&gt;
&lt;li&gt;The stop hook confirms the code actually runs once Claude finishes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One guards intent before each action, the other guards correctness after.&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;h2 id="use-dontask-mode-for-unattended-runs"&gt;Use &lt;code&gt;dontAsk&lt;/code&gt; Mode for Unattended Runs&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Don&amp;rsquo;t ask&lt;/strong&gt; (&lt;strong&gt;``dontAsk`&lt;/strong&gt;) is the right move whenever no human is around to approve prompts, such as: CI pipelines, scheduled jobs, overnight batches.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Only pre-approved tools are allowed, and anything off that list gets auto-denied with no prompt.&lt;/strong&gt; Your pipeline keeps moving instead of hanging on an approval no one is there to give.&lt;/p&gt;
&lt;p&gt;How to enable: Set it with&lt;code&gt;--permission-mode dontAsk&lt;/code&gt;. Example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;claude --permission-mode dontAsk --allowedTools &lt;span class="s2"&gt;&amp;#34;Read,Glob,Grep&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="match-the-mode-to-the-job"&gt;Match the Mode to the Job&lt;/h2&gt;
&lt;p&gt;Pick the mode that fits what you&amp;rsquo;re doing, and let Claude run at that level.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Auto&lt;/strong&gt; is the hands-off mode. The classifier checks intent before each action, and a stop hook checks correctness after.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Don&amp;rsquo;t ask&lt;/strong&gt; covers unattended pipelines where no one is there to approve.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bypass permissions&lt;/strong&gt; belongs only inside isolated containers and VMs.&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Hooks</title><link>https://haobin-tan.netlify.app/doc/claude/claude-code-in-action/01-configure-claude/hooks/</link><pubDate>Sat, 03 Oct 2026 00:00:00 +0000</pubDate><guid>https://haobin-tan.netlify.app/doc/claude/claude-code-in-action/01-configure-claude/hooks/</guid><description>&lt;p&gt;A hook is &lt;strong&gt;deterministic&lt;/strong&gt; code that runs at a &lt;strong&gt;fixed&lt;/strong&gt; point in the loop, so it can guarantee behavior instead of hoping for it. It turns a rule from &amp;ldquo;Claude usually listens&amp;rdquo; into &amp;ldquo;Claude can&amp;rsquo;t skip it.&amp;rdquo;&lt;/p&gt;
&lt;!-- Raw HTML instead of the card shortcode: the shortcode only opens http(s) URLs in a new tab --&gt;
&lt;div class="hb-cards mt-4 grid gap-4 not-prose" style="--hb-cols: 1;"&gt;
&lt;a class="hb-card group" href="https://haobin-tan.netlify.app/uploads/claude-code-in-action/claude_code_hooks_explorer.html" target="_blank" rel="noopener"&gt;
&lt;span class="hb-card-title p-4"&gt;&lt;svg style="height: 1em; width: 1em;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M13.5 6H5.25A2.25 2.25 0 0 0 3 8.25v10.5A2.25 2.25 0 0 0 5.25 21h10.5A2.25 2.25 0 0 0 18 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25"/&gt;&lt;/svg&gt;Interactive Claude Code hooks explorer&lt;/span&gt;
&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id="the-hook-events"&gt;The Hook Events&lt;/h2&gt;
&lt;p&gt;Claude Code fires around 30 hook events over the course of a session. These are the ones worth knowing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PreToolUse&lt;/strong&gt; fires before a tool call. This is your enforcement primitive. It&amp;rsquo;s the one that can stop something before it happens.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PostToolUse&lt;/strong&gt; fires after a successful tool call. This is usually where auto-formatting or an auto-lint goes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stop&lt;/strong&gt; fires when Claude wants to end its turn. You can refuse and say &amp;ldquo;no, you&amp;rsquo;re not done yet&amp;rdquo; if some condition isn&amp;rsquo;t met. There&amp;rsquo;s a matching &lt;strong&gt;SubagentStop&lt;/strong&gt; for when a sub-agent finishes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PreCompact&lt;/strong&gt; and &lt;strong&gt;PostCompact&lt;/strong&gt; fire before and after compaction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;InstructionsLoaded&lt;/strong&gt; fires when a CLAUDE.md or rule file loads. Handy for auditing what actually made it into context.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SessionStart&lt;/strong&gt; fires at the start and primes the environment. Use the &lt;code&gt;startup&lt;/code&gt; source if you only want it on fresh starts.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-emerald-100 dark:bg-emerald-900 border-emerald-500"
data-callout="tip"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-emerald-600 dark:text-emerald-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 18v-5.25m0 0a6 6 0 0 0 1.5-.189m-1.5.189a6 6 0 0 1-1.5-.189m3.75 7.478a12.1 12.1 0 0 1-4.5 0m3.75 2.383a14.4 14.4 0 0 1-3 0M14.25 18v-.192c0-.983.658-1.823 1.508-2.316a7.5 7.5 0 1 0-7.517 0c.85.493 1.509 1.333 1.509 2.316V18"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;Tip&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;p&gt;To re-inject context after compaction, don&amp;rsquo;t use &lt;code&gt;PostCompact&lt;/code&gt;. Use &lt;strong&gt;&lt;code&gt;SessionStart&lt;/code&gt;&lt;/strong&gt; with the compact matcher. That&amp;rsquo;s the one that actually gets its output back into the conversation.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="pretooluse-returning-a-decision-as-json"&gt;PreToolUse: Returning a Decision as JSON&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;PreToolUse&lt;/code&gt; can block a tool call before it runs.&lt;/p&gt;
&lt;p&gt;The way you talk back to Claude is by printing JSON and exiting zero. The key field is &lt;code&gt;permissionDecision&lt;/code&gt;, and it takes one of three values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;allow&lt;/code&gt; — let the call through&lt;/li&gt;
&lt;li&gt;&lt;code&gt;deny&lt;/code&gt; — stop the call&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ask&lt;/code&gt; — hand it back to the user to decide&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The JSON looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;hookSpecificOutput&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;hookEventName&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;PreToolUse&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;permissionDecision&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;deny&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;permissionDecisionReason&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;updatedInput&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;!-- text: required trigger text; content is inserted from clipboard --&gt;
&lt;details class="spoiler " id="spoiler-0"&gt;
&lt;summary class="cursor-pointer"&gt;Visual explanation&lt;/summary&gt;
&lt;div class="rounded-lg bg-neutral-50 dark:bg-neutral-800 p-2"&gt;
&lt;p&gt;
&lt;figure &gt;
&lt;div class="flex justify-center "&gt;
&lt;div class="w-full" &gt;&lt;img src="https://raw.githubusercontent.com/EckoTan0804/upic-repo/master/uPic/image-20261008121704970.png" alt="image-20261008121704970" loading="lazy" data-zoomable /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;figure &gt;
&lt;div class="flex justify-center "&gt;
&lt;div class="w-full" &gt;&lt;img src="https://raw.githubusercontent.com/EckoTan0804/upic-repo/master/uPic/image-20261008105744999.png" alt="PreToolUse" loading="lazy" data-zoomable /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;details class="spoiler " id="spoiler-1"&gt;
&lt;summary class="cursor-pointer"&gt;Example&lt;/summary&gt;
&lt;div class="rounded-lg bg-neutral-50 dark:bg-neutral-800 p-2"&gt;
&lt;p&gt;A PreToolUse hook on the Bash tool. Claude wants to run: &lt;code&gt;rm -rf / &lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Before running the command, the PreToolUse hook is triggered. It prints JSON and exits 0:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;hookSpecificOutput&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;hookEventName&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;PreToolUse&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;permissionDecision&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;deny&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;permissionDecisionReason&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Destructive command&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-emerald-100 dark:bg-emerald-900 border-emerald-500"
data-callout="tip"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-emerald-600 dark:text-emerald-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 18v-5.25m0 0a6 6 0 0 0 1.5-.189m-1.5.189a6 6 0 0 1-1.5-.189m3.75 7.478a12.1 12.1 0 0 1-4.5 0m3.75 2.383a14.4 14.4 0 0 1-3 0M14.25 18v-.192c0-.983.658-1.823 1.508-2.316a7.5 7.5 0 1 0-7.517 0c.85.493 1.509 1.333 1.509 2.316V18"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;Tip&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;p&gt;Instead of just refusing, you can return &lt;code&gt;updatedInput&lt;/code&gt; to rewrite the call. This way, you can strip a secret out of a command and still let it run.&lt;/p&gt;
&lt;p&gt;Notice: &lt;code&gt;updatedInput&lt;/code&gt; replaces the &lt;em&gt;whole&lt;/em&gt; input object, so you have to echo back the fields you aren&amp;rsquo;t changing, or you&amp;rsquo;ll lose them.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="exit-codes"&gt;Exit Codes&lt;/h2&gt;
&lt;p&gt;Not every hook needs to speak JSON. For simpler hooks, exit codes do the job.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Exit code&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Remarks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;success&lt;/td&gt;
&lt;td&gt;&lt;li/&gt;If standard out is JSON, Claude parses it. &lt;br /&gt;&lt;li/&gt;Plain text is ignored on most events, but on SessionStart, UserPromptSubmit, and UserPromptExpansion, plain text gets added to context. That&amp;rsquo;s exactly what makes a state-preserver hook work.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;blocking error&lt;/td&gt;
&lt;td&gt;Standard error gets fed back to Claude as context.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anything else&lt;/td&gt;
&lt;td&gt;Non-blocking&lt;/td&gt;
&lt;td&gt;&lt;li/&gt;Standard error gets logged, and Claude carries on. &lt;br /&gt;&lt;li/&gt;‼️ Gotcha: &lt;strong&gt;exit code 1&lt;/strong&gt; feels like an error, but it does not block. Claude runs the command anyway. So if you meant to stop something, exit 2, not 1.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="preserving-state-across-a-compact"&gt;Preserving State across a Compact&lt;/h2&gt;
&lt;p&gt;Compaction is lossy: When Claude compacts a long conversation, it drops a lot of detail, such as the exact files you were editing, or the branch name.&lt;/p&gt;
&lt;p&gt;Fix: &lt;strong&gt;Use a &lt;code&gt;SessionStart&lt;/code&gt; hook with the &lt;code&gt;compact&lt;/code&gt; matcher&lt;/strong&gt; to put the important facts back, deterministically, right after compaction.&lt;/p&gt;
&lt;!-- Raw HTML instead of the card shortcode: the shortcode only opens http(s) URLs in a new tab --&gt;
&lt;div class="hb-cards mt-4 grid gap-4 not-prose" style="--hb-cols: 1;"&gt;
&lt;a class="hb-card group" href="https://haobin-tan.netlify.app/uploads/claude-code-in-action/preserving_state_across_compact.html" target="_blank" rel="noopener"&gt;
&lt;span class="hb-card-title p-4"&gt;&lt;svg style="height: 1em; width: 1em;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M13.5 6H5.25A2.25 2.25 0 0 0 3 8.25v10.5A2.25 2.25 0 0 0 5.25 21h10.5A2.25 2.25 0 0 0 18 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25"/&gt;&lt;/svg&gt;Interactive example: Preserving State across a Compact&lt;/span&gt;
&lt;/a&gt;
&lt;/div&gt;
&lt;!-- text: required trigger text; content is inserted from clipboard --&gt;
&lt;details class="spoiler " id="spoiler-2"&gt;
&lt;summary class="cursor-pointer"&gt;Example (Python)&lt;/summary&gt;
&lt;div class="rounded-lg bg-neutral-50 dark:bg-neutral-800 p-2"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# .claude/hooks/restore_state.py&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;subprocess&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;git&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;diff&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;--name-only&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;capture_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;branch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;git&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;branch&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;--show-current&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;capture_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Context restored after compaction.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Branch: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;branch&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Files in progress:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# exit 0 (default): stdout from SessionStart is added to context&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the settings.json, a &lt;code&gt;compact&lt;/code&gt; matcher is registered:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;SessionStart&amp;#34;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;matcher&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;compact&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;hooks&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;python3 .claude/hooks/restore_state.py&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/details&gt;</description></item></channel></rss>