Skip to content

Support agent-plugins-spec v1.0.0 format - #135

Merged
yourconscience merged 6 commits into
mainfrom
plugin-support
Aug 8, 2026
Merged

Support agent-plugins-spec v1.0.0 format#135
yourconscience merged 6 commits into
mainfrom
plugin-support

Conversation

@yourconscience

@yourconscience yourconscience commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Summary

  • Consume plugin.json manifests from external_skills sources for richer metadata (name, version, author, license) and opt-in mcp.json MCP server discovery
  • Ship a skills-only plugin.json at the repo root so dotagents is itself consumable by any Agent Plugins v1 client
  • Add plugins as the fifth sync surface (skills, MCP servers, hooks, agent roles, plugins)
  • Codex native plugin projection (.codex-plugin/) tracked as planned for follow-up
  • Graceful degradation: invalid plugin.json disables metadata/MCP only, skill discovery is unaffected

Details

New config fields on external_skills entries:

  • mcp: true -- opt-in to discover stdio MCP servers from the source's mcp.json
  • mcp_agents: [claude-code, codex] -- optional target subset for plugin-derived MCP servers

Plugin consumer behavior:

  • Detects plugin.json at external source root, parses/validates per spec v1.0.0
  • Discovers stdio MCP servers from mcp.json with ${PLUGIN_ROOT} / ${PLUGIN_DATA} placeholder expansion
  • Skips unsupported transports (streamable-http, sse) and servers with cwd (not representable in dotagents' MCP config)
  • User-configured MCP servers always win over plugin-derived ones
  • Plugin name stored as display metadata in lock file, identity stays as repoName(url)

dotagents as a plugin:

  • plugin.json at repo root makes ~/.agents/skills/* discoverable by any Agent Plugins v1 client
  • Included in starter assets via go:embed

Documentation updates:

  • AGENTS.md: plugins added as fifth surface, packaging ban removed
  • README.md: five surfaces, Plugins column in harness table (Codex: planned)
  • PLUGIN-SUPPORT-DESIGN.md: updated status and scope

Test plan

  • Manifest parsing: minimal, full, invalid names, unknown fields, non-object extensions, author validation
  • MCP discovery: stdio servers, cwd rejection, reserved env, unsupported transports, schema mismatch, command containment, server name validation
  • Placeholder expansion: single-pass (no recursive), adversarial nested case
  • Injection: opt-in enforcement, user-wins collision, MCPAgents targeting
  • Full existing test suite passes (zero regressions)

Consume plugin.json manifests from external_skills sources for richer
metadata (name, version, author, license) and opt-in mcp.json MCP server
discovery. Ship a skills-only plugin.json at the repo root so dotagents
is itself consumable by any Agent Plugins v1 client.

New config fields: mcp (bool, opt-in) and mcp_agents on external_skills
entries. Plugin-mode sources with default skill_dir tolerate missing
skills/ (MCP-only plugins). Lock file gains plugin_name/plugin_version.
@sourcery-ai

sourcery-ai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds support for Agent Plugins v1.0.0 plugin.json and mcp.json manifests, including parsing/validation, MCP server discovery/injection, relaxed external skill discovery semantics for plugin-only sources, and embedding a plugin.json so dotagents itself can be consumed as a plugin.

Sequence diagram for plugin-based MCP server injection during config load

sequenceDiagram
    participant CLI
    participant loadContext
    participant injectPluginMCPServers
    participant parsePluginManifest
    participant discoverPluginMCPServers

    CLI->>loadContext: loadContext(opts)
    loadContext->>injectPluginMCPServers: injectPluginMCPServers(&cfg, home)

    injectPluginMCPServers->>injectPluginMCPServers: externalCacheDir(home), externalDataDir(home)
    injectPluginMCPServers->>injectPluginMCPServers: build existingNames from cfg.MCPServers

    loop each cfg.ExternalSkills src
        injectPluginMCPServers->>injectPluginMCPServers: check src.MCP
        injectPluginMCPServers->>injectPluginMCPServers: repoName(src.URL), hasDir(cachePath+"/.git")
        injectPluginMCPServers->>injectPluginMCPServers: hasPluginManifest(cachePath)
        injectPluginMCPServers->>parsePluginManifest: parsePluginManifest(cachePath)
        parsePluginManifest-->>injectPluginMCPServers: manifest, ok
        injectPluginMCPServers->>injectPluginMCPServers: os.MkdirAll(pluginDataPath)
        injectPluginMCPServers->>discoverPluginMCPServers: discoverPluginMCPServers(cachePath, manifest.Schema, pluginDataPath)
        discoverPluginMCPServers-->>injectPluginMCPServers: []mcpServerConfig, problems
        injectPluginMCPServers->>injectPluginMCPServers: apply src.MCPAgents to servers
        injectPluginMCPServers->>injectPluginMCPServers: collect servers by name
    end

    injectPluginMCPServers->>injectPluginMCPServers: skip servers conflicting with existingNames
    injectPluginMCPServers->>injectPluginMCPServers: skip servers declared by multiple sources
    injectPluginMCPServers->>injectPluginMCPServers: append remaining servers to cfg.MCPServers

    loadContext-->>CLI: home, contextDir, cfg, agents
Loading

File-Level Changes

Change Details Files
Persist plugin metadata in the lock file for external skills.
  • Extend externalLockEntry with plugin_name and plugin_version fields.
  • During lock rebuild, detect plugin.json in the cached external repo, parse it, and record plugin name/version when valid.
cmd/dotagents/lock.go
Introduce MCP-related configuration and validation for external skill sources.
  • Add mcp and mcp_agents fields to externalSkillSource.
  • Validate mcp_agents against known agents, normalizing names and warning or dropping entries for agents without MCP support.
cmd/dotagents/main.go
cmd/dotagents/config.go
Relax external skill discovery errors when plugin.json indicates a plugin-only source.
  • Detect plugin-based sources that use the default skills directory and allow them to have missing/empty skills directories without error.
  • Gate this behavior behind hasPluginManifest and a specific skillDir/skillDirs configuration.
cmd/dotagents/external.go
cmd/dotagents/pluginmcp.go
Implement plugin.json parsing and validation according to agent-plugins-spec v1.0.0.
  • Add a pluginManifest type and parser that enforces schema ID, name pattern/length rules, and basic field typing.
  • Track unknown top-level and extensions fields for diagnostics while treating them as non-fatal, and enforce strict validation of author subfields.
  • Expose a hasPluginManifest helper for use by other components.
cmd/dotagents/pluginspec.go
cmd/dotagents/pluginspec_test.go
Implement discovery and injection of plugin-provided MCP servers from mcp.json.
  • Add a JSON model for mcp.json and a discoverPluginMCPServers function that only accepts stdio servers, validates schema version, names, commands, and env, and performs placeholder expansion for PLUGIN_ROOT/PLUGIN_DATA.
  • Introduce injectPluginMCPServers, which scans external skills with mcp: true, derives MCP servers from their mcp.json, applies MCPAgents targeting, and merges them into cfg.MCPServers with user-configured servers taking precedence and conflict/warning handling.
  • Create an external-data directory for per-plugin data roots and ensure commands cannot escape the plugin root.
cmd/dotagents/pluginmcp.go
cmd/dotagents/pluginmcp_test.go
Make dotagents itself consumable as an Agent Plugins v1 plugin.
  • Add a top-level plugin.json to the repo and include it in the embedded starter assets so it is installed alongside other config artifacts.
starter_assets.go
plugin.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 3 issues, and left some high level feedback:

  • isPluginRelaxedSource relies on the literal "skills" for the default skill directory, which could silently diverge from future config defaults; consider centralizing this default in one place or reusing existing helpers/constants.
  • parsePluginManifest treats any unknown field in the author object as a hard failure while unknown top-level fields are tolerated, which may be too strict for real-world manifests; consider aligning author handling with the more permissive top-level unknown-field behavior.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- isPluginRelaxedSource relies on the literal "skills" for the default skill directory, which could silently diverge from future config defaults; consider centralizing this default in one place or reusing existing helpers/constants.
- parsePluginManifest treats any unknown field in the author object as a hard failure while unknown top-level fields are tolerated, which may be too strict for real-world manifests; consider aligning author handling with the more permissive top-level unknown-field behavior.

## Individual Comments

### Comment 1
<location path="cmd/dotagents/config.go" line_range="189-198" />
<code_context>
 		}
 		seenExt[name] = struct{}{}
+
+		if src.MCP && len(src.MCPAgents) > 0 {
+			kept := src.MCPAgents[:0]
+			for _, agentName := range src.MCPAgents {
+				agentName = normalizeAgentName(agentName)
+				if agentName == "" {
+					continue
+				}
+				if len(seen) > 0 {
+					if _, ok := seen[agentName]; !ok {
+						return fmt.Errorf("config external_skills repo %q mcp_agents targets unknown agent %q", name, agentName)
+					}
+				}
+				if !hasMCPSupport(agentName) {
+					fmt.Fprintf(os.Stderr, "warning: config external_skills repo %q mcp_agents targets agent %q without MCP support; target ignored\n", name, agentName)
+					continue
+				}
+				kept = append(kept, agentName)
+			}
+			src.MCPAgents = kept
+		}
 	}
</code_context>
<issue_to_address>
**issue (bug_risk):** Filtering MCPAgents on the range variable does not update cfg.ExternalSkills

Because the loop ranges over `cfg.ExternalSkills` by value (`for _, src := range cfg.ExternalSkills`), `src` is a copy and `src.MCPAgents = kept` does not update `cfg.ExternalSkills`. The MCPAgents filtering/normalization is therefore discarded and `cfg.ExternalSkills[i].MCPAgents` remains unvalidated. To persist the changes, range by index and update the slice element (e.g. `for i := range cfg.ExternalSkills { src := &cfg.ExternalSkills[i]; src.MCPAgents = kept }`) or otherwise assign back into `cfg.ExternalSkills`.
</issue_to_address>

### Comment 2
<location path="cmd/dotagents/pluginmcp_test.go" line_range="311-320" />
<code_context>
+func TestInjectPluginMCPServersWithOptIn(t *testing.T) {
</code_context>
<issue_to_address>
**suggestion (testing):** Add a test to verify MCPAgents targeting is correctly applied when injecting plugin MCP servers.

Currently the new `MCPAgents` field on `externalSkillSource` is only exercised indirectly. Please add a variant of this test where `src.MCPAgents` is set (e.g. `[]string{"claude-code", "codex"}`) and assert that the injected `mcpServerConfig.Agents` is populated with that filtered list, to validate end-to-end agent targeting for plugin-derived servers.

Suggested implementation:

```golang
func TestInjectPluginMCPServersWithOptIn(t *testing.T) {
	home := t.TempDir()
	cacheRoot := filepath.Join(home, ".agents", "external")
	pluginDir := filepath.Join(cacheRoot, "test-plugin")

	makeGitDir(t, pluginDir)
	writePluginJSON(t, pluginDir, `{
		"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
		"name": "test-plugin"
	}`)
	writeMCPJSON(t, pluginDir, `{
		"$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
		"name": "test-plugin-mcp",
		"command": "test-plugin-mcp",
		"args": ["run"],
		"env": {
			"FOO": "BAR"
		}
	}`)

	// Base config with plugin opt-in enabled.
	cfg := Config{
		MCP: true,
		ExternalSkills: []externalSkillSource{
			{
				Directory: cacheRoot,
				OptIn:     []string{"test-plugin"},
			},
		},
	}

	// First scenario: no MCPAgents specified, servers should be injected but with no agent targeting.
	injectPluginMCPServers(&cfg, home)
	if len(cfg.MCPServers) != 1 {
		t.Fatalf("expected 1 MCP server when mcp: true and plugin opted in, got %d", len(cfg.MCPServers))
	}

	server := cfg.MCPServers[0]
	if server.Name != "test-plugin-mcp" {
		t.Fatalf("expected MCP server name %q, got %q", "test-plugin-mcp", server.Name)
	}
	if len(server.Agents) != 0 {
		t.Fatalf("expected injected MCP server to have no agent targeting by default, got %v", server.Agents)
	}

	// Second scenario: specify MCPAgents on the externalSkillSource and verify end-to-end agent targeting.
	cfg = Config{
		MCP: true,
		ExternalSkills: []externalSkillSource{
			{
				Directory:  cacheRoot,
				OptIn:      []string{"test-plugin"},
				MCPAgents:  []string{"claude-code", "codex"},
				PluginName: "test-plugin",
			},
		},
	}

	injectPluginMCPServers(&cfg, home)
	if len(cfg.MCPServers) != 1 {
		t.Fatalf("expected 1 MCP server when mcp: true and plugin opted in with MCPAgents, got %d", len(cfg.MCPServers))
	}

	server = cfg.MCPServers[0]
	expectedAgents := []string{"claude-code", "codex"}
	if !reflect.DeepEqual(server.Agents, expectedAgents) {
		t.Fatalf("expected injected MCP server Agents %v, got %v", expectedAgents, server.Agents)
	}

```

The above edit assumes the following, which you should align with your actual codebase:

1. `Config` has fields `MCP bool`, `ExternalSkills []externalSkillSource`, and `MCPServers []mcpServerConfig` (or similar), and the test file already imports `reflect`. If not, add `import "reflect"` at the top of `cmd/dotagents/pluginmcp_test.go`.
2. `externalSkillSource` has fields `Directory`, `OptIn`, `MCPAgents`, and possibly `PluginName`. If `PluginName` is not needed in your implementation, you can remove it from the test setup; if it has a different name, adjust accordingly.
3. `mcpServerConfig` (or the type used for `cfg.MCPServers`) has fields `Name string` and `Agents []string`. If naming differs, update the test accordingly.
4. If the existing `TestInjectPluginMCPServersWithOptIn` already contains assertions, merge the new scenarios rather than overwriting. The intent is to:
   - Keep the current “opt-in only” behavior assertion.
   - Add a second scenario where `src.MCPAgents` is populated and assert that the resulting `cfg.MCPServers[0].Agents` matches the given list.
</issue_to_address>

### Comment 3
<location path="cmd/dotagents/pluginmcp_test.go" line_range="345-354" />
<code_context>
+func TestInjectPluginMCPServersUserWins(t *testing.T) {
</code_context>
<issue_to_address>
**suggestion (testing):** Add coverage for the case where multiple plugins declare the same MCP server name.

There’s another collision path where two external sources declare the same MCP server name and are skipped with a warning. Please add a test that configures two `ExternalSkills` entries with `MCP: true`, each plugin exposing an `mcp.json` with the same `mcpServers` key, and assert that no additional servers are added to `cfg.MCPServers`. This will cover the multi-source conflict resolution behavior.

Suggested implementation:

```golang
func TestInjectPluginMCPServersUserWins(t *testing.T) {
	home := t.TempDir()
	cacheRoot := filepath.Join(home, ".agents", "external")

	// First plugin exposing an MCP server named "test-server"
	pluginDir1 := filepath.Join(cacheRoot, "test-plugin-1")
	makeGitDir(t, pluginDir1)
	writePluginJSON(t, pluginDir1, `{
		"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
		"name": "test-plugin-1"
	}`)
	writeMCPJSON(t, pluginDir1, `{
		"$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
		"mcpServers": {
			"test-server": {
				"command": ["echo", "plugin-1"],
				"args": [],
				"env": {}
			}
		}
	}`)

	// Second plugin also exposing an MCP server with the same name "test-server"
	pluginDir2 := filepath.Join(cacheRoot, "test-plugin-2")
	makeGitDir(t, pluginDir2)
	writePluginJSON(t, pluginDir2, `{
		"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
		"name": "test-plugin-2"
	}`)
	writeMCPJSON(t, pluginDir2, `{
		"$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
		"mcpServers": {
			"test-server": {
				"command": ["echo", "plugin-2"],
				"args": [],
				"env": {}
			}
		}
	}`)

	// User configuration already declares an MCP server named "test-server"
	cfg := Config{
		MCPServers: []MCPServer{
			{
				Name: "test-server",
				// other fields (e.g. Command, Args, Env) can be populated as needed
			},
		},
		ExternalSkills: []ExternalSkillConfig{
			{
				Name: "test-plugin-1",
				MCP:  true,
				// fields pointing to pluginDir1 as appropriate for your config type
			},
			{
				Name: "test-plugin-2",
				MCP:  true,
				// fields pointing to pluginDir2 as appropriate for your config type
			},
		},
	}

	injectPluginMCPServers(&cfg, home)

	// Assert that no additional servers are added from the two plugins.
	// The user-configured server should "win" and remain the only entry.
	if len(cfg.MCPServers) != 1 {
		t.Fatalf("expected 1 MCP server when user config declares %q and multiple plugins collide, got %d", "test-server", len(cfg.MCPServers))
	}
	if cfg.MCPServers[0].Name != "test-server" {
		t.Errorf("server name = %q, want %q", cfg.MCPServers[0].Name, "test-server")
	}
}

```

To integrate this test with the rest of the codebase, you will likely need to:

1. Adjust the `Config`, `MCPServer`, and `ExternalSkillConfig` types to match your actual configuration structures:
   - Replace `Config` with the real root config type used by `injectPluginMCPServers`.
   - Replace `MCPServer` with the actual type of entries in `cfg.MCPServers` (and set any required fields beyond `Name`).
   - Replace `ExternalSkillConfig` and its fields (`Name`, `MCP`, etc.) with the correct type/field names for external skills.
2. Ensure that each `ExternalSkills` entry correctly points at `pluginDir1` and `pluginDir2`:
   - Depending on your existing tests, you may need fields like `Path`, `CacheDir`, `Source`, or similar to associate the config entry with the plugin directory created under `cacheRoot`.
3. Confirm that `injectPluginMCPServers` is using the same collision semantics this test expects:
   - When a user-configured MCP server exists with a given name, any MCP servers with the same name coming from *any* plugins (including multiple plugins) should be skipped, leaving `cfg.MCPServers` unchanged except for the already-configured entry.
4. If you’d prefer not to repurpose `TestInjectPluginMCPServersUserWins` for the multi-source collision case, you can instead move this new test body into a separate function, e.g. `TestInjectPluginMCPServersMultiSourceCollisionUserWins`, and restore the original single-plugin behavior in `TestInjectPluginMCPServersUserWins`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread cmd/dotagents/config.go
Comment thread cmd/dotagents/pluginmcp_test.go
Comment thread cmd/dotagents/pluginmcp_test.go

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6c1f6f9e34

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread starter_assets.go
Comment thread cmd/dotagents/config.go Outdated
@yourconscience
yourconscience force-pushed the plugin-support branch 2 times, most recently from ea264c9 to fbb5d52 Compare August 8, 2026 12:15

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dae325f767

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread cmd/dotagents/pluginmcp.go
Comment thread cmd/dotagents/external.go
@yourconscience
yourconscience merged commit a5c9a11 into main Aug 8, 2026
4 checks passed
@yourconscience
yourconscience deleted the plugin-support branch August 8, 2026 13:06

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9766803c93

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread AGENTS.md
- dotagents syncs exactly four surfaces: skills, MCP servers, hooks, and agent roles.
- Plugin packaging, plugin delivery modes, and native-plugin projection are intentionally unsupported.
- dotagents syncs exactly five surfaces: skills, MCP servers, hooks, agent roles, and plugins.
- Plugins follow the agent-plugins-spec v1.0.0 format. For harnesses with native plugin systems (Codex), dotagents projects spec-format plugins into the native format. Claude Code plugins (`.claude/plugins/*.ts`) are a planned addition.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Implement Codex native plugin projection before claiming support

For any spec-format external plugin used with Codex, a repo-wide search finds no .codex-plugin writer or adapter; this change only extracts skills and MCP servers, while the README explicitly calls native projection planned. Consequently dotagents does not sync the declared plugin surface for the repository's native-plugin harness, so either implement the projection or keep the invariant marked as planned. Fresh evidence relative to the earlier comment is that the final tree now explicitly requires Codex native projection rather than prohibiting it.

AGENTS.md reference: AGENTS.md:L15-L16

Useful? React with 👍 / 👎.

Comment thread cmd/dotagents/config.go
}
kept = append(kept, agentName)
}
src.MCPAgents = kept

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Do not broaden rejected MCP targets to every harness

When every requested target is filtered out, such as mcp_agents: [pi], this assignment leaves MCPAgents empty; injectPluginMCPServers then treats the empty slice as the default and leaves each derived server's Agents empty, which desiredMCPServersForAgent interprets as all MCP-capable harnesses. A configuration intended only for an unsupported target therefore installs the plugin server into unrelated Codex, Claude, or other harness configurations despite warning that the target was ignored.

Useful? React with 👍 / 👎.

Comment thread cmd/dotagents/sync.go
return err
}
// Re-inject after clone so first sync picks up newly fetched plugins.
injectPluginMCPServers(&cfg, home)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Skip plugin MCP injection when the cache is off its pin

When refreshing a materialized external source fails, syncExternalRepos may continue after warning that it is keeping committed skill copies; if the existing cache is at a different commit, this unconditional injection then reads that off-pin cache's plugin.json and mcp.json and writes its commands into native harness configuration. This lets an ordinary sync expose unreviewed external executable configuration instead of limiting agents to the lock-selected tree, so unavailable sources must be excluded from MCP injection or their cache HEAD must be verified against the prior pin first.

AGENTS.md reference: AGENTS.md:L20-L20

Useful? React with 👍 / 👎.

Comment thread README.md
| Hermes | yes | -- | yes | yes |
| OpenCode | yes† | yes | yes | -- |
| Pi* | yes | --* | --* | -- |
5. **Plugins** — external sources with an [agent-plugins-spec](https://agent-plugins.org) `plugin.json` get their skills and MCP servers discovered automatically. Native plugin projection (Codex `.codex-plugin/`) is planned.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Document the plugin MCP opt-in across user-facing guides

For users following this new description, MCP discovery is not automatic: MCP defaults to false and injectPluginMCPServers skips the source unless its YAML entry includes mcp: true, but neither this README section nor the shipped skills/dotagents/SKILL.md documents that option or mcp_agents (the skill still describes four surfaces). Such users will configure a valid plugin source and never receive its MCP servers; document the opt-in and keep the starter skill and release-site copy consistent.

AGENTS.md reference: AGENTS.md:L48-L50

Useful? React with 👍 / 👎.

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