Skip to content

Discover skills from installed Claude Code plugins on the desktop - #571

Merged
sambitcreate merged 8 commits into
mainfrom
feature/plugin-skill-discovery
Oct 31, 2026
Merged

sambitcreate merged 8 commits into
mainfrom
feature/plugin-skill-discovery

Conversation

@sambitcreate

@sambitcreate sambitcreate commented Oct 21, 2026 •

Copy link
Copy Markdown
Owner

🤖 Generated with Claude Code

https://claude.ai/code/session_018VA6RFoM21JGeMe45njSXW


Update 2026-10-31 (backlog cleanup): the owner chose to keep only the desktop half. The CLI part (--add-dir skill folders and CLI plugin skills) is removed, because the CLI is becoming a headless server (#675). main is merged in (README clash fixed), the CLI-only discoverPluginSkillCandidates export and its test calls are gone, and docs/skills.md now says the CLI does not read installed plugins. Local checks on 890e3df: root typecheck, CI policy, skills-discovery + onboarding-flow (52) and skills-settings (3) tests pass.


Desktop skill discovery now includes enabled installed Claude Code plugins. Plugin skills keep namespaced identities (plugin:name), bounded reads, existing precedence, and workspace permission checks.

Explicit manifest skills: "." and "./" collections scan recursively under existing bounds; implicit root fallback remains direct-only.

Limits: default Claude configuration paths, exact canonical workspace matching, and no parent/worktree installation inheritance. Existing native catalog contracts are reused (phones only see the longer plugin:name display name; their tests were updated). Physical-device acceptance was not performed.

Flaky test record (2026-10-31): head ca575b6 hit tests/e2e/chat-message-queue.spec.ts:719 "messages sent during compaction queue behind it and survive a failed compaction" in Electron E2E (3/3). The chat showed "This chat could not be loaded" and Queue message stayed disabled. It passed on retry, but --fail-on-flaky-tests fails the job. This is the known chat-reload flake family, and this PR does not touch chats or the queue. Failed job. A main merge (d04b0a9) replaced that run before the rerun.

Head d04b0a9 hit main/services/bot-runtime/live-projection.test.ts "while classifying fails, a cached routine stays hidden…" ("retries are throttled, saw 3 calls") in macOS Desktop tests (runtime-subagents). This PR doesn't touch Bot runtime code. The root cause is a real retry-timer bug, fixed in #683. Failed job. A review fix (33ceb3e) replaced that run before the rerun.


Generated by Claude Code

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

Two reproduced edge cases need attention: root-declared skill collections are missed, and CLI invocation-policy filtering can expose a shadowed plugin implementation.

Reviewed changes Local installed-plugin discovery and additional CLI skill directories, including their permission, precedence, and invocation-policy integration.

  • Plugin inventory: Bounded local metadata reads, layered enablement, exact workspace matching, namespaced identities, and integration with desktop discovery budgets.
  • CLI integration: Trusted plugin publication, repeated launch-relative --add-dir options, automatic-discovery gates, and native/explicit skill precedence.
  • User-facing contracts: Settings and onboarding copy, discovery documentation, CLI help, and namespaced-name fixtures for both native clients.
  • Validation: CLI build, desktop and CLI typechecks, and 110 focused tests passed; independent filesystem and built-CLI RPC probes reproduced both inline findings.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using gpt-6.1-sol | 𝕏

Comment thread packages/cli/scripts/build.mjs Resolved

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes Reviewed f7785ca against the previously reviewed ba4b53e, with the full PR diff checked for context.

  • Restored root collections: Allowed explicitly declared skills: "." and "./" collections to scan recursively while retaining the direct-only implicit fallback and existing containment limits.
  • Preserved policy precedence: Claimed the winning CLI plugin identity before invocation-policy filtering, preventing a shadowed implementation from becoming available.
  • Extended behavioral coverage: Added discovery and built-CLI regression assertions for both fixes and documented their behavior. Both earlier review findings are addressed; their threads were already resolved.
  • Verified the delta: Passed 57 discovery/registry tests and 25 built CLI runtime/path tests, plus the CLI build and typecheck. No repository changes were made.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

@very-hermes-bot

very-hermes-bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Hermes Review Bot

Confidence: 4

Engine: opencode/opencode-go/deepseek-v4.1-flash
Review mode: medium
Head: 86c44ba343f70447197e1e413ef16ed80573d1ee
Generated: 2026-10-31T16:18:53+00:00
Reviews: 1

Summary

Desktop skill discovery now also reads enabled, installed Claude Code plugins: main/services/claude-plugin-skill-roots.ts resolves ~/.claude/plugins/installed_plugins.json, merges enabledPlugins from user and active-workspace settings, selects the first applicable install record per plugin key, and returns bounded search roots. main/services/skills-discovery.ts scans those roots and prefixes each authored name with the plugin namespace, with plugin skills sorted below ordinary folders inside the same workspace/global source so authored skills still win. The manifest skills paths are containment-checked, symlinks are rejected, and named SKILL.md files are read at depth 0 while the implicit root fallback stays direct-only. Docs, onboarding, settings copy, and the iOS/Android catalog fixtures were updated to reflect the longer plugin:name display name. A maintainer should double-check the untested manifest path shapes (a manifest that explicitly names a collection) and the fact that managed/synced Claude inventory variants beyond the documented four scopes are not exercised by the new tests.

Confidence Score: 4/5

Traced discovery through SkillRegistry, Bot inventory, Telegram, and the CLI's separate discovery path; verified phone codecs accept the colon name and that the new tests' temp homes actually exercise the roots. Remaining uncertainty is limited to Claude inventory variants and physical-device acceptance, which the PR explicitly leaves out.

📁 Important Files Changed
  • main/services/claude-plugin-skill-roots.ts (new) — reads plugin inventory/settings/manifests, applies workspace matching and namespace/scope rules, and produces bounded search configs.
  • main/services/skills-discovery.ts — adds plugin roots to the authoritative scan, namespaces plugin names, enforces the 80-character identity bound, and adds the baseSkill depth-0 rule.
  • main/services/skills-discovery.test.ts — new behavioral coverage for enablement, scope/permission, manifest containment, symlink rejection, root fallback, and malformed metadata.
  • docs/skills.md, README.md, PRODUCT.md — document plugin discovery, precedence, limits, and the desktop-only scope.
  • renderer/components/settings/skills-settings.tsx, renderer/components/onboarding-feature-gallery.tsx, renderer/components/onboarding-flow.test.tsx — user-facing copy and its rendering assertion.
  • ios/AidenOnTheGoTests/AidenChatTests.swift, android/.../AidenSkillTest.kt — show the existing contract accepts a namespaced display name; no production mobile code changed.

Findings

No findings.

📊 Sequence Diagram
sequenceDiagram
    participant C as Chat/composer
    participant R as SkillRegistry
    participant D as skills-discovery
    participant P as claudePluginSkillRoots
    participant FS as Filesystem
    C->>R: snapshot(workspaceId)
    R->>D: discoverSkillCandidates(workspaceRoot or undefined)
    D->>P: claudePluginSkillRoots(home, workspaceRoot)
    P->>FS: read installed_plugins.json + settings*.json + plugin.json
    P-->>D: bounded plugin roots + namespace + scope
    D->>FS: scan SKILL.md under ordinary and plugin roots
    D-->>R: candidates (namespaced, prioritized)
    R-->>C: catalog/available skills after collision resolution
Loading

Machine-Readable Findings

[]

Last reviewed commit: 86c44ba343f7
Reviews (1) · Comment /hermes review to trigger a new review · /hermes review full for full re-review

Drop the CLI half (--add-dir and CLI plugin skills): the CLI is becoming a headless server, so the owner chose desktop-only. Removes the CLI-only discoverPluginSkillCandidates export and updates docs/skills.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VA6RFoM21JGeMe45njSXW
@sambitcreate sambitcreate changed the title Discover skills from installed plugins and additional CLI directories Discover skills from installed Claude Code plugins on the desktop Oct 31, 2026

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes Reviewed the changes since f7785ca, focusing on the desktop-only scope after the merge of main.

  • Removed CLI additions: Removed installed-plugin discovery, additional-directory options, and their CLI integration and tests while preserving existing CLI skill discovery.
  • Retained desktop coverage: Removed the CLI-only discovery export and updated tests to keep exercising desktop root collections, deduplication, containment, and malformed metadata handling.
  • Clarified supported scope: Updated the skill guide to explicitly distinguish desktop plugin discovery from standalone CLI behavior.
  • Validated the delta: Passed 86 focused desktop tests and 26 built-CLI runtime/path tests, both typechecks, and the CLI build. Electron and native mobile runtime suites were not rerun; their behavior is unchanged by this delta.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

@very-hermes-bot very-hermes-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline review — 1 finding(s) anchored to the diff. See the pinned summary comment for the overview.

claudePluginSkillRoots now uses fs/promises with the same no-follow and size limits, and resolves the home and workspace paths once per call instead of once per install record.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VA6RFoM21JGeMe45njSXW

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes Reviewed aa4d673 against the previously reviewed 890e3df, focusing on the asynchronous plugin-metadata discovery path.

  • Moved metadata I/O off the main thread: Converted metadata opens, descriptor reads, cleanup, and canonical-path resolution to fs/promises, with awaited results throughout the discovery call chain.
  • Preserved discovery semantics: Retained bounded reads, no-follow/nonblocking open flags, ordered installation selection, layered enablement, and exact canonical workspace matching; resolved home/workspace paths once per call.
  • Validated the integration: Passed all 57 focused discovery and registry tests and the root TypeScript check. Electron responsiveness benchmarks and native mobile runtime suites were not run; this delta changes no mobile or wire contracts.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

@very-hermes-bot very-hermes-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline review — 1 finding(s) anchored to the diff. See the pinned summary comment for the overview.

Comment thread main/services/skills-discovery.ts Resolved
plugin:name could pass the 80-character skill name limit and show up as an unavailable Invalid skill. Discovery now skips such a plugin skill; docs/skills.md says so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VA6RFoM21JGeMe45njSXW

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes Reviewed ca575b6 against the previously reviewed aa4d673, focusing on the plugin skill name-length fix.

  • Omitted overlong plugin identities: Added a discovery-time check for composed plugin:name values exceeding 80 code points after NFKC, preventing those candidates from appearing as unavailable “Invalid skill” entries while leaving ordinary skill validation unchanged.
  • Extended coverage and documentation: Added an overlong plugin-name fixture that verifies valid neighboring skills remain discoverable, and documented the omission rule in docs/skills.md.
  • Validated the integration: Passed all 64 focused discovery, registry, and catalog-validation tests and the root TypeScript check. Electron and native mobile runtime suites were not rerun; this delta changes no wire contracts or client implementations.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

@very-hermes-bot very-hermes-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline review — 1 finding(s) anchored to the diff. See the pinned summary comment for the overview.

A plugin manifest that names a SKILL.md was scanned as its parent folder
to depth 12, so it also imported every nested skill beside it. A named
SKILL.md is now read at depth 0. The collection test checks that an
undeclared nested skill stays out, and docs/skills.md says so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VA6RFoM21JGeMe45njSXW

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes Reviewed the manifest-file traversal fix in 33ceb3e against d04b0a9; the intervening main merge had already been reviewed separately.

  • Restricted named-file discovery: Limited explicit SKILL.md paths to a depth-zero search, retaining the named skill without importing nested skills while preserving recursive directory and root-collection declarations.
  • Extended behavioral coverage and documentation: Added an undeclared nested-skill fixture that verifies file-only discovery and documented that distinction in docs/skills.md.
  • Validated the integration: Passed all 65 focused discovery, registry, and catalog-validation tests and the root TypeScript check. Electron and native mobile runtime suites were not rerun; this delta changes no UI or wire contracts.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

@very-hermes-bot very-hermes-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline review — 1 finding(s) anchored to the diff. See the pinned summary comment for the overview.

Comment thread main/services/skills-discovery.ts Resolved
… catalog

The namespace flag let every plugin search take a depth-0 SKILL.md, so a
skills/SKILL.md in the standard collection became a 'plugin:skills' skill.
Ordinary roots and Claude Code count only <name>/SKILL.md there. Each search
now says whether its base may itself be a skill: the root fallback and
manifest-named paths may, the standard collection may not.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VA6RFoM21JGeMe45njSXW

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes Reviewed 86c44ba against the previously reviewed 33ceb3e, focusing on collection-root skill eligibility.

  • Separated collection and skill bases: Replaced namespace-wide base-file eligibility with a per-search baseSkill flag, excluding the standard skills/SKILL.md while retaining explicit manifest paths and the root fallback.
  • Extended behavioral coverage: Added a collection-level SKILL.md fixture whose exact catalog assertion verifies exclusion while retaining ordinary nested skills, custom paths, and the root skill.
  • Validated the integration: Passed all 65 focused discovery, registry, and catalog-validation tests and the root TypeScript check. Electron and native mobile runtime suites were not rerun; this delta changes no UI or wire contracts.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

@sambitcreate
sambitcreate merged commit fd0c262 into main Oct 31, 2026
25 checks passed
@sambitcreate
sambitcreate deleted the feature/plugin-skill-discovery branch October 31, 2026 18:07
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.

3 participants