From a12e77a0d843604d9fc82116dd51015fa13d07cf Mon Sep 17 00:00:00 2001 From: davidmirror-ops Date: Sat, 3 Oct 2026 07:59:59 -0500 Subject: [PATCH 1/2] Make plugins/flyte installable as a Google Antigravity plugin Antigravity identifies a plugin by a bare plugin.json at the plugin root and reads MCP servers from mcp_config.json, requiring `serverUrl` (not `url`/`type`) for remote servers. Add both alongside the Claude Code and Codex manifests so the same skills/ tree installs with `agy plugin install ./plugins/flyte`, MCP servers included. The new files are mirrors, so verify.py checks them against .claude-plugin/plugin.json and .mcp.json, and build.py vendors them into the npm and PyPI packages like the other manifests. Co-Authored-By: Claude Opus 5.5 (1M context) Signed-off-by: davidmirror-ops --- README.md | 51 ++++++++++++++++++++++++------ packaging/build.py | 9 ++++-- packaging/templates/README.md.tmpl | 8 ++--- packaging/verify.py | 44 ++++++++++++++++++++++++-- plugins/flyte/README.md | 21 +++++++++--- plugins/flyte/mcp_config.json | 20 ++++++++++++ plugins/flyte/plugin.json | 4 +++ 7 files changed, 135 insertions(+), 22 deletions(-) create mode 100644 plugins/flyte/mcp_config.json create mode 100644 plugins/flyte/plugin.json diff --git a/README.md b/README.md index e87d6e1..193222e 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,9 @@ A plugin marketplace for working with [Flyte](https://flyte.org) — in [Claude Code](https://docs.claude.com/en/docs/claude-code), -[OpenAI Codex](https://developers.openai.com/plugins), or any agent harness that -supports [Agent Skills](https://agentskills.io). +[OpenAI Codex](https://developers.openai.com/plugins), +[Google Antigravity](https://antigravity.google), or any agent harness that supports +[Agent Skills](https://agentskills.io). 21 skills, plus two **MCP servers** that let Claude search Flyte docs and act on your own cluster. `uvx flyte-skills install` gets you the skills in any harness; @@ -46,7 +47,7 @@ uvx flyte-skills list # list the bundled ski > [!NOTE] > **This installs the skills, not the MCP servers.** The two servers that let Claude search > Flyte docs and act on your cluster ship with the **plugin**, not the CLI — see -> [Install as a plugin](#install-as-a-plugin-claude-code-and-codex) if you want them, or +> [Install as a plugin](#install-as-a-plugin-claude-code-codex-and-antigravity) if you want them, or > [Adding the MCP servers elsewhere](#adding-the-mcp-servers-elsewhere) to wire them up by > hand. @@ -85,7 +86,7 @@ every `install` command above works under either name. They differ in one thing: servers too. To pin a version, `uvx --from flyte-skills== flyte-skills install`. -## Install as a plugin (Claude Code and Codex) +## Install as a plugin (Claude Code, Codex, and Antigravity) Installing the plugin instead of the skills gets you the same 21 skills **plus** both MCP servers, which are declared in `plugins/flyte/.mcp.json`. @@ -132,11 +133,32 @@ the `mcp_servers` the Codex docs show — the manifest struct is `camelCase`, path expanded, so `${CLAUDE_PLUGIN_ROOT}` — which Codex does not expand, [openai/codex#22842](https://github.com/openai/codex/issues/22842) — never comes up. +### Google Antigravity + +Antigravity's docs don't describe adding a third-party marketplace, so install the plugin +from a local checkout. `plugins/flyte/` is an Antigravity plugin as-is — it carries the +`plugin.json` marker Antigravity looks for at the plugin root: + +``` +git clone https://github.com/flyteorg/flyte-agent-plugins.git # add --branch to pin +agy plugin install ./flyte-agent-plugins/plugins/flyte +``` + +`/plugin install ` inside an Antigravity session does the same. `agy plugin list`, +`agy plugin disable flyte`, and `agy plugin uninstall flyte` manage it afterwards. + +Both MCP servers come with it, but from `plugins/flyte/mcp_config.json` rather than +`.mcp.json`: Antigravity reads that file name, and it rejects the `url`/`type` fields on +remote servers in favour of `serverUrl`. The two files otherwise declare the same servers, +and `packaging/verify.py` fails if they drift. Antigravity's `plugin.json` carries only +`name` and `description` — the fields its documented schema defines — so the release +version still lives in `.claude-plugin/plugin.json`. + ## Harness-native installs The skills are plain [Agent Skills](https://agentskills.io) (`SKILL.md` + YAML frontmatter), so they work in any harness that supports the standard. `flyte-agent-plugins -install` above covers all five; each harness also has its own installer, which is what you +install` above covers all of them; each harness also has its own installer, which is what you want when you would rather track the repo than a release, or to install a single skill rather than all 21. @@ -144,10 +166,16 @@ rather than all 21. |---|---|---|---| | Claude Code | all 21 | both, automatically | `--target claude` | | Codex CLI | all 21 | both, automatically | `--target agents` | +| Antigravity | all 21 | both, via the plugin | `--target agents --project` | | Hermes | per-skill | none — add manually | `--target hermes` | | opencode | all 21 | none — add manually | `--target opencode` | | pi | all 21 | none — add manually | `--target pi` | +Antigravity reads `/.agents/skills/`, which is why its row needs `--project`. +Its global skills directory is not `~/.agents/skills/` — it is `~/.gemini/config/skills/` +for the app and IDE, `~/.gemini/antigravity-cli/skills/` for `agy` — so for a skills-only +global install pass that directory with `--dir`, or install the plugin instead. + ### Hermes `flyte-agent-plugins install --target hermes` writes all 21 into `~/.hermes/skills/`, which Hermes @@ -292,7 +320,7 @@ the plugin [README](plugins/flyte/README.md). ### Adding the MCP servers elsewhere Hermes, opencode, and pi all support MCP — this plugin just doesn't configure it for them. -(Claude Code and Codex get both servers from the plugin; use these snippets only if you +(Claude Code, Codex, and Antigravity get both servers from the plugin; use these snippets only if you want them configured globally rather than per-plugin.) Wiring it up yourself is a few lines. @@ -368,19 +396,22 @@ package.json # pi package manifest (pi.skills) plugins/flyte/.claude-plugin/plugin.json # Claude Code plugin manifest plugins/flyte/.codex-plugin/plugin.json # Codex plugin manifest (points at .mcp.json) plugins/flyte/.mcp.json # the two bundled MCP servers +plugins/flyte/plugin.json # Antigravity plugin manifest +plugins/flyte/mcp_config.json # the same servers, in Antigravity's schema plugins/flyte/skills//SKILL.md packaging/build.py # fans plugins/flyte out into the npm + PyPI packages packaging/verify.py # builds every distribution and proves it installs scripts/smoke_test_mcp.py # end-to-end check of the local MCP server ``` -Each harness consumes a different part of this. Claude Code and Codex read the plugin -manifests, so the **plugin name** matters to them. Hermes, opencode, and pi install skills +Each harness consumes a different part of this. Claude Code, Codex, and Antigravity read +the plugin manifests, so the **plugin name** matters to them. Hermes, opencode, and pi install skills by **directory path**, so `plugins/flyte/skills/…` is their interface. `.mcp.json` is shared by Claude Code (which finds it by convention) and Codex (which is -pointed at it by `.codex-plugin/plugin.json`); the skills themselves stay portable across -every harness. +pointed at it by `.codex-plugin/plugin.json`). Antigravity needs its own copy in +`mcp_config.json`, kept in step by `packaging/verify.py`; the skills themselves stay +portable across every harness. The PyPI packages are a fourth consumer: `packaging/build.py` vendors the whole `plugins/flyte/` tree into each one, which is how `flyte-agent-plugins install` can write the diff --git a/packaging/build.py b/packaging/build.py index 2b712e3..79916a6 100755 --- a/packaging/build.py +++ b/packaging/build.py @@ -52,6 +52,7 @@ def has_mcp(dist: str) -> bool: "claude-code", "claude-code-plugin", "codex", + "antigravity", "mcp", "workflow-orchestration", ] @@ -116,11 +117,13 @@ def skill_names() -> list[str]: def copy_plugin(dest: Path) -> None: - """Copy the plugin payload (manifests + .mcp.json + skills) into dest.""" + """Copy the plugin payload (manifests + MCP configs + skills) into dest.""" dest.mkdir(parents=True, exist_ok=True) for name in (".claude-plugin", ".codex-plugin", "skills"): shutil.copytree(PLUGIN_SRC / name, dest / name) - shutil.copy2(PLUGIN_SRC / ".mcp.json", dest / ".mcp.json") + # Antigravity reads its manifest and MCP config from the plugin root. + for name in (".mcp.json", "plugin.json", "mcp_config.json"): + shutil.copy2(PLUGIN_SRC / name, dest / name) def build_npm(dist: str, ver: str, outdir: Path) -> Path: @@ -157,6 +160,8 @@ def build_npm(dist: str, ver: str, outdir: Path) -> Path: ".claude-plugin/", ".codex-plugin/", ".mcp.json", + "plugin.json", + "mcp_config.json", "skills/", "bin/", diff --git a/packaging/templates/README.md.tmpl b/packaging/templates/README.md.tmpl index 2a93a2e..b40fb6b 100644 --- a/packaging/templates/README.md.tmpl +++ b/packaging/templates/README.md.tmpl @@ -79,8 +79,8 @@ editing config files — so it needs one of those CLIs on your PATH: These are tools the agent can call, not inert markdown: `flyte-docs` sends search queries to a Union-operated endpoint, and `flyte-cluster` gets control-plane access to your cluster (which also needs `uv` and a Flyte login). Harnesses that consume -the whole plugin (Claude Code, Codex) pick the servers up from `.mcp.json` -automatically and need none of this. +the whole plugin (Claude Code, Codex, Antigravity) pick the servers up from the +bundled config automatically and need none of this. ## Native install paths @@ -93,8 +93,8 @@ marketplace in its own right: /plugin install flyte@flyte-agent-plugins ``` -See [the repository README]({{REPO_URL}}#readme) for Codex, Hermes, opencode, and -pi instructions, the full skill list, and MCP server details. +See [the repository README]({{REPO_URL}}#readme) for Codex, Antigravity, Hermes, +opencode, and pi instructions, the full skill list, and MCP server details. ## License diff --git a/packaging/verify.py b/packaging/verify.py index 2238d01..47d1051 100755 --- a/packaging/verify.py +++ b/packaging/verify.py @@ -8,6 +8,7 @@ Checks, for both names on both registries: * every manifest agrees on one version; * every skill has frontmatter with a name matching its directory; + * the Antigravity manifests agree with the Claude Code ones they mirror; * the npm tarball carries the dot-directories Claude Code needs at the package root (npm's default file selection is not reliable about those); * the built wheel carries the skills as package data; @@ -58,6 +59,36 @@ def check_versions() -> None: check(len(set(versions.values())) == 1, f"one version across manifests: {versions}") +def check_antigravity() -> None: + """Antigravity reads its own manifest (``plugin.json``) and its own MCP config + (``mcp_config.json``) from the plugin root. Both are hand-maintained mirrors of + the Claude Code files, so drift between them is the failure to catch. + + The one intended difference: Antigravity rejects ``url``/``type`` on remote + servers and requires ``serverUrl`` instead. + """ + print("antigravity") + plugin = builder.PLUGIN_SRC + claude = json.loads((plugin / ".claude-plugin" / "plugin.json").read_text()) + manifest = json.loads((plugin / "plugin.json").read_text()) + check( + manifest == {"name": claude["name"], "description": claude["description"]}, + "plugin.json carries the Claude Code manifest's name and description", + ) + + def as_antigravity(server: dict) -> dict: + if "url" not in server: + return server + return {"serverUrl": server["url"], **{k: v for k, v in server.items() if k not in ("url", "type")}} + + expected = { + name: as_antigravity(server) + for name, server in json.loads((plugin / ".mcp.json").read_text())["mcpServers"].items() + } + actual = json.loads((plugin / "mcp_config.json").read_text())["mcpServers"] + check(actual == expected, f"mcp_config.json mirrors .mcp.json: {sorted(actual)}") + + def check_targets(workdir: Path, npm_pkg: Path, py_exe: str) -> None: """The Python and Node CLIs declare harness targets independently, so a target added to one and forgotten in the other is a real drift risk.""" @@ -150,7 +181,14 @@ def check_npm(dist: str, pkg: Path, workdir: Path) -> None: print(f"npm {dist}") out = run(["npm", "pack", "--dry-run", "--json"], cwd=pkg).stdout files = {f["path"] for f in json.loads(out)[0]["files"]} - for required in (".claude-plugin/plugin.json", ".codex-plugin/plugin.json", ".mcp.json", "bin/cli.mjs"): + for required in ( + ".claude-plugin/plugin.json", + ".codex-plugin/plugin.json", + ".mcp.json", + "plugin.json", + "mcp_config.json", + "bin/cli.mjs", + ): check(required in files, f"tarball contains {required}") packed = {f.split("/")[1] for f in files if f.startswith("skills/")} check(packed == set(builder.skill_names()), f"tarball contains all {len(builder.skill_names())} skills") @@ -186,7 +224,8 @@ def check_pypi(dist: str, pkg: Path, workdir: Path) -> None: names = set(zipfile.ZipFile(wheel).namelist()) mod = builder.module_name(dist) check(f"{mod}/plugin/.claude-plugin/plugin.json" in names, "wheel contains .claude-plugin/plugin.json") - check(f"{mod}/plugin/.mcp.json" in names, "wheel contains .mcp.json") + for required in (".mcp.json", "plugin.json", "mcp_config.json"): + check(f"{mod}/plugin/{required}" in names, f"wheel contains {required}") packed = {n.split("/")[3] for n in names if n.startswith(f"{mod}/plugin/skills/")} check(packed == set(builder.skill_names()), f"wheel contains all {len(builder.skill_names())} skills") @@ -218,6 +257,7 @@ def check_pypi(dist: str, pkg: Path, workdir: Path) -> None: def main() -> int: check_versions() check_skills() + check_antigravity() with tempfile.TemporaryDirectory() as tmp: workdir = Path(tmp) diff --git a/plugins/flyte/README.md b/plugins/flyte/README.md index e5afae5..5985ba5 100644 --- a/plugins/flyte/README.md +++ b/plugins/flyte/README.md @@ -3,7 +3,8 @@ A single plugin for [Flyte](https://flyte.org): cluster deployment and SDK / workflow authoring skills, plus two bundled MCP servers. [Claude Code](https://docs.claude.com/en/docs/claude-code) and -[OpenAI Codex](https://developers.openai.com/plugins) install it as a full plugin — skills +[OpenAI Codex](https://developers.openai.com/plugins), and +[Google Antigravity](https://antigravity.google) install it as a full plugin — skills **and** MCP servers — and any harness that supports [Agent Skills](https://agentskills.io) (Hermes, opencode, pi) can install the skills. @@ -67,9 +68,11 @@ Convert existing Flyte 1 (`flytekit`) code to Flyte 2, distilled from the offici ## Bundled MCP servers The servers live in `.mcp.json`. Claude Code reads that file by convention; Codex picks it -up through the `mcpServers` entry in `.codex-plugin/plugin.json`. Hermes, opencode, and pi -install the skills and nothing else — they all support MCP, so you can add these by hand, -see [Adding the MCP servers elsewhere](../../README.md#adding-the-mcp-servers-elsewhere). +up through the `mcpServers` entry in `.codex-plugin/plugin.json`; Antigravity reads the same +servers from `mcp_config.json`, which uses its `serverUrl` field for the remote one. +Hermes, opencode, and pi install the skills and nothing else — they all support MCP, so you +can add these by hand, see +[Adding the MCP servers elsewhere](../../README.md#adding-the-mcp-servers-elsewhere). `.mcp.json` declares **two MCP servers**, split so nothing is duplicated: @@ -169,6 +172,16 @@ MCP servers come with it: codex plugin marketplace add flyteorg/flyte-agent-plugins # or --ref to pin ``` +## Install (Google Antigravity) + +Install from a local checkout — this directory carries the `plugin.json` marker +Antigravity looks for, and the skills and both MCP servers come with it: + +``` +git clone https://github.com/flyteorg/flyte-agent-plugins.git # add --branch to pin +agy plugin install ./flyte-agent-plugins/plugins/flyte +``` + ## Install (other agent harnesses) The skills are standard [Agent Skills](https://agentskills.io) (`SKILL.md`), so they also diff --git a/plugins/flyte/mcp_config.json b/plugins/flyte/mcp_config.json new file mode 100644 index 0000000..80649e6 --- /dev/null +++ b/plugins/flyte/mcp_config.json @@ -0,0 +1,20 @@ +{ + "mcpServers": { + "flyte-docs": { + "serverUrl": "https://flyte-mcp.apps.demo.hosted.unionai.cloud/flyte-mcp/mcp" + }, + "flyte-cluster": { + "command": "uvx", + "args": [ + "--from", + "flyte[mcp]==2.6.10", + "flyte-mcp", + "--transport", + "stdio", + "--tool-groups", + "task,run,action,logs,app,trigger,project,secret,condition,identity", + "--no-init-from-config" + ] + } + } +} diff --git a/plugins/flyte/plugin.json b/plugins/flyte/plugin.json new file mode 100644 index 0000000..9a69df5 --- /dev/null +++ b/plugins/flyte/plugin.json @@ -0,0 +1,4 @@ +{ + "name": "flyte", + "description": "Work with Flyte 2. Deploy Flyte on AWS or kind, author and run workflows, apps, agents, data, and ML workloads with the SDK, and operate your cluster through bundled MCP servers." +} From 9bc4a1bdd62aadeca45a7a83812fd0638820bfc3 Mon Sep 17 00:00:00 2001 From: davidmirror-ops Date: Sat, 3 Oct 2026 08:15:30 -0500 Subject: [PATCH 2/2] Document Antigravity install behaviour observed in agy 1.2.16 Co-Authored-By: Claude Opus 5.5 (1M context) Signed-off-by: davidmirror-ops --- README.md | 9 ++++++++- plugins/flyte/README.md | 2 ++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 193222e..30e8642 100644 --- a/README.md +++ b/README.md @@ -144,9 +144,16 @@ git clone https://github.com/flyteorg/flyte-agent-plugins.git # add --branch < agy plugin install ./flyte-agent-plugins/plugins/flyte ``` -`/plugin install ` inside an Antigravity session does the same. `agy plugin list`, +`/plugin install ` inside an Antigravity session does the same. The install copies +the plugin into `~/.gemini/config/plugins/flyte/`, so the clone can go afterwards — and to +update, pull (or check out a newer tag) and run `agy plugin install` again. `agy plugin list`, `agy plugin disable flyte`, and `agy plugin uninstall flyte` manage it afterwards. +Antigravity namespaces plugin MCP servers by plugin name, so they appear as +`flyte_flyte-docs` and `flyte_flyte-cluster`. They don't show up in `agy mcp list`, which +lists only servers configured outside a plugin. When changing either manifest, +`agy plugin validate ./plugins/flyte` checks the plugin without installing it. + Both MCP servers come with it, but from `plugins/flyte/mcp_config.json` rather than `.mcp.json`: Antigravity reads that file name, and it rejects the `url`/`type` fields on remote servers in favour of `serverUrl`. The two files otherwise declare the same servers, diff --git a/plugins/flyte/README.md b/plugins/flyte/README.md index 5985ba5..bcdcf20 100644 --- a/plugins/flyte/README.md +++ b/plugins/flyte/README.md @@ -182,6 +182,8 @@ git clone https://github.com/flyteorg/flyte-agent-plugins.git # add --branch < agy plugin install ./flyte-agent-plugins/plugins/flyte ``` +The install is a copy, so re-run it after pulling to update. + ## Install (other agent harnesses) The skills are standard [Agent Skills](https://agentskills.io) (`SKILL.md`), so they also