skman 0.1.0__tar.gz

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.
skman-0.1.0/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ __pycache__/
2
+ *.pyc
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .venv/
7
+ .pytest_cache/
8
+ .DS_Store
skman-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Zhendong Liu
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.
skman-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,372 @@
1
+ Metadata-Version: 2.4
2
+ Name: skman
3
+ Version: 0.1.0
4
+ Summary: Manage and sync coding-agent skills (Claude Code, Codex, skills.sh)
5
+ Project-URL: Homepage, https://github.com/zhendong/skill-man
6
+ Project-URL: Repository, https://github.com/zhendong/skill-man
7
+ Project-URL: Issues, https://github.com/zhendong/skill-man/issues
8
+ Author-email: Zhendong Liu <lzd110@gmail.com>
9
+ License: MIT License
10
+
11
+ Copyright (c) 2026 Zhendong Liu
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
30
+ License-File: LICENSE
31
+ Keywords: agent-skills,ai-agents,claude-code,cli,codex,developer-tools,skills.sh
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Intended Audience :: Developers
34
+ Classifier: License :: OSI Approved :: MIT License
35
+ Classifier: Operating System :: MacOS
36
+ Classifier: Operating System :: POSIX :: Linux
37
+ Classifier: Programming Language :: Python :: 3
38
+ Classifier: Programming Language :: Python :: 3 :: Only
39
+ Classifier: Programming Language :: Python :: 3.10
40
+ Classifier: Programming Language :: Python :: 3.11
41
+ Classifier: Programming Language :: Python :: 3.12
42
+ Classifier: Programming Language :: Python :: 3.13
43
+ Classifier: Topic :: Software Development
44
+ Classifier: Topic :: Utilities
45
+ Requires-Python: >=3.10
46
+ Description-Content-Type: text/markdown
47
+
48
+ # skman
49
+
50
+ A dead simple CLI for managing skills used by coding agents — works with **Claude Code**,
51
+ **Codex CLI**, and any other agent that discovers skills from `~/.agents/skills`
52
+ (the cross-agent dir; also where `skills.sh` / `npx skills` installs).
53
+
54
+ ## What it does
55
+
56
+ 1. **Download** skills from git repos (or local directories).
57
+ 2. **Sync** them on demand — pulls upstream, refreshes state, updates symlinks.
58
+ 3. **Symlink** every managed skill into `~/.agents/skills` and
59
+ `~/.claude/skills`. Codex picks the same skills up automatically via its
60
+ cross-agent fallback to `~/.agents/skills`. The dirs are created on first
61
+ sync — nothing to set up beforehand.
62
+ 4. **Track state** in `~/.skman/state.json`: slug, name, description,
63
+ source, short commit id, install/last-sync times, and enabled flag
64
+ per skill.
65
+ 5. **Disambiguate** skills from different sources by suffixing each
66
+ symlink with a short id derived from the source URL, so two sources
67
+ shipping the same skill name coexist without collision. A warning is
68
+ still printed when `(name, description)` matches across sources, so
69
+ you can spot true duplicates.
70
+ 6. **Record usage** via a Claude Code `PreToolUse` hook and show aggregate
71
+ stats.
72
+
73
+ > Note: pluggable user-edits-as-patches is intentionally out of scope for now.
74
+
75
+ ## Install
76
+
77
+ ### One-line install (recommended)
78
+
79
+ ```bash
80
+ curl -fsSL https://raw.githubusercontent.com/zhendong/skill-man/main/install.sh | sh
81
+ ```
82
+
83
+ Works on macOS and Linux. The installer uses [uv](https://docs.astral.sh/uv/)
84
+ to fetch a Python toolchain and install `skman` from PyPI into an isolated
85
+ environment — you don't need Python or pip beforehand.
86
+
87
+ Env overrides:
88
+ - `SKMAN_FROM_GIT=1` — install from the GitHub repo instead of PyPI (and
89
+ `SKMAN_REF=<branch-or-tag>` to pick a ref).
90
+ - `SKMAN_NO_UV=1` — fall back to `pipx`/`pip` instead of uv.
91
+
92
+ ### Via pip / pipx / uv
93
+
94
+ ```bash
95
+ pipx install skman # recommended for global CLI install
96
+ uv tool install skman # uv equivalent
97
+ pip install --user skman # plain pip
98
+ ```
99
+
100
+ ### From source
101
+
102
+ ```bash
103
+ cd skill-man # repo dir keeps its name; the tool is `skman`
104
+ pip install -e . # exposes `skman` on PATH
105
+ # or:
106
+ uv tool install .
107
+ ```
108
+
109
+ You can also run it without installing:
110
+
111
+ ```bash
112
+ python3 -m skman <args>
113
+ ```
114
+
115
+ State lives in `~/.skman/` (override with `$SKMAN_ROOT`).
116
+
117
+ ### Windows
118
+
119
+ There is no native Windows build. Use **WSL** (Windows Subsystem for Linux) —
120
+ install a distro (Ubuntu/Debian/etc.), open its shell, and run the one-line
121
+ install above from inside the Linux environment. Your agent CLI (Claude
122
+ Code, Codex, etc.) should also run inside WSL so skman's symlinks land in
123
+ the Linux home dir where the agent looks for them.
124
+
125
+ ## First-run setup
126
+
127
+ After install, the fastest way to a working state is:
128
+
129
+ ```bash
130
+ skman setup
131
+ ```
132
+
133
+ This installs the Claude Code usage hook and migrates any skills already
134
+ on disk (see below). It's safe to re-run.
135
+
136
+ ## Quick start
137
+
138
+ ```bash
139
+ skman source add https://github.com/obra/superpowers.git # slug auto-derived as `superpowers`
140
+ skman sync # clones, finds SKILL.md files, links into both target dirs
141
+
142
+ skman list # see what's managed (with install/update times + commit)
143
+ skman install-hook --write # records skill invocations
144
+ skman stats # see what got used
145
+ ```
146
+
147
+ There is no `init` step. All directories — including `~/.agents/skills` and
148
+ `~/.claude/skills` — are created the first time something needs to write into
149
+ them.
150
+
151
+ ### Source layout convention
152
+
153
+ Sources follow the standard pattern: a top-level `skills/` directory holding
154
+ one folder per skill, each with a `SKILL.md` plus any helper files:
155
+
156
+ ```
157
+ <source-repo>/
158
+ └── skills/
159
+ ├── brainstorming/
160
+ │ └── SKILL.md
161
+ └── tdd/
162
+ ├── SKILL.md
163
+ └── examples/
164
+ ```
165
+
166
+ skman auto-detects: if `skills/` exists at the source root it scans
167
+ there; otherwise it scans the whole repo. Sub-categorisation (e.g.
168
+ `skills/foundations/tdd/`) is fine — `SKILL.md` is found recursively.
169
+
170
+ ### Source identifiers
171
+
172
+ You don't pick a name. The slug is derived from the URL's last path segment
173
+ (lowercased, `.git` stripped, unsafe chars replaced):
174
+
175
+ | Input URL | Derived slug |
176
+ |----------------------------------------------------|----------------------|
177
+ | `https://github.com/obra/superpowers.git` | `superpowers` |
178
+ | `git@github.com:obra/superpowers` | `superpowers` |
179
+ | `/Users/me/dev/my-skills` | `my-skills` |
180
+ | second repo whose last segment is also `superpowers` | `superpowers-2` |
181
+
182
+ Adding the same URL twice errors out — `https://h/o/r`, `https://h/o/r/`,
183
+ `https://h/o/r.git`, and `git@h:o/r` are all recognised as the same source.
184
+ Remove with `skman source remove <slug>` or `skman source remove <url>`.
185
+
186
+ ## State
187
+
188
+ Everything lives in one JSON file: `~/.skman/state.json`.
189
+
190
+ ```jsonc
191
+ {
192
+ "version": 1,
193
+ "sources": {
194
+ "superpowers": { "type": "git", "url": "...", "ref": "main" }
195
+ },
196
+ "skills": {
197
+ "brainstorming-ab12cd": {
198
+ "slug": "brainstorming",
199
+ "name": "brainstorming",
200
+ "description": "You MUST use this before any creative work...",
201
+ "source": "superpowers",
202
+ "path": "skills/brainstorming",
203
+ "commit": "a1b2c3d",
204
+ "installed_at": "2026-05-14T10:00:00+00:00",
205
+ "updated_at": "2026-05-14T12:00:00+00:00",
206
+ "enabled": true
207
+ }
208
+ }
209
+ }
210
+ ```
211
+
212
+ The map key (`brainstorming-ab12cd`) is also the symlink name in the
213
+ target dirs. The `-ab12cd` suffix is a 6-char hash of the source URL —
214
+ it lets two sources share a slug without collision.
215
+
216
+ `skman list` renders the state as a table:
217
+
218
+ ```
219
+ LINK NAME SLUG SOURCE COMMIT STATUS INSTALLED UPDATED
220
+ brainstorming-ab12cd brainstorming superpowers a1b2c3d enabled 2026-05-14 10:00 2026-05-14 12:00
221
+ tdd-ab12cd tdd superpowers a1b2c3d enabled 2026-05-14 10:00 2026-05-14 12:00
222
+ ```
223
+
224
+ ## Duplicate detection
225
+
226
+ After every sync, skman groups skills by `(name, description)` from their
227
+ SKILL.md frontmatter and prints a warning when any pair appears in more
228
+ than one state entry — e.g. when two sources both ship a `brainstorming`
229
+ skill with identical frontmatter.
230
+
231
+ The warning is informational: both skills remain installed. Symlink names
232
+ include a short id derived from the source URL (`brainstorming-ab12cd`,
233
+ `brainstorming-ef34gh`), so there's no collision at the filesystem level.
234
+ Resolve true duplicates by removing one of the sources, or by disabling
235
+ one with `skman disable <link-name>`.
236
+
237
+ ## Stats
238
+
239
+ `skman install-hook --write` adds a Claude Code `PreToolUse` hook so
240
+ every Skill tool call is recorded to `~/.skman/stats/usage.jsonl`.
241
+ `skman stats` aggregates:
242
+
243
+ - per-skill invocation count, distinct sessions, last-used time
244
+ - count of managed skills that went unused in the window
245
+
246
+ ```bash
247
+ skman stats # last 30 days
248
+ skman stats --days 7
249
+ skman stats --skill brainstorming
250
+ ```
251
+
252
+ ## Migrating from other tools
253
+
254
+ If you've been using Claude Code, Codex, or `skills.sh` (`npx skills …`),
255
+ you'll likely have skills scattered across these dirs:
256
+
257
+ - `~/.claude/skills/*` — Claude Code personal skills
258
+ - `~/.codex/skills/*` — Codex personal skills (`.system/` is skipped — Codex
259
+ built-ins live there)
260
+ - `~/.agents/skills/*` — cross-agent dir; also where `skills.sh` installs
261
+
262
+ `skman migrate` walks those locations, looks for `SKILL.md` dirs that
263
+ aren't already managed by skman, and adopts them:
264
+
265
+ - Reads `~/.agents/.skill-lock.json` (skills.sh v3) when present and uses
266
+ the recorded `sourceUrl` — your `npx skills` installs become git sources
267
+ tracked by skman, deduplicating skills that share a repo.
268
+ - Else, if the skill lives inside a git checkout, registers the enclosing
269
+ repo as a git source via its `origin`.
270
+ - Else, copies the skill into `~/.skman/imported/<name>/` and registers
271
+ that as a local source.
272
+
273
+ `skman migrate` refuses to overwrite skills you may have edited locally:
274
+
275
+ - **In a git checkout** with uncommitted changes or unpushed commits →
276
+ skipped. Commit + push upstream, then re-run.
277
+ - **In `~/.agents/skills/` with a `skillFolderHash`** in
278
+ `.skill-lock.json` (skills.sh v3) → the local folder's git tree SHA-1
279
+ is recomputed and compared. A mismatch means the folder was edited
280
+ after install; skman skips it. (Macros: `.DS_Store`, `__pycache__`,
281
+ `.git`, `node_modules` are filtered to avoid false positives.)
282
+
283
+ In both cases skman tells you which skill, where it lives, and why —
284
+ then leaves it alone. Resolve manually (commit/push, or revert your
285
+ edits, or just don't manage it with skman) and re-run.
286
+
287
+ After migration, skman manages the skill via its own suffixed symlinks
288
+ (`brainstorming-ab12cd`) and removes the original loose copy so the host
289
+ agent doesn't see both.
290
+
291
+ ```bash
292
+ skman migrate --dry-run # preview what would happen
293
+ skman migrate # interactive (asks for confirmation)
294
+ skman migrate --yes # non-interactive
295
+ skman migrate --keep-originals # don't remove the on-disk copies after import
296
+ skman migrate --scan ~/elsewhere # scan an additional dir (repeatable)
297
+ ```
298
+
299
+ `skman setup` runs `install-hook --write` followed by `migrate` and is the
300
+ recommended first-run command.
301
+
302
+ ## Commands
303
+
304
+ ```
305
+ skman paths
306
+ skman setup [--yes] [--keep-originals]
307
+ skman migrate [--dry-run] [--yes] [--keep-originals] [--scan PATH]
308
+ skman source add <url> [skills-to-enable] | remove <slug-or-url> | list
309
+ skman sync [--source NAME | --skill SLUG]
310
+ skman list
311
+ skman refresh
312
+ skman enable <skill>
313
+ skman disable <skill>
314
+ skman stats [--days N] [--skill SLUG]
315
+ skman hook
316
+ skman install-hook [--write]
317
+ ```
318
+
319
+ `skills-to-enable` is an optional comma-separated whitelist of skill
320
+ slugs. When set, only those skills are enabled after sync; the rest are
321
+ recorded in state but left disabled (no symlink). Examples:
322
+
323
+ ```bash
324
+ skman source add https://github.com/obra/superpowers.git # enable everything in the source
325
+ skman source add https://github.com/obra/superpowers.git brainstorming,tdd
326
+ # enable only those two; others stay disabled
327
+ ```
328
+
329
+ ### Environment overrides (advanced)
330
+
331
+ - `SKMAN_ROOT` — state dir (default `~/.skman`)
332
+ - `SKMAN_TARGET_DIRS` — colon-separated list of agent skill dirs
333
+ (default `~/.agents/skills:~/.claude/skills`). Mainly used by tests.
334
+ - `SKMAN_GITHUB_MIRROR` — rewrite GitHub clone URLs through a mirror
335
+ (useful in regions where `github.com` is slow or blocked). Two forms:
336
+ - **Hostname** (e.g. `hub.fastgit.org`) — replaces `github.com` in
337
+ the URL. `git@github.com:o/r` is converted to HTTPS first, so SSH
338
+ sources work too.
339
+ - **Full URL** (e.g. `https://ghproxy.com`) — treated as a prefix;
340
+ the original `https://github.com/o/r` URL is appended.
341
+ The original `url` recorded in `state.json` is unchanged; the mirror
342
+ only applies at clone/fetch time, and sync prints the rewritten URL.
343
+
344
+ ## Publishing (maintainers)
345
+
346
+ The version is read from `skman/__init__.py` (`__version__`). Bump it,
347
+ commit, then build and upload:
348
+
349
+ ```bash
350
+ # 1. Bump skman/__init__.py __version__ and commit
351
+ # 2. Tag the release (optional but recommended)
352
+ git tag v$(python3 -c "import skman; print(skman.__version__)")
353
+ git push --tags
354
+
355
+ # 3. Build
356
+ python3 -m pip install --upgrade build twine
357
+ rm -rf dist/ && python3 -m build # produces dist/skman-X.Y.Z-py3-none-any.whl and .tar.gz
358
+
359
+ # 4. Sanity-check the artifacts
360
+ python3 -m twine check dist/*
361
+
362
+ # 5. Upload to TestPyPI first, then PyPI
363
+ python3 -m twine upload --repository testpypi dist/*
364
+ python3 -m twine upload dist/*
365
+ ```
366
+
367
+ Configure credentials in `~/.pypirc` (or use API tokens via
368
+ `TWINE_USERNAME=__token__ TWINE_PASSWORD=<pypi-token>`).
369
+
370
+ ## License
371
+
372
+ [MIT](LICENSE).