Fix Claude plugin marketplace and agent discovery - #2272
Conversation
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the Claude Code plugin packaging for the FinOps Toolkit so Claude’s marketplace entry points at the actual plugin root in this repo, and the Claude-specific manifest explicitly declares agents and MCP configuration (with strict mode enabled to keep the manifest authoritative).
Changes:
- Declare Claude plugin
agentsandmcpServersinsrc/templates/agent-plugin/.claude-plugin/plugin.json. - Update PowerShell unit tests to validate Claude manifest paths/components and enforce strict mode in the Claude marketplace entry.
- Fix the Claude marketplace
sourcepath to the repo’s real plugin root for Claude (./src/templates/agent-plugin) and enablestrict: true.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/templates/agent-plugin/.claude-plugin/plugin.json | Adds explicit Claude manifest fields for agents and MCP servers, aligning with supported schema fields. |
| src/powershell/Tests/Unit/AgentPlugins.Tests.ps1 | Updates/extends Pester tests to validate Claude manifest component declarations and strict mode configuration. |
| .claude-plugin/marketplace.json | Points Claude marketplace source at the correct plugin root and enables strict mode for the entry. |
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Roland Krummenacher (RolandKrummenacher)
left a comment
There was a problem hiding this comment.
Verified the premise empirically rather than by reading alone: installed both the dev and PR versions of the plugin into isolated CLAUDE_CONFIG_DIRs and compared claude plugin details, and reproduced the symlink-source failure in a scratch marketplace.
Confirmed:
- On
dev, the.agent.mdfilenames cause Claude to derive agent ids from the filename stem and ignore frontmattername:, so agents surface asazure-capacity-manager.agent,ftk-database-query.agent, etc. This PR's version correctly exposes 5 unsuffixed agents, 1 skill, 1 MCP server. - The
./plugins/microsoft-finops-toolkitsource is genuinely unusable on Windows checkouts (the git symlink materializes as a text file, so install fails withENOTDIR). claude plugin validate --strictpasses on both manifests, and the validator does reject unknown fields, sostrictis a recognized marketplace field.- All 24 Pester tests pass locally.
The fix works for Claude Code. My concern is what it costs on the other platform.
Renaming the agents breaks GitHub Copilot CLI discovery
(Left here rather than inline, since the five renames carry no diff hunks to anchor to.)
The root plugin.json exists specifically for Copilot and declares "agents": "./agents/". GitHub's plugin format requires NAME.agent.md, so dropping the suffix takes Copilot from 5 agents to 0 — while the changelog still describes the plugin as shared between Claude Code and Copilot CLI. Claude auto-discovers agents/ regardless of what the manifest says, so adding a second directory doesn't resolve this; the Copilot-suffixed variant probably needs to be generated at package time in Build-AgentPlugin.ps1.
README is now out of date
src/templates/agent-plugin/README.md:7 isn't in this PR, but it now contradicts both changes — it still says the plugin directory is "used by both marketplace manifests", and that Claude declares only its output style.
Remaining comments inline.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Roland Krummenacher (RolandKrummenacher)
left a comment
There was a problem hiding this comment.
Re-reviewed at 2a0755b. The intent here is right — pointing the marketplace source at a real directory instead of a symlink is a genuine fix, and the modified tests pass in a clean worktree (24/24). One blocker.
Blocking: the .agent.md → .md rename breaks Copilot CLI agent discovery
GitHub Copilot CLI requires the .agent.md extension to discover agents. The root plugin.json still declares "agents": "./agents/" for Copilot, and .github/plugin/marketplace.json exists solely to serve it — so after this change Copilot finds no agents at all. f3935ac (#2167) renamed these five files to .agent.md for exactly that reason.
The rename also isn't needed on the Claude side. Claude Code derives the subagent identifier from the front-matter name: field, and the docs state plainly that the filename doesn't have to match — so finops-practitioner.agent.md was already exposed as finops-practitioner, never finops-practitioner.agent.
Suggested resolution: keep .agent.md, and revert the test assertion that now enforces the opposite (inline comment below). If something in Claude discovery was genuinely failing, could you capture the actual failure? That would point at the real cause, which this rename may be masking rather than fixing.
One caveat on my side: the Copilot breakage is from its documentation and the stated intent of #2167 — I have not run Copilot CLI against this branch. If you have a run showing .agent.md files still being discovered there, that settles it and I'll withdraw the blocker.
Non-blocking
A symlink that is now unreferenced but still committed, and a README claim the branch doesn't actually deliver. Both inline.
Checked and cleared
Relative source paths do resolve from the repo root, so ./src/templates/agent-plugin is correct; dropping agents and mcpServers from .claude-plugin/plugin.json is fine because Claude auto-discovers both from the plugin root; all five agents' front-matter name: values match their new basenames.
|
@Brett Wilson (@MSBrett): you have some new feedback! Please review and resolve all comments and I'll let reviewers know by removing the |
Roland Krummenacher (RolandKrummenacher)
left a comment
There was a problem hiding this comment.
Withdrawing the blocker.
On the .agent.md naming: my condition was that the rename and its CI enforcement land together so nothing on the branch contradicts the convention. That holds — there are no remaining .agent.md references anywhere in the repo. Combined with your Copilot CLI 1.0.80 run against an isolated COPILOT_HOME, which discovered and invoked the agents from the plain NAME.md files, the naming question is settled for both hosts.
On the plugins/microsoft-finops-toolkit symlink: it's now unreferenced repo-wide, but it already exists on dev — this PR only orphans it rather than introducing it. That makes the cleanup optional here; happy for it to be a follow-up. Leaving the thread open so it doesn't get lost.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Michael Flanakin (flanakin)
left a comment
There was a problem hiding this comment.
🤖 [AI][Claude Code] PR Review
Summary: The core fix is right and verified — pointing both marketplace sources at a real directory resolves the Windows ENOTDIR install failure. All 24 Pester tests pass, claude plugin validate --strict is green on both manifests, every agent's front-matter name: matches its new basename, and no stale .agent.md or plugins/microsoft-finops-toolkit references remain anywhere in the repo. Four findings, none blocking.
⚠️ Should fix (2)
"strict": trueis the documented default, so it is a no-op — and the PR describes it as "strict marketplace validation," conflating it with the unrelatedclaude plugin validate --strictflag. A new test pins the redundant field into CI.- The README claims the manifests "avoid relying on repository symlink support," but the directory both manifests now point at still ships two committed symlinks that 186 references across the plugin's own agents, commands, and
SKILL.mddepend on.
💡 Suggestions (2)
Uses a cross-platform source path in both marketplacesasserts a literal string rather than the property that actually broke, so it does not guard against a future symlinked source.Declares resolvable paths for every Claude componentcovers only the explicitly declared components, not every one.
Changelog correctly skipped: v15 is unreleased (package.json is 15.0.0-dev.0, latest tag is v14) and the plugin was added in this same cycle, so this fixes something that never shipped.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
🛠️ Description
Correct the Claude Code marketplace source so it resolves to the repository's actual plugin root, enable strict marketplace validation, and load the shared agents through Claude's standard
agents/auto-discovery. Agent files now use plain.mdnames so Claude exposes the intended identifiers without an.agentsuffix. The MCP configuration remains declared explicitly.Validated against Anthropic's current documentation:
A clean installation from this PR's online branch with Claude Code CLI 2.1.235 reports one skill, five correctly named agents, and one MCP server.
Fixes # N/A
📷 Screenshots
N/A
📋 Checklist
🔬 How did you test this change?
Additional validation:
claude plugin validate . --strictclaude plugin validate src/templates/agent-plugin --strict📦 Deploy to test?
🙋♀️ Do any of the following that apply?
📑 Did you update
docs/changelog.md?📖 Did you update documentation?