mirror of
https://github.com/boshu2/agentops.git
synced 2026-09-14 15:08:13 +08:00
8cdcb5a903
> **Residues closed on the caller's merge instruction** (`499d916a6`): the round-2 findings were the same failure shape — round-1 repairs patched cited lines instead of sweeping the class — so this commit sweeps each file whole: every remaining SATURATED-row-append site in skill-eval now routes to RUNBOOK retirement, the human-only-skills *description* is runtime-conditional, premortem's "(MEASURED)" label is gone, SKILL-API's context table carries all 25 rows and the enforcement table gains `disable-model-invocation`, and the fixture-identity claim is stated precisely (probe id, honesty note, and control arm are the only differing fields — as the acceptance permits). Post-sweep: validators, full Go suite, 68/68 gates, goldens + headroom bats green, projections current, gemini in sync. Merging per Bo's instruction. ## What Train 1 of the accepted [instrument-panel roadmap](docs/plans/2026-08-26-instrument-panel-roadmap.md) (intent landed at `986a4feaf`): the measurement substrate, the skill-context diet, and the retrieval-eval contract. Three worktree-isolated lanes, each independently validated by a fresh context, plus one integration commit. 103 files, +5,510/−76. **L1 — measurement substrate** (`instrument/measurement-substrate`) - Gate `skill.probe-headroom` (advisory, Fast|Full): answers the question `skill.probe-coverage` cannot — not "does a probe result exist" but "could one have existed at all". The rule, ported to Go (`cli/internal/probeheadroom` + `cli/cmd/probe-headroom` behind a thin check script — the witness-crosscheck pattern, **no new `ao` root command**): control arm ≥ 0.75 with ≥ 2 usable reps at ≥ 2 effort levels ⇒ SATURATED (void row, not an honest null); UNMEASURED outranks it; treatment-silent ⇒ FLOOR; else SEPARATED. RED first: both committed fixture pairs read `INERT` to everything else in the repo; the failing separation test predates the implementation, and a bats negative-control swaps fixture bytes and asserts the gate flips. - **First reading on real data: 7 of 11 historical probe groups are SATURATED** — including both `validate-not-proven` runs. Those INERT rows were never honest nulls; they were void. The 0/12 ledger number now argues itself. - Declared denominator for probe-coverage: `scripts/.skill-probe-denominator-exclusions`, fail-closed parser (entry without an argument, stale slug, or duplicate ⇒ exit 2). One entry (`goals`, a pure alias-of `fitness`). Net effect deliberately zero (0/12 → 0/12: alias left, `one-way-door` entered) — the gain is a declared number, not a better-looking one. - Re-landed from the recovered clean-room commit (`9872483bd`), re-validated against *current* main: `skill-eval` (defers saturation to the gate id; its shell scripts dropped, not shipped — ratchet intent), `route`, `one-way-door`, premortem reversibility check, council `caller_challenge` (schema + validator, per the agent-core boundary that the panel may challenge, never overrule). **L4 — context diet** (`instrument/context-diet`) - `disable-model-invocation: true` on 4 human-only skills (key verified verbatim against Anthropic's docs). The plan guessed 35 candidates; the graph said otherwise — 23 carry `user-invocable: true`, and 19 of those are excluded on cited evidence (rpi consumes anti-ceremony/implement/plan/validate; workflow scripts reach others; `goals` is a live migration tombstone). The exclusion evidence is retained in the lane report. - One router skill (`human-only-skills`) — the single always-loaded description that replaces four; it hints, never fires. - `.out-of-scope/` formalized with this week's three refusals (checked-in knowledge corpus; ee self-improvement loops; whole-skill A/B as the measurement unit), each citing its evidence. - Deterministic proof, no model eval: before/after bytes of always-loaded description load reported in the lane summary. **L5 — retrieval-eval contract** (`instrument/retrieval-contract`, lane verdict PASS 10/10) - `AGENTS.md` federated row now names **ee (eidetic-engine)** as a concrete caller-selected memory system — consume, never build; symlink intact. - `schemas/pack-quality-expectations.v1.schema.json` + 4 routing goldens + `scripts/check-routing-probe-goldens.sh` graded against `ao skills find`, wired as an **advisory** nightly job. Zero goldens is a failing state — no new zero-denominator green. - **The instrument caught a real miss on day one — and its own prescription fixed it.** Golden `rq-04` expects `validate` for "judge whether this finished change is actually proven before I merge it"; at authoring, `ao skills find` ranked the *forbidden* `premortem` first and `validate` nowhere in six natural phrasings. The pointer-wording-first repair (validate's description gained the caller's own words: finished, proven, verdict, merge) now ranks it #1 at 0.333; grader 6/6, and the golden pins the repair — a description regression reopens it. ## Integration `regen-all.sh` once over the merged lanes (catalog 52 → 56, four new codex twins, mesh, router, manifests); `skills/route/SKILL.md` catalog/router links became prose repo-root references (the projected twin cannot resolve `../catalog.json` — this was both the portable-conformance failure and the sole broken doc link); `codex-portable-conformance.bats` pin 52 → 56. ## Evidence - `cd cli && go build ./... && go vet ./... && go test ./...` exit 0 · `ao gate check --full` **68/68** · four skill validators PASS · probe-headroom / routing-goldens / probe-coverage bats PASS · `regen-all.sh --check` all current. - Per-lane fresh validators re-ran every suite on detached content; L5 PASS; L1/L4 NOT_PROVEN solely on the projection-regen clause reserved for integration (their remaining acceptance observed green), settled above. Cross-family (Codex) review of the integrated diff recorded in the session report. - Two disclosed scope stretches accepted at integration: a one-line `.gitignore` entry mirroring the witness-crosscheck precedent, and the probe LEDGER.md fact-correction L1's own change made necessary (noted for Train 2's L2, which owns that file next). ## Cross-family review (Codex, fresh context) Round 1: **FAIL** — two blockers (the RED fixtures didn't isolate the control arm; the goldens grader was red where the plan's acceptance says green) and eight majors (contract contradictions in the re-landed skills, a converter-substitution false claim in the codex router twin, two overreaching `.out-of-scope` entries, stale SKILL-API counts). All repaired in one bounded round (`db68935a3`): fixtures now byte-identical outside the control arm, the routing miss actually fixed rather than tolerated, every cited contradiction reconciled at the source and re-projected. Post-repair: full Go suite exit 0, `gate check --full` 68/68, all validators and probe/goldens bats green, projections current, gemini byte-identity restored. Focused re-check verdict recorded in the session report. ## Follow-ups (Train 2, already planned) Seeded-defect probes for the judgment spine (every ledger row citing a passing headroom pre-screen) and the gate-hardening pair (`Gate-Loosen-Reason` tightening ratchet; mechanical grounding-validation over evidence docs). Plus, surfaced by this train: a latent `valid_keys`/schema divergence in `validate-skill-schema.sh` (two keys the schema defines are absent from the script's allowlist — pre-existing).
310 lines
13 KiB
Markdown
310 lines
13 KiB
Markdown
# Codex Skill API Contract
|
|
|
|
> Source of truth for what the Codex runtime actually supports. All converter output and validation must conform to this contract.
|
|
> Orientation contract: [`AGENTS.md`](../../AGENTS.md).
|
|
|
|
**Official docs:**
|
|
- [Codex Skills](https://developers.openai.com/codex/skills/)
|
|
- [Codex Multi-Agent](https://developers.openai.com/codex/multi-agent/)
|
|
- [Codex CLI Features](https://developers.openai.com/codex/cli/features)
|
|
|
|
---
|
|
|
|
## SKILL.md Frontmatter
|
|
|
|
Every generated AgentOps Codex projection emits only the two fields Codex uses
|
|
for discovery:
|
|
|
|
```yaml
|
|
---
|
|
name: skill-name
|
|
description: 'Explain when this skill triggers and when it does not.'
|
|
---
|
|
```
|
|
|
|
The portable Agent Skills specification requires `name` and `description`
|
|
and also permits `license`, `compatibility`, string-to-string `metadata`,
|
|
and the experimental space-separated `allowed-tools` field. The AgentOps
|
|
generator does not currently emit those optional fields. AgentOps-only fields
|
|
such as `skill_api_version`, `context`, `model`, `user-invocable`, and
|
|
`output_contract` must be stripped from Codex output.
|
|
|
|
---
|
|
|
|
## Optional: agents/openai.yaml
|
|
|
|
Codex skills may include `agents/openai.yaml` for display metadata and policy:
|
|
|
|
```yaml
|
|
interface:
|
|
display_name: "User-facing name"
|
|
short_description: "Brief description"
|
|
icon_small: "./assets/small-logo.svg"
|
|
icon_large: "./assets/large-logo.png"
|
|
brand_color: "#3B82F6"
|
|
default_prompt: "Optional surrounding prompt"
|
|
|
|
policy:
|
|
allow_implicit_invocation: false
|
|
|
|
dependencies:
|
|
tools:
|
|
- type: "mcp"
|
|
value: "toolName"
|
|
description: "Tool description"
|
|
transport: "streamable_http"
|
|
url: "https://example.com"
|
|
```
|
|
|
|
| Field | Purpose |
|
|
|-------|---------|
|
|
| `interface.display_name` | User-visible name in Codex UI |
|
|
| `interface.short_description` | Brief description for skill browser |
|
|
| `policy.allow_implicit_invocation` | `false` prevents auto-activation (explicit `$skill` only) |
|
|
| `dependencies.tools` | MCP server dependencies |
|
|
|
|
---
|
|
|
|
## Skill Discovery And Installation
|
|
|
|
The portable Codex skill root is `.agents/skills/` at repository or parent
|
|
scope and `$HOME/.agents/skills/` at user scope. Current Codex desktop installs
|
|
may also index `$HOME/.codex/skills/`; on Bo's development fleet both user roots
|
|
are symlinks to this repository's canonical `skills/` tree.
|
|
|
|
| Scope | Path | Use Case |
|
|
|-------|------|----------|
|
|
| Repo (nearest) | `.agents/skills/` from CWD | Folder-specific workflows |
|
|
| Repo (parent) | `../.agents/skills/` | Nested repo organization |
|
|
| Repo (root) | `$REPO_ROOT/.agents/skills/` | Organization-wide skills |
|
|
| User | `$HOME/.agents/skills/` | Portable personal skill collection |
|
|
| Host compatibility | `$HOME/.codex/skills/` | Codex-host symlink root when configured |
|
|
| Admin | `/etc/codex/skills/` | System-wide defaults |
|
|
| System | Bundled with Codex | Built-in skills |
|
|
|
|
Development symlinks may point directly at `skills/<name>/`; checked-in
|
|
`skills-codex/` packages are the portable Agent Skills release projection.
|
|
Canonical `skills/` frontmatter is intentionally host-extended and is evaluated
|
|
against the AgentOps profile, not mislabeled as portable. The release gate
|
|
`scripts/validate-codex-api-conformance.sh` validates every projected package
|
|
against the portable field, type, identity, body, and relative-resource-link
|
|
contract before applying Codex-specific checks. Plugin caches are neither
|
|
source nor an installation target and may be deleted without affecting the
|
|
canonical repository skills.
|
|
|
|
---
|
|
|
|
## Skill Invocation
|
|
|
|
| Method | Syntax | Description |
|
|
|--------|--------|-------------|
|
|
| Explicit | `$skill-name` or `/skills` menu | User directly requests the skill |
|
|
| Implicit | Automatic | Codex matches task to skill description |
|
|
|
|
Skills are loaded via **progressive disclosure**: metadata first (name,
|
|
description), full SKILL.md only when activated. Because the description is
|
|
the implicit-routing surface, a projection must preserve the source's complete
|
|
`Triggers:` clause while keeping its introductory prose within the catalog
|
|
budget; a generic summary or dropped trigger is a behavioral defect, even when
|
|
the body remains byte-complete.
|
|
|
|
---
|
|
|
|
## Multi-Agent (Sub-Agents)
|
|
|
|
Current Codex releases enable subagent workflows by default. Codex only spawns
|
|
subagents when the operator or parent agent explicitly asks it to do so.
|
|
Subagents inherit the parent sandbox policy and live runtime overrides.
|
|
|
|
### Agent Roles
|
|
|
|
Codex ships with these built-in roles:
|
|
|
|
| Role | Purpose |
|
|
|------|---------|
|
|
| `default` | General-purpose fallback |
|
|
| `worker` | Execution-focused implementation |
|
|
| `explorer` | Read-heavy codebase exploration |
|
|
|
|
Custom agents live as standalone TOML files under `$HOME/.codex/agents/` for
|
|
personal agents or `.codex/agents/` for project-scoped agents. Each custom
|
|
agent file must define `name`, `description`, and `developer_instructions`.
|
|
Optional fields such as `nickname_candidates`, `model`,
|
|
`model_reasoning_effort`, `sandbox_mode`, `mcp_servers`, and `skills.config`
|
|
inherit from the parent session when omitted.
|
|
|
|
Global subagent limits stay in the `[agents]` section of `config.toml`:
|
|
|
|
```toml
|
|
[agents]
|
|
max_threads = 6
|
|
max_depth = 1
|
|
job_max_runtime_seconds = 1800
|
|
|
|
[agents.reviewer]
|
|
description = "Code review specialist"
|
|
config_file = "codex-reviewer.toml"
|
|
```
|
|
|
|
`agents.max_threads` defaults to `6`; `agents.max_depth` defaults to `1`,
|
|
which allows direct child agents but prevents deeper recursive fan-out.
|
|
|
|
### Batch Processing
|
|
|
|
`spawn_agents_on_csv` processes batches of similar tasks:
|
|
|
|
| Parameter | Description |
|
|
|-----------|-------------|
|
|
| `csv_path` | Source CSV file |
|
|
| `instruction` | Worker prompt template with `{column_name}` placeholders |
|
|
| `id_column` | Stable identifiers |
|
|
| `output_schema` | Fixed JSON structure for worker results |
|
|
| `output_csv_path` | Destination CSV containing row metadata and results |
|
|
| `max_concurrency` | Parallel worker limit |
|
|
| `max_runtime_seconds` | Worker timeout |
|
|
|
|
Workers call `report_agent_job_result` exactly once.
|
|
|
|
`sqlite_home` controls where Codex stores the SQLite-backed state used for
|
|
agent jobs and exported results.
|
|
|
|
### Codex Built-in Tools
|
|
|
|
Tools available inside a Codex agent session:
|
|
|
|
| Tool | Purpose |
|
|
|------|---------|
|
|
| `read_file` | Read file contents |
|
|
| `list_dir` | List directory contents |
|
|
| `glob_file_search` | Find files by pattern |
|
|
| `apply_patch` | Apply file edits (diff-based) |
|
|
| `rg` | Ripgrep search |
|
|
| `git` | Git operations |
|
|
| Shell/terminal tool | Shell command execution |
|
|
| `spawn_agent` | Create a focused sub-agent |
|
|
| `send_input` | Send follow-up input to a sub-agent |
|
|
| `wait_agent` | Wait for one or more sub-agents |
|
|
| `close_agent` | Stop a stuck or no-longer-needed sub-agent |
|
|
|
|
### Claude → Codex Primitive Mapping
|
|
|
|
| Claude Code | Codex Equivalent | Converter Action |
|
|
|-------------|-----------------|------------------|
|
|
| `Read` tool | `read_file` | Map |
|
|
| `Edit` tool | `apply_patch` | Map |
|
|
| `Grep` tool | `rg` | Map |
|
|
| `Glob` tool | `glob_file_search` | Map |
|
|
| `Agent(subagent_type="Explore")` | Explorer agent role | Map |
|
|
| `Skill(skill="name")` | `$name` invocation | Map |
|
|
| `TaskCreate` / `TaskList` / `TaskUpdate` | No equivalent (`todo_write`/`update_plan` not available — empirically verified) | Strip |
|
|
| `TeamCreate` / `TeamDelete` | No equivalent | Strip |
|
|
| `SendMessage` | `send_input` for brief follow-up only | Rewrite or strip |
|
|
| `EnterPlanMode` / `ExitPlanMode` | No equivalent | Strip |
|
|
| `EnterWorktree` | No equivalent | Strip |
|
|
| `context.window` | No equivalent | Strip from frontmatter |
|
|
| `context.sections.exclude` | No equivalent | Strip from frontmatter |
|
|
| `context.intel_scope` | Deprecated — ignored, no reader | Does not exist |
|
|
| `disable-model-invocation` | No equivalent — Codex has no model-invocation switch and always advertises a `$name` skill | Strip from frontmatter |
|
|
|
|
Skills referencing these primitives produce **broken instructions** in Codex.
|
|
|
|
`disable-model-invocation` is a Claude Code context-budget control, not a
|
|
behavioral instruction, so stripping it loses nothing a Codex reader could act
|
|
on. The consequence is intended and asymmetric: a human-only skill is invisible
|
|
to Claude's implicit routing but stays `$name`-invocable under Codex. Requirement
|
|
1 below already strips it — the row exists so the divergence is declared rather
|
|
than discovered.
|
|
|
|
---
|
|
|
|
## Converter Requirements
|
|
|
|
When generating Codex skills from source skills:
|
|
|
|
1. **Strip all non-Codex frontmatter** — emit only `name` + `description`,
|
|
compacting introductory prose while preserving the complete source
|
|
`Triggers:` clause as the activation catalog signal
|
|
2. **Map Claude tools to Codex tools** — Read→read_file, Edit→apply_patch, Grep→rg, Glob→glob_file_search
|
|
3. **Rewrite `Skill(skill="X")` to `$X`** — Codex uses dollar-prefix invocation
|
|
4. **Strip ALL task/team primitives** — TaskCreate, TaskList, TeamCreate, SendMessage (none have working Codex equivalents as direct tool calls — `todo_write`/`update_plan` empirically unavailable, and `send_input` is follow-up-only)
|
|
5. **Fix paths** — avoid host-specific installed-skill paths; use repository-relative links in shipped instructions
|
|
6. **Rewrite reference files** — `.md` files in references/ pass through `codex_rewrite_text()` during copy
|
|
7. **Preserve skill body** — the SKILL.md body (instructions) is the skill's value; keep it functional
|
|
|
|
---
|
|
|
|
## Validation Criteria
|
|
|
|
A Codex-conformant skill must:
|
|
|
|
1. Have frontmatter with only `name` and `description`
|
|
2. Contain no Claude-only primitive names (TaskCreate, TeamCreate, SendMessage, etc.)
|
|
3. Contain no Claude-specific paths and no dependency on one host's installed-skill root
|
|
4. Have valid `agents/openai.yaml` if present
|
|
5. Not reference non-existent Codex features (context controls, plan mode, etc.)
|
|
|
|
---
|
|
|
|
## Generated inventories
|
|
|
|
`skills/<name>/SKILL.md` metadata owns the skill inventory and dependency graph.
|
|
Run `scripts/regen-all.sh` after changing it. The CLI command surface is a
|
|
separate executable projection generated from Cobra; no handwritten CLI-to-skill
|
|
map is maintained.
|
|
|
|
---
|
|
|
|
## Codex Skill Maintenance
|
|
|
|
Codex is a first-class runtime in this repo.
|
|
|
|
- `skills/<name>/SKILL.md` is the canonical behavior contract.
|
|
- `skills-codex-overrides/<name>/` is the Codex-specific tailoring layer.
|
|
- `skills-codex-overrides/catalog.json` is the machine-readable treatment map for the full catalog.
|
|
- `skills-codex/<name>/` is the generated checked-in Codex runtime artifact.
|
|
|
|
**Editing an EXISTING parity skill regenerates its Codex twin — not just hashes.**
|
|
`make regen-all` / `scripts/codex-sync.sh` refresh parity-only twins from
|
|
`skills/<name>/` whenever their generated body, prompt, or mirrored references
|
|
drift. `scripts/regen-codex-hashes.sh` remains the bookkeeping step after
|
|
content is current. Manual edits under `skills-codex/<name>/` are reserved for
|
|
bespoke skills or deliberate Codex-only divergence recorded in
|
|
`skills-codex-overrides/catalog.json`; otherwise fix the source skill or the
|
|
codex-sync transform/template and regenerate.
|
|
|
|
The current catalog has no bespoke or pointer twins. Every live Codex package is
|
|
a generated parity projection of `skills/<name>/SKILL.md` plus its linked local
|
|
files. `scripts/codex-sync.sh` owns those packages; manual edits under
|
|
`skills-codex/<name>/` are drift and will be overwritten.
|
|
|
|
`skills-codex-overrides/catalog.json` remains the explicit treatment registry.
|
|
If a future runtime-specific implementation is genuinely necessary, declare it
|
|
there before editing a twin and add focused parity tests in the same change.
|
|
Do not create an undocumented exception or a second skill inventory.
|
|
|
|
When a skill change affects Codex behavior, phrasing, orchestration, or UX:
|
|
|
|
1. Update the source skill under `skills/` when the shared contract changes.
|
|
2. For parity-only skills, update source or the codex-sync transform/template and regenerate. Update `skills-codex/<name>/SKILL.md` directly only when the Codex runtime copy is bespoke, or update `skills-codex-overrides/<name>/` when the Codex experience should differ from Claude.
|
|
- Prompt/operator-layer changes belong in `skills-codex-overrides/<name>/prompt.md`.
|
|
- Durable Codex-only body rewrites belong in `skills-codex-overrides/<name>/SKILL.md`.
|
|
3. Run the semantic audit if the checked-in Codex body looks suspicious:
|
|
|
|
```bash
|
|
bash scripts/audit-codex-parity.sh
|
|
# or target one skill
|
|
bash scripts/audit-codex-parity.sh --skill <name>
|
|
```
|
|
|
|
4. Validate the checked-in Codex artifacts:
|
|
|
|
```bash
|
|
bash scripts/audit-codex-parity.sh
|
|
bash scripts/validate-codex-override-coverage.sh
|
|
bash scripts/validate-codex-generated-artifacts.sh --scope worktree
|
|
bash scripts/validate-headless-runtime-skills.sh
|
|
python3 scripts/check-cathedral-cut-conformance.py
|
|
```
|
|
|
|
Think of `skills/` as the shared contract, `skills-codex-overrides/` as the durable Codex-only tailoring layer, and `skills-codex/` as the checked-in Codex artifact shipped to users.
|