Skip to content

Commit cf393aa

Browse files
authored
docs: refresh Python workflow guidance (#3)
1 parent 09e57d4 commit cf393aa

10 files changed

Lines changed: 92 additions & 40 deletions

File tree

README.md

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ agentskills.io-compatible.
2626

2727
Suppose you ask your agent:
2828

29-
> Create a Python 3.10+ command-line project named `invoice-checker`. Use a
29+
> Create a Python 3.11+ command-line project named `invoice-checker`. Use a
3030
> `src/` layout, add tests and GitHub Actions, and leave it ready to build.
3131
3232
The workflow guides the agent to:
@@ -83,25 +83,27 @@ Make the skill discoverable by your agent.
8383
<details>
8484
<summary><b>Hermes Agent</b></summary>
8585

86-
**Recommended for development — clone the repo and add to `external_dirs`:**
86+
**Install directly from GitHub:**
87+
```bash
88+
hermes skills install CodeSigils/python-project-workflow-skill/skills/python-project-workflow
89+
```
90+
91+
**For development, clone the repo and add its `skills/` directory to `external_dirs`:**
8792
```yaml
8893
skills:
8994
external_dirs:
9095
- /path/to/python-project-workflow/skills
9196
```
9297
Every commit is immediately reflected without reinstalling.
9398
94-
The repository is not currently indexed in the Hermes hub, so no hub-install
95-
command is advertised. Clone plus `external_dirs` is the verified Hermes path
96-
until registration.
97-
9899
*Other agents: see sections below for their native setup commands.*
99100
</details>
100101
101102
<details>
102103
<summary><b>Claude Code</b></summary>
103104
104105
```bash
106+
mkdir -p ~/.claude/skills
105107
cp -r skills/python-project-workflow ~/.claude/skills/
106108
```
107109
</details>
@@ -110,6 +112,7 @@ cp -r skills/python-project-workflow ~/.claude/skills/
110112
<summary><b>Codex</b></summary>
111113

112114
```bash
115+
mkdir -p ~/.agents/skills
113116
cp -r skills/python-project-workflow ~/.agents/skills/
114117
```
115118
</details>
@@ -118,6 +121,7 @@ cp -r skills/python-project-workflow ~/.agents/skills/
118121
<summary><b>Gemini CLI / .agents/ path</b></summary>
119122

120123
```bash
124+
mkdir -p .agents/skills
121125
cp -r skills/python-project-workflow .agents/skills/
122126
```
123127
</details>
@@ -126,6 +130,7 @@ cp -r skills/python-project-workflow .agents/skills/
126130
<summary><b>OpenCode</b></summary>
127131

128132
```bash
133+
mkdir -p .opencode/skills
129134
cp -r skills/python-project-workflow .opencode/skills/
130135
```
131136
</details>
@@ -233,7 +238,7 @@ python-project-workflow/
233238
│ ├── sync-payload.sh # Synchronizes or checks the runtime payload mirror
234239
│ ├── test-validate-ci.py # Regression tests for CI policy enforcement
235240
│ ├── test-sync-payload.py # Regression tests for payload drift behavior
236-
│ ├── validate-ci.py # Enforces CI routing and toolchain policy
241+
│ ├── validate-ci.py # Enforces CI routing, required gates, toolchain policy, and action pins
237242
│ ├── validate.py # Checks skill structure, metadata, and references
238243
│ └── verify-urls.py # Checks documented external links on a schedule
239244
└── skills/

SECURITY.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ metadata, and the canonical-to-payload mirror process. These components must
2828
preserve the declared shipping boundary, avoid exposing credentials, and prevent
2929
unreviewed content from entering the runtime payload.
3030

31-
CI validates payload structure, canonical-reference parity, portable
32-
instructions, security directives, and the absence of known unsafe probes. A
31+
CI validates payload structure, regular-file-only canonical and runtime entries,
32+
canonical-reference parity, portable instructions, security directives, and the
33+
absence of known unsafe probes. A
3334
passing validator is evidence for these defined checks, not a claim that the
3435
repository or generated projects are free of vulnerabilities.
3536

@@ -64,4 +65,4 @@ summarizes the trust boundary; it does not replace those runtime instructions.
6465
from heuristic or filename checks.
6566
- [x] The shipped payload contains no destructive reset, forced-push, or secret-file dumping commands.
6667

67-
Last reviewed: 2026-07-16.
68+
Last reviewed: 2026-07-17.

references/drift-classes.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ difference is critical because they require fundamentally different fixes.
1010

1111
| Class | Name | What Drifts | Root Cause | Detection | Fix |
1212
|-------|------|-------------|------------|-----------|-----|
13-
| **A** | **Payload drift** | Mirrored payload references differ from their canonical root sources, or an undeclared payload file appears | Human edited a canonical reference but forgot to run sync, edited a mirrored reference directly, or left an orphan | Payload sync check (`sync-payload.sh --ci`) fails | Run `bash scripts/sync-payload.sh` to synchronize declared mirrors and remove orphans |
13+
| **A** | **Payload drift** | Mirrored payload references differ from their canonical root sources, an undeclared payload entry appears, or a canonical/runtime entry is a symlink instead of a regular file | Human edited a canonical reference but forgot to run sync, edited a mirrored reference directly, left an orphan, or introduced a link across the shipping boundary | Payload sync check (`sync-payload.sh --ci`) fails | Run `bash scripts/sync-payload.sh` to synchronize declared mirrors and remove payload-side links/orphans; replace canonical source links manually |
1414
| **B** | **Mirror staleness** | Installed copy predates a restructuring | Agent loads a static copy that does not auto-update | `diff -rq <repo>/skills/<name>/ <installed>/skills/<name>/` shows mismatch | Re-install from source or use a client-supported live source directory |
1515

1616
---
@@ -41,12 +41,13 @@ an explicitly allowed authored-in-place file. No scripts currently ship.
4141
3. Added a new source type without updating the manifest or sync policy
4242
4. Renamed/deleted a source file but the old copy remains in payload
4343
5. CI payload sync check was disabled or bypassed
44+
6. Replaced a canonical source or payload entry with a symlink
4445

4546
### Detection
4647

4748
- **CI gate**: `bash scripts/sync-payload.sh --ci` exits 1 on any drift
4849
- **Local check**: Run the same command locally before committing
49-
- **Manifest validation**: the script verifies declared sources and flags payload orphans
50+
- **Manifest validation**: the script requires regular canonical source files and flags payload symlinks and orphans
5051

5152
### Remediation
5253

@@ -147,6 +148,7 @@ prevention for mirror staleness.**
147148
| Committing a mirrored reference change without its root source | Creates reference drift | Keep canonical and mirrored reference content identical through the sync command |
148149
| Installing skill once and never updating | Mirror staleness guaranteed | Use a live source directory for development; schedule re-installs for production |
149150
| Linking individual files instead of the skill directory | Fragile; breaks on restructure | Link or configure the complete `skills/` directory when the client supports it |
151+
| Committing symlinks inside the canonical or runtime payload trees | Can escape the shipping boundary or become broken after copying only the payload | Keep every shipped and canonical reference entry as a regular file; use client-level directory configuration only outside the payload |
150152

151153
---
152154

references/lint-format-typing-testing.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ When testing cross-platform compatibility:
5050

5151
- Use `nox` or `tox` with matrices covering different Python versions and operating systems
5252
- GitHub Actions example:
53-
`strategy.matrix: {os: [ubuntu-latest, windows-latest, macos-latest], python-version: [\"3.10\", \"3.11\", \"3.12\", \"3.13\", \"3.14\"]}`
53+
`strategy.matrix: {os: [ubuntu-latest, windows-latest, macos-latest], python-version: [\"3.11\", \"3.12\", \"3.13\", \"3.14\"]}`
5454
- Test console scripts/installation on all target platforms
5555
- Consider using `cibuildwheel` for building wheels across platforms
5656
- Test path handling with `pathlib` to avoid platform-specific issues
@@ -112,7 +112,8 @@ positives or negatives.
112112

113113
## Special Cases
114114

115-
- **Jupyter notebooks**: use `nbqa ruff check notebook.ipynb`. Keep core logic in `.py` files.
115+
- **Jupyter notebooks**: Ruff supports notebooks directly; use `ruff check notebook.ipynb` and
116+
`ruff format --check notebook.ipynb`. Keep core logic in `.py` files.
116117
- **Cython**: MyPy may need config to understand `.pyx` files; invoke build system before type checking.
117118
- **Generated files**: exclude from lint/format/type checking via `.ruffignore` or tool config. Document ownership.
118119

references/pyproject-template.md

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
This file provides a minimal, modern `pyproject.toml` using PEP 621 metadata. Adjust the values to fit your project.
44

5-
> **Freshness:** Packaging metadata and Python EOL guidance were reviewed on 2026-07-16.
5+
> **Freshness:** Packaging metadata and Python EOL guidance were reviewed on 2026-07-17.
66
> Verify against official docs before using in production.
77
> See [ruff docs](https://docs.astral.sh/ruff/), [mypy docs](https://mypy.readthedocs.io/),
88
> [pytest docs](https://docs.pytest.org/), [uv docs](https://docs.astral.sh/uv/) for current versions.
@@ -23,7 +23,7 @@ name = "your-package"
2323
version = "0.1.0"
2424
description = "A short description of your package."
2525
readme = "README.md"
26-
requires-python = ">=3.10" # or >=3.12 for controlled applications; preserve ecosystem floors
26+
requires-python = ">=3.11" # or >=3.12 for controlled applications; preserve ecosystem floors
2727
authors = [
2828
{name = "Your Name", email = "you@example.com"}
2929
]
@@ -78,7 +78,7 @@ This tells setuptools to look for packages under the `src/` directory.
7878

7979
```toml
8080
[tool.ruff]
81-
target-version = "py310" # Align with requires-python
81+
target-version = "py311" # Align with requires-python
8282
line-length = 88
8383

8484
[tool.ruff.lint]
@@ -94,7 +94,7 @@ quote-style = "double"
9494

9595
```toml
9696
[tool.mypy]
97-
python_version = "3.10" # Target the minimum version in requires-python
97+
python_version = "3.11" # Target the minimum version in requires-python
9898
warn_return_any = true
9999
warn_unused_configs = true
100100
disallow_untyped_defs = true
@@ -134,23 +134,30 @@ When authoring cross-platform Python packages:
134134

135135
- If you control the deployment environment (e.g., internal tool, web service), consider `requires-python = ">=3.12"` to
136136
use the latest features.
137-
- If deploying to older LTS systems (e.g., Ubuntu 22.04 with Python 3.10), use `>=3.10`.
137+
- If deployment must use a distribution's system Python, set the floor to the oldest supported image you actually
138+
deploy. For example, Ubuntu 26.04 LTS currently defaults to Python 3.14; older supported images may require a lower
139+
floor.
138140

139141
### For Libraries
140142

141-
- Aim for broad compatibility: `>=3.10` is the current default when no ecosystem constraint says otherwise.
143+
- Aim for broad compatibility without starting on a near-EOL interpreter: `>=3.11` is the current default when no
144+
ecosystem constraint says otherwise.
145+
- For new projects, do not select Python 3.10 by default: it is in source-only security maintenance and reaches
146+
end-of-life in October 2026. Use `>=3.11` or a newer floor that fits the deployment environment.
147+
- For existing projects that still declare 3.10, preserve the contract unless a compatibility-breaking migration is in
148+
scope. Document the constraint and plan a tested migration before changing `requires-python` or the CI matrix.
142149
- For new projects, do not select Python 3.8: it reached end-of-life in October 2024 and no longer receives security
143-
fixes. Use `>=3.10` or a newer floor that fits the deployment environment.
150+
fixes. Use `>=3.11` or a newer floor that fits the deployment environment.
144151
- For existing projects that still declare 3.8, preserve the contract unless a compatibility-breaking migration is in
145152
scope. Document the legacy constraint, warn that 3.8 is unsupported upstream, and plan a tested migration before
146153
changing `requires-python` or the CI matrix.
147-
- Review this floor as Python 3.10 approaches end-of-life in October 2026.
148154

149155
### Dependency Floor
150156

151157
- When choosing a dependency version, check its `requires-python` to ensure it doesn't declare a higher floor than your
152158
project.
153-
- Use tools like `pip-index-versions` or `pipdeptree` to audit dependency compatibility.
159+
- Use `python -m pip index versions <package>` to inspect available releases and `uv tree` or `pipdeptree` to audit the
160+
resolved dependency graph.
154161

155162
## Notes
156163

scripts/validate.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,16 @@ def check_skill() -> None:
166166
if not contains_markdown_phrase(body, directive):
167167
fail(f"{rel(SKILL)} missing Python 3.8 EOL policy: {directive}")
168168

169+
python_310_directives = [
170+
"For new projects, do not select Python 3.10 by default",
171+
"reaches end-of-life in October 2026",
172+
"For an existing project that still declares Python 3.10",
173+
"do not silently raise `requires-python` or remove 3.10 from CI.",
174+
]
175+
for directive in python_310_directives:
176+
if not contains_markdown_phrase(body, directive):
177+
fail(f"{rel(SKILL)} missing Python 3.10 EOL policy: {directive}")
178+
169179
for command in UV_COMMANDS:
170180
if command not in body:
171181
fail(f"{rel(SKILL)} missing uv-managed verification command: {command}")
@@ -210,6 +220,9 @@ def check_references() -> None:
210220
'license-files = ["LICENSE*"]',
211221
"setuptools>=77.0.3",
212222
"[dependency-groups]",
223+
'requires-python = ">=3.11"',
224+
'target-version = "py311"',
225+
'python_version = "3.11"',
213226
):
214227
if required not in pyproject:
215228
fail(f"pyproject template missing current packaging metadata: {required}")
@@ -222,12 +235,16 @@ def check_references() -> None:
222235
fail(f"tooling reference missing uv-managed command: {command}")
223236
if "python -m uv" in tooling:
224237
fail("tooling reference must invoke the uv executable directly")
238+
if "nbqa ruff check" in tooling:
239+
fail("tooling reference must use Ruff's native notebook support")
225240

226241
drift = read_text_checked(REF_DIR / "drift-classes.md")
227242
if "Edit source (root `SKILL.md`" in drift:
228243
fail("drift guide points to nonexistent root SKILL.md")
229244
if "Its `SKILL.md` is authored in place" not in drift:
230245
fail("drift guide does not describe mixed payload ownership")
246+
if "flags payload symlinks and orphans" not in drift:
247+
fail("drift guide does not describe regular-file payload enforcement")
231248

232249
safe_editing = read_text_checked(REF_DIR / "safe-editing.md")
233250
for platform_marker in ('terminal("cat")', "write_file", "sed -i 's/"):
@@ -253,6 +270,7 @@ def check_readme() -> None:
253270
"agentskills.io-compatible",
254271
"skills/python-project-workflow/",
255272
"Shipping boundary: `skills/python-project-workflow/` is the runtime payload",
273+
"hermes skills install CodeSigils/python-project-workflow-skill/skills/python-project-workflow",
256274
]
257275
for phrase in required:
258276
if not contains_markdown_phrase(readme, phrase):
@@ -269,6 +287,7 @@ def check_security() -> None:
269287
"effective `.gitignore` behavior",
270288
"tracked sensitive files",
271289
"redact sensitive values from reports",
290+
"regular-file-only canonical and runtime entries",
272291
]
273292
for phrase in required:
274293
if not contains_markdown_phrase(security, phrase):

skills/python-project-workflow/SKILL.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,17 +209,24 @@ declared Python version range.
209209

210210
- If you control the deployment environment (e.g., internal tool, web service), consider `requires-python = ">=3.12"` to
211211
use the latest features.
212-
- If deploying to older LTS systems (e.g., Ubuntu 22.04 with Python 3.10), use `>=3.10`.
212+
- If deployment must use a distribution's system Python, set the floor to the oldest supported image you actually
213+
deploy. For example, Ubuntu 26.04 LTS currently defaults to Python 3.14; older supported images may require a lower
214+
floor.
213215

214216
### For Libraries
215217

216-
- Aim for broad compatibility: `>=3.10` is the current default when no ecosystem constraint says otherwise.
218+
- Aim for broad compatibility without starting on a near-EOL interpreter: `>=3.11` is the current default when no
219+
ecosystem constraint says otherwise.
220+
- For new projects, do not select Python 3.10 by default: it is in source-only security maintenance and reaches
221+
end-of-life in October 2026. Use `>=3.11` or a newer floor that fits the deployment environment.
222+
- For an existing project that still declares Python 3.10, preserve the current contract unless the user authorizes a
223+
compatibility-breaking change. Identify the constraint keeping it in scope and recommend a tested migration plan; do
224+
not silently raise `requires-python` or remove 3.10 from CI.
217225
- For new projects, do not select Python 3.8: it reached end-of-life in October 2024 and no longer receives security
218-
fixes. Use `>=3.10` or a newer floor that fits the deployment environment.
226+
fixes. Use `>=3.11` or a newer floor that fits the deployment environment.
219227
- For an existing project that still declares Python 3.8, preserve the current contract unless the user authorizes a
220228
compatibility-breaking change. Warn that 3.8 is unsupported upstream, identify the constraint keeping it in scope,
221229
and recommend a tested migration plan. Do not silently raise `requires-python` or remove 3.8 from CI.
222-
- Review this floor as Python 3.10 approaches end-of-life in October 2026.
223230

224231
## Core Python Footguns
225232

skills/python-project-workflow/references/drift-classes.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ difference is critical because they require fundamentally different fixes.
1010

1111
| Class | Name | What Drifts | Root Cause | Detection | Fix |
1212
|-------|------|-------------|------------|-----------|-----|
13-
| **A** | **Payload drift** | Mirrored payload references differ from their canonical root sources, or an undeclared payload file appears | Human edited a canonical reference but forgot to run sync, edited a mirrored reference directly, or left an orphan | Payload sync check (`sync-payload.sh --ci`) fails | Run `bash scripts/sync-payload.sh` to synchronize declared mirrors and remove orphans |
13+
| **A** | **Payload drift** | Mirrored payload references differ from their canonical root sources, an undeclared payload entry appears, or a canonical/runtime entry is a symlink instead of a regular file | Human edited a canonical reference but forgot to run sync, edited a mirrored reference directly, left an orphan, or introduced a link across the shipping boundary | Payload sync check (`sync-payload.sh --ci`) fails | Run `bash scripts/sync-payload.sh` to synchronize declared mirrors and remove payload-side links/orphans; replace canonical source links manually |
1414
| **B** | **Mirror staleness** | Installed copy predates a restructuring | Agent loads a static copy that does not auto-update | `diff -rq <repo>/skills/<name>/ <installed>/skills/<name>/` shows mismatch | Re-install from source or use a client-supported live source directory |
1515

1616
---
@@ -41,12 +41,13 @@ an explicitly allowed authored-in-place file. No scripts currently ship.
4141
3. Added a new source type without updating the manifest or sync policy
4242
4. Renamed/deleted a source file but the old copy remains in payload
4343
5. CI payload sync check was disabled or bypassed
44+
6. Replaced a canonical source or payload entry with a symlink
4445

4546
### Detection
4647

4748
- **CI gate**: `bash scripts/sync-payload.sh --ci` exits 1 on any drift
4849
- **Local check**: Run the same command locally before committing
49-
- **Manifest validation**: the script verifies declared sources and flags payload orphans
50+
- **Manifest validation**: the script requires regular canonical source files and flags payload symlinks and orphans
5051

5152
### Remediation
5253

@@ -147,6 +148,7 @@ prevention for mirror staleness.**
147148
| Committing a mirrored reference change without its root source | Creates reference drift | Keep canonical and mirrored reference content identical through the sync command |
148149
| Installing skill once and never updating | Mirror staleness guaranteed | Use a live source directory for development; schedule re-installs for production |
149150
| Linking individual files instead of the skill directory | Fragile; breaks on restructure | Link or configure the complete `skills/` directory when the client supports it |
151+
| Committing symlinks inside the canonical or runtime payload trees | Can escape the shipping boundary or become broken after copying only the payload | Keep every shipped and canonical reference entry as a regular file; use client-level directory configuration only outside the payload |
150152

151153
---
152154

0 commit comments

Comments
 (0)