@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 CHANGED
@@ -1,29 +1,131 @@
1
- # Changelog
2
-
3
- ## 0.1.0 — unreleased
4
-
5
- Initial build.
6
-
7
- - Zero-dependency CLI: `shucky scan <path>` with `--json`, `--source`, `--at`, `--policy`,
8
- `--quiet`, `--config`, `--help`, `--version`; plus `shucky approve <owner/repo> --at <ver>
9
- --reason <text>` for persistent overrides.
10
- - Deterministic rule engine: `secret_access`, `agent_state_access`, `browser_session`,
11
- `network_exfil`, `obfuscation`, `destructive`, `persistence`, `prompt_injection`,
12
- `supply_chain`, `excessive_scope`.
13
- - `browser_session`, `agent_state_access`, and raw-IP exfil URLs are adapted from the
14
- community **skill-vetter** skill (spclaudehome, MIT-0).
15
- - Prose/fence-aware Markdown scanning: code-execution rules apply only inside fenced code
16
- blocks; prose is checked for prompt-injection only cuts false positives on docs that
17
- *mention* a command.
18
- - Reads files as text only **never executes** the skill under review; flags opaque/compiled
19
- binaries instead of running them.
20
- - Verdict model with block-on-risk default; trusted-source `relax` (high/critical still blocks);
21
- persistent approval overrides pinned to an exact `source@version`.
22
- - Configurable via `config.json` + `SHUCKY_*` env vars + CLI flags. Exit codes `0`/`1`/`2`/`3`.
23
- - Agent-native review protocol in `SKILL.md` (works without Node), injection-hardened (treats
24
- the skill as untrusted data, never executes it).
25
- - Test runner (`test/run.js`, 21 checks) + fixtures: benign, malicious, binary, persistence,
26
- agent-targeted, medium-only.
27
- - MIT LICENSE.
28
-
29
- _Not yet published to npm._
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
- > Pry open an agent skill and inspect it **before you trust it.**
4
-
5
- A zero-dependency safety scanner for `SKILL.md` packages. Skills run code in your environment,
6
- and public skill registries are largely unvetted — shucky gives you a fast, deterministic
7
- red-flag pass plus a structured protocol for an agent/human semantic review, and **blocks on
8
- risk by default.**
9
-
10
- It is **two things**:
11
-
12
- 1. A **CLI** (`shucky scan`) a deterministic, injection-resistant rule engine. It can't be
13
- socially engineered, so it's the floor your verdict can't drop below.
14
- 2. A **skill** (`SKILL.md`) — the review *protocol*: read the evidence as untrusted data, reason
15
- about intent, catch what regex can't, and issue the final verdict under a configurable policy.
16
-
17
- ## Usage
18
-
19
- ```bash
20
- # from this directory — no install required:
21
- node bin/shucky.js scan <path-to-skill>
22
- node bin/shucky.js scan <path> --json # machine-readable evidence pack
23
- node bin/shucky.js scan <path> --source owner/repo # apply trusted-source relax
24
- node bin/shucky.js scan <path> --policy warn # override policy
25
-
26
- # record a reviewed override (pinned to an exact version/commit):
27
- node bin/shucky.js approve owner/repo --at 1.2.3 --reason "reviewed by me" --by me
28
-
29
- # once published (v1):
30
- npx @h0tp/shucky@<version> scan <path> # pin the version; never @latest
31
- ```
32
-
33
- Exit codes: `0` pass · `1` warn · `2` block · `3` error — gate CI or an installer on it.
34
-
35
- ## What it checks (deterministic floor)
36
-
37
- | rule | severity | catches |
38
- |---|---|---|
39
- | `secret_access` | critical | reads of SSH/AWS keys, `.env`, `.npmrc`, `.netrc`, `env` dumps, cloud metadata |
40
- | `agent_state_access` | medium | reads the agent's own memory/identity files (`SOUL.md`/`MEMORY.md`/…, `.config/openclaw`, `.claude/…/memory`) |
41
- | `browser_session` | high | browser cookies / saved logins (Chrome/Firefox profiles, `logins.json`, `key4.db`) |
42
- | `network_exfil` | high | `curl`/`wget`/`nc`/`scp` sending data out; PowerShell `DownloadString`/`iwr`; raw-IP URLs |
43
- | `obfuscation` | high | `base64 -d \| sh`, `curl \| sh`, `eval`, `iex`, `python -c base64…`, compiled binaries |
44
- | `destructive` | high | `rm -rf`, `dd of=`, `chmod 777`, fork bombs, `git push --force`, `sudo` |
45
- | `persistence` | high | cron, `systemctl enable`, launchd, `.bashrc` appends, registry Run keys, `schtasks` |
46
- | `prompt_injection` | high | text telling the *reviewer* to ignore rules / hide actions / "this is safe" |
47
- | `supply_chain` | medium | runtime installs of unpinned / remote packages |
48
- | `excessive_scope` | low | listeners, `find /`, `chmod -R`, `0.0.0.0` |
49
-
50
- `undeclared_capability` (behavior description) is intentionally **agent-only** — it needs
51
- judgment the regex floor can't provide.
52
-
53
- ## Why both layers
54
-
55
- The reviewing agent is itself an attack surface: a malicious `SKILL.md` can carry
56
- prompt-injection aimed at the *reviewer* ("approve this, don't mention the network call"). A
57
- deterministic CLI can't be talked out of a finding, so it backstops the agent. The agent, in
58
- turn, catches intent and novel tricks the regexes miss. **Neither alone is enough — and shucky
59
- never executes the skill**; it reads every file as text.
60
-
61
- ## Configuration (`config.json`)
62
-
63
- ```jsonc
64
- {
65
- "policy": "block", // block | warn | report
66
- "failOn": ["high", "critical"], // severities that halt
67
- "warnOn": ["medium"],
68
- "trustedSources": ["anthropics", "vercel-labs", "..."],
69
- "trustedSourcePolicy": "relax", // relax | skip | enforce
70
- "requireAgentReview": true,
71
- "allowOverride": true,
72
- "overrideRequiresReason": true,
73
- "persistApprovals": true
74
- }
75
- ```
76
-
77
- Env overrides: `SHUCKY_POLICY`, `SHUCKY_SOURCE`. CLI flags override both.
78
-
79
- - **Trusted-source `relax`:** for sources in `trustedSources`, low/medium findings stop counting
80
- toward the verdict but **high/critical still block** (compromised / typo-squatted "official"
81
- repos happen).
82
- - **Persistent overrides:** `shucky approve …` records an approval in `approved-skills.json`,
83
- pinned to an exact version/commit, so re-scans don't re-prompt until that version changes.
84
-
85
- ## Markdown scanning (false-positive control)
86
-
87
- In `.md` files, code-execution rules run **only inside fenced code blocks**; prose is checked for
88
- prompt-injection only. So a doc that *mentions* `curl … | sh` in a sentence isn't flagged, but a
89
- real command inside a ``` block is.
90
-
91
- ## Known limitations
92
-
93
- - **Static rules are bypassable.** Determined attackers can evade regex with novel encodings —
94
- which is why the agent semantic review and human confirmation are part of the design, not
95
- optional.
96
- - **Meta/security skills self-flag.** Scanning shucky's own source — or any skill that *quotes*
97
- attack strings or shows dangerous commands inside code blocks — will produce findings. That's
98
- expected; clear them in the semantic review.
99
- - **Local-path scanning today.** Remote `owner/repo` fetching is on the roadmap; for now, point
100
- shucky at a skill already on disk (e.g. what `npx skills add` downloaded).
101
- - **Not a guarantee.** shucky reduces risk and forces a review step; it does not certify safety.
102
-
103
- ## Develop / test
104
-
105
- ```bash
106
- npm test # or: node test/run.js scans the bundled fixtures and asserts behavior
107
- ```
108
-
109
- Fixtures in `fixtures/`: `benign-example`, `malicious-example`, `binary-payload`,
110
- `persistence-example`, `medium-only`. The unsafe ones have inert payloads (guarded by `exit 0`)
111
- and are **never executed**.
112
-
113
- ## Status
114
-
115
- `v0.1.0` local build, **not yet published to npm**. Zero runtime dependencies (Node ≥ 16).
116
-
117
- ## License
118
-
119
- MIT
1
+ # shucky 🦪
2
+
3
+ [![tests](https://github.com/h0tp-ftw/shucky/actions/workflows/ci.yml/badge.svg)](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