<?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: Local Plugins</title>
    <description>The latest articles on DEV Community by Local Plugins (@localplugins).</description>
    <link>https://dev.to/localplugins</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%2F4028827%2F63f80f4f-fee5-47cc-a99e-d04953c600ab.png</url>
      <title>DEV Community: Local Plugins</title>
      <link>https://dev.to/localplugins</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/localplugins"/>
    <language>en</language>
    <item>
      <title>Your Claude Code hook doesn't fire on Windows, and nothing tells you why</title>
      <dc:creator>Local Plugins</dc:creator>
      <pubDate>Thu, 16 Jul 2026 13:19:30 +0000</pubDate>
      <link>https://dev.to/localplugins/your-claude-code-hook-doesnt-fire-on-windows-and-nothing-tells-you-why-2dg6</link>
      <guid>https://dev.to/localplugins/your-claude-code-hook-doesnt-fire-on-windows-and-nothing-tells-you-why-2dg6</guid>
      <description>&lt;p&gt;One of my plugins has a SessionStart hook. It loads the active brand kit into context, so a plain request already knows your colors and fonts without you re-explaining them every session.&lt;/p&gt;

&lt;p&gt;On macOS it works. On Windows it does nothing. No error, no warning, no line in the transcript. It just silently isn't there.&lt;/p&gt;

&lt;p&gt;Here's the whole path, including the wrong turn, because the wrong turn is the interesting part.&lt;/p&gt;

&lt;h2&gt;
  
  
  The symptom
&lt;/h2&gt;

&lt;p&gt;The hook is declared like this:&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;"hooks"&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;"SessionStart"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"matcher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"startup|resume"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bash &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&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;"async"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&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;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="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;Nothing wrong with it. Plugin enabled, script present, script executable. On a Mac it fires every session.&lt;/p&gt;

&lt;h2&gt;
  
  
  The wrong theory
&lt;/h2&gt;

&lt;p&gt;First I checked whether the hook was being invoked at all. Claude Code stores a record when a hook fires, so you can audit it. In the failing session:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SessionStart:startup&lt;/code&gt; records: &lt;strong&gt;0&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PreToolUse:Bash&lt;/code&gt; records: &lt;strong&gt;12&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So SessionStart never ran, but a different hook ran twelve times. And a sibling session on the same app version &lt;em&gt;did&lt;/em&gt; have a SessionStart record carrying the exact line my plugin emits. The hook works. It just wasn't invoked here.&lt;/p&gt;

&lt;p&gt;That led to a reasonable theory: the matcher. &lt;code&gt;startup|resume&lt;/code&gt; doesn't match every session source (there are four: &lt;code&gt;startup&lt;/code&gt;, &lt;code&gt;resume&lt;/code&gt;, &lt;code&gt;clear&lt;/code&gt;, &lt;code&gt;compact&lt;/code&gt;), so maybe the desktop app creates sessions through a path that never produces a matching event.&lt;/p&gt;

&lt;p&gt;So I dropped the matcher, which makes it fire on all four. Shipped it. Updated the Windows machine.&lt;/p&gt;

&lt;p&gt;Still nothing.&lt;/p&gt;

&lt;p&gt;That's the useful part. The theory was plausible, it explained the evidence, and it was wrong. Zero records is equally consistent with "the event never arrived" and "the hook ran and failed." I picked one without testing the other.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual cause
&lt;/h2&gt;

&lt;p&gt;The command starts with &lt;code&gt;bash&lt;/code&gt;. So the question was never whether the event arrived. It's whether &lt;code&gt;bash&lt;/code&gt; resolves.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; where.exe bash
INFO: Could not find files for the given pattern(s).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It doesn't. Meanwhile:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Default shell (&lt;code&gt;COMSPEC&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;C:\WINDOWS\system32\cmd.exe&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Git Bash installed?&lt;/td&gt;
&lt;td&gt;Yes, at &lt;code&gt;C:\Program Files\Git\bin\bash.exe&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Is &lt;code&gt;Git\bin&lt;/code&gt; on PATH?&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;No.&lt;/strong&gt; Only &lt;code&gt;Git\cmd&lt;/code&gt; is, which has &lt;code&gt;git.exe&lt;/code&gt; but not &lt;code&gt;bash.exe&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So Claude Code hands &lt;code&gt;bash "...session-start.sh"&lt;/code&gt; to cmd.exe, cmd can't resolve bash, the command errors, the hook exits non-zero, and it gets dropped. Silently.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two things that look like contradictions
&lt;/h2&gt;

&lt;p&gt;Both of these made me believe bash was fine. Both are actually confirmations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Bash tool works.&lt;/strong&gt; I can run bash commands in the session all day. But the tool finds its own Git Bash through a different resolution path than the hook runner, which uses the OS shell and the system PATH. "bash works in my session" tells you nothing about whether the hook can find it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A different hook does fire.&lt;/strong&gt; My PreToolUse hook runs an &lt;code&gt;echo&lt;/code&gt;. It works because &lt;code&gt;echo&lt;/code&gt; is a cmd built-in and needs no bash at all. Only the bash-invoking hooks fail, which is all of them, in every plugin I have.&lt;/p&gt;

&lt;h2&gt;
  
  
  This is the default install, not an edge case
&lt;/h2&gt;

&lt;p&gt;Git for Windows puts &lt;code&gt;Git\cmd&lt;/code&gt; on PATH, not &lt;code&gt;Git\bin&lt;/code&gt;. That's the standard install option. Adding &lt;code&gt;Git\bin&lt;/code&gt; is the option the installer explicitly warns you about, because it puts GNU &lt;code&gt;find&lt;/code&gt; and &lt;code&gt;sort&lt;/code&gt; ahead of the Windows native ones and breaks other tooling.&lt;/p&gt;

&lt;p&gt;So the default Windows setup is: bash is installed, and bash is not on PATH. Every plugin whose hooks shell out to bash silently does nothing for a large share of Windows users, with no error anywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fixes, including the ones that don't work
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Add &lt;code&gt;Git\bin&lt;/code&gt; to PATH.&lt;/strong&gt; Works. It's also the thing Git warns about, and it's per machine, so it fixes you and nobody else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hardcode an absolute path.&lt;/strong&gt; No. There isn't a single correct one. macOS ships bash at &lt;code&gt;/bin/bash&lt;/code&gt;, not &lt;code&gt;/usr/bin/bash&lt;/code&gt;. Most Linux has &lt;code&gt;/usr/bin/bash&lt;/code&gt;. Windows has a path that varies by installer. And cmd can't resolve a POSIX path anyway, so &lt;code&gt;/usr/bin/bash&lt;/code&gt; is meaningless there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use &lt;code&gt;sh&lt;/code&gt; instead.&lt;/strong&gt; Worse. There's no &lt;code&gt;sh&lt;/code&gt; on Windows either, both come from the same Git Bash layer. And my scripts use &lt;code&gt;set -euo pipefail&lt;/code&gt;, and pipefail isn't POSIX, so running them under dash (which is &lt;code&gt;/bin/sh&lt;/code&gt; on Debian and Ubuntu) breaks them immediately. That trades a Windows problem for a Linux problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Put the condition in the command.&lt;/strong&gt; Tempting, but the hook command runs in cmd.exe on Windows and sh on Unix, and their conditional syntax has nothing in common. There's no single string that checks paths in both.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use node.&lt;/strong&gt; This is the one that works. Node's Windows installer puts &lt;code&gt;node&lt;/code&gt; on PATH by default, which is exactly what Git's installer doesn't do for bash. So either port the hook to Node, or keep the bash scripts and add a small Node launcher that walks candidate locations and runs whichever exists:&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="c1"&gt;// candidates, first hit wins&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;candidates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                                   &lt;span class="c1"&gt;// on PATH (mac/linux, or Git\bin on PATH)&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/bin/bash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                              &lt;span class="c1"&gt;// macOS, most Linux&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/usr/bin/bash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                          &lt;span class="c1"&gt;// most Linux&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;C:&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;Program Files&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;Git&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;bin&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;bash.exe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// default Git for Windows&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;C:&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;Program Files&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;Git&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;usr&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;bin&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;bash.exe&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not a guarantee. If node isn't on the hook runner's PATH either, you're back where you started. But it drops the dependency that's broken by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual bug
&lt;/h2&gt;

&lt;p&gt;The PATH thing is a packaging quirk. The real problem is that &lt;strong&gt;the hook failed and told nobody.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The command errored. The plugin silently lost a feature. Nothing in the transcript, no warning, no log line, no exit code surfaced to the user or to me. From the outside it's indistinguishable from a hook that was never registered, which is exactly why I burned a day on the wrong theory.&lt;/p&gt;

&lt;p&gt;If you're building a harness with hooks: surface the failures. A hook that dies quietly is worse than one that doesn't exist, because at least a missing hook is visible.&lt;/p&gt;

&lt;p&gt;And if you're writing plugins with hooks: run &lt;code&gt;where.exe bash&lt;/code&gt; on a Windows box before you assume anything.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Local-first Claude Code plugins: no keys, no network, open source</title>
      <dc:creator>Local Plugins</dc:creator>
      <pubDate>Tue, 14 Jul 2026 13:30:56 +0000</pubDate>
      <link>https://dev.to/localplugins/local-first-claude-code-plugins-no-keys-no-network-open-source-3ak5</link>
      <guid>https://dev.to/localplugins/local-first-claude-code-plugins-no-keys-no-network-open-source-3ak5</guid>
      <description>&lt;p&gt;I keep living inside Claude Code, and I kept wanting small, useful tools in&lt;br&gt;
there that didn't phone home. Not another SaaS with a login and an API key,&lt;br&gt;
just something that runs on my machine, does one job well, and that I can read&lt;br&gt;
before I trust it.&lt;/p&gt;

&lt;p&gt;So I packaged the workflows I actually use into a few open-source plugins and&lt;br&gt;
put them in one marketplace. This is the first write-up.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "local-first" means here
&lt;/h2&gt;

&lt;p&gt;The rule I set for myself: a plugin should run entirely on your machine by&lt;br&gt;
default. No account, no API key, no network call, nothing uploaded or&lt;br&gt;
auto-posted. And if a plugin genuinely needs the network, it should be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;obvious,&lt;/li&gt;
&lt;li&gt;isolated to a single module,&lt;/li&gt;
&lt;li&gt;off by default, and&lt;/li&gt;
&lt;li&gt;using your own key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That way you can &lt;code&gt;grep&lt;/code&gt; the code and see exactly what touches the outside&lt;br&gt;
world. For a tool that generates your logo or your résumé, that inspectability&lt;br&gt;
matters.&lt;/p&gt;

&lt;p&gt;Two honest exceptions, called out up front: &lt;code&gt;docpin&lt;/code&gt; fetches library&lt;br&gt;
documentation from the web (always cited), and &lt;code&gt;brand-forge&lt;/code&gt; has one opt-in&lt;br&gt;
module that can call an image API for AI photography. Everything else is local.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in the suite
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;brand-forge&lt;/strong&gt; — save a brand profile once (colors, fonts, voice), then
generate on-brand logos, social templates, and doc/deck templates as SVG.
The vector output is drawn by local code, so it's deterministic: the same
profile always produces the same asset.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;cv-forge&lt;/strong&gt; — keep one résumé in the JSON Resume schema, generate a clean,
ATS-friendly PDF from a local HTML template and your browser's print. No
Node, no keys, no network.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;content-multiplier&lt;/strong&gt; — turn one idea into on-brand, multi-channel,
multi-language content from a single command.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;docpin&lt;/strong&gt; — ground code against your &lt;em&gt;installed&lt;/em&gt; version of a library by
pulling version-matched, cited docs.&lt;/li&gt;
&lt;li&gt;plus a couple more in the same spirit.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installing
&lt;/h2&gt;

&lt;p&gt;Everything installs through Claude Code's plugin system. In a session:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/plugin marketplace add localplugins/plugins
/plugin install brand-forge@localplugins
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then a natural request like &lt;code&gt;/brand-make instagram post "We just shipped"&lt;/code&gt; uses&lt;br&gt;
your saved brand and returns an editable SVG in &lt;code&gt;output/&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A few design choices worth calling out
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Deterministic generation over an LLM round-trip.&lt;/strong&gt; brand-forge's logos and&lt;br&gt;
templates are generated by plain code from your profile, not by asking a model&lt;br&gt;
to draw them. That makes them reproducible, diffable, and editable, and they&lt;br&gt;
don't drift between runs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The network boundary is a single file.&lt;/strong&gt; In brand-forge, the only module&lt;br&gt;
that can reach the internet is the opt-in image generator. It's off unless you&lt;br&gt;
set an env var and provide your own key, and the text of your asset is&lt;br&gt;
composited locally as an SVG overlay so it never goes into the image prompt.&lt;br&gt;
One file to audit, not a whole codebase.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Plugin anatomy.&lt;/strong&gt; Each plugin is a normal Claude Code plugin: slash commands,&lt;br&gt;
skills that trigger from natural requests, sometimes a SessionStart hook that&lt;br&gt;
loads context, and in brand-forge's case two subagents (an art-director that&lt;br&gt;
plans a multi-asset set, and a visual-guardian that checks output against the&lt;br&gt;
brand for palette and contrast). If you're building your own plugins, they're&lt;br&gt;
small enough to read as examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this isn't
&lt;/h2&gt;

&lt;p&gt;It's not a design tool that will out-polish a human designer, and it isn't&lt;br&gt;
trying to be. It's a way to get consistent, on-brand, good-enough assets and&lt;br&gt;
documents without leaving your terminal or signing up for anything. If you need&lt;br&gt;
pixel-perfect art direction, use it for the scaffolding and finish by hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;It's all MIT and open source, built with Claude Code itself:&lt;br&gt;
&lt;a href="https://github.com/localplugins/plugins" rel="noopener noreferrer"&gt;https://github.com/localplugins/plugins&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'd genuinely like feedback on two things: what feels useful vs. gimmicky, and&lt;br&gt;
where you think the line should be for what a local-first plugin is allowed to&lt;br&gt;
do. Issues and comments welcome.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>design</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
