skillager 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.
- skillager-0.1.0/LICENSE +21 -0
- skillager-0.1.0/PKG-INFO +166 -0
- skillager-0.1.0/README.md +147 -0
- skillager-0.1.0/build_backend/_skillager_build.py +153 -0
- skillager-0.1.0/docs/AGENT_CLI_GUIDE.md +148 -0
- skillager-0.1.0/docs/LIBRARY_AUTHORS.md +105 -0
- skillager-0.1.0/docs/SAFETY_MODEL.md +71 -0
- skillager-0.1.0/docs/SKILL_REPOSITORIES.md +85 -0
- skillager-0.1.0/docs/USER_GUIDE.md +110 -0
- skillager-0.1.0/examples/pandas-data-cleaning/SKILL.md +3 -0
- skillager-0.1.0/examples/pandas-data-cleaning/skillager.yaml +22 -0
- skillager-0.1.0/pyproject.toml +34 -0
- skillager-0.1.0/src/skillager/__init__.py +3 -0
- skillager-0.1.0/src/skillager/__main__.py +9 -0
- skillager-0.1.0/src/skillager/audience.py +133 -0
- skillager-0.1.0/src/skillager/cli.py +2639 -0
- skillager-0.1.0/src/skillager/collections.py +261 -0
- skillager-0.1.0/src/skillager/compatibility.py +158 -0
- skillager-0.1.0/src/skillager/discovery.py +233 -0
- skillager-0.1.0/src/skillager/index.py +91 -0
- skillager-0.1.0/src/skillager/lookback.py +310 -0
- skillager-0.1.0/src/skillager/materialize.py +769 -0
- skillager-0.1.0/src/skillager/onboard.py +22 -0
- skillager-0.1.0/src/skillager/paths.py +108 -0
- skillager-0.1.0/src/skillager/render.py +18 -0
- skillager-0.1.0/src/skillager/review.py +222 -0
- skillager-0.1.0/src/skillager/scan.py +292 -0
- skillager-0.1.0/src/skillager/schema.py +268 -0
- skillager-0.1.0/src/skillager/search.py +70 -0
- skillager-0.1.0/src/skillager/session.py +465 -0
- skillager-0.1.0/src/skillager/simple_yaml.py +34 -0
- skillager-0.1.0/src/skillager/trust.py +112 -0
- skillager-0.1.0/tests/test_skillager.py +1962 -0
skillager-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Skillager Contributors
|
|
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.
|
skillager-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: skillager
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Python environment skill registry and activation layer for coding agents.
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
7
|
+
Requires-Dist: rich>=15.0.0
|
|
8
|
+
Provides-Extra: test
|
|
9
|
+
License: MIT
|
|
10
|
+
Keywords: agents,skills,codex,claude,llm
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Topic :: Software Development
|
|
16
|
+
Author: Skillager Contributors
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# Skillager
|
|
21
|
+
|
|
22
|
+
Agent skills are useful. Loading all of them into every chat is not.
|
|
23
|
+
|
|
24
|
+
Skillager is a local CLI that lets projects, Python libraries, tools, and personal skill repos ship useful agent skills without turning every session into a wall of instructions. It discovers skills, scans them, asks for human approval, and gives agents a small, fast way to find the right skill only when the task needs it.
|
|
25
|
+
|
|
26
|
+
```text
|
|
27
|
+
install package -> discover skills -> approve safety -> agent uses approved metadata -> expose only what matters
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quickstart
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
uv tool install skillager
|
|
34
|
+
cd my-project
|
|
35
|
+
skillager status
|
|
36
|
+
skillager setup
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
No uv:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pipx install skillager
|
|
43
|
+
# or
|
|
44
|
+
python -m pip install --user skillager
|
|
45
|
+
python -m skillager setup
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`setup` is the approval gate. It discovers skills in the current project and environment, scans them, asks what audience you care about, and never trusts a skill unless you approve it.
|
|
49
|
+
|
|
50
|
+
After setup, restart Codex or Claude in the same directory and tell it what you are doing. Skillager installs a tiny project handoff so the agent knows to run `skillager status` once, use approved metadata, and avoid loading unapproved skill bodies.
|
|
51
|
+
|
|
52
|
+
## The Problem
|
|
53
|
+
|
|
54
|
+
Skills want to live everywhere:
|
|
55
|
+
|
|
56
|
+
- inside libraries, next to the APIs they explain
|
|
57
|
+
- inside projects, next to team workflows
|
|
58
|
+
- inside global agent directories
|
|
59
|
+
- inside personal or community skill repos
|
|
60
|
+
|
|
61
|
+
But agents should not see every skill all the time. Irrelevant skills burn context. Unreviewed skills are a safety risk. Similar skills compete. Package-installed skills are hard for agents to discover.
|
|
62
|
+
|
|
63
|
+
Skillager gives that ecosystem a local registry and approval gate.
|
|
64
|
+
|
|
65
|
+
## The Mental Model
|
|
66
|
+
|
|
67
|
+
Skillager keeps two decisions separate:
|
|
68
|
+
|
|
69
|
+
- **Approval:** the user reviewed a skill at its current content hash.
|
|
70
|
+
- **Exposure:** the skill is available to an agent in the current project.
|
|
71
|
+
|
|
72
|
+
An approved skill does not have to be loaded into the agent. It can stay in Skillager's index until a task needs it. When it should be available, Skillager writes one of three project-level representations:
|
|
73
|
+
|
|
74
|
+
- `native`: the full reviewed skill directory copied into the agent's project skill directory
|
|
75
|
+
- `stub`: a tiny native handle that activates the full skill through Skillager on demand
|
|
76
|
+
- `router`: one compact native skill for a curated tag like `gis`, `workflows`, or `release`
|
|
77
|
+
|
|
78
|
+
This keeps the default context small while still giving agents a deterministic path to approved skills.
|
|
79
|
+
|
|
80
|
+
## For Library Authors
|
|
81
|
+
|
|
82
|
+
If you maintain a Python library, Skillager gives you a way to ship agent-facing guidance with the package itself. Users can discover those skills after install, review them locally, and expose all, or just the ones relevant to their project.
|
|
83
|
+
|
|
84
|
+
Example:
|
|
85
|
+
|
|
86
|
+
```text
|
|
87
|
+
your_package/
|
|
88
|
+
__init__.py
|
|
89
|
+
.skills/
|
|
90
|
+
data-cleaning/
|
|
91
|
+
SKILL.md
|
|
92
|
+
skillager.yaml
|
|
93
|
+
references/
|
|
94
|
+
scripts/
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
When a user installs your package, Skillager can discover those skills without importing your library. The user still reviews and approves them before any agent can activate them.
|
|
98
|
+
|
|
99
|
+
This lets a library ship:
|
|
100
|
+
|
|
101
|
+
- user-facing skills for using the API well
|
|
102
|
+
- maintainer skills for internal development workflows
|
|
103
|
+
- domain skills that explain correctness rules and edge cases
|
|
104
|
+
- migration skills for version upgrades
|
|
105
|
+
|
|
106
|
+
See the [library author guide](docs/LIBRARY_AUTHORS.md) for metadata and packaging details.
|
|
107
|
+
|
|
108
|
+
## What Skillager Does
|
|
109
|
+
|
|
110
|
+
- Discovers skills from projects, `.venv`, installed packages, global agent dirs, and skill repos.
|
|
111
|
+
- Scans full skill directories before approval.
|
|
112
|
+
- Tracks trust by skill ID and content hash.
|
|
113
|
+
- Keeps search/list/show metadata safe and compact for agents.
|
|
114
|
+
- Materializes only reviewed skills into Codex or Claude native skill directories.
|
|
115
|
+
- Supports stubs and routers for large skill collections.
|
|
116
|
+
- Records compact local usage signals for lookback, without storing transcripts or skill bodies.
|
|
117
|
+
- Treats manually installed native skills as user-installed while still warning on risk.
|
|
118
|
+
|
|
119
|
+
## Safety Shape
|
|
120
|
+
|
|
121
|
+
The built-in scanner is deterministic and local. It looks for common agent-risk patterns like instruction override attempts, hidden prompt requests, secret exfiltration language, credential paths, download-and-execute flows, network callbacks involving secrets, unattended approval language, shell execution requests, hidden control characters, encoded blobs, and oversized content.
|
|
122
|
+
|
|
123
|
+
**It is not a proof of safety. It is a review aid.**
|
|
124
|
+
|
|
125
|
+
The hard rule is simpler: agents should not activate, materialize, or rely on skills that have not been approved by the user or project trust store.
|
|
126
|
+
|
|
127
|
+
## Skill Repos Without Context Flooding
|
|
128
|
+
|
|
129
|
+
Skill repositories are collections. Collections are inventory; tags are curation; project attachment is intent.
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
skillager collection add ~/skills/workflows --name workflows
|
|
133
|
+
skillager tag create workflows
|
|
134
|
+
skillager tag add workflows workflows/diffuse workflows/brainstorm
|
|
135
|
+
skillager project attach-tag workflows
|
|
136
|
+
skillager setup
|
|
137
|
+
skillager materialize --tag workflows --mode index --agent codex --scope project
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
The agent sees one router skill, not the whole repo. It activates a specific reviewed skill only when the task calls for it.
|
|
141
|
+
|
|
142
|
+
## Lookback
|
|
143
|
+
|
|
144
|
+
Skillager learns from usage as a local feedback loop. It records compact events such as search result IDs, activations, materialization status, and explicit feedback. It does not store chat transcripts or skill bodies.
|
|
145
|
+
|
|
146
|
+
The next `skillager status` can tell the agent that lookback is pending. Then the user can decide whether to promote a repeatedly useful skill, keep a broad skill route-only, block an unwanted one, or resolve overlapping skills.
|
|
147
|
+
|
|
148
|
+
## More Docs
|
|
149
|
+
|
|
150
|
+
- [User guide](docs/USER_GUIDE.md)
|
|
151
|
+
- [Agent CLI guide](docs/AGENT_CLI_GUIDE.md)
|
|
152
|
+
- [Skill repositories](docs/SKILL_REPOSITORIES.md)
|
|
153
|
+
- [Library author guide](docs/LIBRARY_AUTHORS.md)
|
|
154
|
+
- [Safety model](docs/SAFETY_MODEL.md)
|
|
155
|
+
- [Security policy](SECURITY.md)
|
|
156
|
+
|
|
157
|
+
External contributions are not being accepted yet while the 0.1 API and workflow settle.
|
|
158
|
+
|
|
159
|
+
## Development
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
uv run python -m unittest discover -s tests
|
|
163
|
+
uv build
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Skillager is released under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Skillager
|
|
2
|
+
|
|
3
|
+
Agent skills are useful. Loading all of them into every chat is not.
|
|
4
|
+
|
|
5
|
+
Skillager is a local CLI that lets projects, Python libraries, tools, and personal skill repos ship useful agent skills without turning every session into a wall of instructions. It discovers skills, scans them, asks for human approval, and gives agents a small, fast way to find the right skill only when the task needs it.
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
install package -> discover skills -> approve safety -> agent uses approved metadata -> expose only what matters
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quickstart
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
uv tool install skillager
|
|
15
|
+
cd my-project
|
|
16
|
+
skillager status
|
|
17
|
+
skillager setup
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
No uv:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pipx install skillager
|
|
24
|
+
# or
|
|
25
|
+
python -m pip install --user skillager
|
|
26
|
+
python -m skillager setup
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`setup` is the approval gate. It discovers skills in the current project and environment, scans them, asks what audience you care about, and never trusts a skill unless you approve it.
|
|
30
|
+
|
|
31
|
+
After setup, restart Codex or Claude in the same directory and tell it what you are doing. Skillager installs a tiny project handoff so the agent knows to run `skillager status` once, use approved metadata, and avoid loading unapproved skill bodies.
|
|
32
|
+
|
|
33
|
+
## The Problem
|
|
34
|
+
|
|
35
|
+
Skills want to live everywhere:
|
|
36
|
+
|
|
37
|
+
- inside libraries, next to the APIs they explain
|
|
38
|
+
- inside projects, next to team workflows
|
|
39
|
+
- inside global agent directories
|
|
40
|
+
- inside personal or community skill repos
|
|
41
|
+
|
|
42
|
+
But agents should not see every skill all the time. Irrelevant skills burn context. Unreviewed skills are a safety risk. Similar skills compete. Package-installed skills are hard for agents to discover.
|
|
43
|
+
|
|
44
|
+
Skillager gives that ecosystem a local registry and approval gate.
|
|
45
|
+
|
|
46
|
+
## The Mental Model
|
|
47
|
+
|
|
48
|
+
Skillager keeps two decisions separate:
|
|
49
|
+
|
|
50
|
+
- **Approval:** the user reviewed a skill at its current content hash.
|
|
51
|
+
- **Exposure:** the skill is available to an agent in the current project.
|
|
52
|
+
|
|
53
|
+
An approved skill does not have to be loaded into the agent. It can stay in Skillager's index until a task needs it. When it should be available, Skillager writes one of three project-level representations:
|
|
54
|
+
|
|
55
|
+
- `native`: the full reviewed skill directory copied into the agent's project skill directory
|
|
56
|
+
- `stub`: a tiny native handle that activates the full skill through Skillager on demand
|
|
57
|
+
- `router`: one compact native skill for a curated tag like `gis`, `workflows`, or `release`
|
|
58
|
+
|
|
59
|
+
This keeps the default context small while still giving agents a deterministic path to approved skills.
|
|
60
|
+
|
|
61
|
+
## For Library Authors
|
|
62
|
+
|
|
63
|
+
If you maintain a Python library, Skillager gives you a way to ship agent-facing guidance with the package itself. Users can discover those skills after install, review them locally, and expose all, or just the ones relevant to their project.
|
|
64
|
+
|
|
65
|
+
Example:
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
your_package/
|
|
69
|
+
__init__.py
|
|
70
|
+
.skills/
|
|
71
|
+
data-cleaning/
|
|
72
|
+
SKILL.md
|
|
73
|
+
skillager.yaml
|
|
74
|
+
references/
|
|
75
|
+
scripts/
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
When a user installs your package, Skillager can discover those skills without importing your library. The user still reviews and approves them before any agent can activate them.
|
|
79
|
+
|
|
80
|
+
This lets a library ship:
|
|
81
|
+
|
|
82
|
+
- user-facing skills for using the API well
|
|
83
|
+
- maintainer skills for internal development workflows
|
|
84
|
+
- domain skills that explain correctness rules and edge cases
|
|
85
|
+
- migration skills for version upgrades
|
|
86
|
+
|
|
87
|
+
See the [library author guide](docs/LIBRARY_AUTHORS.md) for metadata and packaging details.
|
|
88
|
+
|
|
89
|
+
## What Skillager Does
|
|
90
|
+
|
|
91
|
+
- Discovers skills from projects, `.venv`, installed packages, global agent dirs, and skill repos.
|
|
92
|
+
- Scans full skill directories before approval.
|
|
93
|
+
- Tracks trust by skill ID and content hash.
|
|
94
|
+
- Keeps search/list/show metadata safe and compact for agents.
|
|
95
|
+
- Materializes only reviewed skills into Codex or Claude native skill directories.
|
|
96
|
+
- Supports stubs and routers for large skill collections.
|
|
97
|
+
- Records compact local usage signals for lookback, without storing transcripts or skill bodies.
|
|
98
|
+
- Treats manually installed native skills as user-installed while still warning on risk.
|
|
99
|
+
|
|
100
|
+
## Safety Shape
|
|
101
|
+
|
|
102
|
+
The built-in scanner is deterministic and local. It looks for common agent-risk patterns like instruction override attempts, hidden prompt requests, secret exfiltration language, credential paths, download-and-execute flows, network callbacks involving secrets, unattended approval language, shell execution requests, hidden control characters, encoded blobs, and oversized content.
|
|
103
|
+
|
|
104
|
+
**It is not a proof of safety. It is a review aid.**
|
|
105
|
+
|
|
106
|
+
The hard rule is simpler: agents should not activate, materialize, or rely on skills that have not been approved by the user or project trust store.
|
|
107
|
+
|
|
108
|
+
## Skill Repos Without Context Flooding
|
|
109
|
+
|
|
110
|
+
Skill repositories are collections. Collections are inventory; tags are curation; project attachment is intent.
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
skillager collection add ~/skills/workflows --name workflows
|
|
114
|
+
skillager tag create workflows
|
|
115
|
+
skillager tag add workflows workflows/diffuse workflows/brainstorm
|
|
116
|
+
skillager project attach-tag workflows
|
|
117
|
+
skillager setup
|
|
118
|
+
skillager materialize --tag workflows --mode index --agent codex --scope project
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The agent sees one router skill, not the whole repo. It activates a specific reviewed skill only when the task calls for it.
|
|
122
|
+
|
|
123
|
+
## Lookback
|
|
124
|
+
|
|
125
|
+
Skillager learns from usage as a local feedback loop. It records compact events such as search result IDs, activations, materialization status, and explicit feedback. It does not store chat transcripts or skill bodies.
|
|
126
|
+
|
|
127
|
+
The next `skillager status` can tell the agent that lookback is pending. Then the user can decide whether to promote a repeatedly useful skill, keep a broad skill route-only, block an unwanted one, or resolve overlapping skills.
|
|
128
|
+
|
|
129
|
+
## More Docs
|
|
130
|
+
|
|
131
|
+
- [User guide](docs/USER_GUIDE.md)
|
|
132
|
+
- [Agent CLI guide](docs/AGENT_CLI_GUIDE.md)
|
|
133
|
+
- [Skill repositories](docs/SKILL_REPOSITORIES.md)
|
|
134
|
+
- [Library author guide](docs/LIBRARY_AUTHORS.md)
|
|
135
|
+
- [Safety model](docs/SAFETY_MODEL.md)
|
|
136
|
+
- [Security policy](SECURITY.md)
|
|
137
|
+
|
|
138
|
+
External contributions are not being accepted yet while the 0.1 API and workflow settle.
|
|
139
|
+
|
|
140
|
+
## Development
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
uv run python -m unittest discover -s tests
|
|
144
|
+
uv build
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Skillager is released under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import base64
|
|
4
|
+
import csv
|
|
5
|
+
import hashlib
|
|
6
|
+
import io
|
|
7
|
+
import tarfile
|
|
8
|
+
import zipfile
|
|
9
|
+
from email.message import Message
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
NAME = "skillager"
|
|
13
|
+
VERSION = "0.1.0"
|
|
14
|
+
DIST = f"{NAME}-{VERSION}"
|
|
15
|
+
DIST_INFO = f"{NAME}-{VERSION}.dist-info"
|
|
16
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
|
|
20
|
+
wheel_name = f"{NAME}-{VERSION}-py3-none-any.whl"
|
|
21
|
+
wheel_path = Path(wheel_directory) / wheel_name
|
|
22
|
+
records: list[tuple[str, bytes]] = []
|
|
23
|
+
with zipfile.ZipFile(wheel_path, "w", compression=zipfile.ZIP_DEFLATED) as zf:
|
|
24
|
+
for path in sorted((ROOT / "src" / NAME).rglob("*.py")):
|
|
25
|
+
arcname = f"{NAME}/{path.relative_to(ROOT / 'src' / NAME).as_posix()}"
|
|
26
|
+
data = path.read_bytes()
|
|
27
|
+
zf.writestr(arcname, data)
|
|
28
|
+
records.append((arcname, data))
|
|
29
|
+
metadata = _metadata().encode()
|
|
30
|
+
wheel = "Wheel-Version: 1.0\nGenerator: skillager-build\nRoot-Is-Purelib: true\nTag: py3-none-any\n".encode()
|
|
31
|
+
entry_points = "[console_scripts]\nskillager = skillager.cli:main\n".encode()
|
|
32
|
+
license_data = (ROOT / "LICENSE").read_bytes()
|
|
33
|
+
for arcname, data in (
|
|
34
|
+
(f"{DIST_INFO}/METADATA", metadata),
|
|
35
|
+
(f"{DIST_INFO}/WHEEL", wheel),
|
|
36
|
+
(f"{DIST_INFO}/entry_points.txt", entry_points),
|
|
37
|
+
(f"{DIST_INFO}/LICENSE", license_data),
|
|
38
|
+
):
|
|
39
|
+
zf.writestr(arcname, data)
|
|
40
|
+
records.append((arcname, data))
|
|
41
|
+
record_path = f"{DIST_INFO}/RECORD"
|
|
42
|
+
zf.writestr(record_path, _record(records, record_path))
|
|
43
|
+
return wheel_name
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def build_editable(wheel_directory, config_settings=None, metadata_directory=None):
|
|
47
|
+
wheel_name = f"{NAME}-{VERSION}-py3-none-any.whl"
|
|
48
|
+
wheel_path = Path(wheel_directory) / wheel_name
|
|
49
|
+
records: list[tuple[str, bytes]] = []
|
|
50
|
+
with zipfile.ZipFile(wheel_path, "w", compression=zipfile.ZIP_DEFLATED) as zf:
|
|
51
|
+
pth = str((ROOT / "src").resolve()) + "\n"
|
|
52
|
+
license_data = (ROOT / "LICENSE").read_bytes()
|
|
53
|
+
for arcname, data in (
|
|
54
|
+
(f"{NAME}.pth", pth.encode()),
|
|
55
|
+
(f"{DIST_INFO}/METADATA", _metadata().encode()),
|
|
56
|
+
(f"{DIST_INFO}/WHEEL", "Wheel-Version: 1.0\nGenerator: skillager-build\nRoot-Is-Purelib: true\nTag: py3-none-any\n".encode()),
|
|
57
|
+
(f"{DIST_INFO}/entry_points.txt", "[console_scripts]\nskillager = skillager.cli:main\n".encode()),
|
|
58
|
+
(f"{DIST_INFO}/LICENSE", license_data),
|
|
59
|
+
):
|
|
60
|
+
zf.writestr(arcname, data)
|
|
61
|
+
records.append((arcname, data))
|
|
62
|
+
record_path = f"{DIST_INFO}/RECORD"
|
|
63
|
+
zf.writestr(record_path, _record(records, record_path))
|
|
64
|
+
return wheel_name
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def build_sdist(sdist_directory, config_settings=None):
|
|
68
|
+
sdist_name = f"{DIST}.tar.gz"
|
|
69
|
+
sdist_path = Path(sdist_directory) / sdist_name
|
|
70
|
+
include_roots = ["build_backend", "docs", "examples", "src", "tests"]
|
|
71
|
+
include_files = ["pyproject.toml", "README.md", "LICENSE"]
|
|
72
|
+
with tarfile.open(sdist_path, "w:gz", format=tarfile.PAX_FORMAT) as tf:
|
|
73
|
+
for filename in include_files:
|
|
74
|
+
path = ROOT / filename
|
|
75
|
+
if path.exists():
|
|
76
|
+
tf.add(path, arcname=f"{DIST}/{filename}")
|
|
77
|
+
for root_name in include_roots:
|
|
78
|
+
root = ROOT / root_name
|
|
79
|
+
if root.exists():
|
|
80
|
+
for path in sorted(item for item in root.rglob("*") if item.is_file() and not _excluded(item)):
|
|
81
|
+
tf.add(path, arcname=f"{DIST}/{path.relative_to(ROOT).as_posix()}")
|
|
82
|
+
pkg_info = _metadata().encode()
|
|
83
|
+
info = tarfile.TarInfo(f"{DIST}/PKG-INFO")
|
|
84
|
+
info.size = len(pkg_info)
|
|
85
|
+
tf.addfile(info, io.BytesIO(pkg_info))
|
|
86
|
+
return sdist_name
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None):
|
|
90
|
+
dist_info = Path(metadata_directory) / DIST_INFO
|
|
91
|
+
dist_info.mkdir(parents=True, exist_ok=True)
|
|
92
|
+
(dist_info / "METADATA").write_text(_metadata(), encoding="utf-8")
|
|
93
|
+
(dist_info / "WHEEL").write_text("Wheel-Version: 1.0\nGenerator: skillager-build\nRoot-Is-Purelib: true\nTag: py3-none-any\n", encoding="utf-8")
|
|
94
|
+
(dist_info / "entry_points.txt").write_text("[console_scripts]\nskillager = skillager.cli:main\n", encoding="utf-8")
|
|
95
|
+
return DIST_INFO
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def get_requires_for_build_wheel(config_settings=None):
|
|
99
|
+
return []
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def get_requires_for_build_editable(config_settings=None):
|
|
103
|
+
return []
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def get_requires_for_build_sdist(config_settings=None):
|
|
107
|
+
return []
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _metadata() -> str:
|
|
111
|
+
message = Message()
|
|
112
|
+
message["Metadata-Version"] = "2.1"
|
|
113
|
+
message["Name"] = NAME
|
|
114
|
+
message["Version"] = VERSION
|
|
115
|
+
message["Summary"] = "A Python environment skill registry and activation layer for coding agents."
|
|
116
|
+
message["Requires-Python"] = ">=3.11"
|
|
117
|
+
message["Requires-Dist"] = "pyyaml>=6.0.3"
|
|
118
|
+
message["Requires-Dist"] = "rich>=15.0.0"
|
|
119
|
+
message["Provides-Extra"] = "test"
|
|
120
|
+
message["License"] = "MIT"
|
|
121
|
+
message["Keywords"] = "agents,skills,codex,claude,llm"
|
|
122
|
+
for classifier in (
|
|
123
|
+
"Development Status :: 3 - Alpha",
|
|
124
|
+
"Environment :: Console",
|
|
125
|
+
"License :: OSI Approved :: MIT License",
|
|
126
|
+
"Programming Language :: Python :: 3",
|
|
127
|
+
"Topic :: Software Development",
|
|
128
|
+
):
|
|
129
|
+
message["Classifier"] = classifier
|
|
130
|
+
message["Author"] = "Skillager Contributors"
|
|
131
|
+
message["Description-Content-Type"] = "text/markdown"
|
|
132
|
+
body = (ROOT / "README.md").read_text(encoding="utf-8")
|
|
133
|
+
return message.as_string() + "\n" + body
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _excluded(path: Path) -> bool:
|
|
137
|
+
if any(part in {".git", ".venv", ".skillager", ".codex", ".claude", ".agents"} for part in path.parts):
|
|
138
|
+
return True
|
|
139
|
+
if any(part.endswith(".egg-info") for part in path.parts):
|
|
140
|
+
return True
|
|
141
|
+
if any(part == "__pycache__" for part in path.parts):
|
|
142
|
+
return True
|
|
143
|
+
return path.suffix in {".pyc", ".pyo"}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _record(records: list[tuple[str, bytes]], record_path: str) -> str:
|
|
147
|
+
output = io.StringIO()
|
|
148
|
+
writer = csv.writer(output, lineterminator="\n")
|
|
149
|
+
for arcname, data in records:
|
|
150
|
+
digest = base64.urlsafe_b64encode(hashlib.sha256(data).digest()).decode().rstrip("=")
|
|
151
|
+
writer.writerow([arcname, f"sha256={digest}", str(len(data))])
|
|
152
|
+
writer.writerow([record_path, "", ""])
|
|
153
|
+
return output.getvalue()
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Agent CLI Guide
|
|
2
|
+
|
|
3
|
+
This document is for coding agents reading a project that uses Skillager.
|
|
4
|
+
|
|
5
|
+
Projects may expose a first-party `skillager-working` skill. Treat it as the bootstrap workflow for Skillager-managed projects: check status, respect the user approval gate, ask what the user plans to do, then expose only the narrow router or native skills that fit the session.
|
|
6
|
+
|
|
7
|
+
## Rules
|
|
8
|
+
|
|
9
|
+
- Start with `skillager status` once per session.
|
|
10
|
+
- If status reports `lookback_pending`, ask the user whether to review `skillager lookback` before starting. Do not apply recommendations without user approval.
|
|
11
|
+
- Do not run `skillager setup`, `review`, `trust`, or `block` unless the user asked for setup or approval changes.
|
|
12
|
+
- Do not run `skillager materialize` until you have asked what the user plans to do and can justify the narrow router/native exposure.
|
|
13
|
+
- Do not run `skillager activate` or `skillager show --content` for a skill that is not already reviewed, trusted, or pinned.
|
|
14
|
+
- Do not use `--force` unless the user explicitly instructs you to override Skillager's gate.
|
|
15
|
+
- Prefer `--json` when parsing output.
|
|
16
|
+
- Do not search Skillager on every user message. Search only when the task/domain changes, specialized help is likely useful, you are unsure how to proceed and an approved skill may contain the right workflow, status changed, or the user asks about skills.
|
|
17
|
+
- Once you choose a native skill or router path for a task, keep using it until the task changes.
|
|
18
|
+
|
|
19
|
+
## Safe Metadata Commands
|
|
20
|
+
|
|
21
|
+
These commands do not expose full skill bodies. In a project, normal `list`, `search`, and `show` use effective project inventory: project skills, package/environment skills, and attached collection-tag skills with project-local trust state. `list` hides global native skills by default; pass `--include-global` only when the user is asking about global inventory.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
skillager status --json
|
|
25
|
+
skillager list --json
|
|
26
|
+
skillager list --no-packages --json
|
|
27
|
+
skillager search "<query>" --json
|
|
28
|
+
skillager show <skill-id> --json
|
|
29
|
+
skillager review --summary --json
|
|
30
|
+
skillager search "<user goal>" --trusted-only --json
|
|
31
|
+
skillager tag show <tag> --json
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Use `collection search/show` only for catalog management or debugging. For project work, prefer the normal project-aware commands above.
|
|
35
|
+
`status --json` and `search --json` are intentionally compact for agent use. Use `--full-json` only when debugging Skillager metadata itself.
|
|
36
|
+
`status --json` includes `lookback_pending` and `lookback_summary`; these are next-session hints only. Ask the user before running the full lookback or changing exposure.
|
|
37
|
+
|
|
38
|
+
Project-aware JSON includes:
|
|
39
|
+
|
|
40
|
+
- `availability`: where the skill comes from in this project context.
|
|
41
|
+
- `trust`: effective project-local trust state.
|
|
42
|
+
- `trust_reason`: why Skillager treats a skill as trusted, when relevant. `user-installed` means the user placed it directly in an agent-native skill directory.
|
|
43
|
+
- `exposure`: `hidden`, `native`, `stub`, `router`, or `multiple`.
|
|
44
|
+
- `materialized_targets`: agent/scope/path/status records for native or router exposure.
|
|
45
|
+
- `compatibility`: negative-only compatibility metadata. Missing metadata means "assume usable." `problem` is set only when the skill explicitly excludes the requested `--agent`.
|
|
46
|
+
|
|
47
|
+
Do not treat `trust_reason=user-installed` as suspicious by itself. The user installed that native skill. Still respect scanner findings and high-risk warnings.
|
|
48
|
+
|
|
49
|
+
## Compatibility
|
|
50
|
+
|
|
51
|
+
Skillager defaults to compatibility. Do not hide a skill just because it was written in another agent's style.
|
|
52
|
+
|
|
53
|
+
Use compatibility metadata this way:
|
|
54
|
+
|
|
55
|
+
- If `skillager search --agent codex --json` reports `compatibility.problem`, do not activate or materialize that skill for Codex unless the user explicitly approves `--allow-incompatible`.
|
|
56
|
+
- If `activation_warnings` are present without `problem`, the skill is still available. Treat the warning as adaptation guidance.
|
|
57
|
+
- Prefer `--compatible-only --agent <agent>` only when the user asks for skills that can be used without adaptation.
|
|
58
|
+
- Do not infer incompatibility from advisory warnings alone.
|
|
59
|
+
|
|
60
|
+
Activation and native/stub materialization refuse explicit incompatibility by default:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
skillager activate <skill-id> --agent codex
|
|
64
|
+
skillager materialize <skill-id> --agent codex
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The explicit override is:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
skillager activate <skill-id> --agent codex --allow-incompatible
|
|
71
|
+
skillager materialize <skill-id> --agent codex --allow-incompatible
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Agentic Setup Flow
|
|
75
|
+
|
|
76
|
+
After the user approves skills, setup installs or refreshes the `skillager-working` bootstrap skill for the chosen agent. The user may also have materialized a small always-relevant native set during setup. In the next agent session, ask what the user plans to do in the repo. Then use approved metadata to decide whether to expose:
|
|
77
|
+
|
|
78
|
+
- a narrow native skill for a specific recurring workflow
|
|
79
|
+
- a stub for an approved command the user wants easy access to by name
|
|
80
|
+
- a router skill for a broad attached collection
|
|
81
|
+
- nothing, if the existing project handoff is enough
|
|
82
|
+
|
|
83
|
+
Prefer router materialization for broad skill repositories:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
skillager materialize --tag workflows --mode index --agent codex --scope project
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Prefer native materialization for narrow, high-signal project skills:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
skillager materialize project/gis-domain --agent codex --scope project
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Prefer stub materialization for approved commands the user wants discoverable without loading full instructions:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
skillager materialize personal/deploy-preview --mode stub --agent codex --scope project
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
When a stub tells you to activate a skill, use the exact guarded command from the stub:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
skillager activate <skill-id> --from-stub <stub-slug>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Do not materialize every approved skill just because it is approved. Approval means a skill is allowed to be considered; exposure should still be scoped to the user's stated work.
|
|
108
|
+
|
|
109
|
+
At lookback time, prefer aggregate recommendations over single-session instinct. `skillager lookback` considers the recent session window plus active sessions and reports the sessions behind each recommendation. Do not promote or demote shared project-native exposure based on one isolated session unless the user explicitly asks.
|
|
110
|
+
|
|
111
|
+
Lookback may include `observed_overlaps`. Treat these as behavioral hints, not decisions. They mean skills repeatedly co-occurred in searches or sessions. Ask the user whether to pin a winner, keep the skills route-only, stub commands, block old skills, or ignore the overlap.
|
|
112
|
+
|
|
113
|
+
Search records compact local telemetry for lookback by default: query hash, short query preview, top result IDs, and filters. It does not record skill bodies, chat transcripts, or command output. Use `skillager search ... --no-session-record` for one-off searches that should not affect lookback.
|
|
114
|
+
|
|
115
|
+
## User-Gated Commands
|
|
116
|
+
|
|
117
|
+
These commands change approval state, write skill files, or expose full instructions:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
skillager setup
|
|
121
|
+
skillager setup --source collection --yolo
|
|
122
|
+
skillager review <skill-id> --trust-selected reviewed
|
|
123
|
+
skillager trust <skill-id>
|
|
124
|
+
skillager block <skill-id>
|
|
125
|
+
skillager materialize --agent codex --scope project
|
|
126
|
+
skillager activate <skill-id>
|
|
127
|
+
skillager show <skill-id> --content
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Router Skills
|
|
131
|
+
|
|
132
|
+
A Skillager router skill is a compact project skill that lists reviewed skill IDs and author summaries. It does not contain the hidden skill bodies.
|
|
133
|
+
|
|
134
|
+
When a router tells you to activate a skill, use:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
skillager activate <skill-id> --from-router skillager-<tag>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
This command refuses skills outside the attached tag, blocked skills, and unreviewed skills.
|
|
141
|
+
|
|
142
|
+
## If Status Reports New Skills
|
|
143
|
+
|
|
144
|
+
Tell the user exactly what happened and ask them to run setup:
|
|
145
|
+
|
|
146
|
+
```text
|
|
147
|
+
Skillager reports new or changed skills. Please run `skillager setup` from this project directory before I use Skillager-managed skills.
|
|
148
|
+
```
|