Skip to content

feat(skills): show HUB badge on dashboard for skills synced from a source - #29312

Closed
cypres0099 wants to merge 1 commit into
NousResearch:mainfrom
cypres0099:feat/dashboard-skill-source-badge
Closed

feat(skills): show HUB badge on dashboard for skills synced from a source#29312
cypres0099 wants to merge 1 commit into
NousResearch:mainfrom
cypres0099:feat/dashboard-skill-source-badge

Conversation

@cypres0099

Copy link
Copy Markdown
Contributor

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

…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>
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have tool/skills Skills system (list, view, manage) comp/tui Terminal UI (ui-tui/ + tui_gateway/) labels May 20, 2026
@cypres0099

Copy link
Copy Markdown
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.

@cypres0099 cypres0099 closed this Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/tui Terminal UI (ui-tui/ + tui_gateway/) 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.

2 participants