<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
    <channel>
        <title>Little Cups of Claude</title>
        <link>https://littlecupsofclaude.com</link>
        <description>Tips and techniques for Claude and Claude Code. Short, focused tips with links to the official docs.</description>
        <lastBuildDate>Fri, 30 Oct 2026 19:44:13 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>Little Cups of Claude</title>
            <url>https://littlecupsofclaude.com/logo.png</url>
            <link>https://littlecupsofclaude.com</link>
        </image>
        <copyright>Copyright 2026 Jake Marsh</copyright>
        <item>
            <title><![CDATA[#5: Auto Memory 🧠]]></title>
            <link>https://littlecupsofclaude.com/5</link>
            <guid isPermaLink="false">https://littlecupsofclaude.com/5</guid>
            <pubDate>Fri, 30 Oct 2026 13:00:00 GMT</pubDate>
            <description><![CDATA[<p>Today we&#39;ll look at how <strong>Claude Code</strong> remembers things between sessions with <strong>auto memory</strong>, and how it fits next to the <strong>CLAUDE.md</strong> files we write ourselves.</p>
<p>The split is simple. We write <strong>CLAUDE.md</strong> to give <strong>Claude</strong> instructions. <strong>Claude</strong> writes <strong>auto memory</strong> to keep notes for itself. Auto memory is on by default in local sessions.</p>
<p>Let&#39;s dive in.</p>
<h2>What Gets Saved</h2>
<p>As it works, <strong>Claude</strong> saves four kinds of notes, and records the kind in each file&#39;s frontmatter:</p>
<ul>
<li><strong>user</strong>: our role, expertise, and how we like to work</li>
<li><strong>feedback</strong>: corrections we give and approaches we confirm</li>
<li><strong>project</strong>: ongoing work, deadlines, and decisions the code doesn&#39;t show</li>
<li><strong>reference</strong>: where to find things outside the project, like an issue tracker</li>
</ul>
<p>It skips anything it can work out from the codebase, and anything our <strong>CLAUDE.md</strong> files already say. It also doesn&#39;t save something every session, only what looks useful later. When it does, we&#39;ll see a message like &quot;Saved 2 memories&quot;.</p>
<h2>Where It Lives</h2>
<p>Each project gets its own folder:</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#F97583">~</span><span style="color:#E1E4E8">/.claude/projects/</span><span style="color:#F97583">&#x3C;</span><span style="color:#E1E4E8">project</span><span style="color:#F97583">></span><span style="color:#E1E4E8">/memory/</span></span>
<span class="line"><span style="color:#B392F0">  MEMORY.md</span><span style="color:#6A737D">                 # the index, one line per memory</span></span>
<span class="line"><span style="color:#B392F0">  user_role.md</span><span style="color:#6A737D">              # one memory per file</span></span>
<span class="line"><span style="color:#B392F0">  feedback_testing.md</span></span>
<span class="line"><span style="color:#B392F0">  reference_dashboards.md</span></span></code></pre><p>The <code>&lt;project&gt;</code> comes from the git repository, so every worktree and subdirectory of the same repo shares one memory folder. It stays on our machine, and isn&#39;t synced to other machines or cloud sessions.</p>
<h2>What Loads</h2>
<p>At the start of each conversation, <strong>Claude Code</strong> loads the first 200 lines or 25KB of <code>MEMORY.md</code>, whichever comes first. The topic files don&#39;t load at startup. <strong>Claude</strong> reads them when it needs them.</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#FFAB70">-</span><span style="color:#E1E4E8"> [</span><span style="color:#DBEDFF;text-decoration:underline">Prefers bun</span><span style="color:#E1E4E8">](</span><span style="color:#E1E4E8;text-decoration:underline">feedback_bun.md</span><span style="color:#E1E4E8">): use bun, never node or npm</span></span>
<span class="line"><span style="color:#FFAB70">-</span><span style="color:#E1E4E8"> [</span><span style="color:#DBEDFF;text-decoration:underline">Staging deploys</span><span style="color:#E1E4E8">](</span><span style="color:#E1E4E8;text-decoration:underline">reference_staging.md</span><span style="color:#E1E4E8">): how we ship to staging</span></span>
<span class="line"><span style="color:#FFAB70">-</span><span style="color:#E1E4E8"> [</span><span style="color:#DBEDFF;text-decoration:underline">Q4 freeze</span><span style="color:#E1E4E8">](</span><span style="color:#E1E4E8;text-decoration:underline">project_freeze.md</span><span style="color:#E1E4E8">): no schema changes until Jan 5</span></span></code></pre><p>That&#39;s why the index stays short. When <code>MEMORY.md</code> gets close to the limit, <strong>Claude Code</strong> reminds <strong>Claude</strong> to tighten it up. Neat!</p>
<h2>The /memory Command</h2>
<p><code>/memory</code> is the control panel:</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span>> /memory</span></span></code></pre><p>It lists our <strong>CLAUDE.md</strong> and <strong>CLAUDE.local.md</strong> files, has a toggle for auto memory, and opens the memory folder. Picking a file opens it in our editor. Memory files are plain markdown, so we can edit or delete anything that&#39;s wrong.</p>
<h2>Telling It What To Remember</h2>
<p>When we say something like &quot;remember that the API tests need a local Redis&quot;, <strong>Claude</strong> saves it to auto memory. If we want it in <strong>CLAUDE.md</strong> instead, we just ask: &quot;add this to CLAUDE.md&quot;.</p>
<p>For instructions that only matter in part of the codebase, <code>.claude/rules/</code> is the tidier spot:</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#E1E4E8">---</span></span>
<span class="line"><span style="color:#85E89D">paths</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#E1E4E8">  - </span><span style="color:#9ECBFF">"src/api/**/*.ts"</span></span>
<span class="line"><span style="color:#E1E4E8">---</span></span>
<span class="line"></span>
<span class="line"><span style="color:#79B8FF;font-weight:bold"># API rules</span></span>
<span class="line"><span style="color:#FFAB70">-</span><span style="color:#E1E4E8"> Validate every request body with zod</span></span>
<span class="line"><span style="color:#FFAB70">-</span><span style="color:#E1E4E8"> Use the shared error response format</span></span></code></pre><p>A rule with <code>paths</code> only loads once <strong>Claude</strong> reads or edits a matching file. Rules without <code>paths</code> load at launch, like <strong>CLAUDE.md</strong> does.</p>
<h2>Turning It Off</h2>
<p>The <code>/memory</code> toggle saves <code>autoMemoryEnabled</code> to our user settings. To switch it off for one project, set it in that project&#39;s settings:</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#E1E4E8">{</span></span>
<span class="line"><span style="color:#79B8FF">  "autoMemoryEnabled"</span><span style="color:#E1E4E8">: </span><span style="color:#79B8FF">false</span></span>
<span class="line"><span style="color:#E1E4E8">}</span></span></code></pre><p>And <code>autoMemoryDirectory</code> moves the whole thing somewhere else, if we&#39;d rather keep it in a synced folder.</p>
<h2>Watch Out</h2>
<p>Subagents don&#39;t get the main conversation&#39;s auto memory, apart from forks, which inherit the whole parent conversation. And memory files are never cleaned up automatically. They stay until we or <strong>Claude</strong> edit or delete them, so it&#39;s worth a look through <code>/memory</code> every so often.</p>
<p>More info about <strong>auto memory</strong> can be found at <a href="https://code.claude.com/docs/en/memory">the Claude Code docs</a>.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[#4: Headless Mode 👻]]></title>
            <link>https://littlecupsofclaude.com/4</link>
            <guid isPermaLink="false">https://littlecupsofclaude.com/4</guid>
            <pubDate>Thu, 29 Oct 2026 13:00:00 GMT</pubDate>
            <description><![CDATA[<p>Today we&#39;ll look at running <strong>Claude Code</strong> without the interactive UI, which turns it into a building block for scripts, CI, and cron jobs.</p>
<p>The <code>-p</code> flag (short for <code>--print</code>) is the key. It sends one prompt, lets <strong>Claude</strong> work, prints the result, and exits. The same engine powers the <strong>Agent SDK</strong>, so anything we learn here carries over.</p>
<p>Let&#39;s take a look.</p>
<h2>The Basics</h2>
<p>At its simplest, we pass a prompt and read the answer:</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#B392F0">claude</span><span style="color:#79B8FF"> -p</span><span style="color:#9ECBFF"> "Explain what this project does"</span></span></code></pre><p>It reads stdin too, so it fits right into a pipeline:</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#B392F0">git</span><span style="color:#9ECBFF"> diff</span><span style="color:#9ECBFF"> HEAD~5</span><span style="color:#F97583"> |</span><span style="color:#B392F0"> claude</span><span style="color:#79B8FF"> -p</span><span style="color:#9ECBFF"> "Summarize these changes"</span><span style="color:#F97583"> ></span><span style="color:#9ECBFF"> changelog.txt</span></span></code></pre><p>For scripts and CI, the docs recommend adding <code>--bare</code>. It skips discovery of hooks, skills, plugins, <strong>MCP</strong> servers, auto memory, and <strong>CLAUDE.md</strong>, so startup is faster and the run doesn&#39;t depend on whatever happens to be configured on the machine:</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#B392F0">claude</span><span style="color:#79B8FF"> --bare</span><span style="color:#79B8FF"> -p</span><span style="color:#9ECBFF"> "Summarize README.md"</span><span style="color:#79B8FF"> --allowedTools</span><span style="color:#9ECBFF"> "Read"</span></span></code></pre><h2>Output Formats</h2>
<p>The <code>--output-format</code> flag picks what comes back:</p>
<ul>
<li><strong>text</strong>: just the final answer (the default)</li>
<li><strong>json</strong>: the answer plus metadata like <code>session_id</code>, usage, and <code>total_cost_usd</code></li>
<li><strong>stream-json</strong>: one JSON event per line while <strong>Claude</strong> works</li>
</ul>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#B392F0">claude</span><span style="color:#79B8FF"> -p</span><span style="color:#9ECBFF"> "Analyze this codebase"</span><span style="color:#79B8FF"> --output-format</span><span style="color:#9ECBFF"> json</span><span style="color:#F97583"> |</span><span style="color:#B392F0"> jq</span><span style="color:#79B8FF"> -r</span><span style="color:#9ECBFF"> '.result'</span></span></code></pre><p>For structured data, <code>--json-schema</code> makes the answer match a schema, and it shows up in a <code>structured_output</code> field:</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#B392F0">claude</span><span style="color:#79B8FF"> -p</span><span style="color:#9ECBFF"> "List the exported functions in src/hal.ts"</span><span style="color:#79B8FF"> \</span></span>
<span class="line"><span style="color:#79B8FF">  --output-format</span><span style="color:#9ECBFF"> json</span><span style="color:#79B8FF"> \</span></span>
<span class="line"><span style="color:#79B8FF">  --json-schema</span><span style="color:#9ECBFF"> '{"type":"object","properties":{"functions":{"type":"array","items":{"type":"string"}}},"required":["functions"]}'</span><span style="color:#79B8FF"> \</span></span>
<span class="line"><span style="color:#F97583">  |</span><span style="color:#B392F0"> jq</span><span style="color:#9ECBFF"> '.structured_output'</span></span></code></pre><p>Neat! If <strong>Claude</strong> declines or the run fails, that field is missing, so it&#39;s worth checking for it before using it.</p>
<h2>Turn And Budget Limits</h2>
<p>Unattended runs need guardrails:</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#B392F0">claude</span><span style="color:#79B8FF"> -p</span><span style="color:#9ECBFF"> "Review this PR for bugs"</span><span style="color:#79B8FF"> \</span></span>
<span class="line"><span style="color:#79B8FF">  --max-turns</span><span style="color:#79B8FF"> 5</span><span style="color:#79B8FF"> \</span></span>
<span class="line"><span style="color:#79B8FF">  --max-budget-usd</span><span style="color:#79B8FF"> 1.00</span><span style="color:#79B8FF"> \</span></span>
<span class="line"><span style="color:#79B8FF">  --fallback-model</span><span style="color:#9ECBFF"> sonnet,haiku</span></span></code></pre><p><code>--max-turns</code> caps the agentic turns and exits with an error when it hits the limit. <code>--max-budget-usd</code> stops the run once estimated spend reaches the cap (it&#39;s a client-side estimate, so leave some headroom). <code>--fallback-model</code> takes a list of models to try if the main one is overloaded.</p>
<h2>Permissions</h2>
<p>There&#39;s nobody around to click &quot;Allow&quot; in a script. <code>--allowedTools</code> pre-approves exactly what the job needs, using permission rule syntax:</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#B392F0">claude</span><span style="color:#79B8FF"> -p</span><span style="color:#9ECBFF"> "Look at the staged changes and write a commit"</span><span style="color:#79B8FF"> \</span></span>
<span class="line"><span style="color:#79B8FF">  --allowedTools</span><span style="color:#9ECBFF"> "Bash(git diff *),Bash(git log *),Bash(git status *),Bash(git commit *)"</span></span></code></pre><p>The space before <code>*</code> matters. <code>Bash(git diff *)</code> matches <code>git diff --cached</code> but not <code>git diff-index</code>.</p>
<p>For a locked-down CI run, <code>--permission-mode dontAsk</code> denies anything that would otherwise prompt, while still allowing reads and whatever our allow rules cover.</p>
<h2>In GitHub Actions</h2>
<p>Anthropic publishes an official action, so we don&#39;t have to install the CLI by hand:</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#85E89D">name</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">Claude review</span></span>
<span class="line"><span style="color:#79B8FF">on</span><span style="color:#E1E4E8">: [</span><span style="color:#9ECBFF">pull_request</span><span style="color:#E1E4E8">]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#85E89D">jobs</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#85E89D">  review</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#85E89D">    runs-on</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">ubuntu-latest</span></span>
<span class="line"><span style="color:#85E89D">    steps</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#E1E4E8">      - </span><span style="color:#85E89D">uses</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">actions/checkout@v6</span></span>
<span class="line"><span style="color:#E1E4E8">      - </span><span style="color:#85E89D">uses</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">anthropics/claude-code-action@v1</span></span>
<span class="line"><span style="color:#85E89D">        with</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#85E89D">          anthropic_api_key</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">${{ secrets.ANTHROPIC_API_KEY }}</span></span>
<span class="line"><span style="color:#85E89D">          prompt</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">"Review this pull request for bugs and security issues"</span></span></code></pre><h2>Continuing Conversations</h2>
<p>Multi-step scripts can pick a conversation back up:</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#6A737D"># Save the session ID from the first run</span></span>
<span class="line"><span style="color:#E1E4E8">session_id</span><span style="color:#F97583">=</span><span style="color:#E1E4E8">$(</span><span style="color:#B392F0">claude</span><span style="color:#79B8FF"> -p</span><span style="color:#9ECBFF"> "Start a review of src/"</span><span style="color:#79B8FF"> --output-format</span><span style="color:#9ECBFF"> json</span><span style="color:#F97583"> |</span><span style="color:#B392F0"> jq</span><span style="color:#79B8FF"> -r</span><span style="color:#9ECBFF"> '.session_id'</span><span style="color:#E1E4E8">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D"># Continue that exact conversation</span></span>
<span class="line"><span style="color:#B392F0">claude</span><span style="color:#79B8FF"> -p</span><span style="color:#9ECBFF"> "Now focus on the database queries"</span><span style="color:#79B8FF"> --resume</span><span style="color:#9ECBFF"> "</span><span style="color:#E1E4E8">$session_id</span><span style="color:#9ECBFF">"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D"># Or continue the most recent one</span></span>
<span class="line"><span style="color:#B392F0">claude</span><span style="color:#79B8FF"> -p</span><span style="color:#9ECBFF"> "Summarize everything we found"</span><span style="color:#79B8FF"> --continue</span></span></code></pre><h2>Watch Out</h2>
<p>Without <code>--bare</code>, a <code>-p</code> run in a project folder runs that project&#39;s hooks and connects its <code>.mcp.json</code> servers, even in a folder we&#39;ve never trusted, and there&#39;s no trust dialog to stop it. On CI or with code we didn&#39;t write, <code>--bare</code> is the safer default.</p>
<p>To add instructions for one script without touching any settings, there&#39;s <code>--append-system-prompt</code>.</p>
<p>More info about running <strong>Claude Code</strong> from scripts can be found at <a href="https://code.claude.com/docs/en/headless">the Claude Code docs</a>.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[#3: Custom Slash Commands ⌨️]]></title>
            <link>https://littlecupsofclaude.com/3</link>
            <guid isPermaLink="false">https://littlecupsofclaude.com/3</guid>
            <pubDate>Wed, 28 Oct 2026 13:00:00 GMT</pubDate>
            <description><![CDATA[<p>Today we&#39;ll check out how to build our own slash commands in <strong>Claude Code</strong> using <strong>skills</strong>.</p>
<p><strong>Custom slash commands</strong> started out as single <strong>Markdown</strong> files in a <code>commands</code> folder. They&#39;ve since been merged into <strong>skills</strong>. Both still work, and both show up in the same <code>/</code> menu, but <strong>skills</strong> can do quite a bit more.</p>
<p>Let&#39;s get started.</p>
<h2>Commands And Skills</h2>
<p>A file at <code>.claude/commands/deploy.md</code> creates <code>/deploy</code>. So does a folder at <code>.claude/skills/deploy/</code> with a <code>SKILL.md</code> inside:</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#6A737D"># Older format (still works)</span></span>
<span class="line"><span style="color:#B392F0">.claude/commands/deploy.md</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D"># Skill (recommended for new work)</span></span>
<span class="line"><span style="color:#B392F0">.claude/skills/deploy/SKILL.md</span></span>
<span class="line"><span style="color:#B392F0">.claude/skills/deploy/checklist.md</span></span>
<span class="line"><span style="color:#B392F0">.claude/skills/deploy/scripts/smoke.sh</span></span></code></pre><p>The big difference is the folder. A skill can carry templates, checklists, and scripts alongside its instructions, and <strong>Claude</strong> can load a skill on its own when it&#39;s relevant, without us typing the command.</p>
<p>If both exist with the same name, the skill wins.</p>
<h2>Frontmatter</h2>
<p>Skills are configured with <strong>YAML</strong> frontmatter at the top of <code>SKILL.md</code>:</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#E1E4E8">---</span></span>
<span class="line"><span style="color:#85E89D">name</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">deploy</span></span>
<span class="line"><span style="color:#85E89D">description</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">Build, test and deploy the app to production</span></span>
<span class="line"><span style="color:#85E89D">disable-model-invocation</span><span style="color:#E1E4E8">: </span><span style="color:#79B8FF">true</span></span>
<span class="line"><span style="color:#85E89D">argument-hint</span><span style="color:#E1E4E8">: [</span><span style="color:#9ECBFF">environment</span><span style="color:#E1E4E8">]</span></span>
<span class="line"><span style="color:#85E89D">allowed-tools</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">Bash(bun run build) Bash(bun run deploy *)</span></span>
<span class="line"><span style="color:#E1E4E8">---</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">Deploy to $ARGUMENTS following our release checklist</span></span>
<span class="line"><span style="color:#E1E4E8">in checklist.md.</span></span></code></pre><p>A few fields worth knowing:</p>
<ul>
<li><strong>name</strong> is the command we type. It defaults to the folder name.</li>
<li><strong>description</strong> is how <strong>Claude</strong> decides when the skill applies, so put the main use case first.</li>
<li><strong>disable-model-invocation: true</strong> means only we can run it. Good for anything with side effects.</li>
<li><strong>allowed-tools</strong> pre-approves tools while the skill runs, so we don&#39;t get permission prompts for them.</li>
</ul>
<h2>Arguments</h2>
<p>Everything after the command name lands in <code>$ARGUMENTS</code>. For individual pieces, indexes start at zero:</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#E1E4E8">---</span></span>
<span class="line"><span style="color:#85E89D">name</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">fix-issue</span></span>
<span class="line"><span style="color:#85E89D">arguments</span><span style="color:#E1E4E8">: [</span><span style="color:#9ECBFF">issue</span><span style="color:#E1E4E8">, </span><span style="color:#9ECBFF">branch</span><span style="color:#E1E4E8">]</span></span>
<span class="line"><span style="color:#E1E4E8">---</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">Fix issue #$issue on the $branch branch.</span></span>
<span class="line"><span style="color:#E1E4E8">Same thing by index: #$0 on $1.</span></span></code></pre><p>Running <code>/fix-issue 42 main</code> fills in <code>42</code> and <code>main</code>. Quotes group words, so <code>/fix-issue 42 &quot;release candidate&quot;</code> passes two arguments, not three.</p>
<h2>Live Context</h2>
<p>Lines with <code>!`command`</code> run before <strong>Claude</strong> ever sees the skill, and the output replaces the line:</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#E1E4E8">---</span></span>
<span class="line"><span style="color:#85E89D">name</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">commit</span></span>
<span class="line"><span style="color:#85E89D">description</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">Write a commit for the staged changes</span></span>
<span class="line"><span style="color:#85E89D">allowed-tools</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">Bash(git status) Bash(git diff *) Bash(git log *) Bash(git commit *)</span></span>
<span class="line"><span style="color:#E1E4E8">---</span></span>
<span class="line"></span>
<span class="line"><span style="color:#79B8FF;font-weight:bold">## Context</span></span>
<span class="line"><span style="color:#FFAB70">-</span><span style="color:#E1E4E8"> Status: !</span><span style="color:#79B8FF">`git status`</span></span>
<span class="line"><span style="color:#FFAB70">-</span><span style="color:#E1E4E8"> Staged diff: !</span><span style="color:#79B8FF">`git diff --cached`</span></span>
<span class="line"><span style="color:#FFAB70">-</span><span style="color:#E1E4E8"> Recent commits: !</span><span style="color:#79B8FF">`git log --oneline -10`</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">Write one clear commit message for these changes and commit.</span></span></code></pre><p><strong>Claude</strong> gets the real diff already inlined, no extra tool calls needed. Neat!</p>
<p><code>${CLAUDE_SKILL_DIR}</code> points at the skill&#39;s own folder, which makes bundled scripts easy to call from anywhere.</p>
<h2>Bundled Skills</h2>
<p><strong>Claude Code</strong> ships with a set of skills of its own, like <code>/code-review</code>, <code>/batch</code>, <code>/debug</code>, <code>/loop</code>, and <code>/claude-api</code>. They&#39;re good examples of how to structure longer workflows, and we can turn them off with the <code>disableBundledSkills</code> setting.</p>
<h2>Personal vs Project</h2>
<p>Project skills live in <code>.claude/skills/</code> and get committed for the whole team. Personal ones live in <code>~/.claude/skills/</code> and follow us into every project:</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#B392F0">mkdir</span><span style="color:#79B8FF"> -p</span><span style="color:#9ECBFF"> ~/.claude/skills/explain</span></span>
<span class="line"></span>
<span class="line"><span style="color:#B392F0">cat</span><span style="color:#F97583"> ></span><span style="color:#9ECBFF"> ~/.claude/skills/explain/SKILL.md</span><span style="color:#F97583"> &#x3C;&#x3C;</span><span style="color:#9ECBFF"> 'END'</span></span>
<span class="line"><span style="color:#9ECBFF">---</span></span>
<span class="line"><span style="color:#9ECBFF">description: Explain code for someone new to the project</span></span>
<span class="line"><span style="color:#9ECBFF">---</span></span>
<span class="line"></span>
<span class="line"><span style="color:#9ECBFF">Explain this code for a new teammate. Cover what it does,</span></span>
<span class="line"><span style="color:#9ECBFF">why it's built this way, and any gotchas.</span></span>
<span class="line"><span style="color:#9ECBFF">END</span></span></code></pre><h2>Watch Out</h2>
<p>If a <code>!`command`</code> line fails, the whole skill invocation stops, and <strong>Claude</strong> never sees the skill. Commands that are expected to exit non-zero need <code>|| true</code> on the end.</p>
<p>Those commands also never prompt for permission. Outside auto mode, anything not already allowed makes the skill fail, which is why the commit example lists its git commands in <code>allowed-tools</code>.</p>
<p>More info about <strong>skills</strong> can be found at <a href="https://code.claude.com/docs/en/skills">the Claude Code docs</a>.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[#2: Hook Basics 🪝]]></title>
            <link>https://littlecupsofclaude.com/2</link>
            <guid isPermaLink="false">https://littlecupsofclaude.com/2</guid>
            <pubDate>Tue, 27 Oct 2026 13:00:00 GMT</pubDate>
            <description><![CDATA[<p>Today we&#39;ll look at one of the best ways to make <strong>Claude Code</strong> behave the same way every time: <strong>hooks</strong>.</p>
<p><strong>Hooks</strong> run our own code at key moments in a <strong>Claude Code</strong> session. Instead of hoping <strong>Claude</strong> remembers to format a file or skip a protected directory, we make it happen automatically, on every matching event.</p>
<p>Let&#39;s dive in.</p>
<h2>Setting Them Up</h2>
<p><strong>Hooks</strong> live in our settings files. The user file (<code>~/.claude/settings.json</code>) applies to every project, <code>.claude/settings.json</code> is shared with the team, and <code>.claude/settings.local.json</code> stays on our machine. Plugins, skills, and subagents can bring their own hooks too.</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#E1E4E8">{</span></span>
<span class="line"><span style="color:#79B8FF">  "hooks"</span><span style="color:#E1E4E8">: {</span></span>
<span class="line"><span style="color:#79B8FF">    "PostToolUse"</span><span style="color:#E1E4E8">: [</span></span>
<span class="line"><span style="color:#E1E4E8">      {</span></span>
<span class="line"><span style="color:#79B8FF">        "matcher"</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">"Edit|Write"</span><span style="color:#E1E4E8">,</span></span>
<span class="line"><span style="color:#79B8FF">        "hooks"</span><span style="color:#E1E4E8">: [</span></span>
<span class="line"><span style="color:#E1E4E8">          {</span></span>
<span class="line"><span style="color:#79B8FF">            "type"</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">"command"</span><span style="color:#E1E4E8">,</span></span>
<span class="line"><span style="color:#79B8FF">            "command"</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">"jq -r '.tool_input.file_path' | xargs bunx prettier --write"</span></span>
<span class="line"><span style="color:#E1E4E8">          }</span></span>
<span class="line"><span style="color:#E1E4E8">        ]</span></span>
<span class="line"><span style="color:#E1E4E8">      }</span></span>
<span class="line"><span style="color:#E1E4E8">    ]</span></span>
<span class="line"><span style="color:#E1E4E8">  }</span></span>
<span class="line"><span style="color:#E1E4E8">}</span></span></code></pre><p>This one runs <strong>Prettier</strong> every time <strong>Claude Code</strong> edits or writes a file. Every hook gets a <strong>JSON</strong> payload on stdin, so <code>jq</code> pulls the file path right out of it. Neat!</p>
<h2>The Events</h2>
<p><strong>Claude Code</strong> has more than 30 hook events now. These are the ones we&#39;ll reach for most:</p>
<ul>
<li><strong>PreToolUse</strong> fires before a tool call and can block it</li>
<li><strong>PostToolUse</strong> fires after a tool call succeeds</li>
<li><strong>UserPromptSubmit</strong> fires when we send a prompt, before <strong>Claude</strong> sees it</li>
<li><strong>SessionStart</strong> fires when a session begins or resumes</li>
<li><strong>Stop</strong> fires when <strong>Claude</strong> finishes responding, and can make it keep going</li>
<li><strong>Notification</strong> fires when <strong>Claude Code</strong> wants our attention</li>
<li><strong>PreCompact</strong> and <strong>PostCompact</strong> wrap context compaction</li>
<li><strong>SubagentStart</strong> and <strong>SubagentStop</strong> wrap subagent runs</li>
</ul>
<p>There are also events for config changes, file changes on disk, worktrees, model switches, permission requests, and <strong>MCP</strong> elicitations.</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#E1E4E8">{</span></span>
<span class="line"><span style="color:#79B8FF">  "hooks"</span><span style="color:#E1E4E8">: {</span></span>
<span class="line"><span style="color:#79B8FF">    "Notification"</span><span style="color:#E1E4E8">: [</span></span>
<span class="line"><span style="color:#E1E4E8">      {</span></span>
<span class="line"><span style="color:#79B8FF">        "matcher"</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">"permission_prompt|idle_prompt"</span><span style="color:#E1E4E8">,</span></span>
<span class="line"><span style="color:#79B8FF">        "hooks"</span><span style="color:#E1E4E8">: [{ </span><span style="color:#79B8FF">"type"</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">"command"</span><span style="color:#E1E4E8">, </span><span style="color:#79B8FF">"command"</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">"say 'HAL needs us'"</span><span style="color:#E1E4E8"> }]</span></span>
<span class="line"><span style="color:#E1E4E8">      }</span></span>
<span class="line"><span style="color:#E1E4E8">    ]</span></span>
<span class="line"><span style="color:#E1E4E8">  }</span></span>
<span class="line"><span style="color:#E1E4E8">}</span></span></code></pre><p>That one uses macOS <code>say</code> so we hear it when <strong>Claude</strong> is waiting on us.</p>
<h2>Five Handler Types</h2>
<p>Each hook handler has a <code>type</code>:</p>
<ul>
<li><strong>command</strong> runs a shell command (the most common)</li>
<li><strong>http</strong> POSTs the event JSON to a URL</li>
<li><strong>mcp_tool</strong> calls a tool on one of our <strong>MCP</strong> servers</li>
<li><strong>prompt</strong> asks a <strong>Claude</strong> model for a quick yes/no style decision</li>
<li><strong>agent</strong> spawns a subagent that can read files before deciding (still experimental)</li>
</ul>
<h2>Matchers And <code>if</code></h2>
<p>The <code>matcher</code> field filters what a hook fires on. For tool events it matches the tool name, so <code>Bash</code>, <code>Edit|Write</code>, and <code>mcp__.*</code> all work. For more precise filtering on tool events, the <code>if</code> field takes one permission rule:</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#E1E4E8">{</span></span>
<span class="line"><span style="color:#79B8FF">  "hooks"</span><span style="color:#E1E4E8">: {</span></span>
<span class="line"><span style="color:#79B8FF">    "PreToolUse"</span><span style="color:#E1E4E8">: [</span></span>
<span class="line"><span style="color:#E1E4E8">      {</span></span>
<span class="line"><span style="color:#79B8FF">        "matcher"</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">"Bash"</span><span style="color:#E1E4E8">,</span></span>
<span class="line"><span style="color:#79B8FF">        "hooks"</span><span style="color:#E1E4E8">: [</span></span>
<span class="line"><span style="color:#E1E4E8">          {</span></span>
<span class="line"><span style="color:#79B8FF">            "type"</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">"command"</span><span style="color:#E1E4E8">,</span></span>
<span class="line"><span style="color:#79B8FF">            "if"</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">"Bash(git push *)"</span><span style="color:#E1E4E8">,</span></span>
<span class="line"><span style="color:#79B8FF">            "command"</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">"$CLAUDE_PROJECT_DIR/.claude/hooks/check-branch.sh"</span></span>
<span class="line"><span style="color:#E1E4E8">          }</span></span>
<span class="line"><span style="color:#E1E4E8">        ]</span></span>
<span class="line"><span style="color:#E1E4E8">      }</span></span>
<span class="line"><span style="color:#E1E4E8">    ]</span></span>
<span class="line"><span style="color:#E1E4E8">  }</span></span>
<span class="line"><span style="color:#E1E4E8">}</span></span></code></pre><p>Note that <code>if</code> goes on the handler, next to <code>type</code>. It holds exactly one rule, so two conditions means two handlers.</p>
<h2>Exit Codes</h2>
<p>How our hook exits decides what happens next:</p>
<ul>
<li><strong>Exit 0</strong>: success, and the action goes ahead</li>
<li><strong>Exit 2</strong>: a blocking error. On a <code>PreToolUse</code> hook the tool call is stopped, and our stderr goes back to <strong>Claude</strong> as the reason</li>
<li><strong>Anything else</strong>: a non-blocking error, and the action still goes ahead</li>
</ul>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#6A737D">#!/usr/bin/env python3</span></span>
<span class="line"><span style="color:#F97583">import</span><span style="color:#E1E4E8"> json, sys</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">data </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> json.load(sys.stdin)</span></span>
<span class="line"><span style="color:#E1E4E8">path </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> data.get(</span><span style="color:#9ECBFF">"tool_input"</span><span style="color:#E1E4E8">, {}).get(</span><span style="color:#9ECBFF">"file_path"</span><span style="color:#E1E4E8">, </span><span style="color:#9ECBFF">""</span><span style="color:#E1E4E8">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">if</span><span style="color:#79B8FF"> any</span><span style="color:#E1E4E8">(p </span><span style="color:#F97583">in</span><span style="color:#E1E4E8"> path </span><span style="color:#F97583">for</span><span style="color:#E1E4E8"> p </span><span style="color:#F97583">in</span><span style="color:#E1E4E8"> [</span><span style="color:#9ECBFF">".env"</span><span style="color:#E1E4E8">, </span><span style="color:#9ECBFF">"bun.lock"</span><span style="color:#E1E4E8">, </span><span style="color:#9ECBFF">".git/"</span><span style="color:#E1E4E8">]):</span></span>
<span class="line"><span style="color:#79B8FF">    print</span><span style="color:#E1E4E8">(</span><span style="color:#F97583">f</span><span style="color:#9ECBFF">"Blocked: </span><span style="color:#79B8FF">{</span><span style="color:#E1E4E8">path</span><span style="color:#79B8FF">}</span><span style="color:#9ECBFF"> is protected"</span><span style="color:#E1E4E8">, </span><span style="color:#FFAB70">file</span><span style="color:#F97583">=</span><span style="color:#E1E4E8">sys.stderr)</span></span>
<span class="line"><span style="color:#E1E4E8">    sys.exit(</span><span style="color:#79B8FF">2</span><span style="color:#E1E4E8">)</span></span></code></pre><p><strong>Claude</strong> reads that message and tries another approach.</p>
<h2>Watch Out</h2>
<p>Exit code 1 does not block anything, even though it&#39;s the usual Unix failure code. If a hook is enforcing a policy, use <code>exit 2</code>.</p>
<p>The <code>timeout</code> field is in seconds, and command hooks default to 600. All matching hooks for an event run in parallel. Edits to hooks in our settings files are picked up automatically, and <code>/hooks</code> opens a read-only browser showing every hook and where it came from.</p>
<p>More info about <strong>hooks</strong> can be found at <a href="https://code.claude.com/docs/en/hooks">the Claude Code docs</a>.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[#1: CLAUDE.md Basics 📝]]></title>
            <link>https://littlecupsofclaude.com/1</link>
            <guid isPermaLink="false">https://littlecupsofclaude.com/1</guid>
            <pubDate>Mon, 26 Oct 2026 13:00:00 GMT</pubDate>
            <description><![CDATA[<p>Today we&#39;ll take a look at one of the most useful files in any <strong>Claude Code</strong> project: <strong>CLAUDE.md</strong>.</p>
<p>A <code>CLAUDE.md</code> file gives <strong>Claude Code</strong> instructions about our project that stick around between sessions. <strong>Claude Code</strong> loads it into context at the start of every session, so we stop repeating the same preferences over and over.</p>
<p>Let&#39;s dive in.</p>
<h2>Setting It Up</h2>
<p>The fastest way to get one is to let <strong>Claude Code</strong> write a first draft for us:</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#F97583">></span><span style="color:#E1E4E8"> /init</span></span></code></pre><p><strong>Claude</strong> looks at our codebase and writes a <code>CLAUDE.md</code> with the build commands, test instructions, and conventions it finds. If one already exists, <code>/init</code> suggests improvements instead of overwriting it.</p>
<p>We can also start from scratch:</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#79B8FF;font-weight:bold"># Discovery One</span></span>
<span class="line"><span style="color:#E1E4E8">Use TypeScript for all new files</span></span>
<span class="line"><span style="color:#E1E4E8">Use bun, not node</span></span>
<span class="line"><span style="color:#E1E4E8">Run tests with </span><span style="color:#79B8FF">`bun test`</span></span>
<span class="line"><span style="color:#E1E4E8">The database is SQLite via better-sqlite3</span></span></code></pre><p>From then on, every session in this directory starts out knowing all of that. Neat!</p>
<h2>Where It Can Live</h2>
<p>There are a few places a <code>CLAUDE.md</code> can go, each with a different scope:</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#6A737D"># User: our preferences for every project</span></span>
<span class="line"><span style="color:#F97583">~</span><span style="color:#E1E4E8">/.claude/CLAUDE.md</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D"># Project: checked into git, shared with the team</span></span>
<span class="line"><span style="color:#B392F0">./CLAUDE.md</span><span style="color:#6A737D">          # or ./.claude/CLAUDE.md</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D"># Local: personal notes for this project only</span></span>
<span class="line"><span style="color:#B392F0">./CLAUDE.local.md</span><span style="color:#6A737D">    # add it to .gitignore</span></span></code></pre><p>These don&#39;t override each other. <strong>Claude Code</strong> concatenates all of them into context, broadest first: user, then project, then local. Instructions closer to where we launched get read last.</p>
<h2>Parent And Child Directories</h2>
<p><strong>Claude Code</strong> also walks up the directory tree. If we start it in <code>apps/hal/</code>, it loads <code>apps/hal/CLAUDE.md</code> and also <code>apps/CLAUDE.md</code> and the repo root&#39;s <code>CLAUDE.md</code>.</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#B392F0">monorepo/</span></span>
<span class="line"><span style="color:#B392F0">  CLAUDE.md</span><span style="color:#6A737D">            # loaded at launch</span></span>
<span class="line"><span style="color:#B392F0">  apps/</span></span>
<span class="line"><span style="color:#B392F0">    hal/</span></span>
<span class="line"><span style="color:#B392F0">      CLAUDE.md</span><span style="color:#6A737D">        # loaded at launch (we started here)</span></span>
<span class="line"><span style="color:#B392F0">  packages/</span></span>
<span class="line"><span style="color:#B392F0">    ui/</span></span>
<span class="line"><span style="color:#B392F0">      CLAUDE.md</span><span style="color:#6A737D">        # loaded later, on demand</span></span></code></pre><p>Files in subdirectories below where we started load on demand, the first time <strong>Claude</strong> reads or edits something in that folder. That keeps a big monorepo from dumping every team&#39;s notes into context at once.</p>
<h2>What To Put In It</h2>
<p>The best <code>CLAUDE.md</code> files are short and full of facts <strong>Claude</strong> can&#39;t easily figure out on its own:</p>
<ul>
<li><strong>Commands</strong>: how to build, test, lint, and deploy</li>
<li><strong>Conventions</strong>: naming, patterns to follow or avoid</li>
<li><strong>Layout</strong>: where things live, how modules connect</li>
<li><strong>Gotchas</strong>: the things that bit us last week</li>
</ul>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#79B8FF;font-weight:bold">## Commands</span></span>
<span class="line"><span style="color:#E1E4E8">bun dev    # dev server on :3000</span></span>
<span class="line"><span style="color:#E1E4E8">bun test   # unit tests</span></span>
<span class="line"><span style="color:#E1E4E8">bun lint   # eslint</span></span>
<span class="line"></span>
<span class="line"><span style="color:#79B8FF;font-weight:bold">## Rules</span></span>
<span class="line"><span style="color:#E1E4E8">Prefer unknown over any</span></span>
<span class="line"><span style="color:#E1E4E8">Never edit files in generated/</span></span>
<span class="line"><span style="color:#E1E4E8">Migrations go in db/migrations, one per change</span></span></code></pre><h2>Imports</h2>
<p>A <code>CLAUDE.md</code> can pull in other files with <code>@path</code>:</p>
<pre class="shiki github-dark" style="background-color:#24292e;color:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#E1E4E8">See @README.md for the project overview.</span></span>
<span class="line"><span style="color:#E1E4E8">Our API conventions are in @docs/api.md.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#79B8FF;font-weight:bold"># Personal prefs, shared across worktrees</span></span>
<span class="line"><span style="color:#E1E4E8">@~/.claude/samantha-prefs.md</span></span></code></pre><p>Imported files can import other files, up to four hops deep. Relative paths resolve from the file doing the importing, not from wherever we launched <strong>Claude Code</strong>.</p>
<h2>Watch Out</h2>
<p>The docs suggest aiming for under around ~200 lines per <code>CLAUDE.md</code>. Longer files cost context and <strong>Claude</strong> follows them less reliably. Imports help organize a long file, but they don&#39;t shrink it, since imported files load right along with it.</p>
<p>If something only matters for one part of the codebase, a path-scoped rule in <code>.claude/rules/</code> is a better home. Those only load when <strong>Claude</strong> works with matching files.</p>
<p>To check what loaded, we can run <code>/context</code> and look under <strong>Memory files</strong>.</p>
<p>More info about <strong>CLAUDE.md</strong> can be found at <a href="https://code.claude.com/docs/en/memory">the Claude Code docs</a>.</p>
]]></description>
        </item>
    </channel>
</rss>