Skip to content

Repository files navigation

agent-plugin-sync

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 coverage

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.


Use it in your plugin repo

You write one small file (step 2) that points back at this repo.

1. Run it locally

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 .

2. CI: fail the PR when manifests are stale

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@VERSION

The 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: write

3. Keep the pin current

No custom config needed. Renovate's built-in github-actions manager bumps the uses: tag. Enable Renovate on your repo and it opens the PRs.

What you write vs what is generated

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

Source of truth

  • plugin.json — Agent Plugin spec manifest. Harness-neutral facts plus one extensions["com.google.cloud.data.agent-plugins"] bucket holding the generator input:
    • config[] — user config vars, written once → become Gemini settings and Claude userConfig.
    • 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.

Single plugin or monorepo

[root] may be either:

  • a single pluginplugin.json sits directly in root; or
  • a monorepo — no plugin.json at root, 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).

Commands

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.


Develop this tool

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 tests

Which 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.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages