Your AI agent skills are an unversioned dependency A developer released Skillporter v3.2.0, an MIT-licensed Python package manager that installs, pins, and rolls back AI agent skills across 19 harnesses, deduplicating shared paths like .agents/skills that otherwise cause drift and breakage. The tool writes a lockfile, distinguishes drift (exit 1) from a failed check (exit 2), snapshots installs for rollback, and runs a static scanner that flags known dangerous patterns without executing skill code. Its MCP server exposes read-only detect, diagnose, scan, inspect and matrix tools and denies write operations unless started with --allow-writes. A skill is a prompt that lands in a model's system context. Most teams install them the way we installed libraries in 2009: clone a repo, copy a folder, hope nobody touches it. Then the folder drifts and the agent quietly loads something nobody reviewed. I maintain Skillporter, a package manager for AI agent skills. This is the design problem behind it, not a feature tour. Every harness reads skills from a different directory: Claude Code .claude/skills OpenAI Codex .agents/skills Cursor .agents/skills GitHub Copilot .github/skills Windsurf .windsurf/skills Cline .cline/skills OpenCode .opencode/skills Hermes Agent $HERMES HOME/skills Eight harnesses share .agents/skills as their primary project path, and six more read it as a documented compatibility path. That directory is the trap. Remove a skill to clean up Cursor and you have just broken Codex, Gemini CLI, Zed, OpenHands and Goose for the rest of the team. Two other approaches fail in predictable ways. Symlinks break inside Docker builds, git worktrees and Windows checkouts. Copy scripts drift, because nothing records what the copy was supposed to be. The package manager model maps cleanly: snapshots, so rollback is possible after a bad upstream change uvx skillporter add anthropics/skills --skill pdf --harness all Real output from a clean workspace: + Installed pdf across 19 harness es +12 created, ~0 updated, =7 deduplicated/unchanged + Claude Code created copy via .claude/skills + GitHub Copilot created copy via .github/skills + Hermes Agent created copy via .hermes/skills Twelve directories, seven shared paths deduplicated. That tally is the whole argument for a resolver: a copy script would have written nineteen copies and called it success. Once a skill is pinned, the interesting question stops being what is installed and becomes what changed. skillporter sync reconcile workspace with manifest, write the lock skillporter lock --check exit 1 on drift, exit 2 if the check could not run skillporter outdated compare version, commit and tree hash upstream skillporter rollback pdf restore the last snapshot The exit code split matters more than it looks. A pipeline needs to distinguish a failed check from a check that never ran, otherwise a broken tool reads as a pass. A static scanner finds known dangerous patterns: curl piped to shell, base64 payloads, credential reads, risky permission requests. It reports finding codes and a risk score, and it never executes skill code during install. What it cannot do is catch novel prompt injection written in ordinary prose. A URL can serve harmless content when inspected and something else when the agent fetches it later. If a vendor tells you their scanner proves a skill is safe at runtime, they are selling you certainty they do not have. The docs for this one say so explicitly, which is the main reason I trust the rest of them. The MCP mode is worth a paragraph. An MCP server is designed to be called by a model, which means its arguments may be hostile. So the server exposes detect, diagnose, scan, inspect and matrix, and denies add, install, sync and remove unless started with --allow-writes. The workspace root comes from a flag or an environment variable, not from tool arguments, and traversal, escaping symlinks and UNC paths are rejected. Not a marketplace. Not a sandbox. It does not run skills, and it cannot tell you what a skill will do when a model follows it. What it does is make the set of skills deterministic, visible and reversible. v3.2.0, MIT, Python 3.9+, zero runtime dependencies, single maintainer. Nineteen adapters, of which 1 is runtime verified, 3 are integration tested and 15 are fixture tested. The docs state the tier per harness because pretending otherwise would be the fastest way to lose the trust of the people who hit the bugs. Install, if you want to try it in a throwaway repo: uvx skillporter demo uvx skillporter diagnose . Site: https://skillporter.dev https://skillporter.dev Repo: https://github.com/Shanmukh-l33t/skillporter https://github.com/Shanmukh-l33t/skillporter If a harness path is wrong on your machine, that is the bug report I want most.