Skip to content

Commit c64f635

Browse files
committed
fixes #39
1 parent 0956af7 commit c64f635

3 files changed

Lines changed: 47 additions & 152 deletions

File tree

README.md

Lines changed: 40 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,11 @@
33

44
<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->
55

6-
pyskills is a plugin system that lets Python packages register “skills”
7-
(units of LLM-usable functionality) via standard [entry
8-
points](https://packaging.python.org/en/latest/specifications/entry-points/).
9-
An LLM host (e.g. solveit) discovers available pyskills without
10-
importing them, reads lightweight descriptions via AST inspection, and
11-
selectively loads chosen pyskills into context using standard imports.
12-
13-
It includes
14-
[`list_pyskills()`](https://AnswerDotAI.github.io/pyskills/core.html#list_pyskills)
15-
for discovery,
16-
[`doc()`](https://AnswerDotAI.github.io/pyskills/core.html#doc) for
17-
rendering module/class/function documentation in LLM-friendly format,
18-
[`xdir()`](https://AnswerDotAI.github.io/pyskills/core.html#xdir) for
19-
listing a module or class’s public symbols, and an
20-
[`allow()`](https://AnswerDotAI.github.io/pyskills/core.html#allow)
21-
system for registering safe callable access in sandboxed environments.
22-
Skills can be installed as regular packages with entry points, or
23-
dropped into an XDG data directory for quick local use.
24-
25-
pyskills shares the progressive disclosure philosophy of the [Agent
26-
Skills](https://agentskills.io/specification) specification: both
27-
separate lightweight discovery metadata from full instructions loaded on
28-
demand. However, where Agent Skills uses a file-system convention
29-
(`SKILL.md` with YAML frontmatter, `scripts/`, `references/`
30-
directories), pyskills takes a Python-native approach: pyskills are
31-
regular Python modules discovered via standard entry points, documented
32-
with docstrings, and loaded with `import`. This means pyskills are
33-
directly executable, come with auto-generated structured documentation
34-
via [`doc()`](https://AnswerDotAI.github.io/pyskills/core.html#doc), and
35-
include a sandboxing layer via
36-
[`allow()`](https://AnswerDotAI.github.io/pyskills/core.html#allow) for
37-
safe execution. This makes pyskills a superset that covers discovery,
38-
documentation, execution, and security in one system.
6+
pyskills is a plugin system that lets Python packages register “skills” (units of LLM-usable functionality) via standard [entry points](https://packaging.python.org/en/latest/specifications/entry-points/). An LLM host (e.g. solveit) discovers available pyskills without importing them, reads lightweight descriptions via AST inspection, and selectively loads chosen pyskills into context using standard imports.
7+
8+
It includes [`list_pyskills()`](https://AnswerDotAI.github.io/pyskills/core.html#list_pyskills) for discovery, [`doc()`](https://AnswerDotAI.github.io/pyskills/core.html#doc) for rendering module/class/function documentation in LLM-friendly format, [`xdir()`](https://AnswerDotAI.github.io/pyskills/core.html#xdir) for listing a module or class’s public symbols, and an [`allow()`](https://AnswerDotAI.github.io/pyskills/core.html#allow) system for registering safe callable access in sandboxed environments. Skills can be installed as regular packages with entry points, or dropped into an XDG data directory for quick local use.
9+
10+
pyskills shares the progressive disclosure philosophy of the [Agent Skills](https://agentskills.io/specification) specification: both separate lightweight discovery metadata from full instructions loaded on demand. However, where Agent Skills uses a file-system convention (`SKILL.md` with YAML frontmatter, `scripts/`, `references/` directories), pyskills takes a Python-native approach: pyskills are regular Python modules discovered via standard entry points, documented with docstrings, and loaded with `import`. This means pyskills are directly executable, come with auto-generated structured documentation via [`doc()`](https://AnswerDotAI.github.io/pyskills/core.html#doc), and include a sandboxing layer via [`allow()`](https://AnswerDotAI.github.io/pyskills/core.html#allow) for safe execution. This makes pyskills a superset that covers discovery, documentation, execution, and security in one system.
3911

4012
## Usage
4113

@@ -53,8 +25,7 @@ $ pip install pyskills
5325
from pyskills import *
5426
```
5527

56-
Discover what pyskills are available. This works without importing any
57-
pyskill modules:
28+
Discover what pyskills are available. This works without importing any pyskill modules:
5829

5930
``` python
6031
list_pyskills()
@@ -68,38 +39,28 @@ list_pyskills()
6839
'dialoghelper.termskill': 'Read and edit Solveit dialog (or Jupyter) .ipynb files from a CLI / script. Solveit is an online notebook application (like Jupyter with AI integration) where each notebook is called a "dialog" and is stored as an `.ipynb` file containing `code`, `note` (markdown), and `prompt` (markdown with a special delimiter) messages (aka "cells"). The `dialoghelper` package provides tools for reading, searching, adding, updating, and deleting those messages.',
6940
'ghapi.skill': 'GitHub REST API access via `GhApi`, plus local git operations via `fastgit.Git`. Use this for day-to-day GitHub work: reading/creating issues and PRs, checking CI status, managing releases/branches/gists, and repo-local git operations -- all from Python, no shelling out to `gh`/`git` needed.',
7041
'rgapi.skill': 'Fast and flexible file discovery and search for Python. Use this when code needs `fd`-style file finding or `rg`-style searching.',
42+
'exhash.skill': 'Universal hash-verified text editing for local files. Use this when an LLM needs one safe editing interface for reading, previewing, and modifying text files.',
7143
'cordslite.skill': 'Load this skill when an agent needs to search, summarize, or find information in Discord using cordslite. It covers read-only workflows for connecting to Discord, opening a guild, orienting through channels, searching messages, reading threads, and fetching attachments.',
7244
'bgtmux.skill': 'Use tmux-backed background terminal sessions from Solveit. Useful to have a persistent terminal session that both you and the user can inspect and edit, and that you can send input to from Solveit.',
73-
'clikernel.skill': 'Use the persistent `clikernel` MCP session as the default workspace for any task advanced through live Python execution -- stateful inspection, file-editing workflows, debugging, experiments, API probes, data transforms, or notebook-style work. Read this before writing, running, or debugging Python code in a session with `clikernel` connected.',
74-
'exhash.skill': 'Universal hash-verified text editing for local files. Use this when an LLM needs one safe editing interface for reading, previewing, and modifying text files.'}
45+
'clikernel.skill': 'Use the persistent `clikernel` MCP session as the default workspace for any task advanced through live Python execution -- stateful inspection, file-editing workflows, debugging, experiments, API probes, data transforms, or notebook-style work. Read this before writing, running, or debugging Python code in a session with `clikernel` connected.'}
7546

7647
### The [`doc`](https://AnswerDotAI.github.io/pyskills/core.html#doc) and [`xdir`](https://AnswerDotAI.github.io/pyskills/core.html#xdir) functions
7748

78-
Once you’ve found a pyskill you want to use, import its module using
79-
standard python syntax:
49+
Once you’ve found a pyskill you want to use, import its module using standard python syntax:
8050

8151
``` python
8252
import pyskills.skill
8353
```
8454

85-
Use [`doc()`](https://AnswerDotAI.github.io/pyskills/core.html#doc) to
86-
read its full documentation.
87-
[`doc()`](https://AnswerDotAI.github.io/pyskills/core.html#doc) works on
88-
modules, classes, and functions, rendering LLM-friendly output in each
89-
case.
55+
Use [`doc()`](https://AnswerDotAI.github.io/pyskills/core.html#doc) to read its full documentation. [`doc()`](https://AnswerDotAI.github.io/pyskills/core.html#doc) works on modules, classes, and functions, rendering LLM-friendly output in each case.
9056

91-
For a **module**,
92-
[`doc`](https://AnswerDotAI.github.io/pyskills/core.html#doc) shows all
93-
public classes and functions with their signatures and first docstring
94-
line, submodules, and any
95-
[`allow()`](https://AnswerDotAI.github.io/pyskills/core.html#allow)
96-
calls:
57+
For a **module**, [`doc`](https://AnswerDotAI.github.io/pyskills/core.html#doc) shows all public classes and functions with their signatures and first docstring line, submodules, and any [`allow()`](https://AnswerDotAI.github.io/pyskills/core.html#allow) calls:
9758

9859
``` python
9960
print(doc(pyskills.skill)[-500:])
10061
```
10162

102-
kill.SkillTestClass)
63+
ills.skill.SkillTestClass)
10364
doc(pyskills.skill.skill_test_func)
10465

10566
## Creating pyskills
@@ -108,18 +69,16 @@ print(doc(pyskills.skill)[-500:])
10869
"""
10970

11071
## types:
111-
- class SkillTestClass(str): ... # Some class.
72+
- class SkillTestClass(str): # Some class.
11273

11374
## functions:
114-
- async def async_skill_test_func(x: int = 0) -> str: ... # A test function
115-
- def skill_test_func(x: int = 0) -> str: ... # A test function
75+
- async def async_skill_test_func(x: int = 0) -> str: # A test function
76+
- def skill_test_func(x: int = 0) -> str: # A test function
11677

11778
## submodules:
118-
pyskills.createskill: ... # How to create a pyskills pyskill module.
79+
pyskills.createskill: # How to create a pyskills pyskill module.
11980

120-
For a **function**,
121-
[`doc`](https://AnswerDotAI.github.io/pyskills/core.html#doc) renders
122-
the full signature with parameter comments (docments):
81+
For a **function**, [`doc`](https://AnswerDotAI.github.io/pyskills/core.html#doc) renders the full signature with parameter comments (docments):
12382

12483
``` python
12584
doc(pyskills.skill.skill_test_func)
@@ -129,10 +88,7 @@ doc(pyskills.skill.skill_test_func)
12988
x:int=0, # the input
13089
)->str: # the output"""A test function"""
13190

132-
For a **class**,
133-
[`doc`](https://AnswerDotAI.github.io/pyskills/core.html#doc) shows the
134-
class hierarchy, docstring, `__init__` signature, and all public methods
135-
with their first docstring line:
91+
For a **class**, [`doc`](https://AnswerDotAI.github.io/pyskills/core.html#doc) shows the class hierarchy, docstring, `__init__` signature, and all public methods with their first docstring line:
13692

13793
``` python
13894
doc(pyskills.skill.SkillTestClass)
@@ -148,18 +104,9 @@ doc(pyskills.skill.SkillTestClass)
148104

149105
### The [`allow`](https://AnswerDotAI.github.io/pyskills/core.html#allow) system
150106

151-
When pyskills run in a sandboxed environment like
152-
[safepyrun](https://github.com/AnswerDotAI/safepyrun), they need to
153-
declare which callables are trusted to perform otherwise-denied
154-
operations (filesystem writes, subprocesses, network access). safepyrun
155-
uses [fastaudit](https://github.com/AnswerDotAI/fastaudit) to deny those
156-
effects unless they happen inside a callable registered in the
157-
`__pytools__` registry. The
158-
[`allow()`](https://AnswerDotAI.github.io/pyskills/core.html#allow)
159-
function is how pyskills register their trusted callables.
107+
When pyskills run in a sandboxed environment like [safepyrun](https://github.com/AnswerDotAI/safepyrun), they need to declare which callables are trusted to perform otherwise-denied operations (filesystem writes, subprocesses, network access). safepyrun uses [fastaudit](https://github.com/AnswerDotAI/fastaudit) to deny those effects unless they happen inside a callable registered in the `__pytools__` registry. The [`allow()`](https://AnswerDotAI.github.io/pyskills/core.html#allow) function is how pyskills register their trusted callables.
160108

161-
You can allow individual functions, methods, all public methods of a
162-
type, or one specific callable instance:
109+
You can allow individual functions, methods, all public methods of a type, or one specific callable instance:
163110

164111
``` python
165112
# Allow specific methods on a type
@@ -175,27 +122,11 @@ allow(list_pyskills)
175122
allow(client.images.create_image)
176123
```
177124

178-
An object can also define `__allow__`, returning a list of items to
179-
register in its place;
180-
[`allow`](https://AnswerDotAI.github.io/pyskills/core.html#allow)
181-
recurses into the result, so a container (such as a fastspec client or
182-
op group) can register all its callables at once.
183-
184-
Skill modules typically call
185-
[`allow()`](https://AnswerDotAI.github.io/pyskills/core.html#allow) at
186-
module level, so permissions are registered automatically when the
187-
pyskill is imported. When `safepyrun`’s `RunPython` executes
188-
LLM-generated code, pure computation just runs; an operation with side
189-
effects is only permitted when it happens inside a registered callable.
190-
191-
The `pyskills.skill` module used in the examples above is itself
192-
registered as a pyskill entry point. It ships with pyskills both as a
193-
working sample and as a self-documenting pyskill that explains the
194-
system itself. Its docstring’s “Creating pyskills” section
195-
cross-references `pyskills.createskill`, a companion module (not
196-
registered as an entry point, so not shown in
197-
[`list_pyskills()`](https://AnswerDotAI.github.io/pyskills/core.html#list_pyskills))
198-
that documents how to build your own pyskills:
125+
An object can also define `__allow__`, returning a list of items to register in its place; [`allow`](https://AnswerDotAI.github.io/pyskills/core.html#allow) recurses into the result, so a container (such as a fastspec client or op group) can register all its callables at once.
126+
127+
Skill modules typically call [`allow()`](https://AnswerDotAI.github.io/pyskills/core.html#allow) at module level, so permissions are registered automatically when the pyskill is imported. When `safepyrun`’s `RunPython` executes LLM-generated code, pure computation just runs; an operation with side effects is only permitted when it happens inside a registered callable.
128+
129+
The `pyskills.skill` module used in the examples above is itself registered as a pyskill entry point. It ships with pyskills both as a working sample and as a self-documenting pyskill that explains the system itself. Its docstring’s “Creating pyskills” section cross-references `pyskills.createskill`, a companion module (not registered as an entry point, so not shown in [`list_pyskills()`](https://AnswerDotAI.github.io/pyskills/core.html#list_pyskills)) that documents how to build your own pyskills:
199130

200131
``` python
201132
from pyskills import createskill
@@ -218,18 +149,11 @@ print(doc(createskill)[:300])
218149

219150
## Creating pyskills
220151

221-
A pyskill is a standard Python module that registers itself via entry
222-
points so LLM hosts can discover and load it. Your module needs three
223-
things:
152+
A pyskill is a standard Python module that registers itself via entry points so LLM hosts can discover and load it. Your module needs three things:
224153

225-
- **A docstring**: the first paragraph is the short description shown
226-
during discovery via
227-
[`list_pyskills()`](https://AnswerDotAI.github.io/pyskills/core.html#list_pyskills);
228-
the rest is the detailed documentation the LLM reads after loading.
154+
- **A docstring**: the first paragraph is the short description shown during discovery via [`list_pyskills()`](https://AnswerDotAI.github.io/pyskills/core.html#list_pyskills); the rest is the detailed documentation the LLM reads after loading.
229155
- **`__all__`**: lists the symbols available to the LLM.
230-
- **[`allow()`](https://AnswerDotAI.github.io/pyskills/core.html#allow)
231-
calls**: declares what the LLM is permitted to call in sandboxed
232-
environments.
156+
- **[`allow()`](https://AnswerDotAI.github.io/pyskills/core.html#allow) calls**: declares what the LLM is permitted to call in sandboxed environments.
233157

234158
Here’s a minimal example:
235159

@@ -255,54 +179,32 @@ class MyClass:
255179
allow(my_func, {MyClass: ...})
256180
```
257181

258-
To register your module as a discoverable pyskill, add an entry point in
259-
your `pyproject.toml`:
182+
To register your module as a discoverable pyskill, add an entry point in your `pyproject.toml`:
260183

261184
``` toml
262185
[project.entry-points.pyskills]
263186
my_skill = "mypackage.mymodule"
264187
```
265188

266-
The key is an arbitrary name; the value is the module path. After
267-
installing the package,
268-
[`list_pyskills()`](https://AnswerDotAI.github.io/pyskills/core.html#list_pyskills)
269-
will include your pyskill automatically.
189+
The key is an arbitrary name; the value is the module path. After installing the package, [`list_pyskills()`](https://AnswerDotAI.github.io/pyskills/core.html#list_pyskills) will include your pyskill automatically.
270190

271-
For full details on creating pyskills, including allow policies for
272-
write-guarded operations, see `doc(createskill)` after importing it as
273-
shown above.
191+
For full details on creating pyskills, including allow policies for write-guarded operations, see `doc(createskill)` after importing it as shown above.
274192

275193
### Local pyskills without packaging
276194

277-
The entry point approach above requires installing a package. But
278-
sometimes you want to create pyskills quickly without a full package:
279-
personal utility pyskills, or pyskills shared across multiple projects
280-
that each use isolated environments (like
281-
[uv](https://docs.astral.sh/uv/) venvs).
282-
283-
pyskills provides an
284-
[XDG](https://specifications.freedesktop.org/basedir-spec/latest/)-based
285-
pyskills directory for this. When you first `import pyskills`, it
286-
creates a directory at your platform’s XDG data home (typically
287-
`~/.local/share/pyskills/`) and writes a `.pth` file into
288-
`site-packages`. This `.pth` file tells Python to add the pyskills
289-
directory to `sys.path` on startup, so any modules placed there are
290-
importable as standard Python modules without any special import
291-
machinery. This works across all Python environments on your system,
292-
even separate uv projects with isolated venvs.
293-
294-
You can check where this directory is (although you can use the
295-
functions below without needing to know):
195+
The entry point approach above requires installing a package. But sometimes you want to create pyskills quickly without a full package: personal utility pyskills, or pyskills shared across multiple projects that each use isolated environments (like [uv](https://docs.astral.sh/uv/) venvs).
196+
197+
pyskills provides an [XDG](https://specifications.freedesktop.org/basedir-spec/latest/)-based pyskills directory for this. When you first `import pyskills`, it creates a directory at your platform’s XDG data home (typically `~/.local/share/pyskills/`) and writes a `.pth` file into `site-packages`. This `.pth` file tells Python to add the pyskills directory to `sys.path` on startup, so any modules placed there are importable as standard Python modules without any special import machinery. This works across all Python environments on your system, even separate uv projects with isolated venvs.
198+
199+
You can check where this directory is (although you can use the functions below without needing to know):
296200

297201
``` python
298202
pyskills_dir()
299203
```
300204

301205
Path('/Users/jhoward/.local/share/pyskills')
302206

303-
You can drop pyskill modules directly into this directory, or use
304-
[`register_pyskill`](https://AnswerDotAI.github.io/pyskills/core.html#register_pyskill)
305-
to create one programmatically:
207+
You can drop pyskill modules directly into this directory, or use [`register_pyskill`](https://AnswerDotAI.github.io/pyskills/core.html#register_pyskill) to create one programmatically:
306208

307209
``` python
308210
register_pyskill('my_local.skill', docstr='A quick local pyskill.', code='''
@@ -318,14 +220,6 @@ allow(hello)
318220
''')
319221
```
320222

321-
This writes the module file into the XDG pyskills directory and creates
322-
a minimal entry point, so the pyskill immediately appears in
323-
[`list_pyskills()`](https://AnswerDotAI.github.io/pyskills/core.html#list_pyskills).
324-
325-
You can also manage pyskills with
326-
[`enable_pyskill`](https://AnswerDotAI.github.io/pyskills/core.html#enable_pyskill)
327-
and
328-
[`disable_pyskill`](https://AnswerDotAI.github.io/pyskills/core.html#disable_pyskill)
329-
to toggle their visibility without deleting files, or use
330-
[`disable_pyskill`](https://AnswerDotAI.github.io/pyskills/core.html#disable_pyskill)
331-
to remove one entirely.
223+
This writes the module file into the XDG pyskills directory and creates a minimal entry point, so the pyskill immediately appears in [`list_pyskills()`](https://AnswerDotAI.github.io/pyskills/core.html#list_pyskills).
224+
225+
You can also manage pyskills with [`enable_pyskill`](https://AnswerDotAI.github.io/pyskills/core.html#enable_pyskill) and [`disable_pyskill`](https://AnswerDotAI.github.io/pyskills/core.html#disable_pyskill) to toggle their visibility without deleting files, or use [`disable_pyskill`](https://AnswerDotAI.github.io/pyskills/core.html#disable_pyskill) to remove one entirely.

0 commit comments

Comments
 (0)