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
15 changes: 1 addition & 14 deletions .codex-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,5 @@
"name": "magpie",
"version": "0.9.0.dev202610251812",
"description": "Apache Magpie — agentic skills for maintaining open-source projects.",
"skills": "./skills",
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "/bin/bash -p \"${PLUGIN_ROOT}/plugins/magpie-setup/hooks/check-upgrade.sh\"",
"timeout": 10
}
]
}
]
}
"skills": "./skills"
}
26 changes: 19 additions & 7 deletions docs/setup/marketplace.md
Original file line number Diff line number Diff line change
Expand Up @@ -335,16 +335,27 @@ When step 1 wins, `.codex-plugin/plugin.json` is not ignored — it is merged
over the root manifest as an **overlay**, so it carries Codex-specific fields
rather than the whole manifest.

For this repo that resolves two different ways:
For this repo that resolves three different ways:

| Installed root | Manifest Codex actually reads |
|---|---|
| the repo root | root [`plugin.json`](../../plugin.json) — its AP1 `$schema` matches — with `.codex-plugin/plugin.json` merged over it |
| `plugins/magpie-<family>/` | `.claude-plugin/plugin.json`, reached by fallback: those roots carry neither a `plugin.json` nor a `.codex-plugin/` |
| the repo root | root [`plugin.json`](../../plugin.json) — its AP1 `$schema` matches — with `.codex-plugin/plugin.json` merged over it. No catalogue installs this root as a Codex plugin |
| `plugins/magpie-setup/`, `plugins/magpie-utilities/` | their own `.codex-plugin/plugin.json`, read **instead of** `.claude-plugin/plugin.json` (an overlay applies only over an AP1 root manifest), so it is a complete manifest: the same name, description and shared metadata, `skills`, and a `hooks` path — see below |
| every other `plugins/magpie-<family>/` | `.claude-plugin/plugin.json`, reached by fallback: those roots carry neither a `plugin.json` nor a `.codex-plugin/` |

The second row is why the ten family plugins install into Codex at all despite
The last row is why the family plugins install into Codex at all despite
carrying only a Claude-Code manifest.

**Hooks.**
Codex takes a plugin's hooks from its manifest's `hooks` entry, or, with none, from `hooks/hooks.json`.
It parses each hook file strictly, as an object with only `description` and `hooks`.
Any other top-level key rejects the whole file: Codex reports a load warning and runs none of its hooks.
The `hooks/hooks.json` of `magpie-setup` and `magpie-utilities` belongs to Claude Code and carries `$schema` and `modules` for the [Claude Code mods](../when-to-use-mods.md), so Codex cannot use it.
Each of those two plugins therefore has a `.codex-plugin/plugin.json` whose `hooks` names `./hooks/codex-hooks.json`, a file in the shape Codex parses.
Claude Code reads neither file and keeps using `hooks/hooks.json`.
For `magpie-setup` that file wires the [upgrade check](#automatic-upgrade-detection); for `magpie-utilities` it is empty, which only stops Codex from warning about `hooks/hooks.json` on every start.
`tools/dev/check-family-plugins.py` generates both files with `--fix`, and fails any plugin in the Codex catalogue whose Codex-visible hook file carries another top-level key.

> [!WARNING]
> A plugin root's `plugin.json` must be a regular file. If it is a **symlink**,
> Codex's resolver returns no manifest at all — it does *not* fall back to
Expand Down Expand Up @@ -610,15 +621,16 @@ automatic while the *changes* stay confirmed.
| Agent | Mechanism |
|---|---|
| **Claude Code** | `SessionStart` hook [`plugins/magpie-setup/hooks/check-upgrade.sh`](../../plugins/magpie-setup/hooks/check-upgrade.sh) compares the installed version to a marker in the plugin's persistent data dir and prompts on change. Deterministic. |
| **Codex CLI** | The same [`plugins/magpie-setup/hooks/check-upgrade.sh`](../../plugins/magpie-setup/hooks/check-upgrade.sh), wired inline in the `hooks` block of the root plugin's [`.codex-plugin/plugin.json`](../../.codex-plugin/plugin.json) as `/bin/bash -p "${PLUGIN_ROOT}/plugins/magpie-setup/hooks/check-upgrade.sh"` — Codex uses the same event schema and the same `SessionStart` event. For the root plugin `PLUGIN_ROOT` is the repo root, where the script finds the version manifests and the `skills/setup` symlink it needs. Codex sets `PLUGIN_ROOT`/`PLUGIN_DATA` (and the `CLAUDE_*` pair for compatibility), which the script reads. See the caveat below. |
| **Codex CLI** | The same [`plugins/magpie-setup/hooks/check-upgrade.sh`](../../plugins/magpie-setup/hooks/check-upgrade.sh), on the same `startup` `SessionStart` event, wired in [`plugins/magpie-setup/hooks/codex-hooks.json`](../../plugins/magpie-setup/hooks/codex-hooks.json) as `/bin/bash -p "${PLUGIN_ROOT}/hooks/check-upgrade.sh"`. The plugin's [`.codex-plugin/plugin.json`](../../plugins/magpie-setup/.codex-plugin/plugin.json) names that file, because Codex cannot parse the Claude Code `hooks/hooks.json` (see [Which manifest Codex reads](#which-manifest-codex-reads)). `PLUGIN_ROOT` is the installed `magpie-setup` root, where the script finds its manifests and `skills/setup`. Codex sets `PLUGIN_ROOT`/`PLUGIN_DATA` (and the `CLAUDE_*` pair for compatibility), which the script reads. It runs only once you have trusted it — see the caveat below. |
| **VS Code / Copilot, Cursor, Kiro (AP1)** | None. Agent Plugins 1.0 specifies no hook component and VS Code ignores client extension directories, so there is nothing to fire. Run `/magpie-setup:complete-upgrade` after updating. |
| **Gemini CLI** | No lifecycle hook; the extension context file [`GEMINI.md`](../../GEMINI.md) instructs the agent to compare the extension version to a recorded marker and prompt on change (LLM-driven, advisory). |
| Other agents | Run `/magpie-setup:complete-upgrade` manually after updating the package. |

> [!IMPORTANT]
> **Codex hooks require a separate trust decision.** Current Codex supports plugin-local hooks, but skips non-managed definitions until the operator reviews them in `/hooks`.
> Project trust or plugin installation alone does not activate them.
> Review the upgrade hook and the guard and vetted-ops hooks after installation or a definition change; then verify they actually run.
> After installing `magpie-setup`, open `/hooks`, review its `SessionStart` upgrade hook (source `hooks/codex-hooks.json`), and trust it; it then runs from the next new session.
> Do the same for the guard and vetted-ops hooks, and again after any update that changes a hook definition, since Codex keys trust to the definition's hash; then verify they actually run.
> Older versions affected by [openai/codex#16430](https://github.com/openai/codex/issues/16430) still need manual upgrade checks.
> See [the native hook contract](../adapters/codex.md#deterministic-guard-rules) and [OpenAI’s hook documentation](https://learn.chatgpt.com/docs/hooks).

Expand Down Expand Up @@ -765,7 +777,7 @@ documentation**; what varies is whether it has also been exercised against a
|---|---|---|
| root `plugin.json` | [Agent Plugins 1.0.0 spec](https://github.com/agentplugins/agent-plugins-spec/blob/main/spec/1.0.0.md) + [`plugin.schema.json`](https://agent-plugins.org/schemas/1.0.0/plugin.schema.json) | Conforms to the published closed schema; enforced by `check-family-plugins.py`. Also the manifest Codex resolves first for the repo root — see [Which manifest Codex reads](#which-manifest-codex-reads) |
| `.claude-plugin/*` | Claude Code plugins reference | Verified live — `claude plugin validate . --strict` passes with 0 warnings; a family plugin installs and loads from a local marketplace replica |
| `.codex-plugin/plugin.json`, `.agents/plugins/marketplace.json` | The `codex` binary's own source and enums — native hook behavior is documented in [OpenAI’s hook reference](https://learn.chatgpt.com/docs/hooks); manifest-resolution order was checked against [`plugin_namespace.rs`][codex-resolve] and [`protocol.rs`][codex-paths] | **Verified live** — `codex plugin marketplace add` + `plugin list` against codex 0.154.0. The first live run is what caught the invented `policy` values the documentation check could not; the enums are now enforced by `check-family-plugins.py`. Note `.codex-plugin/plugin.json` is an **overlay** on the root manifest, not the manifest itself. See the hook-trust note above |
| `.codex-plugin/plugin.json`, `.agents/plugins/marketplace.json` | The `codex` binary's own source and enums — native hook behavior is documented in [OpenAI’s hook reference](https://learn.chatgpt.com/docs/hooks); manifest-resolution order was checked against [`plugin_namespace.rs`][codex-resolve] and [`protocol.rs`][codex-paths] | **Verified live** — `codex plugin marketplace add` + `plugin list` against codex 0.154.0. The first live run is what caught the invented `policy` values the documentation check could not; the enums are now enforced by `check-family-plugins.py`. Note the root `.codex-plugin/plugin.json` is an **overlay** on the root manifest, not the manifest itself, while a family plugin's `.codex-plugin/plugin.json` is the whole manifest. The `magpie-setup` upgrade hook was checked live with the app server's `hooks/list` against codex 0.154.0: it loads from `hooks/codex-hooks.json` with no warning, untrusted until reviewed, where the Claude Code `hooks/hooks.json` failed with ``unknown field `$schema` ``. See the hook-trust note above |
| root `marketplace.json` | Copilot / VS Code plugin marketplace docs | Legacy-format catalog, explicitly still supported alongside AP1. Not yet live-installed |
| `gemini-extension.json` | Gemini CLI extensions docs | Follows the published schema. Google has joined the AP1 TSC but has published no migration for this file — keep both |
| `apm.yml` | `microsoft/apm` schema **v0.1** | Pre-1.0 and the most likely to churn; re-check before publish |
Expand Down
14 changes: 14 additions & 0 deletions plugins/magpie-setup/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "magpie-setup",
"description": "Apache Magpie \u2014 framework install/maintenance: install (adopt), upgrade, verify, override, status, secure-agent setup, shared-config sync.",
"version": "0.9.0.dev202610251812",
"author": {
"name": "Apache Magpie",
"url": "https://magpie.apache.org/"
},
"homepage": "https://magpie.apache.org/",
"repository": "https://github.com/apache/magpie",
"license": "Apache-2.0",
"skills": "./skills",
"hooks": "./hooks/codex-hooks.json"
}
13 changes: 8 additions & 5 deletions plugins/magpie-setup/hooks/check-upgrade.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@
# SPDX-License-Identifier: Apache-2.0
# https://www.apache.org/licenses/LICENSE-2.0
#
# Session-start hook for the Apache Magpie plugin. Wired by the Claude Code
# magpie-setup plugin (hooks/hooks.json, SessionStart) and by the root Codex CLI
# plugin (.codex-plugin/plugin.json, same event schema), whose PLUGIN_ROOT is
# the repo root. Agent Plugins 1.0 defines no hook component, so an AP1-only client
# does not run this at all — see docs/setup/marketplace.md.
# Session-start hook for the Apache Magpie plugin. Wired by the magpie-setup
# plugin twice, with the same event schema: for Claude Code in hooks/hooks.json,
# and for Codex CLI in hooks/codex-hooks.json, which .codex-plugin/plugin.json
# names because Codex cannot parse the Claude Code mods' keys in hooks.json.
# Either way the plugin root is this plugin's own root. Codex runs it only once
# the user has trusted it in `/hooks`. Agent Plugins 1.0 defines no hook
# component, so an AP1-only client does not run this at all — see
# docs/setup/marketplace.md.
#
# Also warns, once per session, when the isolated setup is not configured on
# this machine (see `setup_preflight.isolated.session_start`).
Expand Down
17 changes: 17 additions & 0 deletions plugins/magpie-setup/hooks/codex-hooks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"description": "Apache Magpie \u2014 the upgrade check, for Codex. Claude Code reads hooks.json.",
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"type": "command",
"command": "/bin/bash -p \"${PLUGIN_ROOT}/hooks/check-upgrade.sh\"",
"timeout": 10
}
]
}
]
}
}
2 changes: 1 addition & 1 deletion plugins/magpie-setup/skills/setup/uninstall.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ explicit confirmation before any write.
> install — the default path — put nothing in the repo, so there
> is nothing here to reverse: it is removed with the client's own
> verb (`/plugin uninstall <plugin>@apache-magpie` in Claude
> Code, `codex plugin uninstall magpie`,
> Code, `codex plugin remove <plugin>@apache-magpie`,
> `gemini extensions uninstall magpie`). If the repo has no
> `.apache-magpie.lock` and Magpie is plugin-installed, print
> that command instead of a snapshot removal plan.
Expand Down
14 changes: 14 additions & 0 deletions plugins/magpie-utilities/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "magpie-utilities",
"description": "Apache Magpie \u2014 framework meta-skills: write-skill, optimize-skill, skill-reconciler, list-skills.",
"version": "0.9.0.dev202610251812",
"author": {
"name": "Apache Magpie",
"url": "https://magpie.apache.org/"
},
"homepage": "https://magpie.apache.org/",
"repository": "https://github.com/apache/magpie",
"license": "Apache-2.0",
"skills": "./skills",
"hooks": "./hooks/codex-hooks.json"
}
4 changes: 4 additions & 0 deletions plugins/magpie-utilities/hooks/codex-hooks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"description": "Apache Magpie \u2014 no Codex hooks. hooks.json holds Claude Code mods only.",
"hooks": {}
}
9 changes: 5 additions & 4 deletions projects/magpie/release-management-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ mandatory ASF approval + announce mechanisms (`dev-list-vote`,
| `git_upstream_remote` | `upstream` |
| `release_planning_issue_template` | *(none — uses the `release-prepare` default template)* |
| `release_branch_base` | `main` |
| `version_manifest_files` | `pyproject.toml`, `uv.lock`, `.claude-plugin/plugin.json`, `.claude-plugin/marketplace.json`, `plugin.json` (Agent Plugins 1.0), `.codex-plugin/plugin.json`, `gemini-extension.json`, `apm.yml`, and the ten generated `plugins/magpie-<family>/.claude-plugin/plugin.json` manifests |
| `version_manifest_files` | `pyproject.toml`, `uv.lock`, `.claude-plugin/plugin.json`, `.claude-plugin/marketplace.json`, `plugin.json` (Agent Plugins 1.0), `.codex-plugin/plugin.json`, `gemini-extension.json`, `apm.yml`, the ten generated `plugins/magpie-<family>/.claude-plugin/plugin.json` manifests, and the generated Codex manifests `plugins/magpie-setup/.codex-plugin/plugin.json` and `plugins/magpie-utilities/.codex-plugin/plugin.json` |

`pyproject.toml`'s `project.version` is the **single authority** for the
framework version; every other file above mirrors it verbatim, including a
Expand Down Expand Up @@ -116,9 +116,10 @@ The version flows outward in two hops, neither of them hand-edited:
(`.claude-plugin/plugin.json`, the Agent Plugins 1.0 `plugin.json`,
`.codex-plugin/plugin.json`, `gemini-extension.json`, `apm.yml`);
2. `.claude-plugin/plugin.json` → the ten generated
`plugins/magpie-<family>/.claude-plugin/plugin.json` manifests and the
family entries in `.claude-plugin/marketplace.json`, which also inherit
`author`, `homepage`, `repository`, and `license`.
`plugins/magpie-<family>/.claude-plugin/plugin.json` manifests, the two
generated `plugins/magpie-{setup,utilities}/.codex-plugin/plugin.json`
manifests, and the family entries in `.claude-plugin/marketplace.json`,
which also inherit `author`, `homepage`, `repository`, and `license`.

So a bump is one edit plus one command:

Expand Down
Loading
Loading