Skip to content

fix(skills): resolve claude-code marketplaces and commands compatibility#599

Merged
Aaronontheweb merged 4 commits into
devfrom
claude-wt-skills-loading
Apr 11, 2026
Merged

fix(skills): resolve claude-code marketplaces and commands compatibility#599
Aaronontheweb merged 4 commits into
devfrom
claude-wt-skills-loading

Conversation

@Aaronontheweb

@Aaronontheweb Aaronontheweb commented Apr 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • ExternalSkillsConfig.ResolveEnabledSources now resolves the claude-code alias to all of the following:
    • ~/.claude/skills
    • ~/.claude/commands
    • every installed marketplace under ~/.claude/plugins/marketplaces/*/skills/
  • Restores ~/.claude/commands support and handles it correctly: command markdown files without YAML frontmatter are accepted only for the Claude commands path, matching current Claude Code behavior where commands are treated as skills.
  • Keeps deterministic source resolution and probe behavior: marketplace paths are normalized, deduped, and sorted for stable precedence; ProbeWellKnownSources now detects marketplace-only Claude installs.

Why

Two grounding issues needed to be solved together:

  1. Marketplace skills (e.g. dotnet-skills) were missing from Netclaw's resolved external sources, so agents could not see highly relevant C#/.NET skills.
  2. Dropping ~/.claude/commands was incorrect now that Claude Code treats command files as skills. Netclaw should mirror that behavior, but without globally relaxing flat-file validation.

Implementation notes

  • claude-code well-known catalog includes both ~/.claude/skills and ~/.claude/commands.
  • Marketplace enumeration remains dynamic and scoped to claude-code only.
  • Compatibility parsing for frontmatterless flat .md files is enabled only when scanning a resolved path that is exactly ~/.claude/commands.
    • Non-commands paths still require valid YAML frontmatter for flat files.
  • ProbeWellKnownSources now aligns with resolution behavior and can detect marketplace-only setups.

Test plan

  • dotnet test src/Netclaw.Configuration.Tests/Netclaw.Configuration.Tests.csproj --filter FullyQualifiedName~ExternalSkillsConfigTests — 17 passing
  • dotnet test src/Netclaw.Actors.Tests/Netclaw.Actors.Tests.csproj --filter 'FullyQualifiedName~SkillScannerTests|FullyQualifiedName~SkillRegistryTests' — 59 passing
  • dotnet test src/Netclaw.Daemon.Tests/Netclaw.Daemon.Tests.csproj --filter 'FullyQualifiedName~SystemSkillSyncServiceTests|FullyQualifiedName~SessionCatalogServiceTests' — 32 passing
  • dotnet test src/Netclaw.Cli.Tests/Netclaw.Cli.Tests.csproj --filter 'FullyQualifiedName~ExternalSkillsStepViewModelTests|FullyQualifiedName~WizardConfigBuilderTests' — 28 passing
  • dotnet build — clean, 0 warnings, 0 errors
  • dotnet slopwatch analyze — clean
  • Live daemon restart verification: ensure commands load as skills and marketplace inventory appears as expected

New / updated tests

ExternalSkillsConfigTests now covers:

  • Claude resolves skills + commands when no marketplaces are present
  • Commands + marketplaces resolve together
  • Stable deterministic ordering across skills/commands/marketplaces
  • Commands surfaced by probe when skills dir is missing
  • Marketplace-only probe detection

SkillScannerTests now covers:

  • frontmatterless flat-file acceptance in compatibility mode
  • rejection of frontmatterless flat files outside compatibility mode
  • heading-based display/description inference
  • empty-file rejection in compatibility mode
  • ScanAndMerge behavior: compatibility applies to ~/.claude/commands but not arbitrary external paths

Related follow-ups (milestone 0.12)

Filed separately — these aren't in this PR:

ExternalSkillsConfig.ResolveEnabledSources now enumerates every
installed Claude Code plugin marketplace under
~/.claude/plugins/marketplaces/*/skills/ whenever the claude-code
well-known source is being resolved. On a typical dev machine this
picks up 33 skills from the dotnet-skills marketplace
(akka-best-practices, csharp-coding-standards, csharp-concurrency-
patterns, efcore-patterns, slopwatch, and more) plus anything else
installed, so agents working in C#/.NET sessions can actually see
skills relevant to the task instead of guessing at skill_load names.

The version cache under ~/.claude/plugins/cache/ is intentionally
skipped: Claude Code reads the live marketplace path at runtime, and
scanning the cache would double-count every skill. The enumeration is
dynamic rather than driven by known_marketplaces.json so we stay
decoupled from Claude Code's metadata format.

Also drops ~/.claude/commands from the claude-code well-known catalog.
Those files are Claude Code user slash commands with a different
frontmatter schema — scanning them was producing ~25
FlatFileMissingFrontmatter warnings on every sync rebuild with no
skills recovered, hiding real degraded-inventory signals in the
daemon log.

Expected effect on a daemon restart against a machine with
dotnet-skills installed: "accepted=62 rejected=31" shifts to roughly
"accepted=~95 rejected=~6".

Tests:
- ExternalSkillsConfigTests rewritten to cover the new marketplace
  expansion (no-marketplaces, multi-marketplace, skip marketplaces
  missing a skills/ subdir, marketplace-only when the primary
  .claude/skills is absent, no crash when the marketplaces root is
  missing, expansion scoped to the claude-code alias only) plus a
  regression case that ProbeWellKnownSources never surfaces
  ~/.claude/commands.
- SkillRegistryTests multi-path example updated to use a marketplace
  path instead of the removed commands path.
- SkillDirectoryWatcherService comment reflects the new semantics.

Grounding follow-ups tracked under milestone 0.12: #591 feed 404s,
#592 enrichment silent failure, #593 stats counter restart reset,
#594 skill_load tool counter gap.
Post-review cleanup on 9e3600a:

- WellKnownCatalog now references ClaudeCodeAlias instead of the bare
  string literal, so the catalog entry and the dynamic-expansion branch
  in ResolveEnabledSources share a single source of truth.
- Dropped the DirectoryNotFoundException catch in
  EnumerateClaudeCodeMarketplaceSkillPaths. The Directory.Exists
  pre-check already handles the missing-root case, and the remaining
  TOCTOU race window on a cold startup path isn't worth a silent
  fallback. UnauthorizedAccessException is kept because permissions
  are a real operational condition.
- Trimmed the XML doc on the marketplace helper to keep only the
  non-obvious "why": why filesystem is the source of truth (not
  known_marketplaces.json) and why the version cache is skipped.
- Removed three narration comments from the test file that just
  restated the test names.
@Aaronontheweb Aaronontheweb changed the title fix(skills): resolve claude-code plugin marketplaces, drop commands scan fix(skills): resolve claude-code marketplaces and commands compatibility Apr 11, 2026
@Aaronontheweb Aaronontheweb merged commit a9c1135 into dev Apr 11, 2026
3 checks passed
@Aaronontheweb Aaronontheweb deleted the claude-wt-skills-loading branch April 11, 2026 16:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant