Skip to content
Abdul Moiz Shahzad

Case study · Ai-Agent-Skills · Updated

Building a cross-agent skill installer

I’m Abdul Moiz Shahzad, and Ai-Agent-Skills is the skill installer and package manager for AI coding agents that I launched on December 17, 2025 and still maintain. One command installs, updates, and curates reusable agent skills across 12+ runtimes. This page explains the problem it solves, how a skill gets from a repository into an agent, one design tradeoff, what happens when an install fails, and what the adoption numbers do and do not establish.

The problem before a shared installer

A skill is a folder with a SKILL.md in it. In late 2025 that folder had to be copied by hand into every agent you used, and every agent kept its own directory and its own idea of what belonged there. Installing the same skill into two runtimes meant two copies, two versions to keep straight, and no record of which repository either copy came from. When the upstream author fixed something, you found out by noticing your copy was wrong.

I launched the installer on December 17, 2025. The README still carries the sentence I wrote at the time: it shipped before skills.sh existed and before the ecosystem had a clear default universal installer. That is a fact about timing, nothing more. The ecosystem has since grown several installers, and the README now says plainly where mine fits: use skills.sh for the broad ecosystem, use this one when you want a smaller library with shelves, provenance, and notes.

How a skill gets from a repository to a runtime

The library holds two kinds of entries. A house copy is a local folder under skills/<name>/; it ships inside the npm package, installs offline, and installs fast. A cataloged upstream pick is metadata in skills.jsonwith no local folder: which repository, which skill, which shelf it sits on, and why it earned a place. It installs from the source repository when you ask for it. On the day I read the README for this page, the library carried 17 house copies and 123 cataloged upstream entries drawn from 28 source repositories, the two largest being Anthropic’s and OpenAI’s own skill repositories.

Entries sit on six shelves (frontend, backend, mobile, workflow, agent engineering, marketing) and in smaller collections such as a starter stack or the Swift pack. An install resolves the name against the library, or against a repository you name directly, then writes to a destination. The default global destination is ~/.claude/skills/; the project destination, chosen with -p, is .agents/skills/, the directory most runtimes now read. Agent-specific targets remain available through --agent for 11 runtimes, from Claude Code and Cursor to Goose and Letta, plus a project target.

# one skill from the library, to the default global target
npx ai-agent-skills install frontend-design

# the same skill into this project's .agents/skills/
npx ai-agent-skills install frontend-design -p

# a skill straight from any repository, previewed first
npx ai-agent-skills install openai/skills --list
npx ai-agent-skills install openai/skills@linear --dry-run

# keep installed skills current
npx ai-agent-skills sync
npx ai-agent-skills check

The same binary is the curation tool. init-library creates a managed workspace, add, catalog, and vendor place entries on shelves, and build-docs regenerates the README tables from the manifest, so the documentation cannot drift from skills.json. Every mutation takes --area, --branch, and --why. The note is a required field, and it is the part I would keep if I had to cut everything else.

One tradeoff: a catalog entry versus a copy

Copying a skill into the library is the obvious design, and it is wrong as a default. A copy installs offline and ships with the package, and it also goes stale the day its author changes a line. Mirroring the whole ecosystem would have turned the library into a fork of everyone else’s work with my name on the folder. So the default is a catalog entry: the skill stays upstream, the library records where it lives and why it belongs, and the install fetches it fresh. A house copy is the exception, taken when I want to edit a skill or need it to work with no network.

The cost is real. A catalog entry trusts the upstream to still be there and to still be the thing I shelved. The README sentence that summarises the choice is four words long: upstream work stays upstream. The 17 to 123 ratio above is that sentence enforced.

What happens when an install fails

An installer that writes half a set of files and stops is worse than one that never ran, because the agent will read the half. The tool exposes --dry-run so a destination can be previewed before anything is written, and doctor, check, and validate for inspecting what is installed and whether a skill folder is well formed. When a bulk import meets a name it cannot place, the README documents the two behaviours I chose: invalid private-only names are skipped and reported, and low-confidence imports fall back to the workflow shelf with a needs-curation label, where curate review lists them for a human decision.

Testing follows the same idea. npm test covers CLI behaviour, schema rules, routing, and local install flows. npm run test:live runs with no mocks at all: it clones the real upstream repositories, captures their raw SKILL.md frontmatter and file manifests, runs real install, sync, and uninstall flows in isolated temporary homes and projects, drives the terminal UI through a real pseudo-terminal, and writes a report to tmp/live-test-report.json. For an installer, the filesystem and the upstream are the product, and a mock of either tests the mock.

One limit I will state rather than imply: provenance here is recorded, not proven. The library knows which repository a skill came from. It does not verify signatures, and nothing in the tool should be read as a security guarantee about upstream content.

Maintenance and adoption, with dates

The repository has 1,137 stars and 131 forks, and the package has 20.8K npm downloads since 2025-12-17, verified 2026-09. Downloads are downloads: they count installs of the package, not people using it, and stars measure interest, not quality. The GitHub release line ran v2.0.1 and v3.0.0 (2026-03-18), v4.0.0 (2026-03-27), v4.2.0 (2026-04-11), and v4.3.1 (2026-05-03); npm sits at 4.3.2, published 2026-05-05, with 39 versions published since launch. Five community pull requests were open on 2026-09-05, and reviewing them is part of the maintenance.

One independent record exists outside anything I control: Trendshift listed the repository as the third JavaScript repository of the day and the twenty-second of the week in December 2025. That is context for the December numbers, and it is not an endorsement of the code.

Limits and what comes next

The npm description and the README lead still introduce the package as a curated library first, wording from a period when the library was the newer half of the story. The category I settled on in August 2026 is the one at the top of this page: a universal skill installer and package manager, with a curated library inside it. Bringing the package metadata in line with that is on my list, and until it lands the two surfaces disagree.

Refreshing is still a command you run. sync brings installed skills up to date with their upstream, and nothing updates by itself, which is the behaviour I want for files an agent reads before acting, and also the behaviour that lets a skill quietly age on a machine nobody runs check on.

Written by Abdul Moiz Shahzad, AI Engineer, Toronto. Published . More about me and how to reach me on the experience page.

© 2026 Abdul Moiz Shahzad.