Metadata-Version: 2.5
Name: skills-manager-cli
Version: 0.1.0
Summary: A CLI to handle agent skills
License: MIT
License-File: LICENSE
Classifier: License :: OSI Approved :: MIT License
Requires-Python: >=3.12
Requires-Dist: typer>=0.12
Description-Content-Type: text/markdown

# ai-skills-manager

A command-line tool to install, track, and update agent skills — from Git
repositories, local paths, or an existing `skills-lock.json` — across every
agent and project on your machine. Built with
[Typer](https://typer.tiangolo.com/).

Supported agents: Claude Code (`claude`), OpenCode (`opencode`), Codex
(`codex`), Cursor (`cursor`), and Gemini CLI (`gemini`). Only agents found
on your machine are used; the rest are ignored.

## Requirements

- Python 3.12 or newer
- `pip` or [`uv`](https://docs.astral.sh/uv/) (the installer picks `uv`
  first when both are present)
- `git`

## Install

No checkout needed — run one command, then use `skills-manager` from
anywhere (needs a GitHub account with access to the repo):

```sh
git clone https://github.com/alecvinent/ai-skills-manager.git
sh ai-skills-manager/install.sh
```

```powershell
git clone https://github.com/alecvinent/ai-skills-manager.git
.\ai-skills-manager\install.ps1
```

Once the repository is public, these one-liners work instead:

```sh
curl -fsSL https://raw.githubusercontent.com/alecvinent/ai-skills-manager/main/install.sh | sh
```

```powershell
irm https://raw.githubusercontent.com/alecvinent/ai-skills-manager/main/install.ps1 | iex
```

Done with the tool? Uninstalling removes the package but keeps your home
data (`~/.skills-manager`) in place:

```sh
git clone https://github.com/alecvinent/ai-skills-manager.git
sh ai-skills-manager/uninstall.sh
```

```powershell
git clone https://github.com/alecvinent/ai-skills-manager.git
.\ai-skills-manager\uninstall.ps1
```

Once the repository is public, raw one-liners work for these too
(`.../main/uninstall.sh | sh`, `.../main/uninstall.ps1 | iex`).

Prefer to inspect first? Download the script, read it, then run it with
`sh install.sh` (or `install.ps1` in PowerShell). A custom source works
too: `SKILLS_MANAGER_REPO=<git-url> sh install.sh`.

Then verify:

```sh
skills-manager --help
```

If your shell cannot find it, add the user binary directory to PATH (the
installer prints the exact line when this applies):

```sh
export PATH="$HOME/.local/bin:$PATH"  # then re-login or re-source
```

## First steps

Pick which agents receive skills (skills stay installed when you toggle):

```sh
skills-manager agent                    # show detected agents and states
skills-manager agent claude --disable   # stop linking into Claude Code
```

Install a skill everywhere at once:

```sh
skills-manager install addyosmani/agent-skills --global   	# GitHub owner/repo shorthand
skills-manager install https://github.com/example/repo.git  # full URL
skills-manager install ./my-skills --all                    # local path, no picking
skills-manager install ./my-skill                           # a folder whose own SKILL.md is the skill
```

A source is usually a collection (every folder with a `SKILL.md`,
at any depth, installs as one skill under its own folder name); a
source whose `SKILL.md` sits at its own root installs as a single
skill named after the source. A skill name appearing in several
places is a clear error instead of a silent overwrite.

See what is installed and where:

```sh
skills-manager list
# demo (global)
# demo (/path/to/a/project)
```

Keep skills fresh:

```sh
skills-manager check    # what has upstream updates (read-only)
skills-manager update   # pull updates into every copy
```

Remove cleanly:

```sh
skills-manager uninstall demo        # confirm once, gone everywhere
skills-manager uninstall --all       # remove everything
```

Keep the tool itself current:

```sh
skills-manager upgrade --check   # report only, changes nothing
skills-manager upgrade           # verify + swap the binary in place
```

## Working on a project with teammates

Install into the project so the result is committable (`.agents/skills`
plus a `skills-lock.json` entry with no machine-specific paths):

```sh
cd my-project
skills-manager install addyosmani/agent-skills --local
git add .agents/skills skills-lock.json && git commit -m "Add skills"
```

Teammates adopt the lockfile (theirs or an `npx skills` one) with:

```sh
skills-manager import               # defaults to the current directory
skills-manager import /path/to/dir  # or point at one explicitly
```

Adopted a project by other means? Register whatever is already on disk:

```sh
skills-manager sync   # scans the configured locations, registers finds
```

## Scopes

- **Global** (default) — the skill is active everywhere; installing
  fetches and activates it in every enabled agent.
- **Local** (`--local`) — writes a committable project install
  (`.agents/skills` plus a lockfile entry) so teammates get it from the
  lockfile.

A skill installed globally is globally active — there is no separate "fetch
without activating" step. Uninstalling a skill's last install removes it
entirely.

## Security scans

Every `install`/`update` scans fetched content first: high/critical
findings block by default (`--minimum-accepted-severity` adjusts the
ceiling), `--unsafe-install` proceeds anyway while still printing
every finding, and `--exclude` / `--exclude-path` record manual-review
exceptions that updates reapply. `scan` reports the same findings
without installing. Outcomes land in the daily execution log.

## Commands

| Command | Description |
| --- | --- |
| `install [<url\|owner/repo\|path>] [id...] [--all] [--as <name>] [--ref <ref>] [--global\|--local]` | Install into every enabled agent — straight from a repo URL, a GitHub `owner/repo` shorthand, or a path (fetch + pick + install in one step), or by the id of an already-installed skill to add another scope/project. Default scope is **global**; `--local` writes the committable project install. Interactive pickers if no id; `--all` skips them. Link failures warn instead of rolling back the install. Scans fetched content first: findings above `--minimum-accepted-severity` (default `medium`, so high/critical) block; `--unsafe-install` proceeds anyway while still printing every finding; `--exclude` / `--exclude-path` record manual-review exceptions. |
| `import [dir]` | Adopt a project's `skills-lock.json` into skills-manager's tracking: fetch the sources and write any missing copies/links. |
| `uninstall [id...] [--all] [--global\|--local]` | Unlink everywhere and delete the global and project copies + lock entries + registry entry (interactive picker if no id). `--global` / `--local` remove only that scope; removing the last scope removes the skill entirely. |
| `unregister [id...]` | Drop the tracking (registry + lockfile entries) without touching copies or links (interactive picker if no id). |
| `list` | Show every installed skill and where it is installed (global or the project path) — one `<name> (<location>)` line per install, or `No skills installed.` when empty. Read-only. |
| `filter <topic>` | List installed skills matching a topic (case-insensitive substring on name and frontmatter `description`): one executive-summary block per match (name, description, opening body lines, capped). Read-only. |
| `info <id\|source>` | Show everything tracked about one installed skill — source, kind, ref, revision, locations, and linked agents — or about every skill recorded from a source (`owner/repo`, URL, path, or repo name). Read-only. |
| `check` | Report which git skills have upstream updates. Read-only. |
| `scan <source>` | Report security findings for a source's skills without installing (exit 1 when blocked by policy). Read-only. |
| `update [id]` | Pull updates for outdated git skills (all, or one), writing the new content into every install — the global copy and every tracked project's copies and lock entries — and adopt teammate-added lockfile entries. Scans fetched content first: findings above `--minimum-accepted-severity` (default `medium`, so high/critical) block; `--unsafe-install` proceeds anyway while still printing every finding; `--exclude` / `--exclude-path` record manual-review exceptions that updates reapply. |
| `schedule [--install\|--remove] [--time HH:MM]` | Manage a daily `skills-manager --yes update` entry (default 09:00) in the platform scheduler; bare run reports status. The installed time is kept in `skills-manager.conf` (`--time` wins, then the conf value). Read-only unless installing/removing. |
| `agent [name] [--enable\|--disable]` | Show agents, or enable/disable one, reconciling its links right away (skills stay installed). Interactive picker when run bare on a terminal. |
| `upgrade [--check]` | Upgrade skills-manager itself to the latest release: download this platform's archive, verify its SHA256 against the release's `checksums.txt`, and swap the binary in place. `--check` only reports. |
| `sync` | Scan the common paths listed in `skills-manager.conf` for already-installed skills and register any it finds. Skills are copied + recorded even when agent linking fails (e.g. Windows symlink privilege); link problems print as warnings and `doctor` reports the missing links for later repair. Always ends with a stdout summary (`registered X, Y failed`). |
| `doctor` | Report drift between disk, links, and records (missing copies, dead links, unknown lock entries). Read-only. |
| `prune` | Drop cached sources no install references, reporting what went away. |
| `regenerate-config` | Rewrite `skills-manager.conf` from the effective settings (warns and asks before overwriting an existing file). |

Run `skills-manager <command> --help` for exact flags; `skills-manager --help` lists everything.

On interactive terminals, the long commands (`install`, `update`,
`import`, `sync`, `upgrade`) print a progress line as each skill or stage
starts; piped or scripted output stays exactly as documented.

## Global flags

`--force` / `--yes` skip confirmations. `--home <path>` overrides the home
directory (default `~/.skills-manager`) so you can keep separate setups.
`--dry-run` reports what a command would change without changing anything.
`--version` prints the running version and exits.

Global flags work before or after the command: `skills-manager --yes
install <src>` and `skills-manager install <src> --yes` mean the same.

## Execution log

Every run appends one line to `<home>/logs/YYYY-MM-DD.log` (local date):

```
2026-10-11T14:32:01 argv=[list] exit=0
```

One file per calendar day; older files are kept. Logging is best-effort:
it never changes output, exit codes, or behavior.

## Configuration

`skills-manager.conf` (TOML) in the home directory is the single place for
settings — currently the skill search paths and the disabled-agent list:

```toml
search_paths = ["/home/user/.agents/skills", "/home/user/.claude/skills"]

[agents]
disabled = ["cursor"]
```

Missing or empty file: built-in defaults apply (common agent skill
locations, all agents enabled). `~` and relative paths resolve against the
home. On Windows, write paths with forward slashes (`C:/...`) or TOML
literal strings (`'C:\...'`), since backslashes are escapes in TOML. The
file is created on the first setting change (e.g. `agent
... --disable`); an old `agents.json`, if present with no config file, is
honored once. Per-run flags are never stored here.

## `update` vs `upgrade`

`skills-manager update` pulls new revisions of your installed **skills**;
`skills-manager upgrade` replaces the **skills-manager** tool itself. A source
install (or an unstamped build) matches no published release, so `upgrade`
reports that and leaves it alone.

On interactive runs the tool also checks for a new release by itself at
most every 12 hours (stamp file `last-upgrade-check` in the tool home) and
prints a one-line notice pointing at `upgrade` when one is available. The
check never runs piped, for `--dry-run`, for the `upgrade` command itself,
or for unstamped builds — and it can never fail or slow down your command.

## Development

```sh
uv sync
uv run python -m unittest discover -s tests
uv run skills-manager --help
```

New contributor? Start with [`CONTRIBUTING.md`](CONTRIBUTING.md) — setup,
workflow (`BL-xxx` → spec-kit pipeline → PR), and the merge checklist.

## Self-hosted CI runners

CI runs on self-hosted runners (zero hosted minutes); `windows` and
`linux` jobs only. A `preflight` job validates runner presence via the
API and warns when offline — it never blocks the pipeline.

| Runner | Labels | Machine | Location | Keep alive |
| --- | --- | --- | --- | --- |
| `dalaran-wsl` | `self-hosted`, `Linux` | dalaran (WSL) | `~/actions-runner` | `sudo ./svc.sh install && sudo ./svc.sh start` in `~/actions-runner` (today: background `./run.sh`) |
| `dalaran-win` | `self-hosted`, `Windows` | dalaran (Windows) | `C:\actions-runner` | `./run.cmd` as a Windows service (elevated `.\svc.cmd install/start`); today: detached `./run.cmd` |

Recovery: re-run `config.cmd/sh --url https://github.com/alecvinent/ai-skills-manager --token <fresh-token-from-../settings/actions/runners>` (tokens expire in 1 hour; mint with `gh api -X POST repos/alecvinent/ai-skills-manager/actions/runners/registration-token --jq .token`). Verify with `gh api repos/alecvinent/ai-skills-manager/actions/runners --jq '.runners[] | [.name, .status]'`.

## Roadmap & workflow

This project is spec-driven: every feature starts as a `BL-xxx` item in
[`docs/backlog.md`](docs/backlog.md) and flows through the spec-kit pipeline
(`specify → plan → tasks → analyze → implement → converge`) defined in
`.specify/memory/constitution.md`. All backlog items are built; the table
above is the shipped surface.
