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
9 changes: 5 additions & 4 deletions docs/specs/agent-plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/<name>/SKILL.md`. No `mcp.json` (valid — MCP is optional).

Expand All @@ -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**

Expand All @@ -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
27 changes: 13 additions & 14 deletions tests/codex-skill-prompt-budget.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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/"
Expand Down Expand Up @@ -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<string, unknown>
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)
})
})