<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Parker Jones Dev Blog - skills</title>
    <subtitle>Dev Blog of Parker Jones</subtitle>
    <link rel="self" type="application/atom+xml" href="https://parkerjones.dev/tags/skills/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://parkerjones.dev"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-06-26T00:00:00+00:00</updated>
    <id>https://parkerjones.dev/tags/skills/atom.xml</id>
    <entry xml:lang="en">
        <title>Shipping Claude Skills with Nix: a Reproducible Agent Toolkit Across My Fleet</title>
        <published>2026-06-26T00:00:00+00:00</published>
        <updated>2026-06-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://parkerjones.dev/posts/skills-with-nix/"/>
        <id>https://parkerjones.dev/posts/skills-with-nix/</id>
        
        <content type="html" xml:base="https://parkerjones.dev/posts/skills-with-nix/">&lt;p&gt;A coding agent is only as good as the procedures you hand it. Out of the box, a model improvises every task from scratch; give it a &lt;em&gt;skill&lt;&#x2F;em&gt; — a written procedure for &quot;do TDD,&quot; &quot;diagnose a hard bug,&quot; &quot;turn this into issues&quot; — and it stops guessing and starts following a method you trust. I&#x27;ve built up a collection of these, and once you have more than a handful the real problem isn&#x27;t writing them, it&#x27;s &lt;strong&gt;distribution&lt;&#x2F;strong&gt;: getting the same skills onto every machine I work from, version-pinned, without copy-pasting Markdown around.&lt;&#x2F;p&gt;
&lt;p&gt;I solved that with Nix. Here&#x27;s the setup.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-a-skill-is&quot;&gt;What a skill is&lt;&#x2F;h2&gt;
&lt;p&gt;My skills live in a repo (a fork of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mattpocock&#x2F;skills&quot;&gt;Matt Pocock&#x27;s &lt;code&gt;skills&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, credit where it&#x27;s due), organized into buckets — &lt;code&gt;engineering&lt;&#x2F;code&gt;, &lt;code&gt;qa&lt;&#x2F;code&gt;, &lt;code&gt;productivity&lt;&#x2F;code&gt;, &lt;code&gt;personal&lt;&#x2F;code&gt;, &lt;code&gt;misc&lt;&#x2F;code&gt;. Each skill is a directory with a &lt;code&gt;SKILL.md&lt;&#x2F;code&gt;: YAML frontmatter naming it and describing &lt;em&gt;when&lt;&#x2F;em&gt; to use it, then the procedure itself.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;markdown&quot;&gt;---
name: diagnose
description: Disciplined diagnosis loop for hard bugs and performance
  regressions. Reproduce → minimise → hypothesise → instrument → fix →
  regression-test. Use when user says &amp;quot;diagnose this&amp;quot; &#x2F; &amp;quot;debug this&amp;quot;...
---

# Diagnose
...
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;description&lt;&#x2F;code&gt; is load-bearing — it&#x27;s what the agent matches against to decide whether the skill is relevant. A few I reach for constantly: &lt;code&gt;tdd&lt;&#x2F;code&gt; (red-green-refactor), &lt;code&gt;diagnose&lt;&#x2F;code&gt; (the loop above), &lt;code&gt;to-prd&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;to-issues&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;triage&lt;&#x2F;code&gt; (turning a vague ask into tracked work), and &lt;code&gt;write-a-skill&lt;&#x2F;code&gt; (the skill that writes more skills). Small, composable, model-agnostic. No framework owning my process — just procedures I can read, edit, and trust.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;three-ways-to-install-them&quot;&gt;Three ways to install them&lt;&#x2F;h2&gt;
&lt;p&gt;The repo supports three distribution paths, in increasing order of how much I actually rely on them.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;1. &lt;code&gt;npx&lt;&#x2F;code&gt;, for anyone.&lt;&#x2F;strong&gt; The zero-commitment path:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;bash&quot;&gt;npx skills@latest add parallaxisjones&#x2F;skills
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Pick the skills and agents you want, and you&#x27;re set. Great for trying them on a machine that isn&#x27;t mine.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;2. A symlink script, for a local clone.&lt;&#x2F;strong&gt; If I&#x27;ve cloned the repo, &lt;code&gt;link-skills.sh&lt;&#x2F;code&gt; symlinks every &lt;code&gt;SKILL.md&lt;&#x2F;code&gt; into &lt;code&gt;~&#x2F;.claude&#x2F;skills&#x2F;&lt;&#x2F;code&gt; so the CLI picks them up directly. It&#x27;s idempotent — re-run after pulling — and it specifically guards against the footgun where &lt;code&gt;~&#x2F;.claude&#x2F;skills&lt;&#x2F;code&gt; is &lt;em&gt;itself&lt;&#x2F;em&gt; a symlink back into the repo, which would write per-skill symlinks into my own working copy:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;bash&quot;&gt;if [ -L &amp;quot;$DEST&amp;quot; ]; then
  resolved=&amp;quot;$(readlink -f &amp;quot;$DEST&amp;quot;)&amp;quot;
  case &amp;quot;$resolved&amp;quot; in
    &amp;quot;$REPO&amp;quot;&#x2F;*) echo &amp;quot;refusing to pollute the repo&amp;quot;; exit 1 ;;
  esac
fi
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That defensive check is the kind of thing you write &lt;em&gt;after&lt;&#x2F;em&gt; the first time a script eats its own tail.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;3. Nix, for my actual fleet.&lt;&#x2F;strong&gt; This is the one that matters. My skills repo is a flake input in my &lt;a href=&quot;&#x2F;posts&#x2F;nix-fleet-one-flake&#x2F;&quot;&gt;system config&lt;&#x2F;a&gt;, and a home-manager module materializes them declaratively on every machine.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-nix-wiring&quot;&gt;The Nix wiring&lt;&#x2F;h2&gt;
&lt;p&gt;Two inputs do the work — my skills repo, and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Kyure-A&#x2F;agent-skills-nix&quot;&gt;&lt;code&gt;agent-skills-nix&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, a home-manager module that knows how to turn a skills repo into materialized files:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;nix&quot;&gt;# flake.nix
inputs = {
  agent-skills-nix = {
    url = &amp;quot;github:Kyure-A&#x2F;agent-skills-nix&amp;quot;;
    inputs.nixpkgs.follows = &amp;quot;nixpkgs&amp;quot;;
    inputs.home-manager.follows = &amp;quot;home-manager&amp;quot;;
  };
  my-skills.url = &amp;quot;github:parallaxisjones&#x2F;skills&amp;quot;;
};
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then in home-manager I point the module at my repo, filter to the buckets I want live, and enable everything:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;nix&quot;&gt;agent-skills = {
  enable = true;
  sources.mine = {
    input  = &amp;quot;my-skills&amp;quot;;
    subdir = &amp;quot;skills&amp;quot;;
    filter.nameRegex = &amp;quot;^(engineering|misc|personal|productivity)&#x2F;.*&amp;quot;;
  };
  skills.enableAll = true;
  targets.claude.enable = true;
};
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s the whole thing. On &lt;code&gt;nixos-rebuild switch&lt;&#x2F;code&gt; (or &lt;code&gt;darwin-rebuild&lt;&#x2F;code&gt; on the Mac), every &lt;code&gt;SKILL.md&lt;&#x2F;code&gt; matching the regex gets written into Claude&#x27;s skills directory. The &lt;code&gt;deprecated&#x2F;&lt;&#x2F;code&gt; bucket is excluded by the filter, so retiring a skill is a one-line regex change, not a manual delete on five machines.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-bother-what-nix-actually-buys-here&quot;&gt;Why bother — what Nix actually buys here&lt;&#x2F;h2&gt;
&lt;p&gt;You could argue the symlink script is simpler, and for one machine it is. The fleet is where Nix earns it:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pinning.&lt;&#x2F;strong&gt; &lt;code&gt;flake.lock&lt;&#x2F;code&gt; records the exact skills commit each machine is on. &quot;Which version of my &lt;code&gt;triage&lt;&#x2F;code&gt; skill is the laptop running?&quot; has an answer, not a shrug.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Parity from scratch.&lt;&#x2F;strong&gt; A fresh machine reaches full skill parity as a side effect of building its system config. There&#x27;s no separate &quot;and don&#x27;t forget to install your skills&quot; step — it&#x27;s the same &lt;code&gt;switch&lt;&#x2F;code&gt; that installs my shell and my packages.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Atomic rollback.&lt;&#x2F;strong&gt; If a skill edit makes the agent behave worse, rolling back the generation rolls back the skills with it.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;There&#x27;s a framing I lean on for deciding what to manage this way — think of three zones. &lt;em&gt;Zone 1&lt;&#x2F;em&gt; is stable, declarative config (the home-manager module enabling skills). &lt;em&gt;Zone 3&lt;&#x2F;em&gt; is runtime state that should never touch Nix (per-conversation agent memory). Skills sit in &lt;strong&gt;Zone 2&lt;&#x2F;strong&gt;: authored content, edited as plain files in their repo, but &lt;em&gt;materialized&lt;&#x2F;em&gt; onto each machine by Nix. Nix owns where they land and which version; I own what they say.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-honest-caveat&quot;&gt;The honest caveat&lt;&#x2F;h2&gt;
&lt;p&gt;Nix doesn&#x27;t validate skill &lt;em&gt;content&lt;&#x2F;em&gt; — a &lt;code&gt;SKILL.md&lt;&#x2F;code&gt; with a bad &lt;code&gt;description&lt;&#x2F;code&gt; will deploy just as reliably as a good one. This pipeline guarantees distribution and pinning, not quality. The quality comes from treating skills like code: review them, iterate on the descriptions when the agent picks the wrong one, and delete the ones that stop earning their place (that&#x27;s what &lt;code&gt;deprecated&#x2F;&lt;&#x2F;code&gt; is for).&lt;&#x2F;p&gt;
&lt;p&gt;But that&#x27;s the right division of labor. Writing a good procedure is human work. Making sure that procedure is &lt;em&gt;identically present on every machine I touch&lt;&#x2F;em&gt; is exactly the kind of toil Nix exists to kill. Treat your agent&#x27;s skills as part of your declarative system, not as dotfiles you sync by hand.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;— Parker Jones, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;parkerjones.dev&quot;&gt;parkerjones.dev&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
