diff --git a/docs/specs/agent-plugins.md b/docs/specs/agent-plugins.md index b2543bc16..0ee3e2d19 100644 --- a/docs/specs/agent-plugins.md +++ b/docs/specs/agent-plugins.md @@ -10,7 +10,7 @@ Root `plugin.json` follows the Agent Plugins 1.0.0 manifest authoring rules (fie https://agent-plugins.org/schemas/1.0.0/plugin.schema.json ``` -**Why `$schema` is withheld (#1412):** Codex >= 0.147 ([openai/codex#37027](https://github.com/openai/codex/pull/37027)) treats a root `plugin.json` whose `$schema` starts with `https://agent-plugins.org/schemas/` as an Agent Plugin, and for Agent Plugin skills injects only the first `MAX_SKILL_PROMPT_BYTES` (8000) of each `SKILL.md` into the model-visible prompt, silently dropping the rest. Legacy manifests (`.codex-plugin/plugin.json`) are exempt. Most bundled skills exceed 8000 bytes, so shipping the `$schema` truncates them on Codex. `tests/codex-skill-prompt-budget.test.ts` pins this: it forbids the `$schema` while any skill is over budget, and holds a shrink-only allowlist of over-budget skills (CRLF-adjusted, since Windows checkouts inflate the byte count). Restore the `$schema` only once that allowlist is empty. +**Why `$schema` is withheld (#1412):** Codex >= 0.147 ([openai/codex#37027](https://github.com/openai/codex/pull/37027)) treats a root `plugin.json` whose `$schema` starts with `https://agent-plugins.org/schemas/` as an Agent Plugin, and for Agent Plugin skills injects only the first `MAX_SKILL_PROMPT_BYTES` (8000) of each `SKILL.md` into the model-visible prompt, silently dropping the rest. Legacy manifests (`.codex-plugin/plugin.json`) are exempt. Most bundled skills exceed 8000 bytes, so shipping the `$schema` truncates them on Codex. `tests/codex-skill-prompt-budget.test.ts` pins this: it asserts the root manifest carries no Agent Plugins `$schema` at all, and holds a shrink-only allowlist of over-budget skills (CRLF-adjusted, since Windows checkouts inflate the byte count). **A second, independent reason (#1411):** oh-my-pi (omp) >= 17.3 routes on the same `$schema` prefix to its strict `agent-plugins` discovery provider, which rejects any `SKILL.md` whose frontmatter has a key outside the Agent Skills closed set (`argument-hint`, `disable-model-invocation`) or a non-string `allowed-tools` — 30 of 33 skills failed to load. Without the `$schema`, omp's lenient legacy provider loads all of them. **Posture (decided 2026-08-17): the root manifest stays schema-less indefinitely.** Restoring `$schema` at the root is a non-goal, not a milestone: omp's routing has no per-host override (verified in 17.3.5 — `legacyProviderAllowed` locks the lenient provider out on the `$schema` prefix alone, and any other Agent Plugins `$schema` value is fatally invalid rather than a fallback), and the Claude Code top-level keys are load-bearing, so no root manifest can satisfy both. If a strict Agent Plugins client ever needs conformance, serve it an emitted package (the converter target below, with Claude keys relocated under `metadata:` and `allowed-tools` as a string) from its own marketplace `source`, and leave the root Claude-native. The `$schema` assertion is therefore unconditional. Layout already matches the portable package shape: root manifest + `skills//SKILL.md`. No `mcp.json` (valid — MCP is optional). @@ -28,7 +28,7 @@ Agent Plugins discovers skills via the [Agent Skills](https://agentskills.io/spe **What is not proven** -- That shipping Agent Plugins clients run `skills-ref` at load time, or skip skills with extra top-level keys. Many clients may ignore unknown fields and still load the skill. Runtime impact is **unverified** until exercised against a concrete client. +- ~~That shipping Agent Plugins clients run `skills-ref` at load time, or skip skills with extra top-level keys.~~ **Now proven (#1411):** omp 17.3.5's `validateAgentSkillFrontmatter` mirrors `skills-ref` and rejects the skill; the manifest posture above is what keeps omp on its lenient path. **Source policy** @@ -46,9 +46,10 @@ Agent Plugins discovers skills via the [Agent Skills](https://agentskills.io/spe ## Re-verify when -- Every `SKILL.md` fits Codex's 8000-byte prompt bound (then restore `$schema`) +- A strict Agent Plugins client we ship to needs conformance (then add an emitted conformant package for it — do not add `$schema` to the root) +- omp adds a per-host override / lenient fallback for `$schema` packages - Codex changes `MAX_SKILL_PROMPT_BYTES` or applies it to legacy/host skills ([openai/codex#37463](https://github.com/openai/codex/issues/37463)) - Agent Plugins leaves Working Draft / publishes a new schema version - Adding top-level fields to root `plugin.json` -- A concrete Agent Plugins client is observed to skip or reject skills with Claude-only frontmatter +- A concrete Agent Plugins client is observed to skip or reject skills with Claude-only frontmatter (observed 2026-08-17: omp 17.3.5, #1411) - Shipping an `agent-plugins` converter target diff --git a/tests/codex-skill-prompt-budget.test.ts b/tests/codex-skill-prompt-budget.test.ts index 526423147..f1310622b 100644 --- a/tests/codex-skill-prompt-budget.test.ts +++ b/tests/codex-skill-prompt-budget.test.ts @@ -3,14 +3,18 @@ import { readdirSync, readFileSync, statSync } from "node:fs" import path from "node:path" /** - * Codex >= 0.147 (openai/codex#37027) classifies a plugin as an Agent Plugin when the - * root `plugin.json` carries an `https://agent-plugins.org/schemas/...` `$schema`, and - * then injects only the first MAX_SKILL_PROMPT_BYTES (8000) of each SKILL.md into the - * model-visible prompt (#1412). Legacy manifests (`.codex-plugin/plugin.json`) are exempt. + * Two shipping hosts route on a root `plugin.json` `$schema` under the Agent Plugins prefix, + * and both break this plugin when they do: * - * Until every skill entrypoint fits, the root manifest must not carry that `$schema`, - * and no skill may newly cross the bound. Shrink OVER_BUDGET as skills are restructured; - * when it is empty, the `$schema` may return. + * - Codex >= 0.147 (openai/codex#37027, #1412) injects only the first MAX_SKILL_PROMPT_BYTES + * (8000) of each Agent Plugin SKILL.md; 26 skills exceed that. + * - oh-my-pi >= 17.3 (#1411) rejects any SKILL.md whose frontmatter has a key outside the + * Agent Skills closed set; the Claude Code keys `argument-hint` / `disable-model-invocation` + * are load-bearing, so 30 skills vanish. omp has no per-host override. + * + * So the root manifest stays schema-less unconditionally (docs/specs/agent-plugins.md); a + * strict client that needs conformance gets a separately emitted package. Independently, no + * new skill may cross Codex's byte bound, and OVER_BUDGET shrinks as skills are restructured. */ const CODEX_MAX_SKILL_PROMPT_BYTES = 8_000 const AGENT_PLUGINS_SCHEMA_PREFIX = "https://agent-plugins.org/schemas/" @@ -92,16 +96,11 @@ describe("Codex skill prompt budget (#1412)", () => { expect(stale).toEqual([]) }) - test("root plugin.json omits the Agent Plugins $schema while any skill is over budget", () => { + test("root plugin.json never carries an Agent Plugins $schema", () => { const manifest = JSON.parse( readFileSync(path.join(repoRoot, "plugin.json"), "utf8"), ) as Record const schema = typeof manifest.$schema === "string" ? manifest.$schema : "" - const anyOverBudget = [...sizes.values()].some( - (size) => size > CODEX_MAX_SKILL_PROMPT_BYTES, - ) - if (anyOverBudget) { - expect(schema.startsWith(AGENT_PLUGINS_SCHEMA_PREFIX)).toBe(false) - } + expect(schema.startsWith(AGENT_PLUGINS_SCHEMA_PREFIX)).toBe(false) }) })