fix(skills): resolve claude-code marketplaces and commands compatibility#599
Merged
Conversation
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.
3 tasks
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.
Summary
ExternalSkillsConfig.ResolveEnabledSourcesnow resolves theclaude-codealias to all of the following:~/.claude/skills~/.claude/commands~/.claude/plugins/marketplaces/*/skills/~/.claude/commandssupport 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.ProbeWellKnownSourcesnow detects marketplace-only Claude installs.Why
Two grounding issues needed to be solved together:
~/.claude/commandswas 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-codewell-known catalog includes both~/.claude/skillsand~/.claude/commands.claude-codeonly..mdfiles is enabled only when scanning a resolved path that is exactly~/.claude/commands.ProbeWellKnownSourcesnow 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 passingdotnet test src/Netclaw.Actors.Tests/Netclaw.Actors.Tests.csproj --filter 'FullyQualifiedName~SkillScannerTests|FullyQualifiedName~SkillRegistryTests'— 59 passingdotnet test src/Netclaw.Daemon.Tests/Netclaw.Daemon.Tests.csproj --filter 'FullyQualifiedName~SystemSkillSyncServiceTests|FullyQualifiedName~SessionCatalogServiceTests'— 32 passingdotnet test src/Netclaw.Cli.Tests/Netclaw.Cli.Tests.csproj --filter 'FullyQualifiedName~ExternalSkillsStepViewModelTests|FullyQualifiedName~WizardConfigBuilderTests'— 28 passingdotnet build— clean, 0 warnings, 0 errorsdotnet slopwatch analyze— cleanNew / updated tests
ExternalSkillsConfigTestsnow covers:skills + commandswhen no marketplaces are presentSkillScannerTestsnow covers:ScanAndMergebehavior: compatibility applies to~/.claude/commandsbut not arbitrary external pathsRelated follow-ups (milestone 0.12)
Filed separately — these aren't in this PR:
SkillIndexEnrichmentServicefails silently, trigger phrase cache emptynetclaw statsskills_loaded resets on daemon restart — read from daily_stats instead #593 —netclaw statsskills_loadedresets on daemon restart — read fromdaily_statsinsteadskill_loadtool calls #594 —skills_loadedcounter ignores agent-initiatedskill_loadtool calls