Skip to content

fix(skills): make hermes skills reset honest when local copy differs from bundled#29863

Open
briandevans wants to merge 1 commit into
NousResearch:mainfrom
briandevans:fix/skills-reset-honest-message-29856
Open

fix(skills): make hermes skills reset honest when local copy differs from bundled#29863
briandevans wants to merge 1 commit into
NousResearch:mainfrom
briandevans:fix/skills-reset-honest-message-29856

Conversation

@briandevans

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes the misleading success message from hermes skills reset <name> (no --restore) when the user's local copy of a bundled skill genuinely differs from the bundled version.

Today, plain reset always returns:

Cleared manifest entry for '<name>'. Future hermes update runs will re-baseline against your current copy and accept upstream changes.

But the implementation only re-baselines when dir_hash(dest) == bundled_hash. For genuinely modified skills, sync_skills falls into the new-skill-collision branch (tools/skills_sync.py:204), skips the skill, and refuses to poison the manifest. The manifest stays empty, the next sync prints the same "yours was kept. Run hermes skills reset {name}" message (tools/skills_sync.py:222) — and the user runs the exact same command that just told them updates would resume. That's the loop the issue describes.

Mirrors the runtime resolver reset_bundled_skill -> sync_skills: the success message now reflects which branch sync_skills actually took, and every user-facing surface that recommends reset (CLI --help, TUI /skills reset usage line) now points at --restore for modified copies.

Related Issue

Fixes #29856

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • tools/skills_sync.pyreset_bundled_skill(restore=False) now re-reads the manifest after the resync and returns a new manifest_cleared_local_preserved action with an honest message when the local copy differs from bundled. The sync_skills collision hint now suggests hermes skills reset --restore <name> instead of plain reset.
  • hermes_cli/main.pyhermes skills reset --help text updated to mirror the runtime: re-baseline path for byte-identical copies, --restore path for modified copies.
  • hermes_cli/skills_hub.py — TUI /skills reset usage block updated identically.
  • tests/tools/test_skills_sync.py — new test test_reset_on_genuinely_modified_skill_reports_preserved covers the bug repro from the issue (modified copy → must report preserved-with-restore). Existing test_collision_prints_reset_hint updated to assert the --restore suggestion.

How to Test

  1. Reproduce the bug on main:
    # In a fresh ~/.hermes, sync first, then edit a bundled skill:
    hermes  # runs sync_skills() automatically
    echo " # local edit" >> ~/.hermes/skills/productivity/google-workspace/SKILL.md
    hermes  # should now print "~ google-workspace (user-modified, skipping)"
    hermes skills reset google-workspace
    # Today: "Cleared manifest entry... Future updates will accept upstream changes."
    hermes  # should still print "~ google-workspace (user-modified, skipping)" — bug
  2. Apply this PR and re-run:
    hermes skills reset google-workspace
    # Now: "Cleared manifest entry... your local copy differs from the bundled
    # version, so it remains preserved and will not receive upstream updates.
    # Use `hermes skills reset --restore google-workspace` to revert..."
    hermes skills reset --restore google-workspace
    # "Restored 'google-workspace' from bundled source." — actually works.
  3. Focused tests:
    uv run --with pytest --with pytest-xdist --with pytest-asyncio --with pytest-timeout python3 -m pytest tests/tools/test_skills_sync.py -v
    
    46 passed locally (Python 3.11, macOS 15).

Regression guard

Without tools/skills_sync.py changes, both test_reset_on_genuinely_modified_skill_reports_preserved and the updated test_collision_prints_reset_hint fail with the expected old messages, confirming each test is actually checking the fixed behavior:

AssertionError: assert 'hermes skills reset --restore new-skill' in
  '... Run `hermes skills reset new-skill` to replace it with the bundled version.\n...'

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run focused tests for the touched code and all pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS 15.x

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — N/A; the runtime help text in hermes_cli/main.py and hermes_cli/skills_hub.py IS the user-facing doc, and both are updated.
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A (no config changes)
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — pure-Python messaging change, no platform-specific paths.
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A (no tool schema changes)

Audited siblings: website/scripts/generate-skill-docs.py:484 already points users at reset <name> --restore for missing bundled skills (covered by tests/website/test_generate_skill_docs.py:116), so the website docs are already consistent. No further widening needed.

Copilot AI review requested due to automatic review settings May 21, 2026 14:19

Copilot AI 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.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR improves the UX and correctness of hermes skills reset by clarifying when a plain reset can re-baseline bundled-skill tracking vs. when a user’s modified copy will remain preserved (and skipped) unless --restore is used.

Changes:

  • Update collision hint messaging to recommend hermes skills reset --restore <name> instead of looping with plain reset.
  • Refine reset_bundled_skill(..., restore=False) to report whether the skill was actually re-baselined or remains preserved/skipped.
  • Add/adjust tests and CLI help text to reflect the corrected semantics.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
tools/skills_sync.py Adjusts reset messaging logic and collision hint to point users to --restore when needed.
tests/tools/test_skills_sync.py Updates hint assertion and adds a regression test for the “modified copy remains preserved” reset behavior.
hermes_cli/skills_hub.py Updates /skills reset usage guidance to match new behavior.
hermes_cli/main.py Updates argparse help/description to accurately describe reset vs. restore semantics.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tools/skills_sync.py
Comment on lines +415 to +430
manifest_after = _read_manifest()
if name in manifest_after:
action = "manifest_cleared"
message = (
f"Cleared manifest entry for '{name}'. Future `hermes update` runs "
f"will re-baseline against your current copy and accept upstream changes."
)
else:
action = "manifest_cleared_local_preserved"
message = (
f"Cleared manifest entry for '{name}', but your local copy differs "
f"from the bundled version, so it remains preserved and will not "
f"receive upstream updates. Use "
f"`hermes skills reset --restore {name}` to revert to the shipped "
f"version."
)
Comment thread tools/skills_sync.py
Comment on lines +423 to +430
action = "manifest_cleared_local_preserved"
message = (
f"Cleared manifest entry for '{name}', but your local copy differs "
f"from the bundled version, so it remains preserved and will not "
f"receive upstream updates. Use "
f"`hermes skills reset --restore {name}` to revert to the shipped "
f"version."
)
Comment thread tools/skills_sync.py
f"will re-baseline against your current copy and accept upstream changes."
)
else:
action = "manifest_cleared_local_preserved"
@alt-glitch alt-glitch added type/bug Something isn't working comp/cli CLI entry point, hermes_cli/, setup wizard tool/skills Skills system (list, view, manage) P2 Medium — degraded but workaround exists labels May 21, 2026
@briandevans briandevans force-pushed the fix/skills-reset-honest-message-29856 branch 4 times, most recently from 9aa7293 to 2380b93 Compare May 29, 2026 04:10
@briandevans briandevans force-pushed the fix/skills-reset-honest-message-29856 branch 2 times, most recently from 0973c62 to 24affbb Compare June 2, 2026 22:14
…s from bundled

`reset_bundled_skill(restore=False)` always returned the same upbeat message
("Future `hermes update` runs will re-baseline against your current copy and
accept upstream changes."), but for user-modified skills the next sync hits
the new-skill-collision branch, skips the skill, and never writes a manifest
entry — so future updates keep skipping it and printing "yours was kept. Run
`hermes skills reset {name}`", which is exactly the loop the user just took.

Fix:
- `reset_bundled_skill` now reads the manifest after the re-sync and only
  reports `manifest_cleared` when the entry was actually re-baselined. When
  the local copy differs from bundled, it returns a new
  `manifest_cleared_local_preserved` action with a message that says the
  local copy is preserved and points at `--restore` to overwrite it.
- `sync_skills` collision hint now suggests `hermes skills reset --restore`
  instead of plain `reset`, since plain `reset` falls into this same branch
  again for any divergent copy.
- CLI `hermes skills reset --help` and TUI `/skills reset` usage block were
  describing the same misleading "stops marking it as user-modified"
  framing; both are corrected to mirror the runtime behavior.

Refs NousResearch#29856.
@briandevans briandevans force-pushed the fix/skills-reset-honest-message-29856 branch from 24affbb to 30aafbd Compare June 5, 2026 23:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P2 Medium — degraded but workaround exists 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]: hermes skills reset <name> without --restore returns misleading success message for user-modified bundled skills

3 participants