fix(skills): widen call-time skills-dir resolution to skills_sync - #66094
fix(skills): widen call-time skills-dir resolution to skills_sync#66094Fe2-O3 wants to merge 1 commit into
Conversation
Third module in the same lineage as f8723c4 (skills_tool) and c6a3d41 (skill_manager_tool, refs NousResearch#40677): tools/skills_sync binds HERMES_HOME / SKILLS_DIR / MANIFEST_FILE at import, so a long-lived process that later binds a different profile via set_hermes_home_override reads and writes the launch profile instead of the active one. _profile_scope (hermes_cli/web_server.py) documents this exact seam and retargets skills_tool and skill_manager_tool by hand — skills_sync is not retargeted. The dashboard console dispatches skills opt-in|opt-out|reset|diff| list-modified in-process (console_engine.py allowlist -> cmd_skills -> skills_hub -> lazy `from tools.skills_sync import ...`), unlike hub install/update/uninstall which correctly use a fresh profile-scoped subprocess. seed_profile_skills already works around the caching with a subprocess ("Uses subprocess because sync_skills() caches HERMES_HOME at module level"), but that only covers profile seeding. Reproduced: with the module imported under profile A and profile B active, is_bundled_skills_opt_out() returns False while B carries the marker — contradicting its own docstring ("Return True if the active profile carries the opt-out marker") — and set_bundled_skills_opt_out(True) writes the marker into A. reset_bundled_skill() is the sharp edge: its strict-child delete guard is computed from the frozen SKILLS_DIR (skills_sync.py:744). The binding is order-dependent — the first console skills command to run inside a profile scope binds correctly; every subsequent one under a different profile does not. Apply the established pattern: keep the module attributes for tests and external patchers, snapshot them at import, and resolve from the live profile-scoped home on every call when they have not been patched. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Approved
Looks Good
- Small, focused fix: widens call-time skills-dir resolution to include skills_sync
- Two file changes (skills directory resolution + test) — appropriate scope
- No security or code quality concerns
Reviewed by Hermes Agent
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Comment
Widens call-time skills-dir resolution to skills_sync (193 additions / 23 deletions). Prior COMMENT activity noted.
No security issues. No debug artifacts.
Reviewed by Hermes Agent (cron batch 2026-07-17)
|
Thanks for the focused profile-scope fix. The premise remains valid on current The resolver approach matches the established fixes in Automated hermes-sweeper review. |
SummaryOne PR addresses Issue #65828. #66094 replaces import-time profile-path use in tools/skills_sync.py with call-time resolvers and adds regression coverage for active-profile reads, writes, manifests, resolver restoration, and explicit monkeypatch precedence. Related pull requests
Suggested consolidationKeep #66094 open with a salvage path: retain the call-time resolver conversion and the focused two-profile regression suite, rebasing mechanically onto current main if needed. It is the sole PR in this complex, so there are no duplicate PRs to close. Complex graphflowchart LR
classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
classDef merged fill:#dcfce7,stroke:#15803d,color:#14532d
classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
classDef unverified fill:#f3f4f6,stroke:#9ca3af,color:#374151
classDef best stroke-width:3px,stroke:#b45309
classDef target stroke-width:3px,stroke:#4338ca
I65828(["issue #65828 (open)"])
P66094["PR #66094 (open)"]
P66094 -->|best fix| I65828
class I65828 open
class P66094 open
class P66094 best
class P66094 target
click I65828 "https://github.com/NousResearch/hermes-agent/issues/65828"
click P66094 "https://github.com/NousResearch/hermes-agent/pull/66094"
Graph: solid arrow = fixes / best fix, dashed arrow = partial or unverified (see edge label); boxed group = PRs duplicating each other; amber border = best fix; indigo border = target; gray node = closed (state tag in the node label). Cross-PR triage: Reviewed 1 pull request and 1 issue in this complex. Each diff was read against this issue; Assessment working set: 16 kB of PR diffs, 8 kB of issue/PR text, <1 kB of discussion (2 comments), 2 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch. |
Closes #65828.
tools/skills_syncis the third module in the lineage of #40677 —f8723c478fixedskills_tool,c6a3d412dwidened the same fix toskill_manager_tool, andskills_synchas the identical import-time binding with no call-time resolver._profile_scope(hermes_cli/web_server.py) documents the seam and hand-retargets two modules:skills_syncis not among them, and the dashboard console reaches it in-process:console_engine.pyallowlistsskills opt-in|opt-out|reset|diff|list-modified→cmd_skills→skills_hub.skills_command→ lazyfrom tools.skills_sync import ...(:1152,:1195,:1222,:1337). Hubinstall/update/uninstallare unaffected — those correctly use a fresh profile-scoped subprocess (web_server.py:12501).Reproduced
With the module imported under profile A and profile B active:
reset_bundled_skill()is the sharp edge: its strict-child delete guard is computed from the frozenSKILLS_DIR(skills_sync.py:744) — the check that exists so a collapseddestcan't "wipe every installed skill".The binding is order-dependent: the first console skills command to run inside a profile scope binds correctly; every later one under a different profile does not. That's likely why it has survived — it presents as intermittent.
Fix
The established pattern from both prior commits: keep the module attributes for tests and external patchers, snapshot at import, resolve live otherwise.
seed_profile_skillsalready works around this caching with a subprocess ("Uses subprocess because sync_skills() caches HERMES_HOME at module level") — that covers seeding only, not the console.Tests
tests/tools/test_skills_sync_profile_scope.py— behavioral, per AGENTS.md's ban on reading source in tests. Reloads the module under profile A, activates B, and asserts on real reads/writes. All 5 fail against the unfixed module; existingtest_skills_sync.py+test_skills_list_modified_diff.py(75 tests) stay green.Note on AGENTS.md:1193
True for the one-shot CLI, not for the
set_hermes_home_overrideContextVar in long-lived processes — which is the seam_profile_scopeexists to paper over. Happy to correct it here or separately.🤖 Generated with Claude Code