simple-skill-manager 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,458 @@
1
+ Metadata-Version: 2.4
2
+ Name: simple-skill-manager
3
+ Version: 0.1.0
4
+ Summary: Manager of opencode Agent Skills: keeps them in a private folder and links or copies the ones a project needs.
5
+ Author: Tom Janus
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/tomjanus/skill-manager
8
+ Project-URL: Repository, https://github.com/tomjanus/skill-manager
9
+ Project-URL: Issues, https://github.com/tomjanus/skill-manager/issues
10
+ Project-URL: Changelog, https://github.com/tomjanus/skill-manager/blob/master/CHANGELOG.md
11
+ Keywords: opencode,skills,cli,agent
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Topic :: Software Development
23
+ Classifier: Topic :: System :: Filesystems
24
+ Requires-Python: >=3.10
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Provides-Extra: test
28
+ Requires-Dist: pytest>=8.0; extra == "test"
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=8.0; extra == "dev"
31
+ Requires-Dist: ruff>=0.6; extra == "dev"
32
+ Requires-Dist: mypy>=1.11; extra == "dev"
33
+ Requires-Dist: build>=1.2; extra == "dev"
34
+ Requires-Dist: twine>=5.1; extra == "dev"
35
+ Requires-Dist: coverage>=7.6; extra == "dev"
36
+ Dynamic: license-file
37
+
38
+ # simple-skill-manager
39
+
40
+ Keep your opencode **Agent Skills** in a private folder, then link or copy
41
+ the ones a project needs — without hand-managing symlinks.
42
+
43
+ The problem it solves: opencode discovers skills from
44
+ `~/.config/opencode/skills/`, `~/.claude/skills/`, and `~/.agents/skills/`.
45
+ Loading every skill you own into every session is noise. But copying or
46
+ linking skills into each project by hand is tedious.
47
+
48
+ `simple-skill-manager` keeps your skills in a folder of your choosing (by
49
+ default `~/skills`, which opencode does **not** discover), lets you browse
50
+ them, and adds the ones you want to a specific project — as a symlink or a
51
+ copy.
52
+
53
+ - **Linux, macOS, and Windows** (Windows uses a directory junction when
54
+ symlinks are unavailable).
55
+ - **No runtime dependencies** — Python 3.10+ standard library only.
56
+ - **Reproducible** — the project's selection is recorded in a committed
57
+ manifest, so `simple-skill-manager sync` can restore it anywhere.
58
+
59
+ ---
60
+
61
+ ## Install
62
+
63
+ From [PyPI](https://pypi.org/project/simple-skill-manager/), with
64
+ [pipx](https://pipx.pypa.io/):
65
+
66
+ ```bash
67
+ pipx install simple-skill-manager
68
+ ```
69
+
70
+ or, with [uv](https://docs.astral.sh/uv/):
71
+
72
+ ```bash
73
+ uv tool install simple-skill-manager
74
+ ```
75
+
76
+ Both install the `simple-skill-manager` command onto your `PATH` in an
77
+ isolated environment, so the tool's dependencies never touch your system
78
+ Python. The shorter `skill-manager` name is installed as an alias, so
79
+ either command works.
80
+
81
+ From a clone of this repository:
82
+
83
+ ```bash
84
+ git clone https://github.com/tomjanus/skill-manager.git
85
+ pipx install ./skill-manager
86
+ ```
87
+
88
+ Later upgrades:
89
+
90
+ ```bash
91
+ pipx upgrade simple-skill-manager
92
+ uv tool upgrade simple-skill-manager
93
+ ```
94
+
95
+ To run it without installing:
96
+
97
+ ```bash
98
+ PYTHONPATH=src python -m skill_manager --help
99
+ ```
100
+
101
+ To uninstall:
102
+
103
+ ```bash
104
+ pipx uninstall simple-skill-manager
105
+ uv tool uninstall simple-skill-manager
106
+ ```
107
+
108
+ ---
109
+
110
+ ## Getting started
111
+
112
+ ### 1. Initialise the configuration
113
+
114
+ ```bash
115
+ simple-skill-manager init
116
+ ```
117
+
118
+ This creates:
119
+
120
+ | Path | Purpose |
121
+ | --- | --- |
122
+ | `~/.config/skill-manager/.env` | Configuration file (`SKILLS_DIR=~/skills`) |
123
+ | `~/skills` | Your private skills folder (created if missing) |
124
+
125
+ `init` is idempotent — run it again any time; existing files are left alone.
126
+
127
+ ### 2. Put your skills in the source folder
128
+
129
+ Each skill is a directory containing a `SKILL.md` with YAML frontmatter:
130
+
131
+ ```
132
+ ~/skills/
133
+ ├── scientific-python/
134
+ │ ├── SKILL.md
135
+ │ └── references/
136
+ └── tdd/
137
+ └── SKILL.md
138
+ ```
139
+
140
+ `~/skills/scientific-python/SKILL.md`:
141
+
142
+ ```markdown
143
+ ---
144
+ name: scientific-python
145
+ description: Reliable and reproducible Python scientific computing.
146
+ ---
147
+
148
+ # Scientific Python
149
+ ...
150
+ ```
151
+
152
+ `SKILL.md` must be in ALL CAPS. The `name` field must match the directory
153
+ name and be lowercase alphanumeric with single hyphens.
154
+
155
+ ### 3. Add skills to a project
156
+
157
+ ```bash
158
+ cd ~/projects/my-project
159
+ simple-skill-manager add # interactive picker
160
+ simple-skill-manager add tdd scientific-python
161
+ simple-skill-manager add tdd --copy # copy instead of linking
162
+ ```
163
+
164
+ `add` writes into `<project root>/.opencode/skills/<name>/`, which is where
165
+ opencode looks for project skills. The project root is the enclosing git
166
+ worktree, so the command works from any subdirectory.
167
+
168
+ ### 4. See what you have
169
+
170
+ ```bash
171
+ simple-skill-manager list
172
+ ```
173
+
174
+ ```
175
+ NAME STATUS MODE DESCRIPTION
176
+ scientific-python installed link Reliable and reproducible Python scientific...
177
+ tdd outdated copy Test-first implementation and regression...
178
+ pdf external — (managed by opencode)
179
+ water-distribution not-installed — Water-distribution networks, hydraulics...
180
+ ```
181
+
182
+ `list --json` emits the same information as JSON for scripting.
183
+
184
+ ---
185
+
186
+ ## Commands
187
+
188
+ ### `simple-skill-manager init`
189
+
190
+ Creates the configuration file and the source skills directory if they do
191
+ not exist. Safe to re-run.
192
+
193
+ ### `simple-skill-manager list`
194
+
195
+ Merges three sources of truth — your source folder, the project's
196
+ `.opencode/skills/` folder, and the project manifest — into one table.
197
+
198
+ | Status | Meaning |
199
+ | --- | --- |
200
+ | `installed` | Present and matching the source |
201
+ | `outdated` | A copy whose source has changed |
202
+ | `broken` | A link whose target has disappeared |
203
+ | `missing` | In the manifest, but not in the project folder |
204
+ | `missing-source` | In the project, but gone from the source folder |
205
+ | `not-installed` | Available in the source folder, not in the project |
206
+ | `external` | In the project folder but **not** managed by `simple-skill-manager` (for example opencode's own installer) |
207
+
208
+ Flags: `--available` (source only), `--installed` (project only), `--json`.
209
+
210
+ ### `simple-skill-manager add [NAME ...]`
211
+
212
+ Adds skills to the project.
213
+
214
+ - With no names, opens an interactive picker (numbers, comma-separated,
215
+ or `all`). Requires a terminal.
216
+ - **Links by default**, so edits to the source skill are picked up
217
+ immediately. Use `--copy` for a frozen snapshot.
218
+ - If the skill is already installed and unchanged, reports `already up to
219
+ date` and does nothing.
220
+ - If the source changed, or the link is broken, you are asked before
221
+ updating. `--yes` accepts all updates.
222
+ - If the target exists but is **not** managed by `simple-skill-manager`, the
223
+ command refuses to touch it. `--force` replaces it.
224
+
225
+ Flags: `--copy`, `--force`, `--yes`.
226
+
227
+ ### `simple-skill-manager remove NAME ...`
228
+
229
+ Removes skills from the project folder and from the manifest. You are asked
230
+ for confirmation unless `--yes` is given. Skills not managed by
231
+ `simple-skill-manager` are only removed with `--force`.
232
+
233
+ Flags: `--yes`, `--force`.
234
+
235
+ ### `simple-skill-manager sync`
236
+
237
+ Reconciles the skills **already installed** in the project with their
238
+ source. It never adds new skills.
239
+
240
+ - A copy whose source changed is updated after confirmation.
241
+ - A missing or broken link is re-created.
242
+ - A skill whose source disappeared is offered for removal.
243
+ - Anything unchanged is reported as `up to date`.
244
+
245
+ Flags: `--yes`, `--force`.
246
+
247
+ ---
248
+
249
+ ## Configuration
250
+
251
+ Settings live in `~/.config/skill-manager/.env`:
252
+
253
+ ```bash
254
+ # Where your skills live.
255
+ SKILLS_DIR=~/skills
256
+
257
+ # Optional: override the project target folder.
258
+ SKILLS_TARGET_DIR=~/projects/my-project/.opencode/skills
259
+ ```
260
+
261
+ The file is a minimal `KEY=VALUE` file: `#` comments and blank lines are
262
+ ignored, and values may be quoted.
263
+
264
+ ### Precedence
265
+
266
+ **Source directory** (`SKILLS_DIR`):
267
+
268
+ 1. `--skills-dir <path>` on the command line
269
+ 2. `SKILLS_DIR` in the environment file
270
+ 3. `~/skills`
271
+
272
+ **Target directory** (`SKILLS_TARGET_DIR`):
273
+
274
+ 1. `--target-dir <path>` on the command line
275
+ 2. `SKILLS_TARGET_DIR` in the environment file
276
+ 3. `<project root>/.opencode/skills`
277
+
278
+ **Project root**:
279
+
280
+ 1. `--root <path>` on the command line
281
+ 2. the enclosing git worktree
282
+ 3. the current directory
283
+
284
+ **Environment file**: `--env-file <path>`, default
285
+ `~/.config/skill-manager/.env`.
286
+
287
+ Global flags (`--skills-dir`, `--target-dir`, `--root`, `--env-file`) may be
288
+ given before the subcommand:
289
+
290
+ ```bash
291
+ simple-skill-manager --skills-dir /opt/skills list
292
+ ```
293
+
294
+ ---
295
+
296
+ ## The project manifest
297
+
298
+ Each project records its selection in `.skill-manager.json` at the project
299
+ root:
300
+
301
+ ```json
302
+ {
303
+ "skills": {
304
+ "scientific-python": {
305
+ "hash": "3f2a…",
306
+ "mode": "link"
307
+ },
308
+ "tdd": {
309
+ "hash": "9b71…",
310
+ "mode": "copy"
311
+ }
312
+ },
313
+ "version": 1
314
+ }
315
+ ```
316
+
317
+ - `mode` is `link` or `copy`.
318
+ - `hash` is the SHA-256 of the source skill at the time it was added or
319
+ last updated. It is how `sync` detects that a source has changed.
320
+
321
+ This file is intended to be **committed** — it is what makes a project's
322
+ skill selection reproducible on another machine:
323
+
324
+ ```bash
325
+ git clone <repo> && cd <repo>
326
+ simple-skill-manager sync
327
+ ```
328
+
329
+ The target folder `.opencode/skills/` is a build artefact; it is usually
330
+ git-ignored.
331
+
332
+ ---
333
+
334
+ ## Windows notes
335
+
336
+ Windows requires either Administrator rights or Developer Mode to create
337
+ symbolic links. When `os.symlink` fails, `simple-skill-manager` falls back
338
+ to a directory **junction** (`mklink /J`), which needs neither. If even that
339
+ fails, use `--copy`.
340
+
341
+ Junctions are treated exactly like symbolic links: they are detected as
342
+ links, reported as `broken` when their source disappears, and removing one
343
+ never deletes the skill it points at.
344
+
345
+ Windows paths containing backslashes or spaces are handled correctly in the
346
+ `.env` file, but remember that `KEY=VALUE` splits on the first `=`, so a
347
+ value containing `=` should be quoted.
348
+
349
+ ---
350
+
351
+ ## Development
352
+
353
+ ### Requirements
354
+
355
+ - Python 3.10 or newer.
356
+ - No runtime dependencies. The test and tooling dependencies are declared
357
+ as extras in `pyproject.toml` and installed on demand.
358
+
359
+ ### Set up an environment
360
+
361
+ ```bash
362
+ git clone https://github.com/tomjanus/skill-manager.git
363
+ cd skill-manager
364
+ python -m venv .venv
365
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
366
+ pip install -e ".[dev]"
367
+ ```
368
+
369
+ The extras are:
370
+
371
+ | Extra | Contents | Install with |
372
+ | --- | --- | --- |
373
+ | `test` | `pytest` | `pip install -e ".[test]"` |
374
+ | `dev` | `pytest`, `ruff`, `mypy`, `build`, `twine`, `coverage` | `pip install -e ".[dev]"` |
375
+
376
+ Use `test` when you only want to run the test suite, and `dev` for the full
377
+ tooling set.
378
+
379
+ ### Run the tests
380
+
381
+ ```bash
382
+ python -m pytest # the whole suite
383
+ python -m pytest tests/test_cli.py # a single file
384
+ python -m pytest -k sync # everything matching a keyword
385
+ python -m pytest -q # quiet output
386
+ ```
387
+
388
+ The tests are written with `unittest`, so they also run without installing
389
+ any third-party package:
390
+
391
+ ```bash
392
+ python -m unittest discover -s tests -t .
393
+ ```
394
+
395
+ That form still needs the package itself to be importable — use the virtual
396
+ environment above, or prefix the command with `PYTHONPATH=src`.
397
+
398
+ ### Coverage
399
+
400
+ ```bash
401
+ coverage run -m pytest
402
+ coverage report
403
+ ```
404
+
405
+ ### Lint, format and type check
406
+
407
+ ```bash
408
+ ruff check src tests
409
+ ruff format --check src tests
410
+ mypy
411
+ ```
412
+
413
+ `mypy` runs in strict mode over `src/skill_manager`.
414
+
415
+ ### Build the distribution
416
+
417
+ ```bash
418
+ python -m build # writes dist/*.whl and dist/*.tar.gz
419
+ twine check dist/*
420
+ ```
421
+
422
+ `twine check` validates the metadata and the rendered long description
423
+ exactly as PyPI will show them.
424
+
425
+ ### Continuous integration
426
+
427
+ `.github/workflows/ci.yml` runs on every push and pull request:
428
+
429
+ - the test suite on Python 3.10 – 3.14 (Linux),
430
+ - the test suite on macOS and Windows,
431
+ - `ruff check`, `ruff format --check` and `mypy`,
432
+ - a distribution build followed by `twine check` and an install smoke test
433
+ of the built wheel.
434
+
435
+ ### Releasing
436
+
437
+ Releases are published to PyPI from a GitHub release using trusted
438
+ publishing — see [RELEASING.md](RELEASING.md).
439
+
440
+ ### Layout
441
+
442
+ ```
443
+ src/skill_manager/
444
+ ├── cli.py # argument parsing, table output, command dispatch
445
+ ├── config.py # env file parsing, path precedence
446
+ ├── discovery.py # scanning the source folder, frontmatter, hashing
447
+ ├── manifest.py # reading and writing .skill-manager.json
448
+ ├── operations.py # init / list / add / remove / sync
449
+ ├── platform.py # symlink, junction, copy, remove
450
+ ├── project.py # project root discovery, scanning the target folder
451
+ └── ui.py # console interaction (and a fake for tests)
452
+ ```
453
+
454
+ ---
455
+
456
+ ## License
457
+
458
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,17 @@
1
+ simple_skill_manager-0.1.0.dist-info/licenses/LICENSE,sha256=Q95UYRPoxeKLXlXkoZizFB365wGILo3WCGf_yWggH0w,1066
2
+ skill_manager/__init__.py,sha256=wfDPF_KfFCsvEgoEd6uKV0L-Opqq02duj5k-eXfxzrs,90
3
+ skill_manager/__main__.py,sha256=PHELyQc5LfWrZ3A7PuL8sLoEwaQNWip-yIyritLwCRQ,148
4
+ skill_manager/cli.py,sha256=4Cm1rXSneYyM-B5_5sVNk9eKfAJcBd_u3DhhygZA4LE,6287
5
+ skill_manager/config.py,sha256=4O5tDMH-SDwNbR6gJTgXqENL6fNmq9C0X92wm70Vvx0,3641
6
+ skill_manager/discovery.py,sha256=KdyamRIGsXFvAJQ6Aj1y9wjeVltRNfsxqfQOIT3NSpM,3551
7
+ skill_manager/manifest.py,sha256=71uDJCtVcRqoTm33QGLvq0fx7BB42f3Z_2mJ5oBgnRs,3013
8
+ skill_manager/operations.py,sha256=pNVprB_6HCZBPBgucS7P5F69mxM9t-e6dIiYrtOpnNU,14961
9
+ skill_manager/platform.py,sha256=38t2ZY6S6g6bXp9UthusxNOHbeHV9sq21ex_j56MioA,2948
10
+ skill_manager/project.py,sha256=b5kbCfrbZfWG_OBihk4M5ZM78AUUuTbHxlsjFRj1GHo,2196
11
+ skill_manager/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ skill_manager/ui.py,sha256=r8MIbJ_Nrw5VcC19KETvg8PqdqYHM4lvkLjLTC0CTp4,3441
13
+ simple_skill_manager-0.1.0.dist-info/METADATA,sha256=XWJcsai7wl2IDKs7-onslhyhH4j6-RrPaiD__sGzoR8,12911
14
+ simple_skill_manager-0.1.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
15
+ simple_skill_manager-0.1.0.dist-info/entry_points.txt,sha256=IpJLgrqnv8SDEjHgfucCgWHtlfjyfV1VhwrJWBaVibo,103
16
+ simple_skill_manager-0.1.0.dist-info/top_level.txt,sha256=Z-Eu5LTm2Umm3F5jwxgldneXhF5pePYmxJYsDJldjrc,14
17
+ simple_skill_manager-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ simple-skill-manager = skill_manager.cli:main
3
+ skill-manager = skill_manager.cli:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tom Janus
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.
@@ -0,0 +1 @@
1
+ skill_manager
@@ -0,0 +1,3 @@
1
+ """skill-manager: manage opencode Agent Skills across projects."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,6 @@
1
+ """Allow running skill-manager with ``python -m skill_manager``."""
2
+
3
+ from .cli import main
4
+
5
+ if __name__ == "__main__":
6
+ raise SystemExit(main())