Thanks for open-sourcing SkillOpt! While setting up 0.2.0 on Windows with the Claude backend I hit two blocking bugs. Bug 1 affects all platforms; Bug 2 is Windows-specific. A third, minor Windows note is at the end.
Environment
skillopt 0.2.0, installed from PyPI: pip install "skillopt[claude]"
- Python 3.14.5, Windows 10
- Backend:
--backend claude (claude-agent-sdk; Claude Code CLI 2.1.173)
Bug 1 — PyPI wheel ships no prompt files (skillopt/prompts/*.md missing) — all platforms
The wheel installs skillopt/prompts/ containing only __init__.py; every generic prompt .md is missing, as are the per-env prompts under skillopt/envs/<env>/prompts/. Any run fails as soon as it needs a prompt:
FileNotFoundError: Prompt 'analyst_error' not found. Searched: skillopt/prompts/analyst_error.md
(The rollout stage fails the same way on rollout_system.)
Repro:
pip install skillopt
python -c "import os, skillopt; p=os.path.join(os.path.dirname(skillopt.__file__),'prompts'); print(sorted(os.listdir(p)))"
# -> ['__init__.py', '__pycache__'] # all *.md missing
Root cause: the .md files aren't declared as package data, so they're excluded from the wheel; load_prompt() (skillopt/prompts/__init__.py) then can't resolve them. The repo tree has all ~21 generic prompts + per-env prompts, so a source / editable install works — only the wheel is broken.
Suggested fix (setuptools / pyproject):
[tool.setuptools.package-data]
"*" = ["*.md"]
or an equivalent MANIFEST.in (recursive-include skillopt *.md) with include_package_data. A test that imports each registered env and asserts load_prompt(...) resolves would catch regressions.
Bug 2 — Windows: temp-dir cleanup race in the Claude backend → WinError 32
skillopt/model/claude_backend.py::_run_claude_print runs the CLI inside a TemporaryDirectory and passes it as the child's cwd:
with tempfile.TemporaryDirectory(prefix="skillopt_claude_") as temp_dir: # ~L246
...
proc = subprocess.run(cmd, ..., cwd=temp_dir) # ~L273
On Windows the spawned claude / node process still holds a handle on temp_dir when the with block exits, so TemporaryDirectory cleanup raises and the exception propagates out of the model call (masking the real result):
RuntimeError: Claude backend failed after N retries:
[WinError 32] The process cannot access the file because it is being used by another process:
'...\Temp\skillopt_claude_xxxxxxxx'
This makes the claude backend unusable on Windows. Since requires-python >= 3.10, ignore_cleanup_errors=True fixes it cleanly:
with tempfile.TemporaryDirectory(prefix="skillopt_claude_", ignore_cleanup_errors=True) as temp_dir:
(Alternatives: don't set the child cwd to the temp dir, or retry the cleanup.)
Also on Windows (minor) — Unicode print crashes under cp1252
The trainer prints non-ASCII (e.g. the → in the [gate] line, skillopt/engine/trainer.py), which crashes under the default Windows code page before any model call:
UnicodeEncodeError: 'charmap' codec can't encode character '→' ... cp1252
PYTHONUTF8=1 works around it; reconfiguring stdout to UTF-8 (or using ASCII in logs) would fix it for everyone.
With all three addressed, an end-to-end skillopt-train --backend claude run completes cleanly (EXIT=0). Happy to send a PR for Bugs 1 & 2 if useful.
Thanks for open-sourcing SkillOpt! While setting up 0.2.0 on Windows with the Claude backend I hit two blocking bugs. Bug 1 affects all platforms; Bug 2 is Windows-specific. A third, minor Windows note is at the end.
Environment
skillopt0.2.0, installed from PyPI:pip install "skillopt[claude]"--backend claude(claude-agent-sdk; Claude Code CLI 2.1.173)Bug 1 — PyPI wheel ships no prompt files (
skillopt/prompts/*.mdmissing) — all platformsThe wheel installs
skillopt/prompts/containing only__init__.py; every generic prompt.mdis missing, as are the per-env prompts underskillopt/envs/<env>/prompts/. Any run fails as soon as it needs a prompt:(The rollout stage fails the same way on
rollout_system.)Repro:
Root cause: the
.mdfiles aren't declared as package data, so they're excluded from the wheel;load_prompt()(skillopt/prompts/__init__.py) then can't resolve them. The repo tree has all ~21 generic prompts + per-env prompts, so a source / editable install works — only the wheel is broken.Suggested fix (setuptools / pyproject):
or an equivalent
MANIFEST.in(recursive-include skillopt *.md) withinclude_package_data. A test that imports each registered env and assertsload_prompt(...)resolves would catch regressions.Bug 2 — Windows: temp-dir cleanup race in the Claude backend →
WinError 32skillopt/model/claude_backend.py::_run_claude_printruns the CLI inside aTemporaryDirectoryand passes it as the child'scwd:On Windows the spawned
claude/nodeprocess still holds a handle ontemp_dirwhen thewithblock exits, soTemporaryDirectorycleanup raises and the exception propagates out of the model call (masking the real result):This makes the claude backend unusable on Windows. Since
requires-python >= 3.10,ignore_cleanup_errors=Truefixes it cleanly:(Alternatives: don't set the child
cwdto the temp dir, or retry the cleanup.)Also on Windows (minor) — Unicode print crashes under cp1252
The trainer prints non-ASCII (e.g. the
→in the[gate]line,skillopt/engine/trainer.py), which crashes under the default Windows code page before any model call:PYTHONUTF8=1works around it; reconfiguring stdout to UTF-8 (or using ASCII in logs) would fix it for everyone.With all three addressed, an end-to-end
skillopt-train --backend clauderun completes cleanly (EXIT=0). Happy to send a PR for Bugs 1 & 2 if useful.