feat(skills): show HUB badge on dashboard for skills synced from a source - #29312
Closed
cypres0099 wants to merge 1 commit into
Closed
feat(skills): show HUB badge on dashboard for skills synced from a source#29312cypres0099 wants to merge 1 commit into
cypres0099 wants to merge 1 commit into
Conversation
…urce
## What
Adds a small `HUB` badge next to skill names on the dashboard skills page
when a skill came from the hub (a tap, skills.sh, ClawHub, well-known, etc.)
rather than being bundled with Hermes or hand-authored locally. Hover the
badge to see the source adapter and identifier
(e.g. `github: owner/repo/path/to/skill`).
Builtin and local skills get no badge — the default visual stays clean.
## Why
The CLI's `hermes skills list` has always distinguished hub / builtin / local
via a `Source` column, but the dashboard collapses all three into a flat
list with no provenance. For users curating their own taps or marketplaces,
there's no way to tell at a glance which skills are syncing from upstream
vs. which they authored locally — until you hit a sync issue and have to
go looking.
This adds the same trichotomy the CLI already exposes, just on the dashboard.
## Implementation
Backend (`tools/skills_tool.py`):
- New `_load_skill_source_index()` helper snapshots `HubLockFile().list_installed()`
and the builtin manifest once per request. Both fail safe to empty — a
missing or corrupt lock file degrades source classification to `"local"`
rather than failing the whole skills listing.
- New `_classify_skill_source(name, hub_installed, builtin_names)` returns
`("hub" | "builtin" | "local", source_identifier_or_None)`. Hub wins over
builtin when both match (mirrors CLI precedence).
- `_find_all_skills()` calls the classifier once per discovered skill and
appends `source` + `source_identifier` to each returned dict.
API (`hermes_cli/web_server.py`): no change — the dict shape passes through
`/api/skills` transparently.
Frontend (`web/src/lib/api.ts`, `web/src/pages/SkillsPage.tsx`):
- `SkillInfo` gains optional `source?: "hub" | "builtin" | "local"` and
`source_identifier?: string | null`. Optional fields preserve backwards
compatibility with older dashboards talking to a newer gateway (and vice
versa).
- `SkillRow` renders `<Badge tone="secondary" className="text-[10px]">HUB</Badge>`
with a native `title` tooltip showing the source identifier — only when
`skill.source === "hub"`. No badge for builtin/local.
## Tests
`tests/tools/test_skills_tool.py`:
- New `TestClassifySkillSource` class covers all four classification cases
(hub with identifier, hub with empty identifier fallback, builtin, local)
plus the hub-shadows-builtin precedence rule.
- New `TestFindAllSkillsSourceAnnotation` class verifies the
`source`/`source_identifier` fields end up on the returned dicts for
each classification, including a mixed-set integration test.
226 existing skills_tool + skills_hub tests still pass; no TypeScript
errors or new lint warnings in the touched web files.
## Scope
Narrow, single concern. Not bundled:
- Filtering the dashboard skills list by source. The infrastructure is now
there if a future PR wants to add a source filter, but adding it now
would broaden the UI surface beyond a single badge.
- Changes to the CLI's `hermes skills list` — already has the trichotomy.
- Other dashboard pages that don't list skills.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
Author
|
Closing this for now to keep the upstream queue focused on the fixes and reviewed feature work with a clearer merge path. This branch is stale, has old failing CI, and has not received maintainer/reviewer feedback; the HUB badge can be reopened or resubmitted later if maintainers want this dashboard signal. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a small
HUBbadge next to skill names on the dashboard skills pagewhen a skill came from the hub (a tap, skills.sh, ClawHub, well-known, etc.)
rather than being bundled with Hermes or hand-authored locally. Hover the
badge to see the source adapter and identifier
(e.g.
github: owner/repo/path/to/skill).Builtin and local skills get no badge — the default visual stays clean.
Why
The CLI's
hermes skills listhas always distinguished hub / builtin / localvia a
Sourcecolumn, but the dashboard collapses all three into a flatlist with no provenance. For users curating their own taps or marketplaces,
there's no way to tell at a glance which skills are syncing from upstream
vs. which they authored locally — until you hit a sync issue and have to
go looking.
This adds the same trichotomy the CLI already exposes, just on the dashboard.
Implementation
Backend (
tools/skills_tool.py):_load_skill_source_index()helper snapshotsHubLockFile().list_installed()and the builtin manifest once per request. Both fail safe to empty — a
missing or corrupt lock file degrades source classification to
"local"rather than failing the whole skills listing.
_classify_skill_source(name, hub_installed, builtin_names)returns("hub" | "builtin" | "local", source_identifier_or_None). Hub wins overbuiltin when both match (mirrors CLI precedence).
_find_all_skills()calls the classifier once per discovered skill andappends
source+source_identifierto each returned dict.API (
hermes_cli/web_server.py): no change — the dict shape passes through/api/skillstransparently.Frontend (
web/src/lib/api.ts,web/src/pages/SkillsPage.tsx):SkillInfogains optionalsource?: "hub" | "builtin" | "local"andsource_identifier?: string | null. Optional fields preserve backwardscompatibility with older dashboards talking to a newer gateway (and vice
versa).
SkillRowrenders<Badge tone="secondary" className="text-[10px]">HUB</Badge>with a native
titletooltip showing the source identifier — only whenskill.source === "hub". No badge for builtin/local.Tests
tests/tools/test_skills_tool.py:TestClassifySkillSourceclass covers all four classification cases(hub with identifier, hub with empty identifier fallback, builtin, local)
plus the hub-shadows-builtin precedence rule.
TestFindAllSkillsSourceAnnotationclass verifies thesource/source_identifierfields end up on the returned dicts foreach classification, including a mixed-set integration test.
226 existing skills_tool + skills_hub tests still pass; no TypeScript
errors or new lint warnings in the touched web files.
Scope
Narrow, single concern. Not bundled:
there if a future PR wants to add a source filter, but adding it now
would broaden the UI surface beyond a single badge.
hermes skills list— already has the trichotomy.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com