claude-skill-forge 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.
Files changed (41) hide show
  1. claude_skill_forge-0.1.0/.github/workflows/ci.yml +39 -0
  2. claude_skill_forge-0.1.0/.gitignore +29 -0
  3. claude_skill_forge-0.1.0/CHANGELOG.md +28 -0
  4. claude_skill_forge-0.1.0/CONTRIBUTING.md +48 -0
  5. claude_skill_forge-0.1.0/LICENSE +21 -0
  6. claude_skill_forge-0.1.0/PKG-INFO +178 -0
  7. claude_skill_forge-0.1.0/README.md +147 -0
  8. claude_skill_forge-0.1.0/SPEC.md +328 -0
  9. claude_skill_forge-0.1.0/examples/README.md +25 -0
  10. claude_skill_forge-0.1.0/examples/demo.sh +32 -0
  11. claude_skill_forge-0.1.0/examples/sample_tool/pyproject.toml +8 -0
  12. claude_skill_forge-0.1.0/examples/sample_tool/sample_tool/__init__.py +11 -0
  13. claude_skill_forge-0.1.0/examples/sample_tool/sample_tool/cli.py +28 -0
  14. claude_skill_forge-0.1.0/pyproject.toml +55 -0
  15. claude_skill_forge-0.1.0/skill_forge/__init__.py +56 -0
  16. claude_skill_forge-0.1.0/skill_forge/analyzers/__init__.py +66 -0
  17. claude_skill_forge-0.1.0/skill_forge/analyzers/base.py +203 -0
  18. claude_skill_forge-0.1.0/skill_forge/analyzers/cli_help.py +99 -0
  19. claude_skill_forge-0.1.0/skill_forge/analyzers/docs.py +35 -0
  20. claude_skill_forge-0.1.0/skill_forge/analyzers/generic.py +47 -0
  21. claude_skill_forge-0.1.0/skill_forge/analyzers/node.py +73 -0
  22. claude_skill_forge-0.1.0/skill_forge/analyzers/python.py +354 -0
  23. claude_skill_forge-0.1.0/skill_forge/cli.py +166 -0
  24. claude_skill_forge-0.1.0/skill_forge/config.py +32 -0
  25. claude_skill_forge-0.1.0/skill_forge/describe.py +101 -0
  26. claude_skill_forge-0.1.0/skill_forge/errors.py +27 -0
  27. claude_skill_forge-0.1.0/skill_forge/frontmatter.py +77 -0
  28. claude_skill_forge-0.1.0/skill_forge/generate.py +84 -0
  29. claude_skill_forge-0.1.0/skill_forge/llm.py +121 -0
  30. claude_skill_forge-0.1.0/skill_forge/models.py +56 -0
  31. claude_skill_forge-0.1.0/skill_forge/skill.py +39 -0
  32. claude_skill_forge-0.1.0/skill_forge/slug.py +41 -0
  33. claude_skill_forge-0.1.0/skill_forge/templates.py +151 -0
  34. claude_skill_forge-0.1.0/skill_forge/validate.py +147 -0
  35. claude_skill_forge-0.1.0/tests/conftest.py +104 -0
  36. claude_skill_forge-0.1.0/tests/test_analyzers.py +65 -0
  37. claude_skill_forge-0.1.0/tests/test_cli.py +75 -0
  38. claude_skill_forge-0.1.0/tests/test_forge.py +57 -0
  39. claude_skill_forge-0.1.0/tests/test_llm.py +31 -0
  40. claude_skill_forge-0.1.0/tests/test_review_regressions.py +131 -0
  41. claude_skill_forge-0.1.0/tests/test_units.py +149 -0
@@ -0,0 +1,39 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ test:
11
+ name: Lint & test (py${{ matrix.python-version }})
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Set up Python
21
+ uses: actions/setup-python@v5
22
+ with:
23
+ python-version: ${{ matrix.python-version }}
24
+
25
+ - name: Install (core + dev, no provider SDKs)
26
+ run: |
27
+ python -m pip install --upgrade pip
28
+ pip install -e ".[dev]"
29
+
30
+ - name: Ruff
31
+ run: ruff check .
32
+
33
+ - name: Pytest
34
+ run: pytest -q
35
+
36
+ - name: Self-forge (dogfood — generate a skill from this repo and lint it)
37
+ run: |
38
+ python -m skill_forge.cli forge . --name skill-forge -o /tmp/sf-skills --force
39
+ python -m skill_forge.cli lint /tmp/sf-skills
@@ -0,0 +1,29 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+ wheels/
9
+
10
+ # Envs
11
+ .venv/
12
+ venv/
13
+ env/
14
+ .env
15
+ .env.*
16
+ !.env.example
17
+
18
+ # Tooling caches
19
+ .pytest_cache/
20
+ .ruff_cache/
21
+ .mypy_cache/
22
+ .coverage
23
+ htmlcov/
24
+
25
+ # OS / editor
26
+ .DS_Store
27
+ *.swp
28
+ .idea/
29
+ .vscode/
@@ -0,0 +1,28 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format is based on
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to
5
+ [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ### Added
10
+
11
+ - Initial release of `skill-forge`, a CLI that generates a valid Claude `SKILL.md` from a
12
+ codebase, package, or doc.
13
+ - **Deterministic, offline, zero-dependency core** — `analyze → draft → validate` uses only
14
+ the standard library and never executes the target code.
15
+ - **Valid by construction** — every generated skill passes the bundled linter; the tool
16
+ refuses to write a skill that does not lint clean.
17
+ - Analyzers:
18
+ - **Python** — `pyproject.toml` / `setup.cfg`, `__all__` / public defs via `ast`, and
19
+ argparse / click / typer subcommands.
20
+ - **Node** — `package.json` (name, description, keywords, `bin`) + README, TS/JS detection.
21
+ - **Docs** — a single markdown/rst/txt file (title, summary, headings, code blocks).
22
+ - **Generic** — README + a language histogram of the file tree.
23
+ - **CLI help** — `--from-cli "<cmd>"` captures and parses a tool's `--help` (no shell,
24
+ timeout-guarded, explicit opt-in).
25
+ - CLI subcommands: `forge`, `lint`, `check` (CI drift guard), and `version`.
26
+ - Optional `--llm` refinement via Claude (the only extra, lazily imported and fail-safe:
27
+ it never produces a worse skill than the offline path).
28
+ - GitHub Actions CI: ruff + pytest on Python 3.10–3.13, plus a self-forge dogfood step.
@@ -0,0 +1,48 @@
1
+ # Contributing to skill-forge
2
+
3
+ Thanks for helping make Claude skills easier to author. `skill-forge` has one job: take a
4
+ source and emit a `SKILL.md` that is **valid by construction** — so the bar for every change
5
+ is "the output still lints clean, deterministically, offline."
6
+
7
+ ## Philosophy
8
+
9
+ - **Deterministic and offline by default.** The `analyze → draft → validate` path must never
10
+ hit the network and must never import or execute the target code. The Python analyzer uses
11
+ `ast` only. The single exception is the explicit `--from-cli` flag.
12
+ - **Zero runtime dependencies in the core.** `anthropic` is the only optional extra. If a
13
+ change needs a new hard dependency, it almost certainly belongs behind an extra — or not at
14
+ all. Prefer the standard library.
15
+ - **Valid by construction.** If you touch the generators, the property tests in
16
+ `tests/test_forge.py` must still show every fixture rendering to a skill that passes
17
+ `lint_text` with zero errors.
18
+ - **The SPEC is the contract.** [`SPEC.md`](SPEC.md) pins the public API and behavior. Change
19
+ the spec in the same PR when you change the contract; don't let them drift.
20
+
21
+ ## Development
22
+
23
+ ```bash
24
+ python -m venv .venv && source .venv/bin/activate
25
+ pip install -e ".[dev]"
26
+ ruff check .
27
+ pytest -q
28
+ ```
29
+
30
+ CI runs ruff + pytest on Python 3.10–3.13 and a self-forge dogfood step on every push and PR.
31
+
32
+ ## Adding an analyzer
33
+
34
+ 1. Add `skill_forge/analyzers/<kind>.py` exposing `analyze(path) -> SourceSignals`.
35
+ 2. Register it in `analyzers/__init__.py` (`_ANALYZERS`) and teach `detect()` when to pick it.
36
+ 3. Add a fixture in `tests/conftest.py` and a test that asserts the extracted signals, plus a
37
+ `test_forge_valid_by_construction` case so the generated skill is proven valid.
38
+ 4. Keep it pure: no network, no executing the target.
39
+
40
+ ## Reporting issues
41
+
42
+ Found a source that produces a bad (or invalid) skill? Open an issue with a **minimal repro**
43
+ source and the generated `SKILL.md`. A generated skill that fails `skill-forge lint` is a bug
44
+ and the most valuable kind of report.
45
+
46
+ ## License
47
+
48
+ By contributing you agree your work is released under the [MIT License](LICENSE).
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shaxzodbek Sobirov / Blaze
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,178 @@
1
+ Metadata-Version: 2.4
2
+ Name: claude-skill-forge
3
+ Version: 0.1.0
4
+ Summary: Turn a codebase, package, or doc into a valid Claude SKILL.md — offline, deterministic, and valid by construction. Optional Claude refinement. Zero runtime dependencies.
5
+ Project-URL: Homepage, https://github.com/shaxzodbek-uzb/skill-forge
6
+ Project-URL: Repository, https://github.com/shaxzodbek-uzb/skill-forge
7
+ Project-URL: Issues, https://github.com/shaxzodbek-uzb/skill-forge/issues
8
+ Author-email: Shaxzodbek Sobirov <shaxzodbek@blaze.uz>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: agent,anthropic,claude,cli,codegen,linter,mcp,scaffold,skill-md,skills
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
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: Topic :: Software Development :: Code Generators
22
+ Classifier: Topic :: Software Development :: Documentation
23
+ Classifier: Topic :: Utilities
24
+ Requires-Python: >=3.10
25
+ Provides-Extra: anthropic
26
+ Requires-Dist: anthropic>=0.40; extra == 'anthropic'
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest>=8.0; extra == 'dev'
29
+ Requires-Dist: ruff>=0.6; extra == 'dev'
30
+ Description-Content-Type: text/markdown
31
+
32
+ # skill-forge
33
+
34
+ **Point it at your code. Get a valid Claude skill. No API key required.**
35
+
36
+ `skill-forge` turns a codebase, package, or doc into a well-formed Claude
37
+ [`SKILL.md`](https://docs.claude.com/en/docs/agents-and-tools/agent-skills) — and the
38
+ skill it writes is **valid by construction**.
39
+
40
+ ```bash
41
+ pip install claude-skill-forge # the CLI it installs is `skill-forge`
42
+ skill-forge forge ./my-tool # writes .claude/skills/my-tool/SKILL.md
43
+ ```
44
+
45
+ [![CI](https://github.com/shaxzodbek-uzb/skill-forge/actions/workflows/ci.yml/badge.svg)](https://github.com/shaxzodbek-uzb/skill-forge/actions/workflows/ci.yml)
46
+ [![PyPI](https://img.shields.io/pypi/v/claude-skill-forge)](https://pypi.org/project/claude-skill-forge/)
47
+ ![Python](https://img.shields.io/badge/python-3.10%2B-blue)
48
+ ![License](https://img.shields.io/badge/license-MIT-green)
49
+ ![Dependencies](https://img.shields.io/badge/runtime%20deps-0-brightgreen)
50
+
51
+ ---
52
+
53
+ ## Why
54
+
55
+ Writing a good skill is fiddly: the frontmatter has to be exactly right, the `name` has to
56
+ match its directory, and the `description` — the one field an agent actually reads to
57
+ decide *whether to load the skill* — has to say **when** to trigger, inside a tight
58
+ character budget. Get any of it wrong and the skill is silently undiscoverable.
59
+
60
+ Most "ask an LLM to write my SKILL.md" approaches are non-reproducible, need an API key,
61
+ and still emit invalid frontmatter. `skill-forge` is different on two axes:
62
+
63
+ 1. **Offline & deterministic by default.** It reads your source with static analysis — no
64
+ code execution, no network, no key — and emits the skill. Same input → same output.
65
+ The optional `--llm` flag only *refines* the prose; it never owns the structure.
66
+ 2. **Valid by construction.** Every generated skill passes the built-in linter (the same
67
+ rules a skill must satisfy to be discoverable). `skill-forge` refuses to write a skill
68
+ that doesn't lint clean, so you never ship a broken one.
69
+
70
+ It's the *forge* half of a pair: **forge generates, `skillcheck` checks.** The linter is
71
+ bundled here too (`skill-forge lint`) so the tool stands alone.
72
+
73
+ ## Install
74
+
75
+ The package is published on PyPI as **`claude-skill-forge`**; it installs a CLI named
76
+ `skill-forge` (and the import package is `skill_forge`).
77
+
78
+ ```bash
79
+ pip install claude-skill-forge # core: zero runtime dependencies
80
+ pip install 'claude-skill-forge[anthropic]' # adds the optional --llm refiner
81
+ ```
82
+
83
+ ## Quickstart (30 seconds)
84
+
85
+ ```bash
86
+ # From a Python/Node project, a package, or a single doc:
87
+ skill-forge forge ./my-tool # -> .claude/skills/my-tool/SKILL.md
88
+ skill-forge forge ./README.md # generate from docs
89
+ skill-forge forge ./pkg --name my-skill # override the skill name
90
+ skill-forge forge ./my-tool --stdout # preview, don't write
91
+ skill-forge forge ./my-tool --llm # sharpen the prose with Claude
92
+
93
+ # Validate any skill / folder of skills (the bundled checker):
94
+ skill-forge lint .claude/skills
95
+
96
+ # CI drift guard — fail if the skill no longer matches the code:
97
+ skill-forge check ./my-tool --name my-tool
98
+ ```
99
+
100
+ ### What it extracts
101
+
102
+ | Source | What it reads |
103
+ | --- | --- |
104
+ | **Python** | `pyproject.toml` / `setup.cfg` (name, description, keywords, `[project.scripts]`), `__all__` and public defs/classes via `ast`, and argparse / click / typer subcommands — **never importing or running your code** |
105
+ | **Node** | `package.json` (name, description, keywords, `bin`), TS/JS detection, README |
106
+ | **Docs** | A markdown/rst/txt file: H1 title, first paragraph, section headings, fenced code blocks |
107
+ | **Any directory** | README + a language histogram of the file tree |
108
+ | **A CLI tool** | `skill-forge forge --from-cli "mytool"` captures and parses `mytool --help` |
109
+
110
+ The result is a complete `SKILL.md`: trigger-oriented `description`, a `## When to use`
111
+ section, an overview, and `## Commands` / `## API` / `## Usage` sections built from what was
112
+ found.
113
+
114
+ ## Use it from Python
115
+
116
+ ```python
117
+ from skill_forge import forge, render_skill, write_skill
118
+
119
+ draft = forge("./my-tool") # a validated SkillDraft
120
+ print(render_skill(draft)) # the SKILL.md text
121
+ write_skill(draft, ".claude/skills")
122
+ ```
123
+
124
+ ## The `--llm` refiner (optional)
125
+
126
+ `--llm` sends the *extracted signals* (not your source) to Claude to sharpen the
127
+ description's trigger phrasing and tighten the body. It is fail-safe: if the model is
128
+ unavailable it tells you how to fix it, and if its output is anything but a valid
129
+ improvement, `skill-forge` keeps the deterministic draft. You never get a worse skill than
130
+ the offline path. Set `ANTHROPIC_API_KEY` and install the extra to use it.
131
+
132
+ ## CI: catch stale skills
133
+
134
+ `skill-forge check` regenerates the skill in memory and diffs it against the one on disk,
135
+ exiting non-zero if they differ — so a skill that drifted from the code it describes fails
136
+ the build:
137
+
138
+ ```yaml
139
+ - run: pip install claude-skill-forge
140
+ - run: skill-forge check ./my-tool --name my-tool
141
+ ```
142
+
143
+ ## What this is **not**
144
+
145
+ - **Not a replacement for judgment.** Generated skills are a strong *first draft*. The body
146
+ is assembled from your structure, not written from deep understanding — read it, trim it,
147
+ and add the hard-won "do this, not that" guidance only you know.
148
+ - **Not a runtime.** It writes `SKILL.md` files; it does not execute skills.
149
+ - **Not magic prose.** The offline path is deterministic and a little formulaic by design.
150
+ Reach for `--llm` when you want the description polished.
151
+ - **It does not run your code.** The only time it executes anything is the explicit
152
+ `--from-cli` flag, which runs `<cmd> --help` with no shell and a timeout.
153
+
154
+ ## Configuration
155
+
156
+ Environment overrides (all optional):
157
+
158
+ | Variable | Default | Purpose |
159
+ | --- | --- | --- |
160
+ | `SKILL_FORGE_OUTDIR` | `.claude/skills` | Default output directory |
161
+ | `SKILL_FORGE_VERSION` | `0.1.0` | Version stamped on generated skills |
162
+ | `SKILL_FORGE_MODEL_ID` | `claude-haiku-4-5` | Model used by `--llm` |
163
+ | `ANTHROPIC_API_KEY` | — | Required for `--llm` |
164
+
165
+ ## Development
166
+
167
+ ```bash
168
+ pip install -e ".[dev]"
169
+ ruff check .
170
+ pytest -q
171
+ ```
172
+
173
+ The design is pinned in [`SPEC.md`](SPEC.md) — the single source of truth for the public
174
+ API and behavior. See [`CONTRIBUTING.md`](CONTRIBUTING.md) before opening a PR.
175
+
176
+ ## License
177
+
178
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,147 @@
1
+ # skill-forge
2
+
3
+ **Point it at your code. Get a valid Claude skill. No API key required.**
4
+
5
+ `skill-forge` turns a codebase, package, or doc into a well-formed Claude
6
+ [`SKILL.md`](https://docs.claude.com/en/docs/agents-and-tools/agent-skills) — and the
7
+ skill it writes is **valid by construction**.
8
+
9
+ ```bash
10
+ pip install claude-skill-forge # the CLI it installs is `skill-forge`
11
+ skill-forge forge ./my-tool # writes .claude/skills/my-tool/SKILL.md
12
+ ```
13
+
14
+ [![CI](https://github.com/shaxzodbek-uzb/skill-forge/actions/workflows/ci.yml/badge.svg)](https://github.com/shaxzodbek-uzb/skill-forge/actions/workflows/ci.yml)
15
+ [![PyPI](https://img.shields.io/pypi/v/claude-skill-forge)](https://pypi.org/project/claude-skill-forge/)
16
+ ![Python](https://img.shields.io/badge/python-3.10%2B-blue)
17
+ ![License](https://img.shields.io/badge/license-MIT-green)
18
+ ![Dependencies](https://img.shields.io/badge/runtime%20deps-0-brightgreen)
19
+
20
+ ---
21
+
22
+ ## Why
23
+
24
+ Writing a good skill is fiddly: the frontmatter has to be exactly right, the `name` has to
25
+ match its directory, and the `description` — the one field an agent actually reads to
26
+ decide *whether to load the skill* — has to say **when** to trigger, inside a tight
27
+ character budget. Get any of it wrong and the skill is silently undiscoverable.
28
+
29
+ Most "ask an LLM to write my SKILL.md" approaches are non-reproducible, need an API key,
30
+ and still emit invalid frontmatter. `skill-forge` is different on two axes:
31
+
32
+ 1. **Offline & deterministic by default.** It reads your source with static analysis — no
33
+ code execution, no network, no key — and emits the skill. Same input → same output.
34
+ The optional `--llm` flag only *refines* the prose; it never owns the structure.
35
+ 2. **Valid by construction.** Every generated skill passes the built-in linter (the same
36
+ rules a skill must satisfy to be discoverable). `skill-forge` refuses to write a skill
37
+ that doesn't lint clean, so you never ship a broken one.
38
+
39
+ It's the *forge* half of a pair: **forge generates, `skillcheck` checks.** The linter is
40
+ bundled here too (`skill-forge lint`) so the tool stands alone.
41
+
42
+ ## Install
43
+
44
+ The package is published on PyPI as **`claude-skill-forge`**; it installs a CLI named
45
+ `skill-forge` (and the import package is `skill_forge`).
46
+
47
+ ```bash
48
+ pip install claude-skill-forge # core: zero runtime dependencies
49
+ pip install 'claude-skill-forge[anthropic]' # adds the optional --llm refiner
50
+ ```
51
+
52
+ ## Quickstart (30 seconds)
53
+
54
+ ```bash
55
+ # From a Python/Node project, a package, or a single doc:
56
+ skill-forge forge ./my-tool # -> .claude/skills/my-tool/SKILL.md
57
+ skill-forge forge ./README.md # generate from docs
58
+ skill-forge forge ./pkg --name my-skill # override the skill name
59
+ skill-forge forge ./my-tool --stdout # preview, don't write
60
+ skill-forge forge ./my-tool --llm # sharpen the prose with Claude
61
+
62
+ # Validate any skill / folder of skills (the bundled checker):
63
+ skill-forge lint .claude/skills
64
+
65
+ # CI drift guard — fail if the skill no longer matches the code:
66
+ skill-forge check ./my-tool --name my-tool
67
+ ```
68
+
69
+ ### What it extracts
70
+
71
+ | Source | What it reads |
72
+ | --- | --- |
73
+ | **Python** | `pyproject.toml` / `setup.cfg` (name, description, keywords, `[project.scripts]`), `__all__` and public defs/classes via `ast`, and argparse / click / typer subcommands — **never importing or running your code** |
74
+ | **Node** | `package.json` (name, description, keywords, `bin`), TS/JS detection, README |
75
+ | **Docs** | A markdown/rst/txt file: H1 title, first paragraph, section headings, fenced code blocks |
76
+ | **Any directory** | README + a language histogram of the file tree |
77
+ | **A CLI tool** | `skill-forge forge --from-cli "mytool"` captures and parses `mytool --help` |
78
+
79
+ The result is a complete `SKILL.md`: trigger-oriented `description`, a `## When to use`
80
+ section, an overview, and `## Commands` / `## API` / `## Usage` sections built from what was
81
+ found.
82
+
83
+ ## Use it from Python
84
+
85
+ ```python
86
+ from skill_forge import forge, render_skill, write_skill
87
+
88
+ draft = forge("./my-tool") # a validated SkillDraft
89
+ print(render_skill(draft)) # the SKILL.md text
90
+ write_skill(draft, ".claude/skills")
91
+ ```
92
+
93
+ ## The `--llm` refiner (optional)
94
+
95
+ `--llm` sends the *extracted signals* (not your source) to Claude to sharpen the
96
+ description's trigger phrasing and tighten the body. It is fail-safe: if the model is
97
+ unavailable it tells you how to fix it, and if its output is anything but a valid
98
+ improvement, `skill-forge` keeps the deterministic draft. You never get a worse skill than
99
+ the offline path. Set `ANTHROPIC_API_KEY` and install the extra to use it.
100
+
101
+ ## CI: catch stale skills
102
+
103
+ `skill-forge check` regenerates the skill in memory and diffs it against the one on disk,
104
+ exiting non-zero if they differ — so a skill that drifted from the code it describes fails
105
+ the build:
106
+
107
+ ```yaml
108
+ - run: pip install claude-skill-forge
109
+ - run: skill-forge check ./my-tool --name my-tool
110
+ ```
111
+
112
+ ## What this is **not**
113
+
114
+ - **Not a replacement for judgment.** Generated skills are a strong *first draft*. The body
115
+ is assembled from your structure, not written from deep understanding — read it, trim it,
116
+ and add the hard-won "do this, not that" guidance only you know.
117
+ - **Not a runtime.** It writes `SKILL.md` files; it does not execute skills.
118
+ - **Not magic prose.** The offline path is deterministic and a little formulaic by design.
119
+ Reach for `--llm` when you want the description polished.
120
+ - **It does not run your code.** The only time it executes anything is the explicit
121
+ `--from-cli` flag, which runs `<cmd> --help` with no shell and a timeout.
122
+
123
+ ## Configuration
124
+
125
+ Environment overrides (all optional):
126
+
127
+ | Variable | Default | Purpose |
128
+ | --- | --- | --- |
129
+ | `SKILL_FORGE_OUTDIR` | `.claude/skills` | Default output directory |
130
+ | `SKILL_FORGE_VERSION` | `0.1.0` | Version stamped on generated skills |
131
+ | `SKILL_FORGE_MODEL_ID` | `claude-haiku-4-5` | Model used by `--llm` |
132
+ | `ANTHROPIC_API_KEY` | — | Required for `--llm` |
133
+
134
+ ## Development
135
+
136
+ ```bash
137
+ pip install -e ".[dev]"
138
+ ruff check .
139
+ pytest -q
140
+ ```
141
+
142
+ The design is pinned in [`SPEC.md`](SPEC.md) — the single source of truth for the public
143
+ API and behavior. See [`CONTRIBUTING.md`](CONTRIBUTING.md) before opening a PR.
144
+
145
+ ## License
146
+
147
+ MIT — see [LICENSE](LICENSE).