Repository navigation
claude_uninstall still ignores project_dir with project=False (root cause of #2168, unfixed by v0.9.27) #2215
Description
Context
#2168 reported two things: the test suite silently deleting the developer's installed skill, and the API behaviour underneath that makes it possible. It closed with fix option (a) — v0.9.27 adds an autouse _sandbox_home fixture in tests/conftest.py that sandboxes HOME/USERPROFILE/LOCALAPPDATA, clears CLAUDE_CONFIG_DIR/XDG_CONFIG_HOME, and monkeypatches Path.home. That is a solid fix and it does close the contributor-facing damage — running pytest tests/ no longer touches a real ~/.claude.
This issue tracks fix option (b), which did not ship: the root cause is still present in install.py.
Still present at v0.9.27
Verified against the v0.9.27 tag.
claude_uninstall — graphify/install.py:1801:
def claude_uninstall(project_dir: Path | None = None, *, project: bool = False) -> None:
...
project_dir = project_dir or Path(".")
_remove_skill_file("claude", project=project, project_dir=project_dir) # line 1814project still defaults to False. _remove_skill_file (install.py:232) forwards both arguments to _platform_skill_destination (install.py:68), where the project branch is the only one that consults project_dir:
cfg = _PLATFORM_CONFIG[platform_name]
if project:
return (project_dir or Path(".")) / cfg["skill_dst"] # line 117
if platform_name in ("claude", "windows") and os.environ.get("CLAUDE_CONFIG_DIR"):
return Path(os.environ["CLAUDE_CONFIG_DIR"]) / "skills" / "graphify" / "SKILL.md"
return Path.home() / cfg["skill_dst"] # line 121With project=False, the project_dir that was passed in is accepted, defaulted, and forwarded — then ignored. Resolution falls through to Path.home() / cfg["skill_dst"], i.e. ~/.claude/skills/graphify/SKILL.md (_PLATFORM_CONFIG["claude"]["skill_dst"], install.py:328). _remove_skill_file then unlinks SKILL.md (:237) and .graphify_version (:242), shutil.rmtrees references/ (:246), and rmdirs upward through the parents (:250).
For what it's worth, git diff v0.9.25 v0.9.27 -- graphify/install.py contains no claude_uninstall, project_dir, or _platform_skill_destination changes — the install.py delta in that release is the #2167 settings-clobber work.
Why it still matters
The suite is sandboxed now, so the CI/contributor path is closed. The path reachable from real usage is not:
graphify claude uninstallrun from inside a project directory, without--project, removes the global skill rather than that project's. From the user's side it reads as uninstalling the project's copy; the global tree is what disappears, and it fails silently in the sense that nothing indicates the wrong scope was hit.- Any programmatic
claude_uninstall(some_path)call behaves the same way. The signature invites the assumption that passing a path scopes the operation — that assumption is exactly what produced Runningpytest tests/silently deletes the user's installed Claude skill (test_claude_md.py + claude_uninstall project_dir leak) #2168. - A future test that legitimately sidesteps the fixture, or any caller outside the suite, re-opens the original hole. The fixture protects the suite, not the function.
Possible fixes — maintainers' call
Either direction closes it; it's a design decision:
- Honour
project_dirwhen it is passed — treat a non-Noneproject_diras implying project scope. Matches what the signature reads like today. - Keep the current semantics but make them explicit — either drop
project_dirfrom the signature whenprojectis the scope selector, or raise on theproject_dir is not None and not projectcombination instead of silently ignoring it.
(2) is the smaller change and removes the ambiguity outright; (1) is closer to what callers appear to expect. Same offer as last time — happy to submit a PR for whichever you prefer, I didn't want to presume the design call.
Note
Unrelated to #2162.
Activity
fix(install): scope uninstall to project_dir instead of always deleti…
chore: bump to 0.9.28; changelog for #2211/#2213/#2210/#2212/#2215/#2221
safishamsi commentedon Jul 27, 2026
Fixed in v0.9.28. claude/gemini/codebuddy uninstall now scope skill removal to a passed project_dir instead of always deleting the user-global skill (via a new remove_user_skill keyword; uninstall_all opts in explicitly to keep 'graphify uninstall' behavior). This also fixed a CLI bug where 'graphify uninstall --project' deleted the global codebuddy skill. https://github.com/Graphify-Labs/graphify/releases/tag/v0.9.28
fix(install): scope uninstall to project_dir instead of always deleti…
chore: bump to 0.9.28; changelog for Graphify-Labs#2211/Graphify-Labs…