zongwu233/skillctl

Local CLI: a skill package manager, install gate, and context accounting for `SKILL.md`-based agent skills.

0

stars

1

commits

Python

primary language

Sep 10, 2026

updated

README

skillctl

Local CLI: a skill package manager, install gate, and context accounting for SKILL.md-based agent skills.

Doesn't care where skills come from. Cares whether they land on your machine, how much context they eat, and which set each project enables.

Languages: English | 中文

What it does

CommandPurpose
skillctl ls [--all] [--json] [path]List installed skills across runtimes: scope, tokens, flags, conflicts
skillctl why <task>Which skills would grab this task + conflict edges
skillctl budget [--strict] [--json]Description-token total vs budget; exit 1 on breach
skillctl use <profile>Apply a profile by writing each runtime's native enable/disable switch
skillctl scan <git-url|path>Wrap NVIDIA SkillSpector (--no-llm); report only
skillctl add <git-url|path>Gate, then copy-install; DO_NOT_INSTALL needs --force
skillctl prune [--apply]Broken links / duplicate inodes / empty dirs; dry-run by default

Discovered runtimes: Claude Code, Codex (incl. .system, labeled scope=system), OpenCode, pi (recursive collections), omp. Plugin caches are never scanned.

Install

Requires Python ≥ 3.11 and uv.

git clone <repo-url> skillctl
cd skillctl

# 1) Try without installing (creates .venv, resolves the only dep: pyyaml)
uv sync
uv run skillctl ls

# 2) Install as a `skillctl` command on PATH (editable — edits take effect immediately)
uv tool install --editable .
skillctl ls --all

# re-install over an existing link after big changes / remove it
uv tool install --editable . --force
uv tool uninstall skillctl

No tokenizer, no network calls: token estimate is chars / 4, TOML uses the stdlib.

Configuration (optional, all defaults built in)

~/.config/skillctl/config.toml:

default_runtime = "claude"
copy_not_symlink = true
skillspector_bin = "skillspector"
budget.max_skills = 20
budget.max_description_tokens = 2000
budget.max_body_words = 5000

Profiles at ~/.config/skillctl/profiles/<name>.toml:

enable = ["grilling", "using-superpowers"]
disable = ["follow-builders"]
# names not listed are left untouched

Semantics worth knowing

  • Body redlines: 5,000 words / 500 lines → over_body flag. It warns; only budget --strict fails on it. Hard budget failures are max_skills / max_description_tokens.
  • Symlinks are resolved with lstat + stat (dirent sizes lie); broken links are reported and become prune targets; same-inode copies dedupe to one record.
  • use writes only runtime-native switches: Claude skillOverrides, Codex [[skills.config]] (absolute paths). It never edits SKILL.md or renames directories. OpenCode/pi/omp have no known native switch in v0 — those copies are reported on stderr and left untouched.
  • Exit codes: 0 success · 1 budget breach or gate refusal · 2 missing skillspector / scanner error / bad args or IO.

Development

uv sync          # dev group (pytest) included by default
uv run pytest    # isolated tmp HOME — never touches real configs

Design docs (PLAN.md, DESIGN.md) live in docs/ and are intentionally not committed.

License

MIT

Contributors

zongwu233

1 commits

zongwu233/skillctl

Local CLI: a skill package manager, install gate, and context accounting for `SKILL.md`-based agent skills.

0

stars

1

commits

Python

primary language

Sep 10, 2026

updated

README

skillctl

Local CLI: a skill package manager, install gate, and context accounting for SKILL.md-based agent skills.

Doesn't care where skills come from. Cares whether they land on your machine, how much context they eat, and which set each project enables.

Languages: English | 中文

What it does

CommandPurpose
skillctl ls [--all] [--json] [path]List installed skills across runtimes: scope, tokens, flags, conflicts
skillctl why <task>Which skills would grab this task + conflict edges
skillctl budget [--strict] [--json]Description-token total vs budget; exit 1 on breach
skillctl use <profile>Apply a profile by writing each runtime's native enable/disable switch
skillctl scan <git-url|path>Wrap NVIDIA SkillSpector (--no-llm); report only
skillctl add <git-url|path>Gate, then copy-install; DO_NOT_INSTALL needs --force
skillctl prune [--apply]Broken links / duplicate inodes / empty dirs; dry-run by default

Discovered runtimes: Claude Code, Codex (incl. .system, labeled scope=system), OpenCode, pi (recursive collections), omp. Plugin caches are never scanned.

Install

Requires Python ≥ 3.11 and uv.

git clone <repo-url> skillctl
cd skillctl

# 1) Try without installing (creates .venv, resolves the only dep: pyyaml)
uv sync
uv run skillctl ls

# 2) Install as a `skillctl` command on PATH (editable — edits take effect immediately)
uv tool install --editable .
skillctl ls --all

# re-install over an existing link after big changes / remove it
uv tool install --editable . --force
uv tool uninstall skillctl

No tokenizer, no network calls: token estimate is chars / 4, TOML uses the stdlib.

Configuration (optional, all defaults built in)

~/.config/skillctl/config.toml:

default_runtime = "claude"
copy_not_symlink = true
skillspector_bin = "skillspector"
budget.max_skills = 20
budget.max_description_tokens = 2000
budget.max_body_words = 5000

Profiles at ~/.config/skillctl/profiles/<name>.toml:

enable = ["grilling", "using-superpowers"]
disable = ["follow-builders"]
# names not listed are left untouched

Semantics worth knowing

  • Body redlines: 5,000 words / 500 lines → over_body flag. It warns; only budget --strict fails on it. Hard budget failures are max_skills / max_description_tokens.
  • Symlinks are resolved with lstat + stat (dirent sizes lie); broken links are reported and become prune targets; same-inode copies dedupe to one record.
  • use writes only runtime-native switches: Claude skillOverrides, Codex [[skills.config]] (absolute paths). It never edits SKILL.md or renames directories. OpenCode/pi/omp have no known native switch in v0 — those copies are reported on stderr and left untouched.
  • Exit codes: 0 success · 1 budget breach or gate refusal · 2 missing skillspector / scanner error / bad args or IO.

Development

uv sync          # dev group (pytest) included by default
uv run pytest    # isolated tmp HOME — never touches real configs

Design docs (PLAN.md, DESIGN.md) live in docs/ and are intentionally not committed.

License

MIT

Contributors

zongwu233

1 commits

Languages

Python

100.0%