<?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: Pawel</title>
    <description>The latest articles on DEV Community by Pawel (@pawel_nowak).</description>
    <link>https://dev.to/pawel_nowak</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%2F4159320%2F2695c3e7-e63c-4b61-a949-c031452769bf.jpg</url>
      <title>DEV Community: Pawel</title>
      <link>https://dev.to/pawel_nowak</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pawel_nowak"/>
    <language>en</language>
    <item>
      <title>Claude Code Mods Aren't Sandboxed. Neither Is Your Understanding of "Sandboxed".</title>
      <dc:creator>Pawel</dc:creator>
      <pubDate>Sun, 04 Oct 2026 13:49:49 +0000</pubDate>
      <link>https://dev.to/pawel_nowak/claude-code-mods-arent-sandboxed-neither-is-your-understanding-of-sandboxed-77m</link>
      <guid>https://dev.to/pawel_nowak/claude-code-mods-arent-sandboxed-neither-is-your-understanding-of-sandboxed-77m</guid>
      <description>&lt;p&gt;Two statements about Claude Code mods, both true, both from Anthropic's own docs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The module runs in a sandbox of its own, with no DOM and no Node.&lt;/li&gt;
&lt;li&gt;"Mods aren't sandboxed."&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first two days of the mods launch have been one long argument about which of these is the lie. Neither is. The confusion comes from the word "sandbox" doing two different jobs, and once you separate them, the real trust boundary snaps into focus. It is not where most people think it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sandbox #1: the JavaScript runtime
&lt;/h2&gt;

&lt;p&gt;When you write a mod, your module gets a private little world. No &lt;code&gt;document&lt;/code&gt;. No &lt;code&gt;window&lt;/code&gt;. No Node globals. If your code wants to touch anything outside itself, files, processes, the network, the UI, it goes through one object: &lt;code&gt;$&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tool.call&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;listing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readDir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/tmp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// through $, not fs&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is sandbox #1. It is a language-level sandbox: it constrains &lt;em&gt;how&lt;/em&gt; your code reaches the outside world, not &lt;em&gt;whether&lt;/em&gt; it can. Every capability lives behind the &lt;code&gt;$&lt;/code&gt; API, which means the engine can see every request, log it, and (in theory) gate it. Think of it like a phone where every app must use the official APIs. The APIs still include the camera.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sandbox #2: the one that does not exist
&lt;/h2&gt;

&lt;p&gt;Here is what the documentation says, and I am quoting because paraphrasing would soften it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"A mod is code that runs with your permissions. It can read and write your files, start processes, and make network requests. Install mods only from authors and marketplaces you trust."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Mods aren't sandboxed. If you turn on sandboxing, the sandbox isolates the Bash commands Claude runs, and a process that a mod starts runs outside it."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Read that second one twice. Claude Code has a sandboxing feature, and it sandboxes &lt;em&gt;Claude's&lt;/em&gt; Bash commands. A mod that starts its own process steps cleanly outside of it. The fence was built around the agent, not around the extension.&lt;/p&gt;

&lt;p&gt;The capability list gets worse the further you read. A mod can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Read your secrets&lt;/strong&gt;: environment variables and settings files, "including an API key you keep in either".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Approve tool calls you blocked&lt;/strong&gt;: a mod that approves tool calls can green-light one "that an ask rule would prompt for, or that one of your own PreToolUse hooks blocked". Your hook said no. The mod says yes. The mod wins.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rewrite events before you see them&lt;/strong&gt;: hooks form a chain, and a mod can observe, rewrite, or fully answer any event. Including the ones your audit logger was counting on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So when someone says "mods are sandboxed", they are describing the JS runtime. When Anthropic says "mods aren't sandboxed", they are describing your files, your processes, your network, and your API keys. Both true. The second one is the one that matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one hard boundary
&lt;/h2&gt;

&lt;p&gt;There is exactly one thing Anthropic drew a hard line around, and it is telling:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"A mod can restyle much of Claude Code's interface, but not the permission prompt. It can't change what a prompt shows you."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A mod can redraw almost the entire UI, panes, bands above the prompt, toasts, but the permission dialog stays Claude Code's own. Whatever else a mod draws, the moment that asks "are you sure?" cannot be faked, restyled, or have its contents swapped.&lt;/p&gt;

&lt;p&gt;Think about why that specific line exists. If a mod could restyle the permission prompt, it could show you "run tests?" while actually approving &lt;code&gt;rm -rf&lt;/code&gt;. Anthropic hardened the one UI element where your eyes are the security control, and left everything else open. That tells you exactly what threat model they designed for: the mod is untrusted code with your privileges, and the permission prompt is the last honest surface in the room.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mental model that actually works
&lt;/h2&gt;

&lt;p&gt;Stop picturing a browser iframe. The right mental model is much older and much simpler:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installing a mod is giving someone your shell.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not a restricted shell. Not a shell with an auditor watching. Your shell, with your env vars, your files, your network, and the ability to overrule the guardrails you built for the agent. The JS-runtime sandbox is real engineering, it keeps modules from stepping on each other and gives the engine a clean interception point, but it was never a security boundary between the mod and your machine.&lt;/p&gt;

&lt;p&gt;Once you have that model, the hygiene checklist writes itself:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;claude plugin validate&lt;/code&gt; before you install, not after.&lt;/strong&gt; It lists the events a mod handles and what it asks Claude Code to do, file reads, network requests, without running any code. Read it like you would read the permissions screen on a phone app. If a context-bar mod wants network access, ask why.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Know your off switches.&lt;/strong&gt; Disable one plugin from the Installed tab in &lt;code&gt;/plugin&lt;/code&gt;. Start a session with &lt;code&gt;--safe-mode&lt;/code&gt; to drop all customizations. Set &lt;code&gt;"disableAllHooks": true&lt;/code&gt; in &lt;code&gt;~/.claude/settings.json&lt;/code&gt; for the wide kill switch. Organizations get &lt;code&gt;allowManagedModsOnly&lt;/code&gt;, which stops user-installed mods from loading while skills, commands, and MCP servers keep working.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit the small ones hardest.&lt;/strong&gt; A 40-line UI mod feels safe because it is small. But 40 lines is enough to read &lt;code&gt;~/.claude/settings.json&lt;/code&gt;, exfiltrate an API key, and approve the tool call that covers its tracks. Size is not a security property.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of this means you should not install mods. It means you should install them the way you would hand your laptop to a colleague: only to people you trust, and knowing exactly what they can reach while they have it.&lt;/p&gt;

&lt;p&gt;So here is my question: what does your &lt;code&gt;claude plugin validate&lt;/code&gt; say about the mods you have already installed? And did you read it before, or just now?&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>security</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>I Built My First Claude Code Mod Without Writing Code: Claude Wrote It, Validated It, and Hot-Reloaded It</title>
      <dc:creator>Pawel</dc:creator>
      <pubDate>Sat, 03 Oct 2026 09:19:53 +0000</pubDate>
      <link>https://dev.to/pawel_nowak/i-built-my-first-claude-code-mod-without-writing-code-claude-wrote-it-validated-it-and-2mh7</link>
      <guid>https://dev.to/pawel_nowak/i-built-my-first-claude-code-mod-without-writing-code-claude-wrote-it-validated-it-and-2mh7</guid>
      <description>&lt;p&gt;I wanted one thing: to see my context window without typing &lt;code&gt;/context&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Not a dashboard. Not a plugin I install and configure for twenty minutes. Just a small bar above the prompt that tells me how full the window is, the way the &lt;code&gt;/context&lt;/code&gt; command does, but always on screen. One sentence of a prompt later, it was there.&lt;/p&gt;

&lt;p&gt;This is the story of the first Claude Code mod I built without writing a single line of code. Claude wrote it, validated it, tested it, and hot-reloaded it into my session. I just watched.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a mod actually is
&lt;/h2&gt;

&lt;p&gt;Claude Code mods (shipped in v2.1.287, on by default) are small JavaScript or TypeScript modules that live inside a plugin. They see every event in your session as it happens: tool calls, the prompt you submit, turns starting and ending, and every piece of the interface as it is drawn.&lt;/p&gt;

&lt;p&gt;That last part is the new bit. Mods can rewrite what Claude Code does and draw their own UI: a pane, a band above the prompt, a status line entry, a toast. Everything the engine draws is a component you can hook into.&lt;/p&gt;

&lt;p&gt;And here is the part that still feels strange: you do not need to learn the API to try one. You describe the mod you want, and Claude Code builds it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: ask for it
&lt;/h2&gt;

&lt;p&gt;Open any project, run &lt;code&gt;claude&lt;/code&gt;, and paste a prompt like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Create a mod that draws my context window as a stacked bar above the prompt, one colour per category like /context, toggled with /context-bar.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Claude Code loads its own plugin-authoring skill, reads the engine's type declarations, and writes three or four files into a session folder under &lt;code&gt;~/.claude/dev-mods/&lt;/code&gt;. Then it asks one question: allow hot reloading for this session?&lt;/p&gt;

&lt;p&gt;Say yes. When the turn ends, the bar appears above your prompt.&lt;/p&gt;

&lt;p&gt;That is the moment that sold me. I did not open an editor. I did not read the docs. I described a UI in plain English, and it showed up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: make Claude validate its own homework
&lt;/h2&gt;

&lt;p&gt;Before I even looked at the code, I asked for two things while the session was still warm:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Run &lt;code&gt;claude plugin validate&lt;/code&gt; on the folder.&lt;/strong&gt; The validator reads the module the way the engine will and names anything the engine would refuse. Think of it as a compiler for mods: non-negotiable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write a &lt;code&gt;tests/&lt;/code&gt; file and run &lt;code&gt;claude plugin test&lt;/code&gt;.&lt;/strong&gt; That exercises the hooks against the real engine. No TypeScript toolchain needed on your machine.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the difference between "Claude wrote something plausible" and "the engine will actually load this". An LLM will happily produce a mod that looks right and fails at load time. Validate and test are what separate the magic from the garbage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: peek under the hood (optional, but worth it)
&lt;/h2&gt;

&lt;p&gt;Curiosity won, so I read the code. A mod is one module exporting &lt;code&gt;register&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ui.render&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AbovePrompt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Text&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;paddingX&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello from my mod&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})],&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The shape is middleware. Your hook runs, then &lt;code&gt;next(e)&lt;/code&gt; hands the event to the next plugin in the chain, then to Claude Code itself. Every hook does one of three moves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Observe:&lt;/strong&gt; call &lt;code&gt;next(e)&lt;/code&gt;, then look at the result. Record every file edit, take a reading after each turn.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rewrite:&lt;/strong&gt; call &lt;code&gt;next&lt;/code&gt; with a modified event. Change what the rest of the chain sees.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Answer:&lt;/strong&gt; skip &lt;code&gt;next&lt;/code&gt; entirely and serve the event yourself. Refuse a tool call, handle a slash command.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One detail I stole from Addy Osmani's guide: do not keep history in a module-level &lt;code&gt;let&lt;/code&gt;. Hot reload is a fresh load, &lt;code&gt;register&lt;/code&gt; runs again, and module variables start over. Keep readings in &lt;code&gt;$.state&lt;/code&gt;, declared in a small types contract, and they survive reloads. If you skip the contract, &lt;code&gt;claude plugin validate&lt;/code&gt; stops you with an error that names the fix. The tooling here is genuinely good.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: make it permanent
&lt;/h2&gt;

&lt;p&gt;The session folder dies with the session. Copy the mod somewhere stable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/.claude/mods
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; ~/.claude/dev-mods/&amp;lt;session-id&amp;gt;/context-bar ~/.claude/mods/context-bar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep the manifest in &lt;code&gt;.claude-plugin/plugin.json&lt;/code&gt;, the &lt;code&gt;hooks/&lt;/code&gt; folder with its module, and the &lt;code&gt;types/&lt;/code&gt; contract if the mod keeps state. Copy &lt;code&gt;tests/&lt;/code&gt; too, so you can rerun the tests after an update.&lt;/p&gt;

&lt;p&gt;Then tell Claude Code where it lives. The one place that reaches every session, including the ones the desktop app starts, is the &lt;code&gt;env&lt;/code&gt; block of your user settings file. Open &lt;code&gt;~/.claude/settings.json&lt;/code&gt; and add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"CLAUDE_CODE_PLUGIN_DIRS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/Users/you/.claude/mods/context-bar"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the full path, not &lt;code&gt;~&lt;/code&gt;. Several mods are separated with a colon. For a one-off terminal session, &lt;code&gt;claude --plugin-dir ~/.claude/mods/context-bar&lt;/code&gt; does the same without touching settings.&lt;/p&gt;

&lt;p&gt;Open a new session in any project. The bar is above the prompt before you type anything, and &lt;code&gt;/context-bar&lt;/code&gt; hides it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two things that bit me
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Early access means churn.&lt;/strong&gt; The API can change between releases, so a mod written today may need a touch-up after an update. Rerun &lt;code&gt;claude plugin validate&lt;/code&gt; after every upgrade. It is cheap insurance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check which &lt;code&gt;claude&lt;/code&gt; you are running.&lt;/strong&gt; The desktop app bundles its own engine, and the one on your PATH may be older. Mine was, and its validator did not recognize the hooks module at all. Validate with the app's bundled binary, or update the CLI first. This cost me twenty confused minutes staring at an error that was not mine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this feels different
&lt;/h2&gt;

&lt;p&gt;I have used hooks, slash commands, and skills. A settings hook runs a shell command per event and passes JSON over stdin and stdout. A mod loads once, keeps state, draws UI that updates as events happen, and can call back into Claude Code: open a pane, run a process, register a slash command, register a tool the model can call. Some of Claude Code's own features are built as mods, including AGENTS.md support and the &lt;code&gt;/diff&lt;/code&gt; pane. Their source is public, so you can read how the team builds them.&lt;/p&gt;

&lt;p&gt;But the real shift is the loop. The skill for writing mods ships inside Claude Code, so the agent modifies its own runtime, in the same session, and hot reload shows you the result on the next turn. I kept asking for tweaks ("add a legend line with per-category token counts", "show a toast when context crosses 85%") and watched the bar change. It felt less like configuring a tool and more like pair programming with the tool itself.&lt;/p&gt;

&lt;p&gt;If you could describe a mod in one sentence, what would it do?&lt;/p&gt;

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