Make the Claude Code plugin self-contained: fall back to pip/uv-installed skillopt so no repo clone is needed
Goal
After /plugin marketplace add + /plugin install, the Claude Code plugin should work with no additional setup — no repo clone, no SKILLOPT_SLEEP_REPO env var. The plugin shell should auto-update via Claude Code's plugin marketplace, and the engine should auto-update via pip/uv. Two independent update channels, neither requiring manual git pull.
Current state
The plugin's runner (plugins/claude-code/scripts/run-sleep.sh, a bundled copy of the shared plugins/run-sleep.sh) resolves the engine by searching for a skillopt_sleep/ source directory on disk in four locations:
- Co-located (
$SCRIPT_DIR/../skillopt_sleep)
$CLAUDE_PLUGIN_ROOT/../../skillopt_sleep
$SKILLOPT_SLEEP_REPO/skillopt_sleep
- Upward from
$PWD
If none contains the source dir, it errors:
if [ -z "${REPO_ROOT:-}" ]; then
echo "[sleep] ERROR: could not locate the skillopt_sleep package. Set SKILLOPT_SLEEP_REPO to the repo root." >&2
exit 1
fi
cd "$REPO_ROOT"
exec "$PY" -m skillopt_sleep "$@"
There is no fallback to the pip/uv-installed package. The error message mentions "pip install skillopt," but pip install skillopt does not actually make the plugin work — run-sleep.sh's resolution logic never checks for the installed package.
This means the documented v0.2.0 install path (uv tool install skillopt / pip install skillopt for the engine, /plugin marketplace add + /plugin install for the shell) does not produce a working plugin. The user must also git clone the repo and either set SKILLOPT_SLEEP_REPO or rely on the upward-from-CWD search finding the source dir — which defeats the point of publishing the engine to PyPI and doesn't compose with Claude Code's plugin auto-update, since the engine lives outside the plugin's tracked source.
Issue #52 (fixed in PR #72) bundled run-sleep.sh inside the plugin so the runner itself is found after a marketplace install, but the runner's engine-resolution logic was not updated to fall back to the installed package. This issue is the remaining half of that fix.
Desired state
run-sleep.sh falls back to the installed engine before erroring:
skillopt-sleep CLI on PATH — covers uv tool install skillopt, pipx install skillopt, pip install skillopt. All three put the skillopt-sleep console script on PATH.
python -m skillopt_sleep when importable — covers pip install skillopt into the active Python (edge case where the console script isn't on PATH but the package is importable).
Fallback 1 must be checked before fallback 2, because uv tool install / pipx isolate the package from the system Python's import path — python -c "import skillopt_sleep" would fail even though the skillopt-sleep CLI is available.
The existing source-checkout resolution path stays unchanged — repo-clone users keep working as before. The fallbacks only trigger when no source dir is found.
Suggested fix
~10 lines in run-sleep.sh, before the existing error:
# Fallback 1: skillopt-sleep CLI on PATH (uv tool install / pipx / pip install)
if command -v skillopt-sleep >/dev/null 2>&1; then
exec skillopt-sleep "$@"
fi
# Fallback 2: importable as a module (pip install into the active Python)
if "$PY" -c "import skillopt_sleep" >/dev/null 2>&1; then
exec "$PY" -m skillopt_sleep "$@"
fi
echo "[sleep] ERROR: could not locate the skillopt_sleep package." >&2
echo "[sleep] Install it with 'uv tool install skillopt' or 'pip install skillopt'," >&2
echo "[sleep] or set SKILLOPT_SLEEP_REPO to a clone of the SkillOpt repo." >&2
exit 1
The cd "$REPO_ROOT" is dropped for the fallback paths — the engine takes --project explicitly and writes outputs relative to the project dir, not cwd.
Scope
The same run-sleep.sh logic is shared by the Codex plugin (plugins/codex/install.sh calls the shared plugins/run-sleep.sh), so the fix should land in both:
plugins/run-sleep.sh (shared, used by Codex)
plugins/claude-code/scripts/run-sleep.sh (bundled copy, byte-identical, used by the Claude Code marketplace install which fetches only the plugins/claude-code/ subtree)
Fixing both covers Claude Code and Codex in one change.
Out of scope:
- OpenClaw uses a separate Python runner (
plugins/openclaw/run_sleep.py), not the shell runner.
- Devin and Copilot MCP plugins (
plugins/devin/mcp_server.py, plugins/copilot/mcp_server.py) already handle the pip-installed case correctly — they set PYTHONPATH=REPO_ROOT as an addition and run python -m skillopt_sleep, which falls through to site-packages when the repo dir doesn't contain the package. The shell runner is the outlier.
Why this matters
- The v0.2.0 release notes headline SkillOpt-Sleep as a PyPI-published CLI (
skillopt-sleep), but the Claude Code plugin — the primary documented install path for Claude Code users — can't actually use that PyPI package. The two install paths are effectively decoupled.
- Users who enable plugin auto-updates (a common Claude Code setting) get the shell updated automatically, but the engine still requires a manual
git pull of a repo clone — an awkward split that surprises users who reasonably expect pip install + plugin install to be sufficient.
- The Devin and Copilot MCP plugins already handle this correctly. The shell runner is the outlier.
Additional context
- Verified against
main as of 2026-07-06 (v0.2.0).
- I have a PR ready that implements the suggested fix in both files, with shellcheck passing and the fallback paths verified against
uv tool install skillopt.
Make the Claude Code plugin self-contained: fall back to pip/uv-installed
skilloptso no repo clone is neededGoal
After
/plugin marketplace add+/plugin install, the Claude Code plugin should work with no additional setup — no repo clone, noSKILLOPT_SLEEP_REPOenv var. The plugin shell should auto-update via Claude Code's plugin marketplace, and the engine should auto-update via pip/uv. Two independent update channels, neither requiring manualgit pull.Current state
The plugin's runner (
plugins/claude-code/scripts/run-sleep.sh, a bundled copy of the sharedplugins/run-sleep.sh) resolves the engine by searching for askillopt_sleep/source directory on disk in four locations:$SCRIPT_DIR/../skillopt_sleep)$CLAUDE_PLUGIN_ROOT/../../skillopt_sleep$SKILLOPT_SLEEP_REPO/skillopt_sleep$PWDIf none contains the source dir, it errors:
There is no fallback to the pip/uv-installed package. The error message mentions "pip install skillopt," but
pip install skilloptdoes not actually make the plugin work —run-sleep.sh's resolution logic never checks for the installed package.This means the documented v0.2.0 install path (
uv tool install skillopt/pip install skilloptfor the engine,/plugin marketplace add+/plugin installfor the shell) does not produce a working plugin. The user must alsogit clonethe repo and either setSKILLOPT_SLEEP_REPOor rely on the upward-from-CWD search finding the source dir — which defeats the point of publishing the engine to PyPI and doesn't compose with Claude Code's plugin auto-update, since the engine lives outside the plugin's tracked source.Issue #52 (fixed in PR #72) bundled
run-sleep.shinside the plugin so the runner itself is found after a marketplace install, but the runner's engine-resolution logic was not updated to fall back to the installed package. This issue is the remaining half of that fix.Desired state
run-sleep.shfalls back to the installed engine before erroring:skillopt-sleepCLI on PATH — coversuv tool install skillopt,pipx install skillopt,pip install skillopt. All three put theskillopt-sleepconsole script on PATH.python -m skillopt_sleepwhen importable — coverspip install skilloptinto the active Python (edge case where the console script isn't on PATH but the package is importable).Fallback 1 must be checked before fallback 2, because
uv tool install/pipxisolate the package from the system Python's import path —python -c "import skillopt_sleep"would fail even though theskillopt-sleepCLI is available.The existing source-checkout resolution path stays unchanged — repo-clone users keep working as before. The fallbacks only trigger when no source dir is found.
Suggested fix
~10 lines in
run-sleep.sh, before the existing error:The
cd "$REPO_ROOT"is dropped for the fallback paths — the engine takes--projectexplicitly and writes outputs relative to the project dir, not cwd.Scope
The same
run-sleep.shlogic is shared by the Codex plugin (plugins/codex/install.shcalls the sharedplugins/run-sleep.sh), so the fix should land in both:plugins/run-sleep.sh(shared, used by Codex)plugins/claude-code/scripts/run-sleep.sh(bundled copy, byte-identical, used by the Claude Code marketplace install which fetches only theplugins/claude-code/subtree)Fixing both covers Claude Code and Codex in one change.
Out of scope:
plugins/openclaw/run_sleep.py), not the shell runner.plugins/devin/mcp_server.py,plugins/copilot/mcp_server.py) already handle the pip-installed case correctly — they setPYTHONPATH=REPO_ROOTas an addition and runpython -m skillopt_sleep, which falls through to site-packages when the repo dir doesn't contain the package. The shell runner is the outlier.Why this matters
skillopt-sleep), but the Claude Code plugin — the primary documented install path for Claude Code users — can't actually use that PyPI package. The two install paths are effectively decoupled.git pullof a repo clone — an awkward split that surprises users who reasonably expectpip install+plugin installto be sufficient.Additional context
mainas of 2026-07-06 (v0.2.0).uv tool install skillopt.