Skip to content

feat(skills): add stats/archive/restore/prune CLI subcommands#19454

Closed
elmatadorgh wants to merge 2 commits into
NousResearch:mainfrom
elmatadorgh:feat/skills-cli-stats-archive-restore-prune
Closed

feat(skills): add stats/archive/restore/prune CLI subcommands#19454
elmatadorgh wants to merge 2 commits into
NousResearch:mainfrom
elmatadorgh:feat/skills-cli-stats-archive-restore-prune

Conversation

@elmatadorgh
Copy link
Copy Markdown
Contributor

Closes #19384

Summary

Adds the four user-facing CLI verbs requested in #19384, exposing the curator's existing tools/skill_usage.py telemetry through hermes skills:

  • hermes skills stats [--days N] — ranked usage table (uses, views, patches, last activity, idle days, state, pinned)
  • hermes skills archive — archive a skill; refuses if pinned, hints at hermes curator unpin
  • hermes skills restore — restore from .archive/
  • hermes skills prune [--days N] [--yes] [--dry-run] — bulk-archive idle skills (default 90 days)

All four handlers are thin wrappers over functions that already exist on main: agent_created_report(), archive_skill(), restore_skill(), get_record(). No new storage, no curator behavior changes, no per-message ranking added to the system prompt.

Notes

  • Pinning (PR feat(skills): refuse skill_manage writes on pinned skills #17562) is honored: archive refuses pinned skills with a hint pointing at hermes curator unpin , and prune filters them out.
  • prune falls back to created_at when last_activity_at is null, so never-used skills can be pruned (otherwise they'd be immortal).
  • --days 0 and negative values rejected with exit code 2 (argparse-style user error).
  • archive and restore exit non-zero on failure for shell-script friendliness; prune reports per-skill results in a summary line.
  • Rich is imported lazily inside _cmd_stats to keep hermes --help fast, with a plain-text fallback if rich is unavailable.

Relationship to #4406

@fathah's #4406 prototyped the same CLI surface against an older SQLite-based curator design. The CLI shape here mirrors that work; the storage backend uses the merged tools/skill_usage.py (sidecar JSON) instead. The ranking/keyword-relevance pieces from #4406 are intentionally not included, per the issue.

Tests

  • 8 argparse smoke tests added to tests/hermes_cli/test_skills_subparser.py
  • 22 handler tests in new tests/hermes_cli/test_skills_lifecycle.py covering empty/non-empty reports, --days filtering, sort order, pinned refusal, dry-run, confirmation prompts, exclusion rules, and the created_at fallback for never-used skills

tests/hermes_cli/test_skills_subparser.py: 14 passed
tests/hermes_cli/test_skills_lifecycle.py: 22 passed

No regressions in the broader tests/hermes_cli/ run; pre-existing Windows console / missing-deps failures unaffected.

Manual smoke test

Tested on Windows (WSL2 / PowerShell), Python 3.11. hermes skills stats on a workspace with 23 agent-created skills renders the rich table correctly. hermes skills --help and each subcommand's --help render without traceback.

How to test

Run the new tests:

pytest tests/hermes_cli/test_skills_subparser.py tests/hermes_cli/test_skills_lifecycle.py -v

Smoke test the CLI:

hermes skills --help
hermes skills stats
hermes skills prune --dry-run --days 30

The pinned-skill refusal can be exercised by pinning a skill via hermes curator pin first, then running hermes skills archive — should refuse with a hint pointing at hermes curator unpin.

…search#19384)

User-facing CLI for the existing curator (tools/skill_usage.py).
Backed by agent_created_report() / archive_skill() / restore_skill() —
no parallel storage, no per-message ranking, no behavior change to the
agent prompt path.

  hermes skills stats   [--days N]
  hermes skills archive <name>
  hermes skills restore <name>
  hermes skills prune   [--days 90] [--yes] [--dry-run]

Pinned skills (PR NousResearch#17562) are exempt from prune and archive refuses on
them, with a hint pointing at `hermes curator unpin`. References
fathah's NousResearch#4406, which prototyped the same surface against an older
SQLite-based curator design.
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/cli CLI entry point, hermes_cli/, setup wizard tool/skills Skills system (list, view, manage) labels May 4, 2026
teknium1 added a commit that referenced this pull request May 5, 2026
* fix(curator): protect hub skills by frontmatter name

* test(skill_usage): add mark_agent_created to regression test

The cherry-picked test predates #19618/#19621 which rewrote
list_agent_created_skill_names() to require an explicit
created_by: 'agent' provenance marker. Without mark_agent_created(),
my-skill is excluded from the list and the positive assertion fails.

* feat(curator): add archive and prune subcommands

Adds 'hermes curator archive <skill>' and 'hermes curator prune
[--days N] [--yes] [--dry-run]' alongside the existing status, run,
pause, resume, pin, unpin, restore, backup, rollback verbs.

These are the two genuinely new user-facing verbs requested in #19384.
The other verbs proposed there ('stats' and 'restore') already exist
as 'curator status' and 'curator restore', so no duplicate surface is
added — all skill lifecycle commands live under the single 'hermes
curator' namespace.

- archive: manual archive of an agent-created skill. Refuses pinned
  skills with a hint pointing at 'hermes curator unpin'.
- prune: bulk-archive unpinned skills idle for >= N days (default 90).
  Falls back to created_at when last_activity_at is null so never-used
  skills can still be pruned. --dry-run previews, --yes skips prompt.

Adapted from @elmatadorgh's PR #19454 which placed the same verbs
under 'hermes skills' with a separate hermes_cli/skills_config.py
handler and rich table for stats. The 'stats' and 'restore' parts of
that PR duplicated existing surface, so only archive and prune are
kept, rewritten to match hermes_cli/curator.py's existing plain-text
handler style. Tests rewritten from scratch against the new handlers.

Closes #19384

Co-authored-by: elmatadorgh <coktinbaran5@gmail.com>

---------

Co-authored-by: LeonSGP43 <cine.dreamer.one@gmail.com>
Co-authored-by: elmatadorgh <coktinbaran5@gmail.com>
@teknium1
Copy link
Copy Markdown
Contributor

teknium1 commented May 5, 2026

Adapted and merged via PR #20200 (#20200), closing #19384.

The new verbs — hermes curator archive and hermes curator prune — live under the existing hermes curator namespace instead of a parallel hermes skills surface. The stats and restore parts of your PR duplicated existing curator status and curator restore commands (which landed after the issue was written), so only the two genuinely new verbs were kept, rewritten to match hermes_cli/curator.py's plain-text handler style.

Your authorship is preserved via Co-authored-by: elmatadorgh <coktinbaran5@gmail.com> on the squash commit (436672d). AUTHOR_MAP entry added. Thanks for driving this to a working implementation!

@teknium1 teknium1 closed this May 5, 2026
chris-han pushed a commit to chris-han/hermes-agent that referenced this pull request May 6, 2026
* fix(curator): protect hub skills by frontmatter name

* test(skill_usage): add mark_agent_created to regression test

The cherry-picked test predates NousResearch#19618/NousResearch#19621 which rewrote
list_agent_created_skill_names() to require an explicit
created_by: 'agent' provenance marker. Without mark_agent_created(),
my-skill is excluded from the list and the positive assertion fails.

* feat(curator): add archive and prune subcommands

Adds 'hermes curator archive <skill>' and 'hermes curator prune
[--days N] [--yes] [--dry-run]' alongside the existing status, run,
pause, resume, pin, unpin, restore, backup, rollback verbs.

These are the two genuinely new user-facing verbs requested in NousResearch#19384.
The other verbs proposed there ('stats' and 'restore') already exist
as 'curator status' and 'curator restore', so no duplicate surface is
added — all skill lifecycle commands live under the single 'hermes
curator' namespace.

- archive: manual archive of an agent-created skill. Refuses pinned
  skills with a hint pointing at 'hermes curator unpin'.
- prune: bulk-archive unpinned skills idle for >= N days (default 90).
  Falls back to created_at when last_activity_at is null so never-used
  skills can still be pruned. --dry-run previews, --yes skips prompt.

Adapted from @elmatadorgh's PR NousResearch#19454 which placed the same verbs
under 'hermes skills' with a separate hermes_cli/skills_config.py
handler and rich table for stats. The 'stats' and 'restore' parts of
that PR duplicated existing surface, so only archive and prune are
kept, rewritten to match hermes_cli/curator.py's existing plain-text
handler style. Tests rewritten from scratch against the new handlers.

Closes NousResearch#19384

Co-authored-by: elmatadorgh <coktinbaran5@gmail.com>

---------

Co-authored-by: LeonSGP43 <cine.dreamer.one@gmail.com>
Co-authored-by: elmatadorgh <coktinbaran5@gmail.com>
nickdlkk pushed a commit to nickdlkk/hermes-agent that referenced this pull request May 11, 2026
* fix(curator): protect hub skills by frontmatter name

* test(skill_usage): add mark_agent_created to regression test

The cherry-picked test predates NousResearch#19618/NousResearch#19621 which rewrote
list_agent_created_skill_names() to require an explicit
created_by: 'agent' provenance marker. Without mark_agent_created(),
my-skill is excluded from the list and the positive assertion fails.

* feat(curator): add archive and prune subcommands

Adds 'hermes curator archive <skill>' and 'hermes curator prune
[--days N] [--yes] [--dry-run]' alongside the existing status, run,
pause, resume, pin, unpin, restore, backup, rollback verbs.

These are the two genuinely new user-facing verbs requested in NousResearch#19384.
The other verbs proposed there ('stats' and 'restore') already exist
as 'curator status' and 'curator restore', so no duplicate surface is
added — all skill lifecycle commands live under the single 'hermes
curator' namespace.

- archive: manual archive of an agent-created skill. Refuses pinned
  skills with a hint pointing at 'hermes curator unpin'.
- prune: bulk-archive unpinned skills idle for >= N days (default 90).
  Falls back to created_at when last_activity_at is null so never-used
  skills can still be pruned. --dry-run previews, --yes skips prompt.

Adapted from @elmatadorgh's PR NousResearch#19454 which placed the same verbs
under 'hermes skills' with a separate hermes_cli/skills_config.py
handler and rich table for stats. The 'stats' and 'restore' parts of
that PR duplicated existing surface, so only archive and prune are
kept, rewritten to match hermes_cli/curator.py's existing plain-text
handler style. Tests rewritten from scratch against the new handlers.

Closes NousResearch#19384

Co-authored-by: elmatadorgh <coktinbaran5@gmail.com>

---------

Co-authored-by: LeonSGP43 <cine.dreamer.one@gmail.com>
Co-authored-by: elmatadorgh <coktinbaran5@gmail.com>
rmulligan pushed a commit to rmulligan/hermes-agent that referenced this pull request May 11, 2026
* fix(curator): protect hub skills by frontmatter name

* test(skill_usage): add mark_agent_created to regression test

The cherry-picked test predates NousResearch#19618/NousResearch#19621 which rewrote
list_agent_created_skill_names() to require an explicit
created_by: 'agent' provenance marker. Without mark_agent_created(),
my-skill is excluded from the list and the positive assertion fails.

* feat(curator): add archive and prune subcommands

Adds 'hermes curator archive <skill>' and 'hermes curator prune
[--days N] [--yes] [--dry-run]' alongside the existing status, run,
pause, resume, pin, unpin, restore, backup, rollback verbs.

These are the two genuinely new user-facing verbs requested in NousResearch#19384.
The other verbs proposed there ('stats' and 'restore') already exist
as 'curator status' and 'curator restore', so no duplicate surface is
added — all skill lifecycle commands live under the single 'hermes
curator' namespace.

- archive: manual archive of an agent-created skill. Refuses pinned
  skills with a hint pointing at 'hermes curator unpin'.
- prune: bulk-archive unpinned skills idle for >= N days (default 90).
  Falls back to created_at when last_activity_at is null so never-used
  skills can still be pruned. --dry-run previews, --yes skips prompt.

Adapted from @elmatadorgh's PR NousResearch#19454 which placed the same verbs
under 'hermes skills' with a separate hermes_cli/skills_config.py
handler and rich table for stats. The 'stats' and 'restore' parts of
that PR duplicated existing surface, so only archive and prune are
kept, rewritten to match hermes_cli/curator.py's existing plain-text
handler style. Tests rewritten from scratch against the new handlers.

Closes NousResearch#19384

Co-authored-by: elmatadorgh <coktinbaran5@gmail.com>

---------

Co-authored-by: LeonSGP43 <cine.dreamer.one@gmail.com>
Co-authored-by: elmatadorgh <coktinbaran5@gmail.com>
JinyuID pushed a commit to JinyuID/hermes-agent that referenced this pull request May 11, 2026
* fix(curator): protect hub skills by frontmatter name

* test(skill_usage): add mark_agent_created to regression test

The cherry-picked test predates NousResearch#19618/NousResearch#19621 which rewrote
list_agent_created_skill_names() to require an explicit
created_by: 'agent' provenance marker. Without mark_agent_created(),
my-skill is excluded from the list and the positive assertion fails.

* feat(curator): add archive and prune subcommands

Adds 'hermes curator archive <skill>' and 'hermes curator prune
[--days N] [--yes] [--dry-run]' alongside the existing status, run,
pause, resume, pin, unpin, restore, backup, rollback verbs.

These are the two genuinely new user-facing verbs requested in NousResearch#19384.
The other verbs proposed there ('stats' and 'restore') already exist
as 'curator status' and 'curator restore', so no duplicate surface is
added — all skill lifecycle commands live under the single 'hermes
curator' namespace.

- archive: manual archive of an agent-created skill. Refuses pinned
  skills with a hint pointing at 'hermes curator unpin'.
- prune: bulk-archive unpinned skills idle for >= N days (default 90).
  Falls back to created_at when last_activity_at is null so never-used
  skills can still be pruned. --dry-run previews, --yes skips prompt.

Adapted from @elmatadorgh's PR NousResearch#19454 which placed the same verbs
under 'hermes skills' with a separate hermes_cli/skills_config.py
handler and rich table for stats. The 'stats' and 'restore' parts of
that PR duplicated existing surface, so only archive and prune are
kept, rewritten to match hermes_cli/curator.py's existing plain-text
handler style. Tests rewritten from scratch against the new handlers.

Closes NousResearch#19384

Co-authored-by: elmatadorgh <coktinbaran5@gmail.com>

---------

Co-authored-by: LeonSGP43 <cine.dreamer.one@gmail.com>
Co-authored-by: elmatadorgh <coktinbaran5@gmail.com>
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 P3 Low — cosmetic, nice to have tool/skills Skills system (list, view, manage) type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(curator): user-facing CLI for skill usage stats, archive/restore, and prune

3 participants