{"slug": "re-use-your-skills-across-all-your-coding-agents", "title": "Re-use your skills across all your coding agents", "summary": "Developer Greg Herlein released skills-mapper (sm), a Go binary that syncs a user's skill library from git into the per-agent directories used by Claude Code, Copilot, hax, pi, and oh-my-pi, eliminating the need to manually copy files. The tool addresses the fragmentation of skill storage across five agents, each with its own global and project-level skill directories, while preserving the portable SKILL.md format. Herlein, who maintains multiple coding agents to evaluate their harnesses, argues that packaging formats create walls between ecosystems, and sm provides a simple solution.", "body_md": "I use more than one coding agent. Not because I’m indecisive — because I’m testing different agents - and learning how they work - and the field is moving fast. Seems like a new one every week! But every single one of them wants skills in its own directory, and I got tired of `cp -r`\n\nand stale copies. So I wrote a tool.\n\nIt’s called [ sm](https://github.com/gherlein/sm) — skills-mapper. It’s a small Go binary. It does exactly one thing: it takes your library of skills, keeps it fresh from git, and puts it where every agent you use expects to find it.\n\nThat’s it. That’s the whole tool. Let me explain why that’s worth writing.\n\n## The Problem: The Files Are Portable, The Location Isn’t\n\nA skill is not a complicated thing. It’s a directory with a `SKILL.md`\n\nin it — YAML frontmatter with a required `name`\n\n, an optional `description`\n\n, then markdown. That’s the standard. Any agent that reads the format can use the file.\n\nSo the *content* is completely portable. Wonderfully so. You can hand a skill directory to Claude Code, to Copilot, to `pi`\n\n, to a thing you wrote yourself last Tuesday, and they all understand it.\n\nWhat is **not** portable is where it lives:\n\n| Agent | Global directory |\n|---|---|\n`claude-code` |\n`~/.claude/skills` |\n`copilot` |\n`~/.copilot/skills` |\n`hax` |\n`~/.config/hax/skills` |\n`pi` |\n`~/.pi-go/skills` |\n`oh-my-pi` |\n`~/.config/agents/skills` |\n\nFive agents, five directories, five slightly different opinions about where your stuff goes. And that’s just the global scope — each of them also has a *project* directory (`.claude/skills`\n\n, `.github/skills`\n\n, `.agents/skills`\n\n, and so on) for repo-local skills.\n\nNow layer packaging on top of that. If Claude Code is all you use, Claude Code plugins are genuinely a great answer — I’ve [built and shipped one](https://blog.herlein.com/post/unifi-fixed-hosts-skill/) and I’d recommend them. But a Claude Code plugin does absolutely nothing for Copilot. Or `hax`\n\n. Or the agent you’re writing yourself.\n\nEvery ecosystem grows its own packaging, and every packaging format is a wall.\n\n## Why I Suddenly Have Five Agents\n\nThis wasn’t a hypothetical problem. I went looking for it.\n\nBack in March I wrote that [tooling is the new model](https://blog.herlein.com/post/dot-agents/) — the models are good enough, the differentiator is the harness. If I actually believe that, then I should be trying harnesses. Which isn’t just the skills - it’s also the tool calling, and importanly, how the tools are called. So I set out to run new ones alongside Claude Code and `pi`\n\n, and they are each interesting for completely different reasons:\n\n** hax** — a terminal-native coding agent written in\n\n**C**. A single native binary, small dependency set, starts instantly, uses almost no memory. It auto-discovers llama.cpp and other local servers without you configuring anything. It deliberately has\n\n*no*plugin marketplace,\n\n*no*IDE integration,\n\n*no*permission prompts. It streams markdown and tool results while respecting your terminal scrollback, and it gives you an inspectable transcript so you can see exactly what got sent to the model. It’s Unix philosophy applied to agents, and if you’re running local models on constrained hardware it’s a serious option.\n\n** oh-my-pi** (\n\n`omp`\n\n) — a fork of Mario Zechner’s `pi`\n\n, about 80,000 lines of Rust and TypeScript. This one goes the *opposite*direction from hax: it’s “a coding agent with the IDE wired in.” Full LSP support so it actually understands code structure instead of grepping at it. Real DAP debugging — it drives\n\n`lldb`\n\n, `dlv`\n\n, `debugpy`\n\nrather than sprinkling print statements. 31 built-in tools, 60+ providers, subagent coordination with schema-validated results. It treats coding as an *IDE*problem instead of a text problem, which is a thesis I find hard to argue with. It’s a “batteries included” version of pi.\n\n** fx** — a tiny native agent written in\n\n**Zig**. 6.39 MB. Cold start in 10 microseconds. Shell-like sparse output instead of a heavy TUI, minimal system prompts to keep token cost down, model and provider agnostic, and it compiles to WebAssembly so you can embed it in a browser with pluggable networking. It bills itself as being for research and for embedding in larger systems, and that’s the part I’m poking at.\n\nC, Rust, Zig, TypeScript, and one I dabbled with in go. Nobody is converging on anything, and I think that’s *healthy*. Different constraints produce different tools. I want to run all of them against the same problems and see what actually holds up. Oh, and then compare it to Claude Code.\n\nBut here’s the thing — I can’t do a fair comparison if each agent has a different, drifted, hand-copied set of my skills. The agent is the variable I’m testing. The skills need to be the constant.\n\n## The Solution: Placement, Not Transformation\n\nThe open standard for distributing skills already exists and it’s boring: **a git repo of skill directories**. Nothing agent-specific. Clone it, and the files are right there.\n\nWhich means the only real problem left is the last mile — getting one library into every agent’s expected location and keeping it current.\n\nSo that’s all `sm`\n\ndoes. You write a manifest declaring your *sources* and your *agents*:\n\n```\n[skills]\n# A git repo of SKILL.md directories\ngherlein = { git = \"https://github.com/gherlein/skills\", ref = \"main\" }\n\n# Only a subdirectory of a repo\ntools    = { git = \"git@github.com:you/monorepo.git\", ref = \"v1.2.0\", subdir = \"skills\" }\n\n# A local dev checkout — symlinked, never cloned\nlocal    = { path = \"~/dev/my-skills\" }\n\n[agents]\nclaude-code = true\ncopilot     = true\nhax         = true\npi          = true\noh-my-pi    = true\n\n[options]\nprefix_on_collision = false\n```\n\nThen you run `sm sync`\n\nand it does the boring, correct thing.\n\nThree commands is the whole workflow:\n\n```\nsm init                 # write the starter manifest\n$EDITOR ~/.config/skills-mapper/skills.toml\nsm sync                 # fetch sources, place skills\n```\n\n## What `sync`\n\nActually Does\n\nFive steps, in order:\n\n``` php\nflowchart LR\n    F[freshen<br/>clone / git pull sources] --> D[discover<br/>find SKILL.md dirs]\n    D --> R[resolve<br/>map source to target names]\n    R --> L[link<br/>symlink into each agent]\n    L --> C[reconcile<br/>remove stale links sm created]\n```\n\n**freshen**— clone each git source, or`git pull`\n\nif it’s already cached, and prune caches that aren’t in the manifest anymore. Skipped entirely on`--dry-run`\n\n.**discover**— walk each source looking for directories that contain a standard-compliant`SKILL.md`\n\n.`.git`\n\n,`node_modules`\n\n,`vendor`\n\n,`dist`\n\n,`build`\n\nand friends get ignored.**resolve**— compute the`source → target`\n\nname mapping.**link**— whole-directory symlinks into each enabled agent’s skills directory.** reconcile**— remove links`sm`\n\npreviously made that nobody wants anymore.\n\nNote the word **symlink**, repeatedly. `sm`\n\nnever copies and it never transforms. There is one canonical copy of every skill, in the clone cache, and every agent points at it. Update the source repo, run `sync`\n\n, and all five agents get the new version simultaneously because they were all looking at the same file the whole time.\n\nThat’s the entire reason drift stops being possible.\n\n## The Opinionated Bits\n\nA tool this small only earns its keep if it’s opinionated about the right things. Three decisions I’d defend:\n\n**No plugin support. On purpose.** This one surprises people. `sm`\n\nwill not consume a Claude Code plugin as a source. The reason is that the entire point of the tool is that skills follow *one* standard every agent reads. If I let you bridge Claude plugins in, Claude users get to consume skills Copilot users can’t — and I’ve just re-created the exact drift the tool exists to kill. Not doing it.\n\nThere’s a practical version of this trap too, and it bites people. Claude Code caches plugins under a **versioned** path: `~/.claude/plugins/cache/<marketplace>/<plugin>/<version>/skills/`\n\n. If you point a source at that path, it works great right up until Claude Code updates the plugin — at which point it installs into a *new* directory and your manifest keeps happily linking the stale one. Silently. Forever. Point at the plugin’s source repo instead and use `subdir`\n\n.\n\n**Duplicate skill names fail loud.** If two sources both ship a skill called `debugging`\n\n, `sm`\n\nstops and tells you. It does not pick a winner, and it does not quietly alphabetize its way into a decision you’ll discover three weeks later when the wrong skill fires. If you actually want both, set `prefix_on_collision = true`\n\nand be explicit about it.\n\nSilent success is the worst failure mode in tooling. A tool that guesses is a tool that lies to you.\n\n**It only ever touches links it made.** There’s a state file at `~/.local/share/skills-mapper/state.json`\n\ntracking every link `sm`\n\ncreated. If `sm`\n\nfinds a file in an agent’s skills directory that it didn’t put there, it skips it with a warning and **never** clobbers it. Your hand-written skills are safe. I have a healthy paranoia about tools that write into `~/.claude`\n\nunsupervised, and I wasn’t about to ship one.\n\n## Scope: Global and Project\n\nTwo scopes. **Global** is the manifest at `~/.config/skills-mapper/skills.toml`\n\n, installing into each agent’s home directory. **Project** is a `skills.toml`\n\nat your repo root, installing into the repo’s per-project agent directories.\n\nScope auto-detects — `sm`\n\nwalks up from your current directory looking for a `skills.toml`\n\n, stopping before `$HOME`\n\n. Find one, you’re in project scope. Don’t, you’re global. Force it with `--global`\n\nor `--project`\n\nwhen you need to.\n\nThe project scope is the one I’m most interested in long-term. A repo that ships its own `skills.toml`\n\nteaches *any* agent that clones it how to work on that codebase. That’s a much better story than a README section titled “if you use Claude Code, do this.”\n\n## What Doesn’t Work Yet\n\nI built this over the last couple of days and the commit log says “interim commit” more often than I’d like. Being honest about the state of it:\n\n`add`\n\n, `remove`\n\n, `update`\n\n, and `link`\n\nare **stubs**. They return a “not implemented” error. Right now you edit `skills.toml`\n\nby hand and run `sm sync`\n\n. That’s genuinely fine for how I use it — the manifest is six lines and I touch it maybe once a month — but it’s not done done.\n\nWhat *does* work: `init`\n\n, `sync`\n\n(with `--dry-run`\n\nand `-v`\n\n), and `list`\n\n. Which is the actual workflow. The rest is convenience.\n\nThe agent registry is also deliberately extensible — Codex, Amp, and OpenCode are the obvious next entries. Adding one is a table entry, not a refactor. That was the point.\n\n## Why Go, Again\n\nBecause of course it’s Go. Single static binary, no runtime to install, no `npm i -g`\n\nthat fails E404 on some unpublished internal workspace package. (Ask me how I know. The prior-art tool in this space couldn’t be installed at all — unpublished scoped packages, a private registry token baked into its install script, and a TOML grammar living in a package that wasn’t checked out. Three separate installability failures before you get to whether the tool is any good.)\n\nA tool whose entire job is “make setup easy across five agents” has no business being hard to install. `make build`\n\n, one binary, done. I’ve made [this argument](https://blog.herlein.com/post/why-go-for-robotics/) before in a different context and I’ll keep making it.\n\nPlus… I love go. ‘Nuff said.\n\n## Conclusion\n\n`sm`\n\nis not clever. It’s a symlink manager with a manifest and a state file. The clever part — if there is one — is refusing to do more than that.\n\nThe bet underneath it is simple: skills as plain git repos of `SKILL.md`\n\ndirectories is the standard that survives, because it’s the only one that doesn’t require every agent author to agree on anything beyond a file format they already agree on. Everything above that layer is packaging, and packaging is where lock-in lives.\n\nI’ll report back once I’ve run hax, oh-my-pi, and fx against real work for a while — I have opinions forming about all three and they’re not the opinions I expected to have. But that’s a topic for another day.\n\nIf you’re running more than one coding agent, [go grab it](https://github.com/gherlein/sm). It’s MIT, it’s small, and the whole thing is readable in an afternoon. Tell me what agent I should add to the registry.\n\nIf this is useful to you — or if you think the no-plugins stance is wrong and want to tell me why — drop me a note on LinkedIn: [linkedin.com/in/gherlein](https://www.linkedin.com/in/gherlein/).", "url": "https://wpnews.pro/news/re-use-your-skills-across-all-your-coding-agents", "canonical_source": "https://blog.herlein.com/post/skills-mapper-sm/", "published_at": "2026-08-23 08:00:01+00:00", "updated_at": "2026-08-23 18:13:20.505994+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["Greg Herlein", "skills-mapper", "Claude Code", "Copilot", "hax", "pi", "oh-my-pi"], "alternates": {"html": "https://wpnews.pro/news/re-use-your-skills-across-all-your-coding-agents", "markdown": "https://wpnews.pro/news/re-use-your-skills-across-all-your-coding-agents.md", "text": "https://wpnews.pro/news/re-use-your-skills-across-all-your-coding-agents.txt", "jsonld": "https://wpnews.pro/news/re-use-your-skills-across-all-your-coding-agents.jsonld"}}