Install
$ agentstack add skill-umanio-agency-skillctl-skillctl-usage Open-source listing — not yet scanned by AgentStack. Follow the source repository for install instructions.
Security review
⚠ Flagged2 finding(s); flagged for manual review. · v0.1.0 How review works →
- • Prompt-injection patterns
- • Secret / credential exfiltration
- • Dangerous shell & filesystem operations
- • Untrusted network calls
- • Known-malicious package signatures
- high Dangerous shell/eval execution.
- high Pipes remote content directly into a shell (remote code execution).
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ● Dynamic code execution Used
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming — see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps — measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
skillctl-usage
skillctl is a Rust CLI that manages a personal Claude skills library across projects. This skill is the agent-facing reference: it documents how to drive every command without prompts, so any agent (Claude Code or otherwise) can use it as a tool.
> If you're a human reading this, the same flags work in interactive mode — they pre-fill choices and skip the relevant prompts.
How non-interactive mode is selected
skillctl auto-detects whether stdin and stdout are TTYs. When called from a script, agent, or pipe, it switches to non-interactive mode automatically. You can also force it explicitly with the global --no-interaction flag, or with --json (which implies it).
In non-interactive mode, every decision must come from a flag. If a required input is missing, the command exits with a clear error rather than silently falling back to a prompt.
Structured output: --json
The global --json flag suppresses the human-readable cliclack output and emits a single JSON object on stdout at the end of the command. --json implies --no-interaction. Errors continue to go to stderr.
Per-command top-level shape:
// init
{"command":"init","library":{"url":"…","cache_path":"…"}}
// list
{"command":"list","library":"…","skills":[{"name":"…","path":"…","description":"…|null","tags":["…"]}]}
// add
{"command":"add","destination":"…|null","results":[{"name":"…","status":"installed|skipped|aborted","…":"…"}],"summary":{"installed":N,"skipped":N,"aborted":N}}
// push
{"command":"push","results":[{"name":"…","status":"pushed|forked|promoted|pr_opened|skipped","operation":"update|fork|pr","pr_url":"…","branch":"…","new_name":"…","library":"…","…":"…"}],"commit":{"sha":"…","message":"…"}|null,"summary":{"pushed":N,"forked":N,"promoted":N,"pr_opened":N,"skipped":N}}
// pull
{"command":"pull","results":[{"name":"…","status":"pulled|skipped","fork_local":"…|null","fork_local_path":"…","source_sha":"…"}],"summary":{"pulled":N,"forked_locally":N,"skipped":N}}
// detect
{"command":"detect","target":"…|null","results":[{"name":"…","status":"added|skipped","library_path":"…","local_path":"…","source_sha":"…"}],"commit":{"sha":"…","message":"…"}|null,"summary":{"added":N,"skipped":N}}
// remove
{"command":"remove","results":[{"name":"…","status":"removed|failed","path":"…","removed_folder":true|false,"removed_entry":true|false,"reason":"…"}],"summary":{"removed":N,"failed":N}}
Stable rules:
- The
commandfield always matches the subcommand name. results[]only contains skills that were acted on (installed, pushed, forked, pulled, added, or explicitly skipped). Skills that were silently no-ops (e.g. unchanged onpush) are not inresults[]. To enumerate everything, useskillctl list --json.summarytotals exactly equal the count of correspondingstatusvalues inresults[].commitisnullwhen no commit was made (nothing to apply, or library-only-read commands likepull/list).
One-time setup: link a library
skillctl init https://github.com//
- Clones the library repo into a platform-appropriate cache.
- Persists the URL in a global config file as the default library (named
personal, accesswrite). - Re-running
initagainst the same URL refreshes the cache; against a different URL re-points the default library. - Any git host works — GitHub, GitLab, or self-hosted — over HTTPS or SSH (e.g.
git@host:owner/repo.git). Cleartexthttp://is refused.
Multiple libraries
skillctl can track more than one library. A library carries an access level — read (consume only), write (direct commit), or pr (branch + PR/MR) — and exactly one is the default. The personal library from init is just the default.
skillctl library add [--access read|write|pr] [--default]
skillctl library list
skillctl library remove
skillctl library set-default
library addclones the repo immediately (fail-fast on a bad URL/credentials). Added libraries default to--access readso you can't push to them by accident. The nameallis reserved.- The default library is what every command acts on when you don't say otherwise.
--from(onlist/add) reads from another library; non-default reads are treated as untrusted third-party content (see the audit notes below). pullandpushboth follow each skill's provenance — a skill installed from any configured library is refreshed from / written back to that library (a run may touch several). A skill whose recorded provenance is no longer configured is listed and skipped (runskillctl library addto restore it).pushto awrite-access library commits directly; to apr-access library it pushes askillctl/branch and opens a PR (gh) or MR (glab), returning the URL. A skill from aread-access source can't be written back — promote it into a writable library withpush --to(see the push section). Opening a PR/MR uses your existinggh/glabauth — no token is stored; unsupported hosts get a "push done, open it manually" message.- Each repository may be configured at most once:
skillctl library addrefuses a URL that resolves to an already-configured repo (same repo under two access levels would make a skill's write target depend on config order). - Interactive only: running
skillctl addin a terminal with more than one library configured (orskillctl add --from all) opens a picker with a tab per library (←/→ to switch, opens on the default); selections accumulate across tabs into one install. Agents/non-interactive runs use the flags above instead.
Commands
skillctl list — read-only
skillctl list
skillctl list --from # list a specific library
skillctl list --from all # list every configured library
skillctl list --tag [--tag …] [--all-tags]
Refreshes the library cache (best-effort git fetch) and prints every skill with its name, any frontmatter tags in […], and a one-line description.
| Flag | Purpose | |---|---| | --from | List a named library instead of the default. --from all spans every configured library, grouped by library (each section shows the library name, access, and URL). | | --tag | Filter to skills carrying this tag. Repeatable; default semantics is union (any of the given tags). | | --all-tags | Switch to intersection (skill must carry every requested tag). Requires --tag. |
Under --json, a single-library list emits { "command": "list", "library": , "skills": [...] }; --from all emits { "command": "list", "from": "all", "libraries": [ { "name", "url", "access", "default", "skills": [...] } ] }.
skillctl add — install skills from the library into a project
skillctl add --skill [--skill …] --dest
skillctl add --all --dest
skillctl add --tag [--tag …] [--all-tags] --dest
skillctl add --from --skill --dest # install from one named library
skillctl add --from all --tag --dest # install matching skills from every library
| Flag | Purpose | Required in non-interactive | |---|---|---| | --from | Install from a named library instead of the default. A git URL or github:owner/repo / gitlab:owner/repo shorthand installs ad-hoc from a remote source that isn't a configured library (see below). --from all installs matching skills from every configured library in one run (non-interactive: requires a selection — --all/--skill/--tag). Installing from any non-default source forces the content audit on. | No | | --save-as | Only with an ad-hoc --from : also register the source as a read-access library under this name, so skillctl pull can track it later. Ignored when --from names an already-configured library. | No | | --skill | Install a specific skill (repeatable). Mutually exclusive with --all and --tag. | Yes, unless --all or --tag | | --all | Install every skill in the library. Mutually exclusive with --skill and --tag. | Yes, unless --skill or --tag | | --tag | Install every skill carrying this tag (repeatable). Default semantics is union (any of the given tags). Mutually exclusive with --skill and --all. | Yes, unless --skill or --all | | --all-tags | Switch tag matching from union to intersection (skill must carry every requested tag). Requires --tag. | No | | --dest | Project-relative destination folder (e.g. .claude/skills). The folder is created if missing. | Yes | | --on-conflict | Strategy when a destination skill folder already exists. | Yes if any conflict is encountered | | --no-audit | Skip the content security audit of skills before installing. | No | | --fail-on | Refuse the whole batch (install nothing, exit 5) if any selected skill's content audit reaches this severity. Without it the audit is warn-only. | No |
Before anything is copied, add runs a content security audit (see skillctl audit) on each selected skill. By default it is warn-only (findings are logged, the install proceeds); under --json each installed skill's result carries an "audit_verdict" field (safe/caution/warning/dangerous) so a non-interactive caller still sees the signal. Pass --fail-on to block, or --no-audit to skip the scan entirely. The same gate covers pull (incoming library content) and detect (local content before publishing) — see their sections.
Interactive triage (TTY only). In an interactive terminal on the warn-only path (no --fail-on), if any skill is flagged (verdict ≥ warning) add/pull/detect present a batch-triage menu before applying: Decide for each (walk each flagged skill — include / skip / view findings), Proceed with all, or Cancel everything (nothing is applied, exits 0). Non-flagged skills always proceed. This never triggers non-interactively (agents/--json use --fail-on/--no-audit instead), so it does not affect scripted runs.
When installing from a non-default library (--from where ` isn't the default, or --from all while any non-default library is configured), the content is untrusted third-party material, so the audit is **mandatory**: --no-audit is refused (exit 2). It is still warn-only unless you add --fail-on`. Installs from the default library are unaffected.
Ad-hoc remote install (--from ): skillctl add --from github:owner/repo --skill foo --dest .claude/skills clones the repo into the cache, audits its content (mandatory — --no-audit refused), and installs the selected skills with their remote-URL provenance. By default the source stays ephemeral — recorded in .skills.toml by URL but not added to config.toml, so pull/push skip it (it's a one-shot install). To keep tracking it, pass --save-as (or accept the interactive "keep as a library?" offer) and it's registered as a read library. If the URL already matches a configured library, --from simply installs from that library. Accepts the github:/gitlab: shorthand and full https:///git@/ssh:// URLs; installs from the default branch HEAD.
With --from all, the default library is installed first and keeps the skill's bare name; if another library offers a skill whose name (or destination folder) is already taken, that install is suffixed - (e.g. deploy from personal + deploy-team from team), so both land with distinct names, folders, and provenance. The JSON results[] entries carry a library field naming the source.
Each installed skill is recorded in .skills.toml at the project root with the source path inside the library, the library commit SHA at install time, the local destination, an RFC3339 timestamp, and the provenance (library name + library_url) it was installed from.
Tags are read from the SKILL.md frontmatter. Both inline and block forms work:
---
name: claude-api
description: Build and tune Claude API apps with prompt caching.
tags: [api, claude, caching]
---
---
name: claude-api
tags:
- api
- claude
- caching
---
A bare scalar tags: foo is accepted and treated as a single-tag list. Tag flags on push and pull read tags from each skill's local SKILL.md (the user's current view), so retagging locally takes effect on the next run without needing to push or pull first.
description: accepts both a single-line value and YAML block scalars:
description: |
Multi-line literal description.
Newlines are preserved.
description: >
Multi-line folded description that
joins lines with spaces, useful for
one long sentence wrapped in source.
skillctl push — propagate local edits back to the library
skillctl push --skill [--skill …]
skillctl push --all
skillctl push --tag [--tag …] [--all-tags]
| Flag | Purpose | |---|---| | --to | Promotion mode. Publish the selected skills into this writable library (rewriting their provenance) instead of pushing each back to its own. Use it to contribute a skill installed from a read-only source into your own/team library. On a path collision in the target, --on-divergence applies. | | --skill | Push only specific skills by name (repeatable). Mutually exclusive with --all/--tag. | | --all | Push every skill that has pushable changes. Mutually exclusive with --skill/--tag. | | --tag | Push every pushable skill whose local SKILL.md carries this tag. Repeatable; default semantics is union (any of). Mutually exclusive with --skill/--all. | | --all-tags | Switch tag matching to intersection (skill must carry every requested tag). Requires --tag. | | --on-divergence | Strategy for divergent (and library-missing) skills. Default when omitted: skip with a warning. | | --fork-suffix | Required when --on-divergence fork is used non-interactively. New name = -. | | --message | Override the auto-generated commit message. For a pr-access library it is also the PR/MR description. | | --pr-title | Title for the PR/MR opened against a pr-access library (default: auto-generated). Ignored for write libraries. | | --yes | Skip the interactive PR/MR confirmation (open it without prompting). Always implied in non-interactive mode. | | --propagate | After the push succeeds, fan each pushed update out to every other project on disk that installed it from the same library (same engine as skillctl propagate). Mutually exclusive with --to. | | --root | Directory to scan for install sites when --propagate is set (repeatable). Requires --propagate; falls back to [propagate] roots in config.toml when omitted. |
For each pushable skill, skillctl push runs a content diff (via git blob hashes) and applies the chosen strategy. push follows provenance: each skill is written back to the library it was installed from.
- For a
writelibrary: commits and pushes to its default branch, one commit per library (a run touching several makes several commits); each pushed.skills.tomlentry'ssource_shais rewritten to that library's new HEAD. In--json,commitis the single commit when exactly onewritelibrary was pushed, otherwisenull(each result carries itssource_sha). - For a
prlibrary: pushes askillctl/branch and opens a PR (gh) / MR (glab); the result carries"status":"pr_opened","pr_url", and"branch", and the URL is shown in the outro..skills.tomlis not changed (the skill isn't merged yet). Interactive runs show an editable title + confirm;--yes/non-interactive open it directly.
Skills from read libraries, and skills whose provenance is no longer configured, are listed and skipped (see the access notes above).
Promotion (push --to ): publishes the selected skills' local content into ` (regardless of where they came from) and rewrites their .skills.toml` provenance to it — the way to contribute a skill installed from a read-only source. Each skill lands a
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: umanio-agency
- Source: umanio-agency/skillctl
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.