{"slug": "your-ai-agent-skills-are-an-unversioned-dependency", "title": "Your AI agent skills are an unversioned dependency", "summary": "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.", "body_md": "A skill is a prompt that lands in a model's system context. Most teams install\n\nthem the way we installed libraries in 2009: clone a repo, copy a folder, hope\n\nnobody touches it. Then the folder drifts and the agent quietly loads something\n\nnobody reviewed.\n\nI maintain Skillporter, a package manager for AI agent skills. This is the design\n\nproblem behind it, not a feature tour.\n\nEvery harness reads skills from a different directory:\n\n```\nClaude Code        .claude/skills\nOpenAI Codex       .agents/skills\nCursor             .agents/skills\nGitHub Copilot     .github/skills\nWindsurf           .windsurf/skills\nCline              .cline/skills\nOpenCode           .opencode/skills\nHermes Agent       $HERMES_HOME/skills\n```\n\nEight harnesses share .agents/skills as their primary project path, and six more\n\nread it as a documented compatibility path. That directory is the trap. Remove a\n\nskill to clean up Cursor and you have just broken Codex, Gemini CLI, Zed, OpenHands\n\nand Goose for the rest of the team.\n\nTwo other approaches fail in predictable ways. Symlinks break inside Docker\n\nbuilds, git worktrees and Windows checkouts. Copy scripts drift, because nothing\n\nrecords what the copy was supposed to be.\n\nThe package manager model maps cleanly:\n\nsnapshots, so rollback is possible after a bad upstream change\n\nuvx skillporter add anthropics/skills --skill pdf --harness all\n\nReal output from a clean workspace:\n\n```\n+ Installed pdf across 19 harness(es) (+12 created, ~0 updated, =7 deduplicated/unchanged)\n  + Claude Code          created    (copy via .claude/skills)\n  + GitHub Copilot       created    (copy via .github/skills)\n  + Hermes Agent         created    (copy via .hermes/skills)\n```\n\nTwelve directories, seven shared paths deduplicated. That tally is the whole\n\nargument for a resolver: a copy script would have written nineteen copies and\n\ncalled it success.\n\nOnce a skill is pinned, the interesting question stops being what is installed and\n\nbecomes what changed.\n\n```\nskillporter sync          # reconcile workspace with manifest, write the lock\nskillporter lock --check  # exit 1 on drift, exit 2 if the check could not run\nskillporter outdated      # compare version, commit and tree hash upstream\nskillporter rollback pdf  # restore the last snapshot\n```\n\nThe exit code split matters more than it looks. A pipeline needs to distinguish a\n\nfailed check from a check that never ran, otherwise a broken tool reads as a pass.\n\nA static scanner finds known dangerous patterns: curl piped to shell, base64\n\npayloads, credential reads, risky permission requests. It reports finding codes\n\nand a risk score, and it never executes skill code during install.\n\nWhat it cannot do is catch novel prompt injection written in ordinary prose. A URL\n\ncan serve harmless content when inspected and something else when the agent fetches\n\nit later. If a vendor tells you their scanner proves a skill is safe at runtime,\n\nthey are selling you certainty they do not have. The docs for this one say so\n\nexplicitly, which is the main reason I trust the rest of them.\n\nThe MCP mode is worth a paragraph. An MCP server is designed to be called by a\n\nmodel, which means its arguments may be hostile. So the server exposes detect,\n\ndiagnose, scan, inspect and matrix, and denies add, install, sync and remove unless\n\nstarted with --allow-writes. The workspace root comes from a flag or an environment\n\nvariable, not from tool arguments, and traversal, escaping symlinks and UNC paths\n\nare rejected.\n\nNot a marketplace. Not a sandbox. It does not run skills, and it cannot tell you\n\nwhat a skill will do when a model follows it. What it does is make the set of\n\nskills deterministic, visible and reversible.\n\nv3.2.0, MIT, Python 3.9+, zero runtime dependencies, single maintainer. Nineteen\n\nadapters, of which 1 is runtime verified, 3 are integration tested and 15 are\n\nfixture tested. The docs state the tier per harness because pretending otherwise\n\nwould be the fastest way to lose the trust of the people who hit the bugs.\n\nInstall, if you want to try it in a throwaway repo:\n\n```\nuvx skillporter demo\nuvx skillporter diagnose .\n```\n\nSite: [https://skillporter.dev](https://skillporter.dev)\n\nRepo: [https://github.com/Shanmukh-l33t/skillporter](https://github.com/Shanmukh-l33t/skillporter)\n\nIf a harness path is wrong on your machine, that is the bug report I want most.", "url": "https://wpnews.pro/news/your-ai-agent-skills-are-an-unversioned-dependency", "canonical_source": "https://dev.to/shanmukhdheekonda/your-ai-agent-skills-are-an-unversioned-dependency-i8g", "published_at": "2026-11-15 13:45:58+00:00", "updated_at": "2026-11-15 13:49:16.450955+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "agent-protocols", "ai-safety"], "entities": ["Skillporter", "Claude Code", "OpenAI Codex", "Cursor", "GitHub Copilot", "Windsurf", "Cline", "OpenCode"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/your-ai-agent-skills-are-an-unversioned-dependency", "markdown": "https://wpnews.pro/news/your-ai-agent-skills-are-an-unversioned-dependency.md", "text": "https://wpnews.pro/news/your-ai-agent-skills-are-an-unversioned-dependency.txt", "jsonld": "https://wpnews.pro/news/your-ai-agent-skills-are-an-unversioned-dependency.jsonld"}}