Skip to content

fix: protect externally managed skills - #2371

Open
EmanuelFaria wants to merge 1 commit into
Graphify-Labs:v8from
EmanuelFaria:fix/externally-managed-skills
Open

fix: protect externally managed skills#2371
EmanuelFaria wants to merge 1 commit into
Graphify-Labs:v8from
EmanuelFaria:fix/externally-managed-skills

Conversation

@EmanuelFaria

Copy link
Copy Markdown

Summary

  • add a .graphify_externally_managed ownership marker for skills maintained by configuration managers
  • suppress stale-skill warnings for marked integrations
  • refuse skill overwrite, removal, and platform hook or instruction mutations while the marker exists
  • refuse bulk uninstall rather than partially deleting an externally managed setup
  • document how to return ownership to Graphify

Why

Graphify currently tells users with a stale skill to run its installer. That is unsafe when another system intentionally owns Claude, Codex, or other assistant configuration. The installer can replace reviewed instructions and platform hooks.

This follows the externally managed ownership pattern: package use and upgrades remain available, while assistant configuration stays under its declared manager.

Tests

  • 188 installer and uninstall regression tests passed
  • 1 unrelated platform-specific test skipped
  • Ruff passed on all changed Python files
  • git diff check passed

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).


Graphify review — findings

This PR introduces an "externally managed" ownership marker (.graphify_externally_managed) for Graphify's assistant skill installations, mirroring Python's EXTERNALLY-MANAGED convention. When this marker file is present beside a platform's SKILL.md, the installer is intended to suppress version warnings and refuse to overwrite/remove the skill, mutate hooks, or touch instruction files—both for named-platform and bulk install/uninstall commands. The change adds a _is_externally_managed helper plus refusal guards wired into _copy_skill_file, _remove_skill_file, _refresh_all_version_stamps, _check_skill_version, and the CLI dispatch path, and updates the README to document the marker. It also adds tests covering the skill overwrite/removal refusal, named-platform install refusal for Claude and Codex, and silenced version warnings under the marker.

Worth a look

  • install ordering: hooks/instructions may be written before _copy_skill_file refuses externally-managed skillgraphify/install.py · Escalate · high
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • _refuse_externally_managed_cli_action only guards subcmd at argv[2], missing scope-specific skill destinationgraphify/install.py:45 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 431 functions depend on the 220 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: dispatch_install_cli() — 2 callers, 33 callees
  • worse: _copy_skill_file() — 8 callers, 4 callees
  • worse: _remove_skill_file() — 11 callers, 2 callees
  • worse: _check_skill_version() — 7 callers, 2 callees

Verification — 431 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 431 function(s) in the blast radius were not formally verified this run

· 2 grounded finding(s) anchored inline below; 2 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/__main__.py
@@ -163,6 +164,8 @@ def __getattr__(name: str) -> str:

def _check_skill_version(skill_dst: Path) -> None:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regression_check_skill_version()

7 callers depend on it (afferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread graphify/install.py
@@ -232,6 +300,9 @@ def _copy_skill_file(platform_name: str, *, project: bool = False, project_dir:
def _remove_skill_file(platform_name: str, *, project: bool = False, project_dir: Path | None = None) -> bool:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regression_remove_skill_file()

11 callers depend on it (afferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant