Skip to content

fix(skills): resolve symlinks before relative_to in skill install - #53541

Open
AlexFucuson9 wants to merge 1 commit into
NousResearch:mainfrom
AlexFucuson9:fix/skill-install-symlink
Open

fix(skills): resolve symlinks before relative_to in skill install#53541
AlexFucuson9 wants to merge 1 commit into
NousResearch:mainfrom
AlexFucuson9:fix/skill-install-symlink

Conversation

@AlexFucuson9

Copy link
Copy Markdown
Contributor

Bug

After a skill is successfully installed, do_install tries to print the install location relative to SKILLS_DIR. It calls Path.relative_to() on raw (unresolved) paths.

When either SKILLS_DIR or the install directory contains a symlink component (common when ~/.hermes or its skills/ dir is itself a symlink), the lexical prefix check in relative_to fails and raises ValueError, aborting an otherwise-successful install.

Fix

Resolve both paths before calling relative_to():

# Before
install_path=str(install_dir.relative_to(SKILLS_DIR))

# After  
install_path=str(install_dir.resolve().relative_to(SKILLS_DIR.resolve()))

1 line change.

Fixes #53403

Path.relative_to() does a lexical prefix check that fails when either
path contains symlink components. When ~/.hermes or its skills/ dir is
a symlink (common on systems where home dir is symlinked), the install
succeeds but printing the relative path raises ValueError.

Fix by resolving both paths before calling relative_to.

Fixes NousResearch#53403
@alt-glitch alt-glitch added type/bug Something isn't working tool/skills Skills system (list, view, manage) P2 Medium — degraded but workaround exists duplicate This issue or pull request already exists labels Jun 27, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Duplicate of #49885 — this is the identical one-line .resolve().relative_to(...resolve()) fix at the same install_from_quarantine site (tools/skills_hub.py). #49885 (2026-06-21) is the earliest open PR making this exact fix. Note the broader open PRs #53409 and #53493 fix both this site and the do_install print site (hermes_cli/skills_hub.py:715); a maintainer may prefer one of those for completeness.

@tonydwb tonydwb 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.

Code Review Summary

Verdict: Approved

Resolves symlinks before calling relative_to in skill install to prevent ValueError when the install path is a symlink pointing outside the skills directory.

Looks Good

  • .resolve() on both sides ensures the relative path computation works correctly
  • Minimal one-line change, correct fix

Reviewed by Hermes Agent

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the focused fix. The underlying backend failure still exists on current main: _resolve_lock_install_path() returns a resolved directory at tools/skills_hub.py:288, but lock recording compares it with unresolved _skills_dir() at tools/skills_hub.py:3644.

Problems

  • The same bug class remains in the successful install display at hermes_cli/skills_hub.py:730-731; after this PR's backend change, a symlinked root can still fail while printing Installed:.
  • This branch predates the dynamic-path refactor in 10e60060d; current main uses _skills_dir() rather than the internal SKILLS_DIR expression changed by this diff.
  • No regression test covers a symlinked skills root and both affected outputs.

Suggested changes

  • Port the backend fix to _skills_dir().resolve(), fix the CLI display site with the same resolved-root calculation, and add one regression covering the lock entry plus the success output.

Automated hermes-sweeper review.

Comment thread tools/skills_hub.py
scan_verdict=scan_result.verdict,
skill_hash=content_hash(install_dir),
install_path=str(install_dir.relative_to(SKILLS_DIR)),
install_path=str(install_dir.resolve().relative_to(SKILLS_DIR.resolve())),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This addresses lock recording, but current main also computes an unresolved relative path in the successful CLI display at hermes_cli/skills_hub.py:731. Please fix that sibling site and cover both paths with one symlink-root regression.

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

Labels

area/install-update Installer, updater, packaging, wheels, doctor duplicate This issue or pull request already exists P2 Medium — degraded but workaround exists sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades tool/skills Skills system (list, view, manage) type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: skill install crashes with ValueError when SKILLS_DIR or install path contains a symlink

4 participants