Skills mounted from skills.external_dirs are externally authored, but every
provenance surface flattened them into 'agent': the usage report, the
dashboard's set-based twin, the desktop catalog/detail UI, and the learning
journey graph (where a used external mount rendered as a learned skill).
- tools/skill_usage: provenance() gains an 'external' tier (external-only:
a local copy of the same name keeps winning, mirroring is_agent_created's
external exclusion and _external_skill_names() scans external dirs once
for the router's set-based twin.
- web_routers/skills: /api/skills classifies hub > bundled > external > agent.
- learning_graph: skills whose path resolves under an external dir are tagged
source='external' and are never learning milestones — a mount is configured,
not learned, even when used.
- desktop: SkillInfo.provenance gains 'external'; the catalog labels mounts
'external' and the detail pane keeps them editable in place. Origin only,
never mutability: read-only enforcement for external mounts was deliberately
rejected by maintainers (commit 8c8fc6c1ec / PR #17512 — a refusal just
breeds silent local duplicates). Provenance decisions extracted into
skill-provenance.ts pure helpers (testable without source-reading tests).
- curator: usage report/filter knows the 'external' origin.
The desktop edit logic in this commit is the natural reading of 8c8fc6c1ec
(external dirs exist so the user can point Hermes at a vault they curate
elsewhere); if maintainers prefer the read-only half as well, it slots in
behind isEditableProvenance() in one place.
EOF
)