skillcask 0.10.6 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -662
- package/npm-shrinkwrap.json +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,698 +1,144 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/GetResponse/skillcask/master/docs/assets/wordmark-dark.svg">
|
|
4
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/GetResponse/skillcask/master/docs/assets/wordmark-light.svg">
|
|
5
|
+
<img alt="skillcask" src="https://raw.githubusercontent.com/GetResponse/skillcask/master/docs/assets/wordmark-light.svg" width="480">
|
|
6
|
+
</picture>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<strong>A lockfile-first package manager for AI agent skills.</strong><br>
|
|
11
|
+
One manifest, one lock, every agent's skill directory.
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<a href="https://github.com/GetResponse/skillcask/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/GetResponse/skillcask/actions/workflows/ci.yml/badge.svg"></a>
|
|
16
|
+
<a href="https://crates.io/crates/skillcask"><img alt="crates.io" src="https://img.shields.io/crates/v/skillcask"></a>
|
|
17
|
+
<a href="https://www.npmjs.com/package/skillcask"><img alt="npm" src="https://img.shields.io/npm/v/skillcask"></a>
|
|
18
|
+
<a href="https://github.com/GetResponse/homebrew-tap"><img alt="Homebrew: getresponse/tap" src="https://img.shields.io/badge/homebrew-getresponse%2Ftap-orange"></a>
|
|
19
|
+
<a href="#license"><img alt="License: MIT OR Apache-2.0" src="https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue"></a>
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
skillcask installs skills (directories with a `SKILL.md`, read by Claude Code, Codex, Junie and
|
|
23
|
+
others) the way Cargo or Composer install libraries: a manifest with version constraints, a
|
|
24
|
+
committed lock with content hashes, and frozen installs in CI that fail on drift. It ships as a
|
|
25
|
+
single static binary with no runtime, and takes skills from Composer repositories, GitHub (which
|
|
26
|
+
covers most of what [skills.sh](https://skills.sh) lists) and any git repository over HTTPS.
|
|
16
27
|
|
|
17
28
|
## Install
|
|
18
29
|
|
|
19
|
-
**macOS, Linux**
|
|
20
|
-
|
|
21
30
|
```sh
|
|
22
|
-
brew install getresponse/tap/skillcask
|
|
23
|
-
# or, without Homebrew:
|
|
31
|
+
brew install getresponse/tap/skillcask # macOS, Linux
|
|
24
32
|
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/GetResponse/skillcask/releases/latest/download/skillcask-installer.sh | sh
|
|
33
|
+
npm install -g skillcask # or: cargo install --locked skillcask
|
|
25
34
|
```
|
|
26
35
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
```powershell
|
|
30
|
-
powershell -ExecutionPolicy Bypass -c "irm https://github.com/GetResponse/skillcask/releases/latest/download/skillcask-installer.ps1 | iex"
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
The two installer scripts download the binary for your platform from the latest release and put
|
|
34
|
-
it in `~/.cargo/bin` (`%USERPROFILE%\.cargo\bin` on Windows).
|
|
35
|
-
|
|
36
|
-
**Desktop app (macOS 14+ only for now)**
|
|
37
|
-
|
|
38
|
-
```sh
|
|
39
|
-
brew install getresponse/tap/skillcask getresponse/tap/skillcask-app
|
|
40
|
-
skillcask app # or open Skillcask from Applications
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
Install with the full names: Homebrew loads a third-party tap's cask only when it is named in full
|
|
44
|
-
(or listed by `brew trust`); after that, `brew upgrade` takes the short name.
|
|
45
|
-
|
|
46
|
-
The tap was `puniserv/tap` before 0.10.5. If you installed from it, move to the new name once
|
|
47
|
-
(your app settings stay):
|
|
48
|
-
|
|
49
|
-
```sh
|
|
50
|
-
brew uninstall --cask puniserv/tap/skillcask-app # skip if you have no app
|
|
51
|
-
brew uninstall puniserv/tap/skillcask
|
|
52
|
-
brew untap puniserv/tap
|
|
53
|
-
brew install getresponse/tap/skillcask getresponse/tap/skillcask-app
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
Without Homebrew:
|
|
57
|
-
|
|
58
|
-
```sh
|
|
59
|
-
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/GetResponse/skillcask/releases/latest/download/skillcask-app-installer.sh | sh
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
The installer downloads `Skillcask-X.Y.Z-macos-universal.zip` (signed and notarized, with its own
|
|
63
|
-
CLI inside) from the latest release, checks its sha256 and Gatekeeper's verdict, and moves the app
|
|
64
|
-
to `/Applications`; an earlier copy goes to the Trash. It leaves a Homebrew install alone.
|
|
65
|
-
`SKILLCASK_VERSION=X.Y.Z` picks a release, `SKILLCASK_APP_DIR` another folder.
|
|
66
|
-
|
|
67
|
-
Linux and Windows have the terminal UI, `skillcask ui`. More in [macOS app](#macos-app).
|
|
68
|
-
|
|
69
|
-
**npm, bun**
|
|
70
|
-
|
|
71
|
-
```sh
|
|
72
|
-
npm install -g skillcask # global
|
|
73
|
-
bun add -g skillcask # global, bun
|
|
74
|
-
npx skillcask install --frozen
|
|
75
|
-
bunx skillcask install --frozen
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
The npm package is a thin wrapper that downloads the release binary for your platform from
|
|
79
|
-
GitHub. It does not check a checksum itself; where that matters, use Homebrew or a release
|
|
80
|
-
archive and verify it.
|
|
81
|
-
|
|
82
|
-
**Cargo**
|
|
83
|
-
|
|
84
|
-
```sh
|
|
85
|
-
cargo install --locked skillcask
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
**Release archives** for macOS, Linux and Windows are on the
|
|
89
|
-
[releases page](https://github.com/GetResponse/skillcask/releases), with sha256 checksums and GitHub
|
|
90
|
-
build provenance attestations:
|
|
91
|
-
|
|
92
|
-
```sh
|
|
93
|
-
gh attestation verify skillcask-x86_64-unknown-linux-gnu.tar.xz -R GetResponse/skillcask
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
Releases up to 0.10.2 were built before the repository moved and verify with `--owner puniserv --signer-repo puniserv/skillcask`.
|
|
36
|
+
Windows, the desktop app, bun, release archives with attestations, the GitHub Action and updating:
|
|
37
|
+
[Install guide](docs/guide/install.md).
|
|
97
38
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
```yaml
|
|
101
|
-
permissions:
|
|
102
|
-
contents: read
|
|
103
|
-
attestations: read # for the provenance check
|
|
104
|
-
steps:
|
|
105
|
-
- uses: actions/checkout@<sha>
|
|
106
|
-
- uses: GetResponse/skillcask@<commit sha of a release tag> # vX.Y.Z
|
|
107
|
-
with:
|
|
108
|
-
version: X.Y.Z # needed when the action is pinned to a sha, not a tag
|
|
109
|
-
args: install --frozen # default
|
|
110
|
-
# working-directory: .
|
|
111
|
-
# verify-attestation: "true" # default
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
The action downloads the release archive for the runner (Linux x64 and arm64, macOS, Windows
|
|
115
|
-
x64), checks its sha256 and its build provenance attestation, puts `skillcask` on `PATH` and runs
|
|
116
|
-
it with `args`. It runs no other action. Used at a tag (`@vX.Y.Z`) it takes the version from the
|
|
117
|
-
tag.
|
|
118
|
-
|
|
119
|
-
### Update
|
|
120
|
-
|
|
121
|
-
`skillcask self-update` reruns the release's installer when `skillcask-installer.sh` installed
|
|
122
|
-
this binary (Linux, macOS); for any other install it prints the one command to run and exits 1.
|
|
123
|
-
`SKILLCASK_SELF_UPDATE=0` makes it print the installer command too. By hand:
|
|
124
|
-
|
|
125
|
-
```sh
|
|
126
|
-
brew update && brew upgrade skillcask skillcask-app # Homebrew (skillcask alone without the app)
|
|
127
|
-
npm install -g skillcask@latest # npm (bun: bun add -g skillcask@latest)
|
|
128
|
-
cargo install --locked skillcask # Cargo
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
The installer scripts (`skillcask-installer.sh`, `skillcask-installer.ps1`,
|
|
132
|
-
`skillcask-app-installer.sh`) install the latest release when run again; the app's installer moves
|
|
133
|
-
the earlier copy to the Trash. The app's own CLI updates with the app; Homebrew updates the app and
|
|
134
|
-
the CLI on your `PATH` separately, which is why `brew upgrade` names both. For the GitHub Action,
|
|
135
|
-
bump the pinned commit and `version`. `skillcask --version` prints what you have.
|
|
136
|
-
|
|
137
|
-
## Use
|
|
39
|
+
## Quickstart
|
|
138
40
|
|
|
139
41
|
```sh
|
|
140
|
-
skillcask
|
|
141
|
-
skillcask add
|
|
142
|
-
skillcask
|
|
143
|
-
skillcask status
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
`add` creates:
|
|
147
|
-
|
|
148
|
-
```
|
|
149
|
-
skills.toml # manifest, commit it
|
|
150
|
-
skills.lock # lock, commit it
|
|
151
|
-
.agents/skills/<name>/ # installed skill (gitignored)
|
|
152
|
-
.agents/skills/.skillcask-installed # what this machine installed (gitignored)
|
|
153
|
-
.claude/skills/<name> -> ../../.agents/skills/<name>
|
|
154
|
-
.gitignore # managed block
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
Project skills live in `.skills/<name>/SKILL.md` (`[agents] local`). skillcask links each one
|
|
158
|
-
into the store (`.agents/skills/<name> -> ../../.skills/<name>`) and from there into every agent
|
|
159
|
-
directory. These links are committed, so they work in every clone. A directory written by hand
|
|
160
|
-
straight into `.agents/skills/` is linked the same way. A project skill with the same name as a
|
|
161
|
-
locked one is an error. When a skill with the same name exists in your home (`~/.claude/skills`,
|
|
162
|
-
`~/.agents/skills`, …), `install` and `doctor` print a warning: Claude Code runs the personal one,
|
|
163
|
-
Codex lists both.
|
|
164
|
-
|
|
165
|
-
### skills.toml
|
|
166
|
-
|
|
167
|
-
```toml
|
|
168
|
-
[repositories]
|
|
169
|
-
acme = { type = "composer", url = "https://git.example.com/api/v4/group/42/-/packages/composer/packages.json" }
|
|
170
|
-
# A repository you review yourself can skip the cooldown; the others keep it.
|
|
171
|
-
own = { url = "https://git.example.com/own/packages.json", min-release-age = "0" }
|
|
172
|
-
# Default sources, written by `init`; `= false` turns one off. Packagist is always searched last.
|
|
173
|
-
packagist = { url = "https://repo.packagist.org" }
|
|
174
|
-
github = { type = "github", url = "https://api.github.com" } # GitHub Enterprise: its API URL
|
|
175
|
-
|
|
176
|
-
[skills]
|
|
177
|
-
"netresearch/agent-jira-skill" = "^3.34"
|
|
178
|
-
"acme/agents-md" = { version = "^1.0", repository = "acme" }
|
|
179
|
-
"acme/review" = { version = "1.4.2", repository = "acme", skills = ["review"] }
|
|
180
|
-
"mattpocock/skills" = { github = true, version = "^1.3", skills = ["tdd", "code-review"], rename = { code-review = "mp-code-review" } }
|
|
181
|
-
"anthropics/skills" = { github = true, skills = ["pdf"] } # default branch
|
|
182
|
-
|
|
183
|
-
[agents]
|
|
184
|
-
targets = ["claude", "kiro"] # agent names or paths with a "/"; default: config.toml, else ["claude"]
|
|
185
|
-
local = ".skills" # project skills
|
|
186
|
-
|
|
187
|
-
[policy]
|
|
188
|
-
min-release-age = "3d" # cooldown for add/update; "0" disables
|
|
189
|
-
allow-ranges = true # false: every version must be exact
|
|
190
|
-
packagist = true # false: drop the implicit Packagist repository
|
|
191
|
-
github-requires = false # true: dependencies may come from GitHub or git URLs
|
|
192
|
-
allow-sources = ["acme", "own", "packagist", "github"] # only these sources; default: all
|
|
193
|
-
deny-patterns = false # true: risky patterns and invisible characters in new skill text fail instead of warning
|
|
194
|
-
deny-packages = ["evil/*"] # refused by name from any source, also in a lock; default: none
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
### Agents
|
|
198
|
-
|
|
199
|
-
Most agents read `.agents/skills` themselves (Codex, Copilot, Cursor, Gemini CLI, OpenCode, Amp,
|
|
200
|
-
Junie, Devin/Windsurf, Roo Code, Cline, Goose, Factory, Mistral Vibe), so they need no link.
|
|
201
|
-
`[agents] targets` lists the agents that need one, by name, or any directory as a path with a `/`:
|
|
202
|
-
|
|
203
|
-
| Name | Project | Home (`--global`) |
|
|
204
|
-
|---|---|---|
|
|
205
|
-
| `claude` | `.claude/skills` | `~/.claude/skills` |
|
|
206
|
-
| `kiro` | `.kiro/skills` | `~/.kiro/skills` |
|
|
207
|
-
| `junie` | store | `~/.junie/skills` |
|
|
208
|
-
| `codex`, `copilot`, `cursor`, `gemini`, `opencode`, `amp`, `devin`, `roo`, `cline`, `goose`, `factory`, `vibe` | store | store |
|
|
209
|
-
|
|
210
|
-
Set the list once in `config.toml` next to the global manifest; a `skills.toml` that sets
|
|
211
|
-
`targets` replaces it. Manifests from before 0.6.0 carry an explicit list: delete the line to
|
|
212
|
-
follow `config.toml`.
|
|
213
|
-
|
|
214
|
-
```toml
|
|
215
|
-
# ~/.config/skillcask/config.toml
|
|
216
|
-
[agents]
|
|
217
|
-
targets = ["claude", "kiro"]
|
|
218
|
-
|
|
219
|
-
[search]
|
|
220
|
-
skills-sh = true # search also asks skills.sh (it receives the query); written by search --remember or skillcask -g config search.skills-sh true
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
When a target is dropped, the next `install` removes the links skillcask made there; `doctor`
|
|
224
|
-
reports them. `status` prints the targets, where they came from and the directories they link.
|
|
225
|
-
|
|
226
|
-
Constraints follow Composer semantics: `^0.3` means `>=0.3.0 <0.4.0`, `~1.2` means
|
|
227
|
-
`>=1.2 <2.0`, and pre-releases are only selected when the constraint names a stability
|
|
228
|
-
(`^1.0@beta`).
|
|
229
|
-
|
|
230
|
-
### Allowed sources and policy for every project
|
|
231
|
-
|
|
232
|
-
`allow-sources` lists the only places skills may come from: repository names, `packagist`, `github`,
|
|
233
|
-
or `https://` URL prefixes (`https://api.github.com/repos/acme/` allows one GitHub organisation).
|
|
234
|
-
End a prefix with `/` (`https://gitlab.example.com/`): an entry without one also names a registry
|
|
235
|
-
declared at exactly that URL, whose archives may then come from any host. Other repositories get no
|
|
236
|
-
request, and `install` refuses a lock entry from them, also with `--frozen`, so a committed lock
|
|
237
|
-
cannot bring them back. Dependencies follow the same rule.
|
|
238
|
-
|
|
239
|
-
`deny-packages` refuses packages by name, `vendor/name` or a whole `vendor/*`, whatever source
|
|
240
|
-
serves them (a GitHub `owner/repo` counts as `owner/repo`). A plain git entry is matched by its key
|
|
241
|
-
in `skills.toml`, which the project picks, so limit git URLs with `allow-sources`. It is checked
|
|
242
|
-
before any download and again on every lock entry, so it also stops a dependency or a committed
|
|
243
|
-
lock. Enforced in `config.toml`, the list is a floor: a project may add packages to it, not drop
|
|
244
|
-
any.
|
|
245
|
-
|
|
246
|
-
Policy can also come from `config.toml` next to the global manifest (`~/.config/skillcask`) and
|
|
247
|
-
from the environment. The first layer that sets a key wins:
|
|
248
|
-
|
|
249
|
-
1. `SKILLCASK_ALLOW_SOURCES`, `SKILLCASK_MIN_RELEASE_AGE`, `SKILLCASK_ALLOW_RANGES`,
|
|
250
|
-
`SKILLCASK_PACKAGIST`, `SKILLCASK_GITHUB_REQUIRES`, `SKILLCASK_DENY_PATTERNS`,
|
|
251
|
-
`SKILLCASK_DENY_PACKAGES` (lists comma-separated; against an enforced key only a stricter value
|
|
252
|
-
is accepted: a longer cooldown, `deny-patterns` on, the others off, narrower sources, more
|
|
253
|
-
denied packages);
|
|
254
|
-
2. keys `config.toml` lists in `enforce`: a project that sets them otherwise fails;
|
|
255
|
-
3. `[policy]` in `skills.toml`;
|
|
256
|
-
4. the other keys of `config.toml`, as defaults.
|
|
257
|
-
|
|
258
|
-
```toml
|
|
259
|
-
# ~/.config/skillcask/config.toml: only the company registry and GitHub, in every project
|
|
260
|
-
[policy]
|
|
261
|
-
allow-sources = ["https://gitlab.example.com/", "github"]
|
|
262
|
-
enforce = ["allow-sources"]
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
`"github"` in an enforced `allow-sources` is public GitHub (`https://api.github.com/repos/`):
|
|
266
|
-
`SKILLCASK_GITHUB_API` and `GITHUB_API_URL` do not move it. For GitHub Enterprise, enforce its
|
|
267
|
-
prefix, e.g. `"https://ghe.example.com/api/v3/repos/"`.
|
|
268
|
-
|
|
269
|
-
An enforced `min-release-age` also applies to a repository's own `min-release-age`: a project
|
|
270
|
-
may only make it longer. Exceptions, by URL prefix, stay in `config.toml`:
|
|
271
|
-
|
|
272
|
-
```toml
|
|
273
|
-
[policy]
|
|
274
|
-
min-release-age = "3d"
|
|
275
|
-
enforce = ["min-release-age"]
|
|
276
|
-
|
|
277
|
-
[policy.repository-min-release-age]
|
|
278
|
-
"https://gitlab.example.com/" = "0" # internal skills, reviewed in merge requests
|
|
42
|
+
skillcask init # create skills.toml
|
|
43
|
+
skillcask add netresearch/agent-jira-skill # resolve, write skills.toml + skills.lock, install
|
|
44
|
+
skillcask add github:mattpocock/skills/tdd # one skill from a GitHub repository
|
|
45
|
+
skillcask status # manifest vs lock vs installed files
|
|
46
|
+
skillcask install --frozen # CI: install exactly the lock or exit non-zero
|
|
279
47
|
```
|
|
280
48
|
|
|
281
|
-
`
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
also sets, may only make an enforced key stricter. A pinned version is not scanned again for `deny-
|
|
285
|
-
patterns`, and its release time is what the lock says. Under `allow-sources`, a GitHub or git entry
|
|
286
|
-
downloads only from its repository, and a registry the list admits only by a prefix only from inside
|
|
287
|
-
the list; the archive URL of Packagist or a registry the list names (or gives by its exact URL,
|
|
288
|
-
without a trailing `/`) is what the lock says, so review lock changes. `enforce` does not stop the
|
|
289
|
-
person running skillcask: `SKILLCASK_HOME`, `XDG_CONFIG_HOME` or `HOME` can point at a config
|
|
290
|
-
without it. For a rule nobody may skip, run `skillcask install --frozen` as a required check on pull
|
|
291
|
-
requests, with the policy in the job's environment and `.github/workflows/` protected (CODEOWNERS or
|
|
292
|
-
a required workflow), since a pull request runs its own copy of the workflow.
|
|
49
|
+
Commit `skills.toml` and `skills.lock`; the installed skills are gitignored. In GitHub Actions,
|
|
50
|
+
`uses: GetResponse/skillcask@<commit sha of a release tag>` with `version: X.Y.Z` runs
|
|
51
|
+
`install --frozen` ([setup](docs/guide/install.md)).
|
|
293
52
|
|
|
294
|
-
|
|
295
|
-
whatever a project calls it. `skillcask status` prints each key that is set and where it came
|
|
296
|
-
from.
|
|
53
|
+
## Why skillcask
|
|
297
54
|
|
|
298
|
-
|
|
55
|
+
- **Locked and verified.** The lock pins the version, the commit reference, the sha256 of the
|
|
56
|
+
downloaded archive and the tree hash of every installed skill; `install` verifies both hashes.
|
|
57
|
+
- **Every agent.** Skills go to `.agents/skills`, which most agents read themselves, with links
|
|
58
|
+
into `.claude/skills`, `.kiro/skills` or any directory you name.
|
|
59
|
+
- **Your sources.** Packagist, GitLab's Composer registry, Satis, Private Packagist, GitHub, any
|
|
60
|
+
git server over HTTPS, or a static repository built by `skillcask publish`.
|
|
61
|
+
- **Reviewable updates.** A release-age cooldown (`init` writes `3d`), `outdated --strict` for
|
|
62
|
+
scheduled jobs, and `diff` / `diff --from old.lock` to read the skill text a change brings in.
|
|
63
|
+
- **Policy for every project.** `allow-sources`, `deny-packages`, exact versions only, and keys that
|
|
64
|
+
`config.toml` enforces so a project cannot loosen them.
|
|
65
|
+
- **Audit.** `audit` lists what each skill reaches (commands, hosts, paths, env vars, scripts),
|
|
66
|
+
flags risky lines and invisible characters, and prints SARIF; `--advisories` also checks
|
|
67
|
+
published security advisories.
|
|
68
|
+
- **Data only.** No package code runs, ever. No telemetry. No PHP, Composer or Node needed.
|
|
299
69
|
|
|
300
|
-
|
|
70
|
+
## How it works
|
|
301
71
|
|
|
302
|
-
```yaml
|
|
303
|
-
---
|
|
304
|
-
name: gitlab-branch-mr
|
|
305
|
-
version: 1.2.0
|
|
306
|
-
requires:
|
|
307
|
-
acme/security-review: ^1.0
|
|
308
|
-
github:mattpocock/skills/pr: main
|
|
309
|
-
"git:https://git.example.com/team/skills.git#review": ^2.0
|
|
310
|
-
---
|
|
311
72
|
```
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
stay out of `skills.toml`; the lock records each package's `requires` and switches to
|
|
316
|
-
`version = 2`. A dependency is looked up only in your repositories, in order, then Packagist;
|
|
317
|
-
a `github:` or `git:<url>[#skill]` one needs `github-requires = true`. `remove` drops dependencies nobody needs any
|
|
318
|
-
more, and `status` shows them as `via <requirer>`.
|
|
319
|
-
|
|
320
|
-
### Name conflicts
|
|
321
|
-
|
|
322
|
-
Skills have no namespaces: an agent knows a skill by its name. Two skills with the same name in
|
|
323
|
-
one project are an error. Install one of them under another name with `rename`:
|
|
324
|
-
|
|
325
|
-
```toml
|
|
326
|
-
"mattpocock/skills" = { github = true, rename = { code-review = "mp-code-review" } }
|
|
73
|
+
skills.toml ──add/update──▶ skills.lock ──install──▶ .agents/skills/<name>/ read by Codex, Cursor, Gemini CLI, …
|
|
74
|
+
manifest, lock, commit it ├─▶ .claude/skills/<name> link ([agents] targets)
|
|
75
|
+
commit it └─▶ .kiro/skills/<name> link
|
|
327
76
|
```
|
|
328
77
|
|
|
329
|
-
|
|
330
|
-
`
|
|
331
|
-
|
|
332
|
-
`add`, `install` and `update` offer the rename when they hit a conflict in a terminal.
|
|
78
|
+
`add` and `update` resolve the constraints in `skills.toml` and write the exact versions and
|
|
79
|
+
hashes to `skills.lock`; `install` installs exactly what the lock pins and fails on any hash
|
|
80
|
+
mismatch. Details: [Use](docs/guide/usage.md).
|
|
333
81
|
|
|
334
|
-
|
|
82
|
+
## macOS app
|
|
335
83
|
|
|
336
|
-
|
|
337
|
-
|
|
84
|
+
<picture>
|
|
85
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/GetResponse/skillcask/master/docs/assets/macos-app-dark.png">
|
|
86
|
+
<img alt="Skillcask for macOS: a project's skills with their state, and the details of one skill" src="https://raw.githubusercontent.com/GetResponse/skillcask/master/docs/assets/macos-app-light.png" width="800">
|
|
87
|
+
</picture>
|
|
88
|
+
|
|
89
|
+
<table>
|
|
90
|
+
<tr>
|
|
91
|
+
<td width="33%"><picture>
|
|
92
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/GetResponse/skillcask/master/docs/assets/macos-updates-dark.png">
|
|
93
|
+
<img alt="Reviewing an update as a diff before applying it" src="https://raw.githubusercontent.com/GetResponse/skillcask/master/docs/assets/macos-updates-light.png">
|
|
94
|
+
</picture></td>
|
|
95
|
+
<td width="33%"><picture>
|
|
96
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/GetResponse/skillcask/master/docs/assets/macos-audit-dark.png">
|
|
97
|
+
<img alt="Security findings for a skill" src="https://raw.githubusercontent.com/GetResponse/skillcask/master/docs/assets/macos-audit-light.png">
|
|
98
|
+
</picture></td>
|
|
99
|
+
<td width="33%"><picture>
|
|
100
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/GetResponse/skillcask/master/docs/assets/macos-add-dark.png">
|
|
101
|
+
<img alt="Searching and adding a skill" src="https://raw.githubusercontent.com/GetResponse/skillcask/master/docs/assets/macos-add-light.png">
|
|
102
|
+
</picture></td>
|
|
103
|
+
</tr>
|
|
104
|
+
<tr><td align="center">Review updates</td><td align="center">Audit findings</td><td align="center">Add skills</td></tr>
|
|
105
|
+
</table>
|
|
106
|
+
|
|
107
|
+
A SwiftUI app for macOS 14+ over the CLI: see each skill's state, updates and audit findings, read
|
|
108
|
+
its SKILL.md and diffs, and add, update or remove skills. Linux and Windows have the terminal UI,
|
|
109
|
+
`skillcask ui`.
|
|
338
110
|
|
|
339
111
|
```sh
|
|
340
|
-
|
|
341
|
-
skillcask -g install --frozen # e.g. from a dotfiles repository
|
|
112
|
+
brew install getresponse/tap/skillcask getresponse/tap/skillcask-app
|
|
342
113
|
```
|
|
343
114
|
|
|
344
|
-
|
|
345
|
-
(`$XDG_CONFIG_HOME/skillcask`; `SKILLCASK_HOME` overrides both). Keep them in your dotfiles.
|
|
346
|
-
- Skills go to `~/.agents/skills` (read by most agents), with links in `~/.claude/skills`
|
|
347
|
-
(`[agents] targets`, see Agents). Links are absolute, so a symlinked
|
|
348
|
-
`~/.claude` works. `[agents] local` does not apply.
|
|
349
|
-
- Personal skills you wrote by hand stay where they are and are not linked anywhere. `status`
|
|
350
|
-
lists them, and copies other tools put in a target, as `not managed`; `status --json` names the
|
|
351
|
-
source `npx skills` recorded for one. `skillcask -g add --adopt <source>` moves such a skill to
|
|
352
|
-
`~/.config/skillcask/adopted/` and installs the package's skill of the same name in its place.
|
|
353
|
-
- The list of managed paths is `~/.agents/skills/.skillcask-installed`, local to the machine;
|
|
354
|
-
nothing touches git.
|
|
115
|
+
More in [macOS app](docs/guide/macos-app.md).
|
|
355
116
|
|
|
356
|
-
|
|
117
|
+
## Documentation
|
|
357
118
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
| Command | |
|
|
119
|
+
| Guide | |
|
|
361
120
|
|---|---|
|
|
362
|
-
|
|
|
363
|
-
|
|
|
364
|
-
|
|
|
365
|
-
|
|
|
366
|
-
|
|
|
367
|
-
|
|
|
368
|
-
|
|
|
369
|
-
|
|
|
370
|
-
|
|
|
371
|
-
| `info <vendor/name[@constraint]\|github:owner/repo\|git:url\|skill>` | A package's skills, versions, description, license and requirements, or which package installs a skill. |
|
|
372
|
-
| `status` | Exit 1 when manifest, lock or installed files disagree. Also lists the repositories in use (name, type, URL without credentials) and whether `allow-sources` admits each. |
|
|
373
|
-
| `doctor [--fix]` | Broken or committed links, stale gitignore block, modified skills; lists each check it ran. |
|
|
374
|
-
| `audit [--json\|--sarif] [--advisories]` | What each installed skill reaches (commands, hosts, paths, env vars, scripts) and its findings: modified files, risky lines, invisible characters; with `--advisories` also published security advisories and abandoned packages. Exit 1 on any finding. |
|
|
375
|
-
| `config [key [value…]] [--unset] [--json]` | Settings with where each comes from: `[policy]` and `[agents] targets` of `skills.toml`, or with `-g` of `config.toml` (also `policy.enforce` and `search.skills-sh`). `config policy.min-release-age 5d` sets a key, `--unset` removes it, each checked before the file is written; `config edit` opens the file in `$VISUAL`/`$EDITOR` and checks it afterwards. |
|
|
376
|
-
| `search [query] [--skills-sh\|--no-skills-sh [--remember]]` | Packagist (`type=ai-agent-skill`) and skill packages of the other repositories, GitLab included; with skills.sh on, also the GitHub skills it lists, as `github:owner/repo/skill` with their install count. skills.sh is off until you turn it on, since it receives the query: the first search in a terminal asks once, `--remember` saves a flag's choice (no query needed), both in `config.toml`. |
|
|
377
|
-
| `auth set\|remove <host>` | Keep a registry token in git's credential helper (Keychain, Credential Manager, libsecret). |
|
|
378
|
-
| `publish --vendor v --base-url URL --out DIR [--inline] [--dist-url TPL] [paths…]` | Build a static Composer repository from a monorepo. |
|
|
379
|
-
| `validate [paths…]` | Check `SKILL.md` files against the Agent Skills spec, see below. |
|
|
380
|
-
| `projects [dirs…]` | Directories that hold `skills.toml` under the given ones (default: the current one), up to 6 levels down; hidden directories, `node_modules`, `vendor`, `target` and `Library` are skipped. |
|
|
381
|
-
| `ui` | A terminal UI over the commands above: skills with their state and updates, `info`, SKILL.md and `audit` per skill, add, adopt (also offered when an add hits a skill skillcask does not manage), update (diff first), remove, doctor, a filter of the list, search of the registries (and skills.sh, asked once), the repositories in use (`R`, `S` turns skills.sh on or off) and a projects picker; `g` switches between the project and `--global`. |
|
|
382
|
-
| `app` | Opens the macOS app (see [macOS app](#macos-app)); exits 1 when it is not installed, and on Linux and Windows. |
|
|
383
|
-
| `self-check [--json]` | Whether a newer skillcask is released, from the `skillcask-app` cask file of the tap; one anonymous request, only when run; writes nothing. |
|
|
384
|
-
| `self-update [--dry-run]` | Update skillcask: reruns the release's installer for an installer-script install (Linux, macOS), else prints the Homebrew, npm, cargo or app command and exits 1. `--dry-run` prints what would run. |
|
|
385
|
-
| `<other>` | Runs `skillcask-<other>` from `PATH`, like git and cargo plugins. |
|
|
386
|
-
|
|
387
|
-
`status`, `outdated`, `info`, `search`, `doctor`, `audit`, `projects`, `config` and
|
|
388
|
-
`self-check` take `--json`: one JSON document on one line of stdout, with the same exit code;
|
|
389
|
-
warnings and errors stay on stderr. Package text in it is escaped as in the terminal
|
|
390
|
-
(`<U+202E>`). `status --json` has `repositories`
|
|
391
|
-
(`[{"name", "type", "url", "allowed"}]`) and `skills-sh`; `search --json` results carry `source` (the repository
|
|
392
|
-
name, or `skills.sh`) and `installs`, and the document has `"skills-sh": true|false|null` (`null`:
|
|
393
|
-
never decided). `self-check --json` is `{"version", "latest", "newer"}` (`latest` is `null` when
|
|
394
|
-
the cask holds no readable version). For example `skillcask outdated --json | jq
|
|
395
|
-
'.packages[] | select(.within != .locked)'`.
|
|
396
|
-
|
|
397
|
-
Exit codes: 0 ok, 1 manifest/lock/status problems, 2 authentication, 3 network, 4 hash mismatch,
|
|
398
|
-
5 IO or archive error. `self-update` exits 1 when it updated nothing and printed the command to run;
|
|
399
|
-
when it runs the installer, the installer's exit code is its own.
|
|
400
|
-
|
|
401
|
-
Output is coloured in a terminal (`NO_COLOR` turns it off, `CLICOLOR_FORCE` on) and errors name
|
|
402
|
-
the next step on a `hint:` line. For coding agents, `--agent` or `SKILLCASK_AGENT=1` prints terse,
|
|
403
|
-
uncoloured, tab-separated output with only the rows that need action; it is on by itself when
|
|
404
|
-
`AI_AGENT` or `CLAUDECODE=1` is set, unless `SKILLCASK_AGENT=0`.
|
|
405
|
-
|
|
406
|
-
A failed connection, HTTP 429 or a 5xx response is retried twice, after 1 s and 2 s or after the
|
|
407
|
-
`Retry-After` seconds the server sends. A `Retry-After` above 60 s, a spent GitHub rate limit, a
|
|
408
|
-
timeout or a TLS error fails at once.
|
|
409
|
-
|
|
410
|
-
`add`, `update` and `outdated` warn about a package its registry marks `abandoned` and name the
|
|
411
|
-
replacement when there is one (and it is a valid package name). Installing from the lock does not ask the registry.
|
|
412
|
-
|
|
413
|
-
**Reviewing an update:** a skill is a prompt, so read what changes before you take it.
|
|
414
|
-
`skillcask diff` prints a unified diff of the skill files, from the locked version to the one
|
|
415
|
-
`update` would lock (newest within the constraint, past the cooldown), for every entry in
|
|
416
|
-
`skills.toml` with a newer version; `diff vendor/name --to 2.0.0` compares one package with
|
|
417
|
-
another version. A package new to the lock, such as a dependency a new version adds, is shown as
|
|
418
|
-
all added. Nothing is installed or written. Control characters, bidi controls and other
|
|
419
|
-
invisible characters in the diff are shown as `<U+XXXX>` (a carriage return too, when the line
|
|
420
|
-
ends change), and invisible characters in changed files are warned about. Files over 1 MiB or
|
|
421
|
-
10,000 lines print `Files differ (too large to show)`. `update --diff` prints the same diff
|
|
422
|
-
before it writes the lock, then installs without asking: run `skillcask diff` first to review
|
|
423
|
-
and decide. A scheduled CI job can run `skillcask outdated --strict` (exit 1 when something is to
|
|
424
|
-
update), then `skillcask update --diff` and open a pull request with the output.
|
|
425
|
-
|
|
426
|
-
**Reviewing a lock change:** `skillcask diff --from old.lock` prints the same diff from the
|
|
427
|
-
versions in another lock to those in `skills.lock`, plus the packages it drops, so a reviewer
|
|
428
|
-
sees the skill text a pull request brings in instead of new versions and hashes. Each new dist
|
|
429
|
-
is verified against `skills.lock` as `install` would, and the policy decides which repositories
|
|
430
|
-
may be fetched. skillcask does not run git; the job fetches the old lock:
|
|
431
|
-
|
|
432
|
-
```yaml
|
|
433
|
-
# GitLab CI: print the diff in the merge request pipeline
|
|
434
|
-
skills-diff:
|
|
435
|
-
rules:
|
|
436
|
-
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
437
|
-
changes: [skills.lock]
|
|
438
|
-
script:
|
|
439
|
-
- git fetch --depth 1 origin "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME"
|
|
440
|
-
- git show FETCH_HEAD:skills.lock | skillcask diff --from -
|
|
441
|
-
```
|
|
442
|
-
|
|
443
|
-
`--from -` reads the old lock from stdin. On GitHub the same lines run in a `pull_request` job with `$GITHUB_BASE_REF`; posting the
|
|
444
|
-
output as a comment is up to the CI.
|
|
445
|
-
|
|
446
|
-
**Where a skill comes from:** `skillcask info vendor/name` shows the package's skills with their
|
|
447
|
-
descriptions, its versions, description, license, `abandoned` and `requires`, for the locked
|
|
448
|
-
version or else the newest one `add` would take (`@constraint` for another); `info
|
|
449
|
-
github:owner/repo` lists the skills of a GitHub repository before you add it. `skillcask info
|
|
450
|
-
<skill>` names the package that installs an installed skill and the `skills.toml` entry, or the
|
|
451
|
-
chain of `requires`, that brings it in.
|
|
452
|
-
|
|
453
|
-
**Merge conflicts in `skills.lock`:** a lock with conflict markers fails with a hint. Resolve
|
|
454
|
-
`skills.toml`, keep either side of the lock (`git checkout --theirs skills.lock`) and run
|
|
455
|
-
`skillcask install`: it locks the entries from the other side that the kept lock lacks.
|
|
456
|
-
|
|
457
|
-
### Skills from GitHub and skills.sh
|
|
458
|
-
|
|
459
|
-
[skills.sh](https://skills.sh) lists skills as `owner/repo/skill`, for example
|
|
460
|
-
`mattpocock/skills/grill-me`. Put `github:` in front and add it:
|
|
461
|
-
|
|
462
|
-
```sh
|
|
463
|
-
skillcask add github:mattpocock/skills/grill-me # one skill
|
|
464
|
-
skillcask add github:mattpocock/skills/tdd # a second one from the same repository
|
|
465
|
-
skillcask add github:anthropics/skills # every skill in the repository
|
|
466
|
-
```
|
|
467
|
-
|
|
468
|
-
All skills of one repository share one entry in `skills.toml`:
|
|
469
|
-
|
|
470
|
-
```toml
|
|
471
|
-
"mattpocock/skills" = { github = true, version = "^1.3", skills = ["grill-me", "tdd"] }
|
|
472
|
-
```
|
|
473
|
-
|
|
474
|
-
Which version you get:
|
|
475
|
-
|
|
476
|
-
- **Repository with version tags** (`v1.3.1`): `add` writes `version = "^<major.minor>"`, like
|
|
477
|
-
for Composer packages, and `update` moves within it. The release time of a tag is its commit
|
|
478
|
-
date.
|
|
479
|
-
- **Repository without tags**: the entry follows the default branch; `ref = "main"` names a
|
|
480
|
-
branch, tag or commit instead. The lock pins the commit sha, so `install` keeps installing that
|
|
481
|
-
commit until you run `update`.
|
|
482
|
-
- `@` picks explicitly: `github:owner/repo@^2.0` (version tags), `github:owner/repo@main` or
|
|
483
|
-
`@<commit sha>` (ref).
|
|
484
|
-
- With `policy.allow-ranges = false` a branch counts as a range: `add` writes the full commit sha
|
|
485
|
-
as `ref`, and a hand-written branch name is rejected.
|
|
486
|
-
|
|
487
|
-
Skills are found by their `SKILL.md` anywhere in the repository, except inside another skill.
|
|
488
|
-
The install name is the frontmatter `name`; when that is not a valid name (`Jira Automation`), the
|
|
489
|
-
directory name is used. `skills = [...]` takes these names.
|
|
490
|
-
|
|
491
|
-
GitHub allows 60 anonymous API requests per hour. `add`, `update` and `outdated` use a few per
|
|
492
|
-
entry; `install` from the lock uses none, it downloads the pinned archive. Set `GITHUB_TOKEN`
|
|
493
|
-
(GitHub Actions has one) or Composer's `"github-oauth": {"github.com": "<token>"}` in `auth.json`
|
|
494
|
-
for a higher limit and for private repositories. `SKILLCASK_GITHUB_API` points at GitHub
|
|
495
|
-
Enterprise (`https://ghe.example.com/api/v3`). `GITHUB_TOKEN` is sent only to the API the user or
|
|
496
|
-
the runner names: `SKILLCASK_GITHUB_API`, else GitHub Actions' `GITHUB_API_URL`, else
|
|
497
|
-
`api.github.com`; for an Enterprise URL set only in `skills.toml`, use
|
|
498
|
-
`skillcask auth set ghe.example.com --username oauth2` or `github-oauth` in `auth.json`.
|
|
499
|
-
|
|
500
|
-
skills.sh itself is not queried: its API is undocumented and may change without notice. Search
|
|
501
|
-
on the website, then add what you picked.
|
|
502
|
-
|
|
503
|
-
### Skills from any git repository
|
|
504
|
-
|
|
505
|
-
GitLab, Bitbucket, Azure DevOps, Gitea or a self-hosted server work without a Composer registry:
|
|
506
|
-
|
|
507
|
-
```sh
|
|
508
|
-
skillcask add git:https://gitlab.example.com/acme/skills.git
|
|
509
|
-
skillcask add git:https://gitlab.example.com/acme/skills.git@main
|
|
510
|
-
```
|
|
511
|
-
|
|
512
|
-
```toml
|
|
513
|
-
"acme/skills" = { git = "https://gitlab.example.com/acme/skills.git", version = "^1.0" }
|
|
514
|
-
```
|
|
515
|
-
|
|
516
|
-
Versions, `ref` and `skills = [...]` work as for GitHub; the entry is named after the last two
|
|
517
|
-
parts of the URL. skillcask speaks git's HTTPS protocol itself: no git binary runs, so no hook or
|
|
518
|
-
filter of the repository can. It fetches the one commit it needs and checks every file against
|
|
519
|
-
the commit's object ids. Credentials come from the same places as for registries (`auth.json`,
|
|
520
|
-
the credential helper, `$CI_JOB_TOKEN` in GitLab CI). Git servers keep no release or push times,
|
|
521
|
-
so `min-release-age` uses commit dates, which the committer sets; a branch whose newest commit is
|
|
522
|
-
too young falls back to an older commit when the server supports partial fetches (`filter`).
|
|
121
|
+
| [Install](docs/guide/install.md) | Every install method, the GitHub Action, updating |
|
|
122
|
+
| [Use](docs/guide/usage.md) | `skills.toml`, agents, dependencies, name conflicts, personal skills (`--global`) |
|
|
123
|
+
| [Commands](docs/guide/commands.md) | Every command, `--json`, exit codes, reviewing updates and lock changes |
|
|
124
|
+
| [Sources](docs/guide/sources.md) | Skills from GitHub, skills.sh and any git repository |
|
|
125
|
+
| [Policy](docs/guide/policy.md) | Allowed sources and policy for every project |
|
|
126
|
+
| [Security](docs/guide/security.md) | What is verified, warnings, `audit`, credentials |
|
|
127
|
+
| [Publishing skills](docs/guide/publishing.md) | Packages, monorepos with `skillcask publish`, `validate` |
|
|
128
|
+
| [macOS app](docs/guide/macos-app.md) | Installing and building the app |
|
|
129
|
+
| [Design](docs/specs/2026-10-19-skillcask-v1.md) | Goals, non-goals and numbered decisions |
|
|
523
130
|
|
|
524
131
|
## Security
|
|
525
132
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
- HTTPS only, verified against the system trust store, so corporate CAs work. Verification
|
|
530
|
-
cannot be turned off; `SKILLCASK_CA_FILE` replaces the trust store with a PEM bundle.
|
|
531
|
-
- Archives with absolute paths, `..`, devices or symlinks that leave their skill are rejected.
|
|
532
|
-
No symlink is ever written from a package. Size and file count are capped (`--max-download`,
|
|
533
|
-
`--max-unpacked`, `--max-files`).
|
|
534
|
-
- File names must be valid on every OS: Windows-reserved names, `<>:"|?*\`, control characters
|
|
535
|
-
and paths that collide by case or Unicode form fail a skill that contains them, and are
|
|
536
|
-
skipped outside the selected skills.
|
|
537
|
-
- No package code runs, ever. No telemetry.
|
|
538
|
-
- `self-check` and the app's "Check for Updates…" send nothing but the request for the tap's cask
|
|
539
|
-
file, which carries the skillcask version in its User-Agent (`skillcask/<version>`): no token,
|
|
540
|
-
account, project or skill data; GitHub sees your IP address. The app checks
|
|
541
|
-
daily only after you say yes. `SKILLCASK_SELF_CHECK_URL` points it at a mirror (HTTPS only).
|
|
542
|
-
- `self-update` sends the same request, then, for an installer-script install only, downloads that
|
|
543
|
-
release's `skillcask-installer.sh` the same way (`SKILLCASK_SELF_UPDATE_URL` replaces the
|
|
544
|
-
download base) and runs it with `/bin/sh`, without your `SKILLCASK_*`, `INSTALLER_*` and
|
|
545
|
-
`CARGO_DIST_*` variables. The script checks the archive's sha256 with `sha256sum`, so
|
|
546
|
-
`self-update` refuses to run it when `sha256sum` is not on `PATH`.
|
|
547
|
-
- `add` and `update` (and `install` when it resolves) warn about characters a reviewer cannot
|
|
548
|
-
see in the text files of new content: bidi controls (`U+202A`-`U+202E`, `U+2066`-`U+2069`,
|
|
549
|
-
`U+200E`, `U+200F`, `U+061C`), zero-width characters (`U+200B`-`U+200D`, `U+2060`, `U+FEFF`) and
|
|
550
|
-
Unicode tags (`U+E0000`-`U+E007F`), as `warning: acme/x: skills/foo/SKILL.md:12: U+202E
|
|
551
|
-
RIGHT-TO-LEFT OVERRIDE`, at most five per file. A leading byte order mark and a zero width
|
|
552
|
-
joiner inside an emoji are not reported; right-to-left and Indic text can trigger warnings.
|
|
553
|
-
Installing from the lock does not warn again.
|
|
554
|
-
- The same commands warn about lines that usually mean harm, as `warning: acme/x:
|
|
555
|
-
skills/foo/SKILL.md:12: downloads code into a shell`, at most five per file:
|
|
556
|
-
|
|
557
|
-
| Warning | Matches (case-insensitive) |
|
|
558
|
-
|---|---|
|
|
559
|
-
| downloads code into a shell | `curl`, `wget`, `irm`, `iwr`, `Invoke-WebRequest` or `Invoke-RestMethod` piped (`\|`) into `sh`, `bash`, `zsh`, `dash`, `iex`, `Invoke-Expression`, `python`, `perl`, `ruby` or `node`, also after `sudo` |
|
|
560
|
-
| decodes base64 and runs it | `base64 -d`, `base64 --decode`, `b64decode` or `FromBase64String` with a pipe into a shell, `eval`, `exec(` or `iex` |
|
|
561
|
-
| reads SSH keys | `~/.ssh`, `$HOME/.ssh`, `id_rsa`, `id_ed25519` |
|
|
562
|
-
| reads system account files | `/etc/passwd`, `/etc/shadow` |
|
|
563
|
-
| tells the agent to ignore its instructions | "ignore (all) previous/prior instructions", "disregard all previous/prior" |
|
|
564
|
-
|
|
565
|
-
Skills that teach shell setup trigger some of these legitimately, so they are warnings. With
|
|
566
|
-
`deny-patterns = true` under `[policy]` (or enforced in `config.toml`) they, and the invisible
|
|
567
|
-
characters above, fail the command with exit 1 and nothing is written.
|
|
568
|
-
- `skillcask audit` reviews what is installed now, every skill in `.agents/skills` and the project
|
|
569
|
-
skills: the commands its shell code blocks run, the hosts of its URLs, the paths in the home
|
|
570
|
-
directory or under system roots, the environment variables it reads and the files an agent could
|
|
571
|
-
run. That is read from the text, so it is a hint for review, not a sandbox, and a skill without
|
|
572
|
-
findings is not known to be safe. It also reports a locked skill that differs from the lock, and
|
|
573
|
-
every risky line and invisible character above, with no limit per file, and exits 1 on any of
|
|
574
|
-
them.
|
|
575
|
-
- `skillcask audit --advisories` also asks the sources of the locked packages what is published
|
|
576
|
-
about them: security advisories from a Composer repository that offers them (Packagist does) and
|
|
577
|
-
from a GitHub repository's security advisories, matched against the locked version, and
|
|
578
|
-
packages marked abandoned. An entry locked at a commit has no version to match, so only
|
|
579
|
-
advisories published after that commit count. A source that cannot be read fails the run;
|
|
580
|
-
packages whose source publishes no advisories, and plain git entries, are listed as unchecked.
|
|
581
|
-
Plain `audit` stays offline. To warn users of
|
|
582
|
-
your skill, publish a GitHub security advisory on its repository (for a Composer package, with
|
|
583
|
-
the `composer` ecosystem and the package name, so Packagist lists it too).
|
|
584
|
-
- `--sarif` prints a SARIF 2.1.0 log for code scanning, e.g. in GitHub Actions. Scripts a skill
|
|
585
|
-
bundles with their own dependencies (`package.json`, `requirements.txt`) are not covered by
|
|
586
|
-
`--advisories`; [OSV-Scanner](https://github.com/google/osv-scanner) checks those:
|
|
587
|
-
|
|
588
|
-
```yaml
|
|
589
|
-
- uses: GetResponse/skillcask@v0.10.5
|
|
590
|
-
with:
|
|
591
|
-
args: install --frozen
|
|
592
|
-
- run: skillcask audit --advisories --sarif > skills.sarif
|
|
593
|
-
env:
|
|
594
|
-
GITHUB_TOKEN: ${{ github.token }} # anonymous GitHub API calls are limited to 60 an hour
|
|
595
|
-
- uses: github/codeql-action/upload-sarif@v3
|
|
596
|
-
if: always()
|
|
597
|
-
with:
|
|
598
|
-
sarif_file: skills.sarif
|
|
599
|
-
# optional, needs osv-scanner on PATH (e.g. google/osv-scanner-action): dependencies of bundled scripts
|
|
600
|
-
- run: osv-scanner scan source -r .agents/skills
|
|
601
|
-
```
|
|
602
|
-
- Plain git sources pin the commit; the lock's `dist-sha256` hashes the commit's file list
|
|
603
|
-
(path, mode, sha256 of the content), so it does not depend on how a server packs objects.
|
|
604
|
-
- `min-release-age` for GitHub sources uses times GitHub sets: release publication for tags,
|
|
605
|
-
push times from the Activity API for branches. A tag without a release, or a ref GitHub lists no
|
|
606
|
-
pushes for, falls back to commit dates, which the committer sets; reviewing what `add`/`update`
|
|
607
|
-
change in `skills.lock` is the real check there.
|
|
608
|
-
- Credentials come from Composer's `auth.json` / `COMPOSER_AUTH` (`http-basic`, `bearer`,
|
|
609
|
-
`gitlab-token`, `gitlab-oauth`), then from git's credential helper, and are never printed.
|
|
610
|
-
`skillcask auth set git.example.com` keeps a token in the macOS Keychain, the Windows Credential
|
|
611
|
-
Manager or libsecret instead of a plain-text file (the default username `PRIVATE-TOKEN` sends
|
|
612
|
-
GitLab's header; `--username oauth2` a Bearer token). `SKILLCASK_GIT_CREDENTIALS=0` turns the
|
|
613
|
-
helper off. In GitLab CI use `http-basic` with the
|
|
614
|
-
user `gitlab-ci-token` and the password `$CI_JOB_TOKEN`.
|
|
615
|
-
|
|
616
|
-
## Publishing skills
|
|
617
|
-
|
|
618
|
-
**One repository per skill:** a `composer.json` with `"type": "ai-agent-skill"` (the
|
|
619
|
-
[netresearch convention](https://github.com/netresearch/composer-agent-skill-plugin)) and semver
|
|
620
|
-
tags. Packagist or GitLab's Composer registry picks up the tags; skillcask plays no part.
|
|
621
|
-
|
|
622
|
-
**Monorepo:** give each `SKILL.md` a `version` in its frontmatter and run
|
|
623
|
-
|
|
624
|
-
```sh
|
|
625
|
-
skillcask publish --vendor acme --base-url https://skills.example.com --out public skills/
|
|
626
|
-
```
|
|
627
|
-
|
|
628
|
-
This writes `packages.json`, `p2/acme/<name>.json` and deterministic zips under `dist/`. Published
|
|
629
|
-
versions are immutable, and re-running on unchanged skills changes no file. Serve the directory
|
|
630
|
-
over HTTPS.
|
|
631
|
-
|
|
632
|
-
Check the skills before publishing; `validate` exits 1 on any error and warns about invisible
|
|
633
|
-
Unicode, as `add` does:
|
|
634
|
-
|
|
635
|
-
```sh
|
|
636
|
-
skillcask validate skills/
|
|
637
|
-
```
|
|
638
|
-
|
|
639
|
-
It follows the [Agent Skills specification](https://agentskills.io/specification): `name` 1-64
|
|
640
|
-
lowercase letters, digits and single hyphens, equal to the directory name; `description` 1-1024
|
|
641
|
-
characters; `compatibility` at most 500. Without paths it searches the current directory, skipping
|
|
642
|
-
hidden ones; `skillcask validate .agents/skills` checks the skills installed in a project.
|
|
643
|
-
`publish` skips a `SKILL.md` without `name` or `version` and names it in a warning.
|
|
644
|
-
|
|
645
|
-
To retire a skill, publish a new version with `deprecated: true`, or `deprecated: vendor/name`
|
|
646
|
-
naming its replacement, in the frontmatter. It becomes Composer's `abandoned`, and consumers see a
|
|
647
|
-
warning on `add`, `update` and `outdated`.
|
|
648
|
-
|
|
649
|
-
Hosts that cannot serve `/` inside file names (GitLab's Generic Package Registry) take a single
|
|
650
|
-
file instead:
|
|
651
|
-
|
|
652
|
-
```sh
|
|
653
|
-
skillcask publish --inline --vendor acme --out composer/ skills/ \
|
|
654
|
-
--dist-url 'https://git.example.com/api/v4/projects/7/packages/generic/{vendor}-{name}/{version}/{name}-{version}.zip'
|
|
655
|
-
```
|
|
656
|
-
|
|
657
|
-
`--inline` puts every package into `packages.json` and writes no `p2/`. Upload each
|
|
658
|
-
`dist/<vendor>/<name>/<version>.zip` to the URL the template gives, and commit `packages.json` to
|
|
659
|
-
a repository. A repository `url` with a query string is used as given, so clients can read the
|
|
660
|
-
file through the GitLab raw files API
|
|
661
|
-
(`.../repository/files/composer%2Fpackages.json/raw?ref=main`) with a `gitlab-token`.
|
|
662
|
-
|
|
663
|
-
## macOS app
|
|
664
|
-
|
|
665
|
-
`macos/` holds a SwiftUI app for macOS 14+ over the CLI (D35): open My Skills (the `-g` scope) or a
|
|
666
|
-
project folder, see each skill's state, updates and audit findings, read its SKILL.md and diffs,
|
|
667
|
-
and run `add` (also `--adopt`), `update`, `remove`, `install` and `doctor --fix`; its Settings
|
|
668
|
-
change every key `skillcask -g config` lists. It has no package logic of its own: it runs the
|
|
669
|
-
`skillcask` binary, 0.9.4 or newer, and reads its `--json` output.
|
|
670
|
-
|
|
671
|
-
Install it with Homebrew, then open it from Applications or with `skillcask app`. The cask depends
|
|
672
|
-
on the formula; name both, since Homebrew loads from a third-party tap only what it was asked for
|
|
673
|
-
or what `brew trust` lists:
|
|
674
|
-
|
|
675
|
-
```sh
|
|
676
|
-
brew install getresponse/tap/skillcask getresponse/tap/skillcask-app
|
|
677
|
-
```
|
|
678
|
-
|
|
679
|
-
Every release also has `Skillcask-X.Y.Z-macos-universal.zip`, signed with a Developer ID and
|
|
680
|
-
notarized (D50): unzip it into `/Applications`.
|
|
681
|
-
|
|
682
|
-
The app tells you about a newer release but installs nothing ([Update](#update)). Its app menu
|
|
683
|
-
has Check for Updates…, which runs `skillcask self-check`; it checks daily only after you say yes
|
|
684
|
-
once (it asks in the sidebar; Settings › Updates switches it). A newer version gets a card and a
|
|
685
|
-
sheet with the Homebrew command to copy, or the release page for a download (D51).
|
|
686
|
-
|
|
687
|
-
`macos/bundle.sh` builds a universal `Skillcask.app` that carries its own CLI at
|
|
688
|
-
`Contents/Helpers/skillcask`. Run outside a bundle (`swift run` from `macos/`), the app uses the
|
|
689
|
-
path set in its Settings, else looks on `PATH`, in `/opt/homebrew/bin`, `/usr/local/bin` and
|
|
690
|
-
`~/.cargo/bin`. Building it needs Xcode 26.x with Swift 6.3 or newer, not only the Command Line
|
|
691
|
-
Tools. Building, signing, Gatekeeper, tests and renders: [macos/README.md](macos/README.md).
|
|
133
|
+
HTTPS only, hashes checked on every install, archives that escape their skill rejected, and no
|
|
134
|
+
package code run. The threat model and every check are in [Security](docs/guide/security.md);
|
|
135
|
+
report a vulnerability as [SECURITY.md](SECURITY.md) describes.
|
|
692
136
|
|
|
693
|
-
##
|
|
137
|
+
## Contributing
|
|
694
138
|
|
|
695
|
-
|
|
139
|
+
Read [AGENTS.md](AGENTS.md) for the checks CI runs and the project's invariants, and the
|
|
140
|
+
[design spec](docs/specs/2026-10-19-skillcask-v1.md) before changing how the manifest, lock,
|
|
141
|
+
install or publish behave.
|
|
696
142
|
|
|
697
143
|
## License
|
|
698
144
|
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"hasInstallScript": true,
|
|
20
20
|
"license": "MIT OR Apache-2.0",
|
|
21
21
|
"name": "skillcask",
|
|
22
|
-
"version": "0.
|
|
22
|
+
"version": "0.11.0"
|
|
23
23
|
},
|
|
24
24
|
"node_modules/detect-libc": {
|
|
25
25
|
"engines": {
|
|
@@ -48,5 +48,5 @@
|
|
|
48
48
|
}
|
|
49
49
|
},
|
|
50
50
|
"requires": true,
|
|
51
|
-
"version": "0.
|
|
51
|
+
"version": "0.11.0"
|
|
52
52
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"artifactDownloadUrls": [
|
|
3
|
-
"https://github.com/GetResponse/skillcask/releases/download/v0.
|
|
3
|
+
"https://github.com/GetResponse/skillcask/releases/download/v0.11.0"
|
|
4
4
|
],
|
|
5
5
|
"bin": {
|
|
6
6
|
"skillcask": "run-skillcask.js"
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
"zipExt": ".tar.xz"
|
|
105
105
|
}
|
|
106
106
|
},
|
|
107
|
-
"version": "0.
|
|
107
|
+
"version": "0.11.0",
|
|
108
108
|
"volta": {
|
|
109
109
|
"node": "18.14.1",
|
|
110
110
|
"npm": "9.5.0"
|