Generate harness-specific plugin manifests from a single Agent Plugin spec source.
You edit one source (plugin.json + mcp.json). This tool derives the rest:
your-plugin-repo/
├── plugin.json ← you edit
├── mcp.json ← you edit
├── skills/ ← you write (optional)
│
├── gemini-extension.json generated (Gemini CLI)
├── mcp_config.json generated (Antigravity)
├── .claude-plugin/
│ └── plugin.json generated (Claude Code: manifest + MCP)
├── .codex-plugin/
│ ├── plugin.json generated (Codex: manifest)
│ └── .mcp.json generated (Codex: MCP + env_vars)
│
└── .github/workflows/
└── agent-plugin-sync.yml you add (calls this repo's CI)
| Harness | Reads | Generated by this tool |
|---|---|---|
| Gemini CLI | gemini-extension.json |
✅ |
| Claude Code | .claude-plugin/plugin.json |
✅ |
| Codex | .codex-plugin/ |
✅ |
| Antigravity | root plugin.json + mcp_config.json |
✅ |
Codex gets the legacy .codex-plugin/ layout because the spec mcp.json cannot
forward user environment variables; that also means the root plugin.json must
omit $schema, which validate enforces. See
docs/harness-plugin-layouts.md.
Marketplace files are out of scope: their shape differs between the single-repo and monorepo models.
You write one small file (step 2) that points back at this repo.
Not on PyPI yet, so run it straight from this repo. Replace VERSION with the
latest release, for
example 0.1.1. Use a release rather than main, which may be unreleased work.
uvx --from git+https://github.com/wangauone/agent-plugin-sync@VERSION \
agent-plugin-sync generate .Already have a gemini-extension.json and nothing else? Seed the source from it
once, then review the inferred fields:
uvx --from git+https://github.com/wangauone/agent-plugin-sync@VERSION \
agent-plugin-sync migrate .Add .github/workflows/agent-plugin-sync.yml to your repo. It calls the
reusable workflow here, so there is nothing to copy or keep in sync:
name: agent-plugin-sync
on: pull_request
jobs:
sync:
uses: wangauone/agent-plugin-sync/.github/workflows/sync.yml@VERSIONThe tag on that uses: line picks both the workflow and the tool version it
installs, so one pin covers both.
Set auto_sync to have it regenerate and push the fix instead of just failing.
Useful on Renovate PRs that bump an MCP server version:
jobs:
sync:
uses: wangauone/agent-plugin-sync/.github/workflows/sync.yml@VERSION
with:
auto_sync: true
permissions:
contents: writeNo custom config needed. Renovate's built-in github-actions manager bumps the
uses: tag. Enable Renovate on your repo and it opens the PRs.
| File | Who owns it |
|---|---|
plugin.json, mcp.json |
you (the only source) |
.github/workflows/agent-plugin-sync.yml |
you (5 lines, calls this repo) |
gemini-extension.json, .claude-plugin/, .codex-plugin/, mcp_config.json |
generated, never hand-edit |
plugin.json— Agent Plugin spec manifest. Harness-neutral facts plus oneextensions["com.google.cloud.data.agent-plugins"]bucket holding the generator input:config[]— user config vars, written once → become Geminisettingsand ClaudeuserConfig.gemini— Gemini-only bits (contextFileName,mcpServerName).codex— Codex-only bits (interface, copied verbatim into the Codex manifest).
mcp.json— Agent Plugin spec MCP server config.
The bucket is validated against the typed models in
src/agent_plugin_sync/models/extension.py;
validate reports any errors prefixed with the com.google.cloud.data.agent-plugins
namespace so authors can locate them.
[root] may be either:
- a single plugin —
plugin.jsonsits directly inroot; or - a monorepo — no
plugin.jsonatroot, one in each subdirectory.
Every plugin found is processed, each with its own plugin.json + mcp.json;
there is no shared source across plugins. Generated .claude-plugin manifests
are never mistaken for new plugins (dot-directories are skipped).
agent-plugin-sync generate [root] # write all harness manifests
agent-plugin-sync validate [root] # source valid AND generated files current
agent-plugin-sync migrate [root] # one-time: seed the source from gemini-extension.json
agent-plugin-sync --version[root] defaults to the current directory.
uv sync # or: pip install -e .
python -m agent_plugin_sync generate ./repo # run from source
uv run --group dev pytest # unit tests
uv run pytest -m integration # drives real harness CLIs; needs auth
uvx ruff check src testsWhich files serve whom:
| File | Audience |
|---|---|
.github/workflows/sync.yml |
other repos call it; do not copy it |
.github/workflows/tests.yml |
this repo (lint + unit on every PR) |
.github/workflows/release-please.yml |
this repo (opens the release PR) |
release-please-config.json, .release-please-manifest.json |
this repo (release config) |
Releases are conventional-commit driven: merge the release PR and release-please
tags it, bumping the version in pyproject.toml and __init__.py.
release-please must not touch files under .github/workflows/: its token cannot
write workflow files, and the run fails. sync.yml therefore carries no version;
it installs the tool from job.workflow_sha, the commit the caller pinned. That
context is unavailable on GitHub Enterprise Server.