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.
Files changed (33) hide show
  1. skillager-0.1.0/LICENSE +21 -0
  2. skillager-0.1.0/PKG-INFO +166 -0
  3. skillager-0.1.0/README.md +147 -0
  4. skillager-0.1.0/build_backend/_skillager_build.py +153 -0
  5. skillager-0.1.0/docs/AGENT_CLI_GUIDE.md +148 -0
  6. skillager-0.1.0/docs/LIBRARY_AUTHORS.md +105 -0
  7. skillager-0.1.0/docs/SAFETY_MODEL.md +71 -0
  8. skillager-0.1.0/docs/SKILL_REPOSITORIES.md +85 -0
  9. skillager-0.1.0/docs/USER_GUIDE.md +110 -0
  10. skillager-0.1.0/examples/pandas-data-cleaning/SKILL.md +3 -0
  11. skillager-0.1.0/examples/pandas-data-cleaning/skillager.yaml +22 -0
  12. skillager-0.1.0/pyproject.toml +34 -0
  13. skillager-0.1.0/src/skillager/__init__.py +3 -0
  14. skillager-0.1.0/src/skillager/__main__.py +9 -0
  15. skillager-0.1.0/src/skillager/audience.py +133 -0
  16. skillager-0.1.0/src/skillager/cli.py +2639 -0
  17. skillager-0.1.0/src/skillager/collections.py +261 -0
  18. skillager-0.1.0/src/skillager/compatibility.py +158 -0
  19. skillager-0.1.0/src/skillager/discovery.py +233 -0
  20. skillager-0.1.0/src/skillager/index.py +91 -0
  21. skillager-0.1.0/src/skillager/lookback.py +310 -0
  22. skillager-0.1.0/src/skillager/materialize.py +769 -0
  23. skillager-0.1.0/src/skillager/onboard.py +22 -0
  24. skillager-0.1.0/src/skillager/paths.py +108 -0
  25. skillager-0.1.0/src/skillager/render.py +18 -0
  26. skillager-0.1.0/src/skillager/review.py +222 -0
  27. skillager-0.1.0/src/skillager/scan.py +292 -0
  28. skillager-0.1.0/src/skillager/schema.py +268 -0
  29. skillager-0.1.0/src/skillager/search.py +70 -0
  30. skillager-0.1.0/src/skillager/session.py +465 -0
  31. skillager-0.1.0/src/skillager/simple_yaml.py +34 -0
  32. skillager-0.1.0/src/skillager/trust.py +112 -0
  33. skillager-0.1.0/tests/test_skillager.py +1962 -0
@@ -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.
@@ -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
+ ```