help2skill 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.
- help2skill/__init__.py +243 -0
- help2skill/__main__.py +3 -0
- help2skill/_argparse.py +173 -0
- help2skill/_click.py +256 -0
- help2skill/cli.py +264 -0
- help2skill/click.py +98 -0
- help2skill/model.py +89 -0
- help2skill/privacy.py +33 -0
- help2skill/py.typed +0 -0
- help2skill/render.py +286 -0
- help2skill/sync.py +448 -0
- help2skill/testing.py +37 -0
- help2skill/typer.py +42 -0
- help2skill-0.1.0.dist-info/METADATA +206 -0
- help2skill-0.1.0.dist-info/RECORD +18 -0
- help2skill-0.1.0.dist-info/WHEEL +4 -0
- help2skill-0.1.0.dist-info/entry_points.txt +2 -0
- help2skill-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: help2skill
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Make Python CLIs ready for LLM agents: --llms output, SKILL.md generation and drift checks for Click, Typer and argparse.
|
|
5
|
+
Project-URL: Homepage, https://github.com/huysonmind/help2skill
|
|
6
|
+
Project-URL: Issues, https://github.com/huysonmind/help2skill/issues
|
|
7
|
+
Project-URL: Changelog, https://github.com/huysonmind/help2skill/blob/main/CHANGELOG.md
|
|
8
|
+
Author-email: huysonmind <350970572+huysonmind@users.noreply.github.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agent-skills,agents,argparse,cli,click,llm,llms-txt,skill-md,typer
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Topic :: Software Development :: Documentation
|
|
18
|
+
Classifier: Topic :: Software Development :: User Interfaces
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# help2skill
|
|
24
|
+
|
|
25
|
+
> **Status: alpha.** The output format may still change before 1.0.
|
|
26
|
+
|
|
27
|
+
`--help` for LLM agents. Make a Click, Typer or argparse CLI easy for coding agents
|
|
28
|
+
(Claude Code, Codex, Cursor, Gemini CLI…) to use correctly:
|
|
29
|
+
|
|
30
|
+
- **`--llms` flag**: prints a compact Markdown reference of the command tree (every
|
|
31
|
+
subcommand, argument, option, choice, default and env var), generated from the CLI
|
|
32
|
+
itself, so it never goes stale.
|
|
33
|
+
- **`SKILL.md` export**: writes an [Agent Skills](https://agentskills.io) file whose
|
|
34
|
+
reference block is regenerated from the CLI while your hand-written guidance is kept.
|
|
35
|
+
- **Drift check for CI**: fails when the generated block is stale, or when hand-written
|
|
36
|
+
examples mention a subcommand or option that does not exist (or an option placed at
|
|
37
|
+
the wrong level, e.g. a group option after the subcommand).
|
|
38
|
+
|
|
39
|
+
No runtime dependencies. Works with Typer ≥ 0.26 (vendored Click), where code that does
|
|
40
|
+
`isinstance(cmd, click.Group)` silently finds nothing.
|
|
41
|
+
|
|
42
|
+
## Quick start
|
|
43
|
+
|
|
44
|
+
### Click
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
import click
|
|
48
|
+
from help2skill.click import llms_option
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@click.group()
|
|
52
|
+
@llms_option()
|
|
53
|
+
def cli(): ...
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```console
|
|
57
|
+
$ mytool --llms
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`llms_option()` adds the flag to the root only, which prints the whole tree. To get
|
|
61
|
+
`--llms` on every subcommand too (`mytool db --llms` prints just that subtree):
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from help2skill.click import add_llms_option
|
|
65
|
+
|
|
66
|
+
add_llms_option(cli)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Typer
|
|
70
|
+
|
|
71
|
+
Root flag, no change to your entry point:
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
import typer
|
|
75
|
+
from help2skill.typer import LlmsOption
|
|
76
|
+
|
|
77
|
+
app = typer.Typer()
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@app.callback()
|
|
81
|
+
def main(llms: LlmsOption = False): ...
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Or `--llms` at every level: build the command once and make it your console script.
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
# mytool/cli.py
|
|
88
|
+
import help2skill.typer
|
|
89
|
+
|
|
90
|
+
main = help2skill.typer.command(app, name="mytool")
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
```toml
|
|
94
|
+
# pyproject.toml
|
|
95
|
+
[project.scripts]
|
|
96
|
+
mytool = "mytool.cli:main"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
No `click` package is needed with Typer ≥ 0.26, which ships its own copy.
|
|
100
|
+
|
|
101
|
+
### argparse
|
|
102
|
+
|
|
103
|
+
argparse has no hook for an extra flag, so use the command line (or the Python API):
|
|
104
|
+
|
|
105
|
+
```console
|
|
106
|
+
$ help2skill markdown mytool.cli:parser
|
|
107
|
+
$ help2skill markdown "mytool.cli:build_parser()" # a function that returns the parser
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Large CLIs
|
|
111
|
+
|
|
112
|
+
`--llms` prints the full reference when it fits in 20,000 characters (about 5k tokens).
|
|
113
|
+
Above that it prints the top-level help plus an index of every command, and tells the
|
|
114
|
+
agent how to ask for one command (`mytool <command> --llms`, or `--help` when only the
|
|
115
|
+
root has the flag). Set `HELP2SKILL_LLMS_MAX_CHARS=0` for everything. Options repeated
|
|
116
|
+
identically in three or more commands are described once, under "Shared options".
|
|
117
|
+
|
|
118
|
+
### Lazy commands
|
|
119
|
+
|
|
120
|
+
Click's documented `LazyGroup` pattern works as is. Placeholder commands with a
|
|
121
|
+
`materialize()` method are loaded automatically; for anything else pass
|
|
122
|
+
`resolve=` (Python API) or `--resolve module:func` (command line).
|
|
123
|
+
|
|
124
|
+
## SKILL.md and drift checks
|
|
125
|
+
|
|
126
|
+
```console
|
|
127
|
+
$ help2skill skill mytool.cli:app --name mytool --description "Use mytool to ..." \
|
|
128
|
+
-o src/mytool/.agents/skills/mytool/SKILL.md
|
|
129
|
+
$ help2skill check mytool.cli:app src/mytool/.agents/skills/mytool/SKILL.md
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
`skill` creates the file, or refreshes only the block between
|
|
133
|
+
`<!-- help2skill:begin … -->` and `<!-- help2skill:end -->` if it already exists
|
|
134
|
+
(`--name` is then optional). Write your own guidance above or below the block.
|
|
135
|
+
|
|
136
|
+
**Program name.** Commands are written with the name users type. help2skill uses
|
|
137
|
+
`--program` if given, else the installed console script that points at the target,
|
|
138
|
+
else the CLI's own name (`@click.group(name="mytool")`, `ArgumentParser(prog="mytool")`),
|
|
139
|
+
else the skill name. `markdown` warns when it can only guess.
|
|
140
|
+
|
|
141
|
+
**Settings are stored in the file.** The begin marker records the program name,
|
|
142
|
+
`--max-chars` and `--hide-default`, so `check`, a refresh and the pytest helper reuse
|
|
143
|
+
them without repeating any option.
|
|
144
|
+
|
|
145
|
+
**Stable in CI.** The output does not depend on the machine or on the Click/Typer
|
|
146
|
+
version: commands are sorted, type names are normalised and your home directory is
|
|
147
|
+
written as `~` (other machine-specific paths trigger a warning). A default computed at
|
|
148
|
+
run time (CPU count, today's date) would still differ, so leave it out:
|
|
149
|
+
|
|
150
|
+
```console
|
|
151
|
+
$ help2skill skill mytool.cli:app -o SKILL.md --hide-default workers --hide-default --since
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
When the reference is longer than 30,000 characters, `SKILL.md` keeps an index and the
|
|
155
|
+
full reference goes to `references/commands.md` beside it (fully generated; agents read
|
|
156
|
+
it on demand). Change the limit with `--max-chars` (0 = never split).
|
|
157
|
+
|
|
158
|
+
**What the check catches** in code spans and fenced blocks of your hand-written text:
|
|
159
|
+
unknown subcommands and options (with "did you mean"), options at the wrong level,
|
|
160
|
+
values not among an option's or argument's choices, values given to flags, and
|
|
161
|
+
single-letter clusters such as `-fq`. Lines continued with `\` are joined, and lines
|
|
162
|
+
are recognised with launchers in front: `uv run [--with …] mytool …`, `uvx`,
|
|
163
|
+
`pipx run`, `poetry run`, `python -m mytool`, `VAR=value mytool …`.
|
|
164
|
+
|
|
165
|
+
Shipping the skill inside your package under `.agents/skills/<name>/` makes it
|
|
166
|
+
installable with [library-skills](https://github.com/tiangolo/library-skills). With
|
|
167
|
+
setuptools, add the folder to `package-data`; hatchling includes it by default.
|
|
168
|
+
|
|
169
|
+
In pytest (build the path from `__file__` so the test runs from any directory):
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
from pathlib import Path
|
|
173
|
+
|
|
174
|
+
from help2skill.testing import assert_skill_in_sync
|
|
175
|
+
from mytool.cli import app
|
|
176
|
+
|
|
177
|
+
SKILL = Path(__file__).parents[1] / "src/mytool/.agents/skills/mytool/SKILL.md"
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def test_skill_in_sync():
|
|
181
|
+
assert_skill_in_sync(app, SKILL)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
With a `src/` layout that is not installed, pass `--app-dir src` to the command line.
|
|
185
|
+
|
|
186
|
+
## Python API
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
import help2skill
|
|
190
|
+
|
|
191
|
+
tree = help2skill.introspect(app, "mytool") # Click, Typer or argparse
|
|
192
|
+
print(help2skill.render_markdown(tree))
|
|
193
|
+
help2skill.write_skill(app, "SKILL.md", name="mytool")
|
|
194
|
+
problems = help2skill.check_skill_file(app, "SKILL.md")
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Security
|
|
198
|
+
|
|
199
|
+
`help2skill` imports the module you point it at, the same as running your CLI. It calls
|
|
200
|
+
a function only when you write `module:func()` or the function's name contains
|
|
201
|
+
"parser"; it never calls your `main()`. Generated files copy your help text verbatim, so review them
|
|
202
|
+
for machine-specific values before committing. See [SECURITY.md](https://github.com/huysonmind/help2skill/blob/main/SECURITY.md).
|
|
203
|
+
|
|
204
|
+
## License
|
|
205
|
+
|
|
206
|
+
[MIT](https://github.com/huysonmind/help2skill/blob/main/LICENSE). Built with AI assistance (Claude).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
help2skill/__init__.py,sha256=Bqc3NtdXN1EqOc2cqps5b9AWZwu1f969MlNJ8a9-Xuw,8687
|
|
2
|
+
help2skill/__main__.py,sha256=k1ocEWawweo1qCJWNFAAvyxz3tcY13dzvCenHszij30,48
|
|
3
|
+
help2skill/_argparse.py,sha256=x58Yc7Dzc9WRp4e64JpsyXfvP3jLe_r-6l5K4xhWWrM,6262
|
|
4
|
+
help2skill/_click.py,sha256=BbpK2BercOkat9Y98m_F7vGxXBg2u5-3huO8dCcug94,8945
|
|
5
|
+
help2skill/cli.py,sha256=0Fn6nmtFLq1TEIBWPdwJ7JdwqaAxaZr9KQmkZDGf6qE,10030
|
|
6
|
+
help2skill/click.py,sha256=0TWSFvzgY2d2SXpoG9TjdV5kdPzj1K5wnykF0mbLmcw,2968
|
|
7
|
+
help2skill/model.py,sha256=aVmDl-fp4EtZSC8bxpswSedduxDlmnQi2TvOzXbjD54,3021
|
|
8
|
+
help2skill/privacy.py,sha256=OdeL59R2E7ltWaPug0Z0u3SkMpy_dHhRYqPKym1YKLM,1234
|
|
9
|
+
help2skill/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
help2skill/render.py,sha256=hZpruGwot5pjoOzCUh_flTpCpPVpCFb0AnlAgj6ZfWs,9933
|
|
11
|
+
help2skill/sync.py,sha256=0Jccq8UHNrCH-gJ1uVp5eFybQNTdlAG9PsMLdR0-VAA,17391
|
|
12
|
+
help2skill/testing.py,sha256=66f0LeEyihN9a0FnMbIWIPHq0fDzedXGD8h-amVhwPs,1235
|
|
13
|
+
help2skill/typer.py,sha256=dieYYFdtz14qPevPrrs0TBOpvt9Z3UaCsZq1OzOYpyE,1034
|
|
14
|
+
help2skill-0.1.0.dist-info/METADATA,sha256=UBLJ2RqGsxVjIadNRPEiKo_BIkb4l3RZ4k_QAzOaPpQ,7569
|
|
15
|
+
help2skill-0.1.0.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
|
|
16
|
+
help2skill-0.1.0.dist-info/entry_points.txt,sha256=ozWOfUQCiT1o6LodAg9x8Z6Bwoh4u8-HXHowgi_wbCk,51
|
|
17
|
+
help2skill-0.1.0.dist-info/licenses/LICENSE,sha256=6sVsij8RLQMer7EYynJVovhnk1ESme1Eh5KokDX0Gg8,1067
|
|
18
|
+
help2skill-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 huysonmind
|
|
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.
|