# I Built a TUI Package Manager for AI Agent Skills — Here's Why

If you've been using AI coding agents for a while, you've probably collected a pile of `SKILL.md` files scattered across different folders. One for Claude Code, another for Cursor, maybe a third sitting in a GitHub repo you keep re-cloning every time you set up a new machine.

I got tired of that. So I built **skmp** — a full-screen TUI package manager for AI agent skills, inspired by how Homebrew and npm handle software packages, but purpose-built for the chaotic multi-harness world of agentic AI tools.

* * *

## The Problem It Solves

Modern AI coding agents — Claude Code, Codex, Cursor, Antigravity, pi, OpenCode — all support skills or custom instructions. The problem is that each tool expects them in a different directory, with no shared standard.

You end up with something like this:

*   `~/.claude/skills/` for Claude Code
    
*   `~/.codex/skills/` for Codex
    
*   `~/.cursor/skills/` for Cursor
    
*   `~/.agents/skills/` for pi
    
*   `~/.gemini/antigravity-ide/skills/` for Antigravity
    

Every time you install a new skill, you either manually copy it into each folder or you forget and wonder why it isn't available in half your tools.

skmp fixes this with a single store and symlinks:

```plaintext
~/.skmp/skills/         ← downloaded once, skmp owns this
     ↓ symlinked to
~/.agents/skills/
~/.claude/skills/
~/.codex/skills/
~/.cursor/skills/
~/.gemini/antigravity-ide/skills/
```

Install a skill once. It appears everywhere.

* * *

## What It Looks Like

![](https://cdn.hashnode.com/uploads/covers/69d007f5e466e2b7625cd1df/06ee168a-9fbd-488b-93f8-1847ac393cb4.png align="center")

The interface is a split-pane terminal UI built with [Bubble Tea](https://github.com/charmbracelet/bubbletea) and [Lipgloss](https://github.com/charmbracelet/lipgloss). On the left, a scrollable list of skills. On the right, a detail pane with the description, author, version, and tags. Four tabs let you switch between all skills, bundles, your installed skills, and your installed bundles.

Navigation is fully keyboard-driven in a vim-ish style:

| Key | Action |
| --- | --- |
| `j` / `k` | move down / up |
| `K` / `J` | jump to top / bottom |
| `tab` | focus detail pane |
| `i` / `x` | install / remove |
| `/` | search |

* * *

## Install in Seconds

```bash
npm install -g skmp-cli
```

Or via Homebrew:

```bash
brew tap Nitesh000/tap
brew install skmp
```

Or grab a binary directly from the [Releases page](https://github.com/Nitesh000/skmp/releases).

Once installed, just run `skmp`. It fetches the registry on first launch, caches it for 24 hours, and you're browsing.

* * *

## The Registry Model

This is the part I'm most proud of architecturally. The registry is just a `index.json` file living in the GitHub repo, served directly from `raw.githubusercontent.com`. No CDN middleman, no server infrastructure to maintain.

Each entry is metadata only:

```json
{
  "name": "caveman",
  "description": "Ultra-compressed communication mode. Cuts token usage ~75%.",
  "author": "yuu",
  "version": "1.0.0",
  "source": "https://raw.githubusercontent.com/...",
  "harnesses": ["claude-code", "pi", "codex"],
  "tags": ["communication", "tokens"]
}
```

The actual skill files live in their author's own repository. skmp only stores the URL. This means:

*   **Authors own their skills.** You push an update to your repo, all users get it on next install.
    
*   **The registry is just an index.** No assets, no binary blobs, no storage costs.
    
*   **Contributing is a one-PR process.** Add your entry to `registry/index.json`, open a PR, done.
    

* * *

## How Search Works

Fuzzy full-text search is powered by [Bleve](https://blevesearch.com/), an embedded Go search library. The tricky part was handling skill names that contain hyphens and dots — by default, most text analyzers tokenize `write-a-skill` into three separate tokens (`write`, `a`, `skill`), which breaks exact name queries.

The fix was a custom Bleve analyzer using a `keyword` tokenizer (treats the whole string as one token) plus a `to_lower` filter. This means `write-a-skill` is indexed and searchable as a single unit. Hyphenated names, versioned names like `tdd-v2`, multi-word names — all work correctly.

* * *

## The Harness Abstraction

Each AI tool skmp supports is called a **harness**. Harnesses are detected automatically at runtime by checking if a known binary is present on your `$PATH`.

| Harness | Binary Detected | Skills Path |
| --- | --- | --- |
| pi | `pi` | `~/.agents/skills/` |
| Claude Code | `claude` | `~/.claude/skills/` |
| Antigravity | `agy-ide` | `~/.gemini/antigravity-ide/skills/` |
| Codex | `codex` | `~/.codex/skills/` |
| Cursor | `cursor` | `~/.cursor/skills/` |
| OpenCode | `opencode` | registered in `opencode.jsonc` |

When you install a skill, skmp symlinks it into every harness it detects. If you install a new AI tool later, just run `skmp sync` to wire up your existing skills into the new harness automatically.

OpenCode is a special case — it doesn't read from a skills directory; it reads paths from its own config file. So skmp registers `~/.skmp/skills` under `skills.paths` in `~/.config/opencode/opencode.jsonc` instead of symlinking.

* * *

## What's Next

A few things on the roadmap:

*   **Skill updates** — `skmp upgrade` to pull the latest version of every installed skill
    
*   **Private registries** — point skmp at your own `index.json` for internal team skills
    
*   **More harnesses** — Windsurf, Zed, and others as their skill systems mature
    

* * *

## Try It

```bash
npm install -g skmp-cli
skmp
```

The repo is at [github.com/Nitesh000/skmp](https://github.com/Nitesh000/skmp). PRs, bug reports, and new skill submissions are all welcome — the contributing bar is intentionally low.

If you've got a skill you've been carrying around manually, consider submitting it to the registry. The whole point of skmp is that a skill you write once should be available everywhere with a single command.
