feat(skills): add opt-in external_dirs_readonly guard - #51412
Conversation
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Approved
Add external_dirs_readonly config flag (default true).
Looks Good
- Good safety feature: prevents agent from modifying skills in external directories
- Properly implemented with config flag and skill_manage integration
- Default (True) is the safe choice
- Well-documented with clear rationale
- Tests verify the guard behavior
Reviewed by Hermes Agent
teknium1
left a comment
There was a problem hiding this comment.
Thanks for the focused guard and mutation coverage. The default needs a maintainer design decision before this can be salvaged.
Problems
hermes_cli/config.py:2014changes the default to reject foreground edits, but current main deliberately allows them:tools/skill_manager_tool.py:302-307limits the external read-only boundary to autonomous curation, andwebsite/docs/user-guide/features/skills.md:333-334documents update-in-place. Commit8c8fc6c1chose this specifically to avoid silently duplicating external skills locally.- Current main already owns this classification in
agent/skill_utils.py:579-596asis_external_skill_path; the newis_external_skill_dirduplicates that mechanism. - The behavior change needs a corresponding update to
website/docs/user-guide/features/skills.md:333-334and an integration test using a temporaryHERMES_HOME, rather than only mocked config/discovery.
Suggested changes
- Resolve whether foreground external-directory edits should change from the established contract. If approved, reuse
is_external_skill_path, document the changed default, and add the real config-path test.
Automated hermes-sweeper review.
| # external directories are typically managed by an external package | ||
| # manager (npx skills, git, etc.) — modifications by the agent would be | ||
| # silently lost on the next update. Set to false to allow modifications. | ||
| "external_dirs_readonly": True, |
There was a problem hiding this comment.
Making this default true reverses the current foreground-edit contract: tools/skill_manager_tool.py:302-307 permits user-directed external-skill edits, and commit 8c8fc6c1 deliberately removed the old read-only gate to avoid duplicate local skills. Please obtain a maintainer decision before changing this default.
e8ab3d9 to
ba0f898
Compare
Adds a new opt-in config key `skills.external_dirs_readonly` (default `false`) that prevents skill_manage from mutating skills in external directories when enabled. - hermes_cli/config.py: register the opt-in config key - tools/skill_manager_tool.py: add the external-directory guard - tools/skill_manager_tool.py: reuse is_external_skill_path Skills in external_dirs are typically managed by an external package manager (npx skills, git, etc.). Agent modifications may be silently lost on the next update. Users can set the flag to true when protection is required.
10 tests covering: - edit/patch/delete/write_file/remove_file blocked when protection is enabled - create not affected (always writes to local) - mutations allowed when the flag is false or unset - real temporary-HERMES_HOME config-path coverage - config value resolution and fallback behavior
ba0f898 to
341461b
Compare
GottZ
left a comment
There was a problem hiding this comment.
This was generated by AI during triage.
Summary
Two PRs address the same opt-in protection against skill_manage mutating external skills while preserving the existing writable-by-default contract. #51412 guards skills discovered under configured external directories, whereas #65270 implements the broader ownership boundary needed to cover configured roots, resolved targets, nested external roots, and symlink escapes.
Related pull requests
- #51412
related— (+199/-2) — superseded duplicate: Addsskills.external_dirs_readonly, reusesis_external_skill_path, documents the default-false behavior, and tests all existing-skill mutation actions, but its guard only classifies the skill directory and does not cover resolved mutation targets or a symlinked active skills root. Despite the visible APPROVED review on #51412, the diff is materially narrower than #65270; the contributor review's earlier default/helper/docs/integration concerns are addressed in the current revision, but the broader ownership cases remain absent. - #65270
duplicate— (+743/-33) — preferred implementation: Adds default-falseskills.external_read_onlypreflight enforcement across every mutation, including create, configured roots nested under local storage, resolved targets outside the active profile, local symlink escapes, and a symlinked active skills root, while preserving reads and safe final-symlink unlinking. The current diff directly addresses the contributor keep_open review on #65270 by rejecting a symlinked<HERMES_HOME>/skillsroot and adding profile-config coverage for both create and an existing-skill mutation.
Duplicates
#51412 and #65270 implement the same opt-in external-skill read-only feature; #65270 substantially subsumes #51412 with a resolved ownership boundary and symlink-aware coverage.
Suggested consolidation
Merge #65270 after normal CI verification because it preserves the established default while covering the full mutation and path-resolution boundary, including the contributor-reviewed symlinked-root gap. Close #51412 as superseded by #65270; despite its APPROVED review, its diff provides only the narrower configured-external-directory guard.
Complex graph
flowchart 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
subgraph Dup51412 ["PRs duplicating each other"]
P51412["PR #51412 (open)"]
P65270["PR #65270 (open)"]
end
class P51412 open
class P65270 open
class P51412 target
click P51412 "https://github.com/NousResearch/hermes-agent/pull/51412"
click P65270 "https://github.com/NousResearch/hermes-agent/pull/65270"
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 or no verify verdict yet (state tag in the node label).
Cross-PR triage: Reviewed 2 pull requests and 0 issues in this complex. Each diff was read against this issue; Assessment working set: 59 kB of PR diffs, 4 kB of issue/PR text, 3 kB of discussion (3 comments), 1 verify verdict. verdicts reflect diff content, not PR titles. Part of an automated triage batch.
What
Adds
skills.external_dirs_readonlyas an opt-in guard for skills in external directories.Skills in
external_dirsare typically managed by an external package manager (npx skills, git, etc.). When enabled, the guard preventsskill_managefrom modifying them, avoiding changes that may be silently overwritten on the next update.The default remains
falseto preserve the existing foreground-edit contract. Users can enable protection with:The guard reuses the canonical
is_external_skill_pathhelper. New skills are still created locally.How to test
Add an external directory to
config.yaml:Create a skill there and run Hermes.
Set
skills.external_dirs_readonly: trueand try to patch it viaskill_manage. The operation should fail with an error mentioningexternal_dirs_readonly.Remove the flag or set it to
false. The foreground patch should be allowed again.Run:
Expected: 118 passed, including real temporary-
HERMES_HOMEconfig-path coverage.Platforms tested
Related