Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ tmp
.github/copilot-instructions.md
.github/copilot-instructions.md.bak.*
.mcp.json
!tests/fixtures/plugin-marketplace/plugins/engineering/.mcp.json
.opencode/command
.opencode/command.bak.*
.opencode/command/
Expand Down
56 changes: 45 additions & 11 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ clap = { version = "4.5", features = ["derive", "env"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", features = ["preserve_order"] }
toml = "1.0"
toml_edit = "0.22.27"
serde_yaml = "0.9"
regex = "1"
chrono = { version = "0.4", features = ["serde"] }
Expand Down
42 changes: 42 additions & 0 deletions openspec/changes/2026-08-23-plugin-materialization/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Design: Repository-owned plugin materialization

## Configuration

`[plugins]` is disabled by default for backwards compatibility. Marketplaces are named source
declarations and selections identify the plugin to resolve. Mutable references are accepted only
by explicit add/update operations.

The project lockfile is `.agents/plugins.lock.toml` by default. It uses schema `v1`, stable TOML
ordering, full Git commit SHAs or `local:<tree-sha256>` revisions, plugin tree hashes, per-skill
hashes, MCP names, and source provenance.

## Apply data flow

```text
agentsync.toml selection -> plugins.lock.toml -> source verification
-> marketplace manifest -> plugin component validation
-> skills materialized under .agents/skills
-> existing linker fan-out and MCP formatters
```

Apply is offline and fails closed when the lockfile, source, component set, or content hash does
not match. Add/update may resolve a GitHub reference and writes the lock atomically.
For Git sources, add/update also materialize a project-owned snapshot under
`.agents/.agentsync-plugin-sources`; apply/status/dry-run never download a source.

## Supported components

The first adapter accepts a vendor marketplace manifest at `.agents/plugins/marketplace.json` or
`.claude-plugin/marketplace.json`, a local plugin source, conventional skill directories, and a
root `.mcp.json` with `mcpServers`. AgentSync rejects plugin-level agents, commands, hooks, LSPs,
apps, and vendor-specific MCP fields instead of silently flattening them.

Plugin MCP names are namespaced as `plugin/<marketplace>/<plugin>/<server>`. They are merged with
explicit project servers only after collision checks and are never executed.

## Atomicity and safety

Skill copies reject symlinks and unsafe IDs/paths. Existing unmanaged skills are never replaced.
Plugin-owned replacements require matching registry provenance. Lockfile and config writes use
same-directory temporary files and atomic replacement. No vendor CLI, lifecycle hook, executable,
LSP, or MCP process is started.
21 changes: 21 additions & 0 deletions openspec/changes/2026-08-23-plugin-materialization/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Proposal: Repository-owned plugin materialization

## Intent

Provide a deterministic, vendor-neutral path from a selected marketplace plugin to AgentSync's
canonical skills and MCP configuration without relying on Claude or Codex user caches.

## Scope

In scope: typed marketplace/plugin selections, immutable project lockfile and provenance, local and
pinned GitHub sources, conventional `skills/<id>/SKILL.md` bundles, root `.mcp.json` declarations,
safe apply/update/remove/drift behavior, and Claude/Codex/Gemini/OpenCode fan-out.

Out of scope: vendor cache installation or enablement, hooks, scripts, binaries, LSPs, apps, and
execution of MCP servers.

## Compatibility

Existing skill registry metadata, installed-state JSON, symlink targets, and explicit
`[mcp_servers.*]` configuration remain supported. Plugin provenance is additive and the curated
maintainer registry is not reused as the project plugin lockfile.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Plugin Materialization

## Requirement: Locked project sources

AgentSync MUST require a valid project plugin lockfile before applying enabled selections. The lock
MUST contain an immutable Git commit or local content revision and content hashes.

### Scenario: Offline apply

- GIVEN a selected plugin with a valid local lock entry
- WHEN `agentsync apply` runs without network access
- THEN AgentSync verifies the source and materializes the locked content
- AND it MUST NOT resolve a new reference

### Scenario: Drift is rejected

- GIVEN a source or installed skill whose content differs from the lock
- WHEN apply or status runs
- THEN AgentSync reports drift and MUST NOT replace unmanaged content

## Requirement: Safe supported materialization

AgentSync MUST materialize only conventional skills and standard `.mcp.json` declarations. It MUST
reject unsupported lifecycle components and MUST NOT execute plugin content.

### Scenario: Skill fan-out

- GIVEN a locked plugin containing `skills/review/SKILL.md`
- WHEN apply succeeds
- THEN `.agents/skills/review/` contains the validated skill and references
- AND configured agent targets receive it through the existing linker

### Scenario: MCP fan-out

- GIVEN a locked plugin containing a valid root `.mcp.json`
- WHEN apply succeeds
- THEN the server is namespaced and generated through the existing agent formatters
- AND no MCP command is started

### Scenario: Unsupported component

- GIVEN a plugin containing hooks, agents, commands, apps, or LSP components
- WHEN add or update is requested
- THEN the operation fails explicitly before materialization
11 changes: 11 additions & 0 deletions openspec/changes/2026-08-23-plugin-materialization/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Tasks

- [x] Add typed plugin configuration and project lockfile model.
- [x] Add local/pinned GitHub source resolution and provenance/hash validation.
- [x] Add safe conventional skill discovery and materialization.
- [x] Merge plugin MCP declarations through the existing linker/generator path.
- [x] Add plugin CLI commands for add, update, list, status, and remove.
- [x] Add local marketplace fixtures and safety/drift integration tests.
- [x] Add broader CLI contract and supported-agent MCP fan-out coverage.
- [x] Complete plugin documentation and targeted repository validation.
- [ ] Complete the full repository suite after the existing catalog fixture checkout is restored.
1 change: 1 addition & 0 deletions src/commands/dev_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ pub(crate) mod fixtures {
gitignore: Default::default(),
mcp: Default::default(),
mcp_servers: Default::default(),
plugins: Default::default(),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod dev_bench;
pub mod doctor;
#[cfg(test)]
mod doctor_tests;
pub mod plugin;
pub mod skill;
pub mod status;
#[cfg(test)]
Expand Down
Loading
Loading