@h0tp/shucky 0.1.0 → 0.4.4
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/CHANGELOG.md +131 -29
- package/LICENSE +21 -21
- package/NOTICE +24 -0
- package/README.md +214 -119
- package/SKILL.md +168 -124
- package/bin/shucky.js +13 -13
- package/config.json +28 -28
- package/lib/agents.js +163 -0
- package/lib/approvals.js +50 -50
- package/lib/archive.js +173 -0
- package/lib/cli.js +782 -118
- package/lib/config.js +52 -52
- package/lib/discover.js +143 -0
- package/lib/fetch.js +303 -0
- package/lib/find.js +162 -0
- package/lib/lock.js +119 -0
- package/lib/place.js +247 -0
- package/lib/registry.js +141 -0
- package/lib/report.js +53 -53
- package/lib/rules.js +162 -162
- package/lib/safeurl.js +139 -0
- package/lib/scan.js +148 -148
- package/lib/sources.js +311 -0
- package/package.json +43 -41
package/CHANGELOG.md
CHANGED
|
@@ -1,29 +1,131 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## 0.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
|
|
29
|
-
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.4.4
|
|
4
|
+
|
|
5
|
+
- **`shucky self-update`** — update shucky *itself* (the CLI). It detects how shucky was installed and
|
|
6
|
+
runs the matching update: `git pull --ff-only` for a source / `npm link` checkout, `npm i -g
|
|
7
|
+
@h0tp/shucky@latest` for a global npm install, or a no-op + hint when run via npx. `--check`
|
|
8
|
+
previews the command without running it. (To re-fetch + RE-SCAN the skills shucky installed *for
|
|
9
|
+
you*, use `shucky update`.)
|
|
10
|
+
|
|
11
|
+
## 0.4.3
|
|
12
|
+
|
|
13
|
+
- **Comprehensive test suite + unified runner.** `npm test` now runs `test/run-all.js`, which runs
|
|
14
|
+
every suite in its own process and prints one aggregated summary (per-suite ✓/✗ + grand total),
|
|
15
|
+
showing full output only for a suite that fails. **183 zero-dep checks across 6 suites:**
|
|
16
|
+
- `run-rules.js` — every deterministic scan rule fired in isolation, a meta-check that *all* rules
|
|
17
|
+
are covered, and the prose-vs-fence Markdown logic.
|
|
18
|
+
- `run-coverage.js` — edge cases across every module (sources/safeurl/discover/place/lock/registry/
|
|
19
|
+
archive) plus full CLI integration: the install → list → update → remove lifecycle, multi-skill
|
|
20
|
+
gating (worst-exit-wins), `--skill`, `--policy report`, and `--json` output shapes.
|
|
21
|
+
- plus `run.js`, `run-install.js`, `run-manager.js`, `run-archive.js`.
|
|
22
|
+
- Shared zero-dep harness `test/_util.js` (check / eq / throws / tmp / quiet / capture + tar/zip
|
|
23
|
+
builders).
|
|
24
|
+
|
|
25
|
+
## 0.4.2
|
|
26
|
+
|
|
27
|
+
- **Per-command `--help`.** `shucky <command> --help` now prints detailed help for that command —
|
|
28
|
+
usage, positional arguments, every option, and examples — for `install`, `scan`, `find`, `list`,
|
|
29
|
+
`remove`, `update`, `source` (incl. its `add` / `list` / `remove` subcommands), and `approve`.
|
|
30
|
+
Aliases (`add`/`i`, `rm`, `ls`, `search`, `upgrade`, …) resolve to the right help, and the global
|
|
31
|
+
`shucky --help` points to it.
|
|
32
|
+
|
|
33
|
+
## 0.4.1
|
|
34
|
+
|
|
35
|
+
- **`shucky find --github`** — also search GitHub: precise `SKILL.md` **code search** when
|
|
36
|
+
`GITHUB_TOKEN` / `GH_TOKEN` is set, otherwise an unauthenticated **repo search** filtered to
|
|
37
|
+
skill/agent repos. Ranked + trust-annotated alongside skills.sh; opt-in (default `find` unchanged).
|
|
38
|
+
- **ClawHub-ready** — `SKILL.md` gains a `metadata.openclaw` block (emoji, `user-invocable`, an npm
|
|
39
|
+
install helper for the `shucky` bin) so shucky publishes cleanly to [ClawHub](https://clawhub.ai).
|
|
40
|
+
`CLAWHUB.md` documents the (account-gated) `clawhub skill publish` flow; users then
|
|
41
|
+
`openclaw skills install shucky`.
|
|
42
|
+
- `safeGet` now supports custom request headers (for the GitHub API). New flags: `--github`, `--local`.
|
|
43
|
+
|
|
44
|
+
## 0.4.0
|
|
45
|
+
|
|
46
|
+
- **Archive sources** — `install`/`scan` now accept `.tar.gz` / `.tgz` / `.zip` (a remote URL,
|
|
47
|
+
incl. GitHub `…/archive/….tar.gz`, or a local file). New `lib/archive.js` extracts with pure Node
|
|
48
|
+
(zlib), hardened against the classic archive attacks: **zip-slip** (every entry path is resolved
|
|
49
|
+
and must stay inside the destination), **symlink / hardlink / device entries are dropped** (never
|
|
50
|
+
written — same reason placement drops symlinks), and **zip-bomb caps** (entry count, per-entry +
|
|
51
|
+
total uncompressed size, plus gunzip / inflate `maxOutputLength`). Archives carry no owner/repo
|
|
52
|
+
identity, so they are always fully scanned (no trust relax). "From anywhere" now includes tarballs.
|
|
53
|
+
- Tests: `test/run-archive.js` (10 checks, builds tar/zip in-process) — 112 zero-dep checks total.
|
|
54
|
+
|
|
55
|
+
## 0.3.0
|
|
56
|
+
|
|
57
|
+
Phase 2 — shucky becomes a full manager: it now manages many skill sources and discovers across them.
|
|
58
|
+
|
|
59
|
+
- **`shucky find [query]`** (`search`, `f`, `s`) — search the public registry (skills.sh) + your
|
|
60
|
+
registered sources/lists; results ranked by installs and annotated with source-trust. Selecting
|
|
61
|
+
one hands off to `install`, so every result is scanned before it lands. `--json`, `--limit`.
|
|
62
|
+
- **`shucky source add|list|remove <spec>`** — a registry of the repos / registries / curated lists
|
|
63
|
+
you trust. `--trust trusted` feeds the scanner's relax policy (low/medium relax; high/critical
|
|
64
|
+
still block). Two files: `~/.shucky/sources.json` (global) + `./shucky-sources.json` (project).
|
|
65
|
+
- **Curated lists:** register a `.json` manifest as a `list` source and install the whole bundle
|
|
66
|
+
with `shucky install --list <name>` (each member independently scanned).
|
|
67
|
+
- **`shucky remove <name>`** (`rm`) — uninstall across agent dirs + prune the lockfile (path-guarded
|
|
68
|
+
to the skill's own directory).
|
|
69
|
+
- **`shucky update [name]`** — re-fetch → **re-scan** → re-place installed skills; if a once-clean
|
|
70
|
+
skill now BLOCKS it is left as-is and flagged, not silently reinstalled. Skips local/raw sources.
|
|
71
|
+
- New modules `lib/registry.js`, `lib/find.js`; `lib/place.js` gains `unplaceSkill`. New flags:
|
|
72
|
+
`--name`, `--trust`, `--type`, `--limit`, `--list`.
|
|
73
|
+
- Tests: `test/run-manager.js` (20 checks) — 102 zero-dep checks total.
|
|
74
|
+
|
|
75
|
+
## 0.2.0
|
|
76
|
+
|
|
77
|
+
shucky becomes find · scan · **install** — the safe front door for adding skills. Self-contained;
|
|
78
|
+
**no runtime dependency on `npx skills`** (its logic is reimplemented; `git` is the only external
|
|
79
|
+
binary, for git sources).
|
|
80
|
+
|
|
81
|
+
- **`shucky install <source>`** (`add`, `i`) — resolve → fetch → **scan** → gate → place → record.
|
|
82
|
+
The scan gate is un-bypassable: BLOCK installs nothing, WARN installs only with `-y` (never a
|
|
83
|
+
BLOCK), PASS installs. The *only* way past a BLOCK is a logged `shucky approve`. shucky scans the
|
|
84
|
+
exact bytes it installs (one fetch — no time-of-check/time-of-use gap).
|
|
85
|
+
- **From anywhere:** `owner/repo[/sub][@skill][#ref]`, github/gitlab URLs (incl. self-hosted),
|
|
86
|
+
`…/blob/…/SKILL.md`, any git/ssh URL, `gist:<id>`, a raw `SKILL.md` URL, and `.well-known` hosts —
|
|
87
|
+
plus local paths. (Broader than `npx skills`, which rejects bare file URLs.)
|
|
88
|
+
- **Comprehensive multi-environment install** ported from `vercel-labs/skills` (MIT, see `NOTICE`):
|
|
89
|
+
~70-agent registry, canonical `.agents/skills` + per-agent symlinks, copy/junction fallback,
|
|
90
|
+
agent detection, idempotent re-install, Claude-Code plugin manifests.
|
|
91
|
+
- **`shucky scan`** now also accepts remote sources (fetches into a temp dir, scans, cleans up).
|
|
92
|
+
- **`shucky list`** — lists skills shucky installed, from the lockfiles.
|
|
93
|
+
- **Hardened fetcher:** SSRF guard (metadata/loopback/private/`*.internal`) with DNS-rebind defense
|
|
94
|
+
+ redirect re-validation; the installer **drops symlinks** on copy (the scanner skips them, so
|
|
95
|
+
dereferencing would smuggle in unscanned bytes); git runs `--depth 1`, no prompts/LFS, array-args.
|
|
96
|
+
- **Provenance lockfiles:** `shucky-skills.json` (project, committed, sorted, timestamp-free) and
|
|
97
|
+
`~/.shucky/installed-skills.json` (global) record source, resolved commit, content hash, and the
|
|
98
|
+
scan verdict — so a future `update` can re-scan and flag drift. Approvals pin to the commit SHA.
|
|
99
|
+
- New modules: `lib/sources.js`, `lib/safeurl.js`, `lib/fetch.js`, `lib/discover.js`,
|
|
100
|
+
`lib/agents.js`, `lib/place.js`, `lib/lock.js`. New flags: `-g/--global`, `--scope`, `-a/--agent`,
|
|
101
|
+
`--all`, `--skill`, `--dir`, `--copy`, `-y/--yes`.
|
|
102
|
+
- Tests: `test/run-install.js` (61 checks) covering source parsing, SSRF/rebind, discovery,
|
|
103
|
+
placement (incl. symlink-drop), lockfiles, and the full install gate — 82 checks total.
|
|
104
|
+
|
|
105
|
+
## 0.1.0 — unreleased
|
|
106
|
+
|
|
107
|
+
Initial build.
|
|
108
|
+
|
|
109
|
+
- Zero-dependency CLI: `shucky scan <path>` with `--json`, `--source`, `--at`, `--policy`,
|
|
110
|
+
`--quiet`, `--config`, `--help`, `--version`; plus `shucky approve <owner/repo> --at <ver>
|
|
111
|
+
--reason <text>` for persistent overrides.
|
|
112
|
+
- Deterministic rule engine: `secret_access`, `agent_state_access`, `browser_session`,
|
|
113
|
+
`network_exfil`, `obfuscation`, `destructive`, `persistence`, `prompt_injection`,
|
|
114
|
+
`supply_chain`, `excessive_scope`.
|
|
115
|
+
- `browser_session`, `agent_state_access`, and raw-IP exfil URLs are adapted from the
|
|
116
|
+
community **skill-vetter** skill (spclaudehome, MIT-0).
|
|
117
|
+
- Prose/fence-aware Markdown scanning: code-execution rules apply only inside fenced code
|
|
118
|
+
blocks; prose is checked for prompt-injection only — cuts false positives on docs that
|
|
119
|
+
*mention* a command.
|
|
120
|
+
- Reads files as text only — **never executes** the skill under review; flags opaque/compiled
|
|
121
|
+
binaries instead of running them.
|
|
122
|
+
- Verdict model with block-on-risk default; trusted-source `relax` (high/critical still blocks);
|
|
123
|
+
persistent approval overrides pinned to an exact `source@version`.
|
|
124
|
+
- Configurable via `config.json` + `SHUCKY_*` env vars + CLI flags. Exit codes `0`/`1`/`2`/`3`.
|
|
125
|
+
- Agent-native review protocol in `SKILL.md` (works without Node), injection-hardened (treats
|
|
126
|
+
the skill as untrusted data, never executes it).
|
|
127
|
+
- Test runner (`test/run.js`, 21 checks) + fixtures: benign, malicious, binary, persistence,
|
|
128
|
+
agent-targeted, medium-only.
|
|
129
|
+
- MIT LICENSE.
|
|
130
|
+
|
|
131
|
+
_Not yet published to npm._
|
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Clamshell skills contributors
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Clamshell skills contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/NOTICE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
shucky
|
|
2
|
+
Copyright (c) 2026 h0tp-ftw
|
|
3
|
+
Licensed under the MIT License (see LICENSE).
|
|
4
|
+
|
|
5
|
+
------------------------------------------------------------------------
|
|
6
|
+
This product reimplements logic derived from:
|
|
7
|
+
|
|
8
|
+
vercel-labs/skills — https://github.com/vercel-labs/skills
|
|
9
|
+
Licensed under the MIT License. Copyright (c) Vercel, Inc. and contributors.
|
|
10
|
+
|
|
11
|
+
The following shucky modules adapt logic from that project:
|
|
12
|
+
|
|
13
|
+
lib/sources.js <- src/source-parser.ts (source-spec grammar)
|
|
14
|
+
lib/agents.js <- src/agents.ts (agent -> skills-dir registry)
|
|
15
|
+
lib/place.js <- src/installer.ts (canonical-dir + symlink/copy install)
|
|
16
|
+
lib/discover.js <- src/plugin-manifest.ts (Claude-Code plugin manifest discovery)
|
|
17
|
+
|
|
18
|
+
shucky reimplements this logic from scratch as zero-dependency CommonJS, adds a mandatory
|
|
19
|
+
safety-scan gate (and, for security, DROPS symlinks on copy rather than dereferencing them),
|
|
20
|
+
and does NOT depend on the `skills` package at runtime.
|
|
21
|
+
|
|
22
|
+
------------------------------------------------------------------------
|
|
23
|
+
Earlier scan heuristics (browser_session, agent_state_access, raw-IP exfil) are adapted from
|
|
24
|
+
the community "skill-vetter" skill (spclaudehome), MIT-0.
|
package/README.md
CHANGED
|
@@ -1,119 +1,214 @@
|
|
|
1
|
-
# shucky 🦪
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
1
|
+
# shucky 🦪
|
|
2
|
+
|
|
3
|
+
[](https://github.com/h0tp-ftw/shucky/actions/workflows/ci.yml)
|
|
4
|
+
|
|
5
|
+
> Find, vet, and install agent skills from anywhere — **shucked before they land.**
|
|
6
|
+
|
|
7
|
+
A zero-dependency tool for `SKILL.md` skills. Skills run code in your environment and public
|
|
8
|
+
registries are largely unvetted, so shucky **fetches a skill from anywhere, scans it as untrusted
|
|
9
|
+
data, and only installs it if it passes** — block-on-risk by default. The safe front door:
|
|
10
|
+
`npx skills`, but it installs on *proof*, not trust.
|
|
11
|
+
|
|
12
|
+
No runtime dependency on any other tool. (Uses your system `git` for git sources.)
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
shucky is a single zero-dependency Node CLI — **Node ≥ 16** (plus your system `git` for git sources).
|
|
17
|
+
|
|
18
|
+
**From source — the current full version** (recommended today; see the note below):
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
git clone https://github.com/h0tp-ftw/shucky && cd shucky
|
|
22
|
+
npm link # adds a `shucky` command to your PATH (points at this checkout)
|
|
23
|
+
shucky --version # 0.4.3
|
|
24
|
+
# …or run it directly, no link:
|
|
25
|
+
node bin/shucky.js --help
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Via npm / npx** (once v0.4.x is published — pin the version, never `@latest`, for a security tool):
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm i -g @h0tp/shucky # global `shucky` command
|
|
32
|
+
npx @h0tp/shucky@0.4.3 --help # run without installing (pinned)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
> ⚠️ The npm registry currently has **`@h0tp/shucky@0.1.0` (scanner only)**. The full
|
|
36
|
+
> find · scan · install · manage CLI lives on GitHub `main` until it's published — so for now
|
|
37
|
+
> install **from source** above, or run `node bin/shucky.js`.
|
|
38
|
+
|
|
39
|
+
**Update shucky later** with `shucky self-update` — it detects a git-checkout vs a global-npm
|
|
40
|
+
install and runs the right thing (`--check` to preview).
|
|
41
|
+
|
|
42
|
+
## Quick start
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
shucky find pdf # discover skills (skills.sh + your sources)
|
|
46
|
+
shucky install anthropics/skills@pdf # fetch → scan → install (into your detected agents)
|
|
47
|
+
shucky install owner/repo --global --agent claude-code
|
|
48
|
+
shucky install ./my-local-skill # a local folder
|
|
49
|
+
shucky scan owner/repo # vet without installing (local OR remote)
|
|
50
|
+
shucky list # what shucky installed
|
|
51
|
+
shucky remove pdf
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Every command has detailed help — `shucky <command> --help`. shucky never runs a skill; it reads
|
|
55
|
+
files as text and installs only what passes the scan. (No `shucky` command yet? Use
|
|
56
|
+
`node bin/shucky.js <command>` from a clone — see **Install** above.)
|
|
57
|
+
|
|
58
|
+
## Commands
|
|
59
|
+
|
|
60
|
+
| command | what it does |
|
|
61
|
+
|---|---|
|
|
62
|
+
| `install <source>` (`add`, `i`) | fetch → **scan** → install into your agent dirs → record |
|
|
63
|
+
| `scan <path\|source>` | vet a skill → block / warn / pass (local or remote) |
|
|
64
|
+
| `find [query]` (`search`) | search skills.sh + your registered sources, ranked + trust-annotated |
|
|
65
|
+
| `list` (`ls`) | list skills shucky installed (`--global`, `--json`) |
|
|
66
|
+
| `remove <name>` (`rm`) | uninstall across agent dirs + prune the lock |
|
|
67
|
+
| `update [name]` | re-fetch → **re-scan** → re-place installed skills |
|
|
68
|
+
| `self-update [--check]` | update shucky itself (`git pull` / `npm -g`, auto-detected) |
|
|
69
|
+
| `source add\|list\|remove <spec>` | manage the sources registry + curated lists |
|
|
70
|
+
| `approve <owner/repo> --at <ver> --reason …` | log a human override of a BLOCK (pinned to a version/commit) |
|
|
71
|
+
|
|
72
|
+
> Run `shucky <command> --help` for usage, arguments, and examples of any command.
|
|
73
|
+
|
|
74
|
+
### Sources — "from anywhere"
|
|
75
|
+
|
|
76
|
+
`install` / `scan` accept any of:
|
|
77
|
+
|
|
78
|
+
- `owner/repo[/subpath][@skill][#ref]` — GitHub shorthand
|
|
79
|
+
- a `github.com` repo URL, `…/tree/<ref>/<path>`, or `…/blob/<ref>/SKILL.md`
|
|
80
|
+
- GitLab incl. self-hosted: `https://gitlab.example.com/g/r/-/tree/<ref>/<path>`
|
|
81
|
+
- any git URL: `git@host:owner/repo.git`, `ssh://…`, `https://….git`
|
|
82
|
+
- `gist:<id>` or a `gist.github.com` URL
|
|
83
|
+
- a **raw `SKILL.md` URL** (e.g. `raw.githubusercontent.com/…/SKILL.md`)
|
|
84
|
+
- a `.well-known` host serving `/.well-known/agent-skills/index.json`
|
|
85
|
+
- a **`.tar.gz` / `.zip` archive** (remote URL or local file) — extracted with zip-slip / zip-bomb / symlink guards
|
|
86
|
+
- a local `./path` or `/abs/path`
|
|
87
|
+
|
|
88
|
+
### Install options
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
-g, --global install user-wide for all your agents (default: this project)
|
|
92
|
+
-a, --agent <name> target a specific agent (repeatable; default: auto-detected)
|
|
93
|
+
--all target every supported agent
|
|
94
|
+
--skill <name> install only this skill from a multi-skill source (repeatable)
|
|
95
|
+
--copy copy files instead of symlinking
|
|
96
|
+
-y, --yes assume yes (installs WARN; NEVER installs a BLOCK)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## How install works
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
resolve → fetch (temp dir) → discover SKILL.md(s) → scan → gate → place → record
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
- **The scan is the gate, and it can't be bypassed.** BLOCK ⇒ nothing is written. WARN ⇒ installs
|
|
106
|
+
only with `-y` (or an interactive yes). PASS ⇒ installs. The *only* way past a BLOCK is a logged
|
|
107
|
+
`shucky approve` — there is no `--force`.
|
|
108
|
+
- shucky scans the **exact bytes it then installs** (one fetch, no re-download) — no
|
|
109
|
+
time-of-check/time-of-use gap.
|
|
110
|
+
- Placement uses the `.agents/skills` convention: one canonical copy + a symlink into each detected
|
|
111
|
+
agent (Claude Code, Cursor, Codex, Windsurf … ~70 agents); `--copy` copies instead.
|
|
112
|
+
- Every install is recorded in `shucky-skills.json` (project, committed) and
|
|
113
|
+
`~/.shucky/installed-skills.json` (global) with the **scan verdict + resolved commit SHA**, so a
|
|
114
|
+
re-scan can tell whether a once-clean skill changed. Approvals pin to the resolved commit, so any
|
|
115
|
+
upstream change re-triggers a scan.
|
|
116
|
+
|
|
117
|
+
Exit codes: `0` ok/pass · `1` warn (skipped) · `2` block (refused) · `3` error — gate CI on them.
|
|
118
|
+
|
|
119
|
+
## Sources registry, curated lists & find
|
|
120
|
+
|
|
121
|
+
Register the repos / registries / lists you trust, then search and bulk-install across them:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
shucky source add anthropics/skills --trust trusted # a repo you trust (relaxes low/medium)
|
|
125
|
+
shucky source add https://example.com/team.json --name team # a curated bundle (a .json list)
|
|
126
|
+
shucky source list
|
|
127
|
+
|
|
128
|
+
shucky find pdf # search skills.sh + your sources, ranked by installs, trust-annotated
|
|
129
|
+
shucky install --list team # install every skill in the curated list (each one scanned)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
- A `trusted` source feeds the scanner's relax policy (low/medium relax; **high/critical still block**).
|
|
133
|
+
- A `list` is a `.json` manifest — `["owner/repo@skill", …]` or `{ "skills": [{ "source", "skill" }] }`.
|
|
134
|
+
- `find` results are install-ready; picking one runs the full scan gate — **find never installs by itself.**
|
|
135
|
+
- Sources live in `~/.shucky/sources.json` (global) and `./shucky-sources.json` (project, committed).
|
|
136
|
+
- `find --github` also searches GitHub — precise `SKILL.md` code search with `GITHUB_TOKEN`, else filtered repo matches.
|
|
137
|
+
|
|
138
|
+
## What the scan checks (deterministic floor)
|
|
139
|
+
|
|
140
|
+
| rule | severity | catches |
|
|
141
|
+
|---|---|---|
|
|
142
|
+
| `secret_access` | critical | SSH/AWS keys, `.env`, `.npmrc`, `.netrc`, `env` dumps, cloud metadata |
|
|
143
|
+
| `agent_state_access` | medium | the agent's own memory/identity files |
|
|
144
|
+
| `browser_session` | high | browser cookies / saved logins |
|
|
145
|
+
| `network_exfil` | high | `curl`/`wget`/`nc`/`scp` exfil, PowerShell download, raw-IP URLs |
|
|
146
|
+
| `obfuscation` | high | `base64 -d \| sh`, `curl \| sh`, `eval`, `iex`, compiled binaries |
|
|
147
|
+
| `destructive` | high | `rm -rf`, `dd of=`, `chmod 777`, fork bombs, `git push --force`, `sudo` |
|
|
148
|
+
| `persistence` | high | cron, `systemctl enable`, launchd, `.bashrc`, registry Run keys |
|
|
149
|
+
| `prompt_injection` | high | text telling the *reviewer* to ignore rules / hide actions |
|
|
150
|
+
| `supply_chain` | medium | runtime installs of unpinned / remote packages |
|
|
151
|
+
| `excessive_scope` | low | listeners, `find /`, `chmod -R`, `0.0.0.0` |
|
|
152
|
+
|
|
153
|
+
Two layers by design: the deterministic CLI can't be socially engineered (a malicious `SKILL.md`
|
|
154
|
+
can't talk it out of a finding), and the agent-native `SKILL.md` protocol catches intent and novel
|
|
155
|
+
tricks the regexes miss. `undeclared_capability` (behavior ≠ description) is intentionally
|
|
156
|
+
agent-only judgment. **Neither layer alone is enough — and shucky never executes the skill.**
|
|
157
|
+
|
|
158
|
+
## Security model (the fetch surface)
|
|
159
|
+
|
|
160
|
+
shucky pulls untrusted content over the network, so the fetcher is hardened:
|
|
161
|
+
|
|
162
|
+
- **SSRF:** https-only; metadata IP / loopback / private ranges / `*.internal` blocked, re-checked
|
|
163
|
+
**after DNS resolution** (rebind defense) and **on every redirect hop**.
|
|
164
|
+
- **No symlink escape:** the scanner skips symlinks, so the installer **drops** them too — it never
|
|
165
|
+
copies a symlink's target into your skills dir.
|
|
166
|
+
- **git sandboxed:** `--depth 1`, no credential prompts, no LFS, array-args (no shell), validated
|
|
167
|
+
ref, time/size caps.
|
|
168
|
+
- **Path traversal & archives:** subpaths and skill names are sanitized; archive extraction
|
|
169
|
+
(`lib/archive.js`) is guarded against zip-slip, zip-bombs, and symlink/hardlink/device entries.
|
|
170
|
+
|
|
171
|
+
## Configuration (`config.json`)
|
|
172
|
+
|
|
173
|
+
```jsonc
|
|
174
|
+
{
|
|
175
|
+
"policy": "block", // block | warn | report
|
|
176
|
+
"failOn": ["high", "critical"],
|
|
177
|
+
"warnOn": ["medium"],
|
|
178
|
+
"trustedSources": ["anthropics", "vercel-labs", "..."],
|
|
179
|
+
"trustedSourcePolicy": "relax", // trusted: low/medium relax; high/critical STILL block
|
|
180
|
+
"allowOverride": true,
|
|
181
|
+
"overrideRequiresReason": true
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Env: `SHUCKY_POLICY`, `SHUCKY_SOURCE`, `SHUCKY_MAX_FETCH_BYTES`. CLI flags override both. In `.md`
|
|
186
|
+
files, code-execution rules run only inside fenced blocks (prose is checked for prompt-injection
|
|
187
|
+
only), so a doc that merely *mentions* `curl … | sh` isn't flagged.
|
|
188
|
+
|
|
189
|
+
## Develop / test
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
npm test # → test/run-all.js (183 zero-dep checks across 6 suites, one aggregated summary)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Fixtures in `fixtures/` carry inert payloads and are **never executed**.
|
|
196
|
+
|
|
197
|
+
## Requirements
|
|
198
|
+
|
|
199
|
+
Node ≥ 16. `git` on PATH for git-type sources (GitHub / GitLab / SSH). No npm dependencies.
|
|
200
|
+
|
|
201
|
+
## Status
|
|
202
|
+
|
|
203
|
+
`v0.4.1` — find (incl. GitHub) · scan · install (incl. `.tar.gz`/`.zip`) · manage. **ClawHub-ready**
|
|
204
|
+
(see `CLAWHUB.md`); publishing to npm / ClawHub is the maintainer's account-gated step.
|
|
205
|
+
|
|
206
|
+
## Credits
|
|
207
|
+
|
|
208
|
+
Source-spec parsing, the agent registry, and the install/symlink logic are reimplemented from
|
|
209
|
+
[`vercel-labs/skills`](https://github.com/vercel-labs/skills) (MIT) — see `NOTICE`. shucky adds the
|
|
210
|
+
mandatory scan gate and does **not** depend on that tool at runtime.
|
|
211
|
+
|
|
212
|
+
## License
|
|
213
|
+
|
|
214
|
+
MIT
|