{
  "family": "agent-workflow",
  "schema": 1,
  "name": "codex-cli-bridge",
  "kind": "execution-backend",
  "version": "3.5.0",
  "posture": { "model": "gpt-5.6-sol", "effort": "xhigh", "tier": null },
  "provides": ["execute", "review"],
  "roles": {
    "execute": {
      "cmd": "codex-exec",
      "source": "bin/codex-exec.sh",
      "output": "diff",
      "contract": {
        "invocations": [
          "codex-exec [--nonce <n>] <plan-file|->",
          "codex-exec [--nonce <n>] <plan-file|-> -- <extra codex flags...>"
        ],
        "grounding": "automatic — the root AGENTS.md (Hard Constraints) is auto-merged into codex's context and the wrapper prepends the orchestrator execution contract; no grounding flags",
        "continue": [
          "codex-exec --resume-last [--nonce <n>] <plan-file|->",
          "codex-exec --resume <session-id> [--nonce <n>] <plan-file|->"
        ],
        "receipt": "side effect — a NONCED run mints ONE exec receipt beside the delegation store: the dispatch nonce seam is the AW_DISPATCH_NONCE environment value or its plain-argument equivalent --nonce <n>, recognised ONLY before the prompt operand (after the operand or a literal '--' it is passthrough payload, never a flag), under the safe grammar [A-Za-z0-9._-]{1,64} — anything else, a duplicate, or a flag disagreeing with a non-empty env value refuses PRE-SPEND. The store directory resolves exactly as the kit's delegation store does: the dirname of an ABSOLUTE AW_DELEGATION_STORE (a relative one, or one ending in a path separator, refuses), else the git common dir. The artifact is agent-workflow-exec-receipt-<backendLength>-<backend>-<nonce>.json in two states: 'reserved' is written atomically and NO-CLOBBER immediately before the CLI runs — that write IS the nonce reservation, so a second dispatch on the same nonce, or an already-taken report name, refuses BEFORE any spend — and 'terminal' replaces it in place at exit. A nonced run also refuses pre-spend when no timeout/gtimeout binary can cap it (an accounted dispatch that cannot be capped can never honour the terminal-exit rule; a nonce-LESS run still warns and runs uncapped), when node is missing (the mint core), and when the prompt rides on stdin instead of a contract FILE — contractDigest is computed BY THIS WRAPPER from the dispatch file it was actually handed, so the kit can refuse a run that executed a different contract than the one it opened. That digest is taken from the SAME bytes already read as the prompt, never a second open of the path: two reads leave a window in which the file can be swapped, and the run would then execute one contract while its receipt claimed the digest of another. The header's own nonce must EQUAL the dispatch nonce — 'dispatch open' copies the nonce FROM the header, so a disagreeing --nonce could only reserve an identity no return would ever absorb, and it refuses pre-spend. A contract file edited BETWEEN 'dispatch open' and the run is caught at ABSORB by the contractDigest comparison, not pre-spend: the wrapper never reads the ledger, and that boundary is what the whole lane rests on. At exit the wrapper FIRST re-reads its reservation and verifies its own opaque owner token — a foreign owner refuses having published NOTHING, neither report nor receipt — THEN writes the delegate's final message atomically to agent-workflow-exec-report-<backendLength>-<backend>-<nonce>.txt, THEN re-verifies the owner and REPLACES the reservation with the terminal receipt {schema, kind, state, backend, nonce, owner, contractDigest, wrapperVersion, posture {model, effort, tier}, capS, killGraceS, sessionId, exitStatus, outcome, reportDigest, reportLength, timestamp}: the report is complete on disk before any artifact says the run arrived. capS and killGraceS are the cap the run ACTUALLY applied. outcome is the wrapper's own SUBSET of the ledger's vocabulary — exit 0 with a session id -> success, exit 0 without one -> missing-identity, ANY nonzero exit including the timeout codes 124 and 137 -> transport-failure; every orchestrator judgment is recorded at absorb time, never claimed here. The session id is captured BEFORE outcome branching, so a FAILED run records one too; in resume mode it is the validated resume id. FAIL-CLOSED, deliberately NOT the review lane's warn-only receipt: a publication that cannot complete exits nonzero with a DISTINCT status, and the message states only what the run can still prove. 70: the reservation could not be verified BEFORE any publication — NOTHING was published, not the report and not the receipt, and because the artifact found there belongs to another run it is never a '--no-receipt' source. 71: a publication stopped after that point — either the report write failed (nothing beyond the reservation was published; the '--no-receipt' absorb then records reportLength 0, ineligible by the name empty-report) or the report IS on disk and the terminal receipt was not completed (the absorb reads it, report-if-present). The post-report lane never claims the reservation still stands, because after that point its fate is no longer something this run observed. Every lane names the tree as partial/dirtied rather than untouched. A nonce-LESS invocation is byte-unchanged: no reservation, no receipt, no artifact, no node.",
        "passthrough": {
          "policy": "guarded",
          "blocked": ["-c*", "--config*", "-s*", "--sandbox*", "--dangerously-bypass-approvals-and-sandbox", "--dangerously-bypass-hook-trust", "--full-auto", "--oss", "--local-provider*", "-p*", "--profile*", "-m*", "--model*", "-o*", "--output-last-message*", "--json*", "--color*", "--output-schema*", "--ephemeral*"],
          "probeRelaxed": ["--add-dir*", "-C*", "--cd*", "--skip-git-repo-check", "--ignore-rules", "--enable*", "--disable*"]
        },
        "notes": [
          "nested-sandbox limit: codex-exec ships its OWN OS sandbox (bwrap workspace-write) and cannot run nested inside a harness sandbox (the FS turns read-only) — route it OUTSIDE the harness sandbox (excludedCommands / a per-run consented bypass) on the OBSERVED bwrap/EPERM failure, never a preemptive blanket",
          "exec posture banner: ONE stderr line before dispatch states the ACTUAL run posture — exec posture: model=… effort=… tier=… sandbox=workspace-write session=fresh|resume:<id> timeout=… — from RESOLVED post-validation values; the resume id is validated pre-spend, and control bytes in any banner field refuse pre-spend",
          "threat model: the sidecar byte and grammar screens detect corrupted input under a trusted parent environment. A hostile parent environment — including exported shell functions or PATH substitution of core/backend commands — is outside the threat model and can substitute the backend itself. Targeted shadow-proof resolution protects banner/dispatch honesty from accidental shadowing; it is not an environment security boundary",
          "the exec posture banner appends a banner-only timeout=<duration|uncapped> field — exactly the duration handed to timeout(1), uncapped when no timeout/gtimeout binary caps the run; INFORMATIONAL only: it is never persisted in a receipt or session sidecar",
          "quote the posture banner verbatim when labeling this dispatch — the banner is the machine-stated posture; a prose re-type drifts",
          "every-run nested-sandbox scan (DUAL policy, deliberately two different rules): the scan runs on EVERY completed run, not only a failed one, because a run that SURVIVES the nested-sandbox failure exits 0 with an ungrounded answer and nothing said so. Failed run (rc != 0): the existing loose whole-trace combination rule prints the recovery hint. Successful run (rc == 0): a warning fires ONLY on precise per-item evidence — both a sandbox-mechanism token AND a permission/read-only failure token inside the aggregated_output of ONE command_execution item whose failure is PROVEN (a nonzero exit_code, or the serialized status \"failed\"); a null exit_code is never failure by itself, tokens split across two items never fire, and a successful command's output never fires. The answer is printed FIRST on stdout, then the warning on stderr. HONEST RESIDUAL: the exit status does NOT change on that lane (a distinct nonzero exit would give a heuristic scan DENY polarity, refusing real work whenever the scan over-warns), so an orchestrator keying on exit status alone can still bank an ungrounded answer — the stderr warning is the signal"
        ]
      }
    },
    "review": {
      "cmd": "codex-review",
      "source": "bin/codex-review.sh",
      "modes": ["plan", "code"],
      "output": "advisory",
      "contract": {
        "invocations": [
          "codex-review plan <plan-file> [--nonce <n>]",
          "codex-review code [--nonce <n>] [extra focus...]"
        ],
        "grounding": "automatic — the wrapper precomputes the full working-tree change set (repo map, status, diffs, untracked contents) and codex auto-merges the root AGENTS.md; no grounding flags",
        "continue": [],
        "receipt": "side effect — a successful review appends one JSON receipt line to <git dir>/agent-workflow-review-receipts.jsonl (AW_REVIEW_RECEIPTS overrides): fingerprint = sha256 over the canonical uncommitted-state payload (staged diff + unstaged diff + untracked-not-ignored contents — the review-payload domain; never-committable untracked paths — character/block devices, FIFOs, sockets — are excluded from the domain entirely, untracked symlinks/directories ride as name-only notes) in code mode, the artifact-file sha256 in plan mode; verdict parsed from the mandated literal verdict line (schema mode: the verdict field); always fresh:true (one-shot) + grounded:true (native AGENTS.md auto-merge, factsHash null); probe = whether the run relaxed the quality guards (CODEX_PROBE=1), written on EVERY receipt so it self-declares — the kit's review-state gate rejects a probe-marked receipt (a probe review never attests) and equally rejects an unmarked one (silence is not a declaration); posture = the ACTUAL run posture {model, effort, tier} (tier null on the standard tier), written on EVERY receipt (D5) — the gate rejects a receipt with an absent/invalid posture (a pre-D5 wrapper minted it; re-run the review), one stderr banner line states the same posture, and a posture value carrying control bytes refuses pre-spend in every mode; a run whose final message carries NO recognized 'Verdict: <ship|revise|rethink>' line — empty or missing output included — exits 4 with NO receipt (D4: a FAILED review to RE-RUN, never a fatal session error); when the dispatch nonce seam is supplied — the AW_REVIEW_NONCE environment value or its plain-argument equivalent --nonce <n> (one seam: the flag assigns the same value; supplying both with different values refuses pre-spend) — under the safe grammar [A-Za-z0-9._-]{1,64} (anything else refuses pre-spend), the wrapper first mints the finding MANIFEST {schema, backend, nonce, fingerprint, findings} beside the receipts file (agent-workflow-finding-manifest-<backend>-<nonce>.json; atomic, no-clobber — a byte-identical rewrite is an idempotent no-op, different bytes refuse loudly) ORDERED before the receipt append — a failed manifest write EXCLUDES the receipt append, so a nonce-supplied dispatch can never land a receipt without its readable manifest; a nonce-less invocation adds NO nonce field and mints NO finding manifest (the existing wrapperVersion field still changes with each bridge release); a write failure warns, never fails the review",
        "notes": [
          "the review posture banner appends a banner-only timeout=<duration> field — exactly the duration handed to timeout(1); the hard-timeout preflight fails CLOSED when no timeout/gtimeout binary exists (the wrapper refuses by name before any CLI run, so an uncapped review run can no longer happen), and the field never enters the receipt posture or the D5 banner↔receipt parity",
          "quote the posture banner verbatim when labeling this dispatch — the banner is the machine-stated posture; a prose re-type drifts"
        ]
      }
    }
  },
  "modeCatalog": [
    {
      "key": "exec",
      "kind": "primary",
      "role": "execute",
      "purpose": "Execute a bounded plan in a sandboxed workspace and hand back a diff to review.",
      "whenToUse": [
        "a bounded sub-task whose acceptance criteria are already pinned",
        "work you will review and commit yourself — the backend never commits"
      ],
      "whenNotTo": [
        "work whose design is still open — decide it first, then delegate",
        "anything you cannot check: the diff is advisory until you review it"
      ],
      "invocationRefs": [
        { "contractField": "invocations", "index": 0 },
        { "contractField": "invocations", "index": 1 }
      ],
      "operands": [
        { "slot": "[--nonce <n>]", "required": false, "description": "the delegation dispatch nonce — the plain-argument lane onto the AW_DISPATCH_NONCE seam (dispatch open records it; flag and a non-empty env must agree), recognised only before the prompt operand" },
        { "slot": "<plan-file|->", "required": true, "description": "the plan or instruction file, or - to read it from stdin (a nonced dispatch requires the FILE — contractDigest binds it)" },
        { "slot": "<extra codex flags...>", "required": false, "description": "extra codex flags, filtered by the guarded passthrough tiers" }
      ],
      "guardrails": [
        { "value": "runs under codex's OWN OS sandbox (workspace-write)", "enforcement": "enforced", "condition": "it cannot nest inside another sandbox — the FS turns read-only; route it outside on the OBSERVED failure", "source": "capability.json roles.execute.contract.notes" },
        { "value": "the guarded passthrough blocks model / sandbox / approval overrides", "enforcement": "enforced", "source": "bin/codex-exec.sh" },
        { "value": "hard wall-clock cap CODEX_HARD_TIMEOUT (built-in default 3600s)", "enforcement": "enforced", "condition": "only while timeout(1)/gtimeout is on PATH — otherwise the wrapper warns and runs uncapped, and a NONCED run refuses pre-spend", "source": "capability.json settings.CODEX_HARD_TIMEOUT" },
        { "value": "ONE exec posture stderr banner line states the ACTUAL run posture before dispatch (session=fresh|resume:<id>; timeout is banner-only)", "enforcement": "enforced", "source": "bin/codex-exec.sh" },
        { "value": "a NONCED run reserves its nonce before any spend and publishes a fail-closed terminal receipt at exit", "enforcement": "enforced", "condition": "nonce-supplied runs only — a nonce-less invocation writes no artifact at all", "source": "capability.json roles.execute.contract.receipt" }
      ],
      "customHooks": ["CODEX_PROBE"]
    },
    {
      "key": "exec.resume-last",
      "kind": "continuation",
      "role": "execute",
      "purpose": "Continue the most recent codex-exec session with a follow-up instruction.",
      "whenToUse": ["a small delta on work the same session already holds in context"],
      "whenNotTo": ["a fresh task — a stale session carries stale assumptions"],
      "invocationRefs": [{ "contractField": "continue", "index": 0 }],
      "operands": [
        { "slot": "[--nonce <n>]", "required": false, "description": "the delegation dispatch nonce — the plain-argument lane onto the AW_DISPATCH_NONCE seam, recognised only before the prompt operand" },
        { "slot": "<plan-file|->", "required": true, "description": "the follow-up instruction file, or - to read it from stdin (a nonced dispatch requires the FILE — contractDigest binds it)" }
      ],
      "guardrails": [
        { "value": "ONE exec posture stderr banner line states the ACTUAL run posture before dispatch (session=resume:<id> only AFTER the sidecar id is resolved and validated; timeout is banner-only)", "enforcement": "enforced", "source": "bin/codex-exec.sh" }
      ],
      "customHooks": ["CODEX_PROBE"]
    },
    {
      "key": "exec.resume",
      "kind": "continuation",
      "role": "execute",
      "purpose": "Continue a NAMED codex-exec session by the session id it printed.",
      "whenToUse": ["resuming a specific earlier session after other runs happened in between"],
      "invocationRefs": [{ "contractField": "continue", "index": 1 }],
      "operands": [
        { "slot": "<session-id>", "required": true, "description": "the session id the original run printed on stderr" },
        { "slot": "[--nonce <n>]", "required": false, "description": "the delegation dispatch nonce — the plain-argument lane onto the AW_DISPATCH_NONCE seam, recognised only before the prompt operand" },
        { "slot": "<plan-file|->", "required": true, "description": "the follow-up instruction file, or - to read it from stdin (a nonced dispatch requires the FILE — contractDigest binds it)" }
      ],
      "guardrails": [
        { "value": "ONE exec posture stderr banner line states the ACTUAL run posture before dispatch (session=resume:<id> only AFTER the explicit id is validated against the session-id grammar; timeout is banner-only)", "enforcement": "enforced", "source": "bin/codex-exec.sh" }
      ],
      "customHooks": ["CODEX_PROBE"]
    },
    {
      "key": "review.plan",
      "kind": "primary",
      "role": "review",
      "submode": "plan",
      "purpose": "Critique an implementation plan before any of its code exists.",
      "whenToUse": [
        "a plan draft heading into its review council",
        "checking whether a cold executor could really run the plan"
      ],
      "whenNotTo": ["a working-tree change set — that is review.code"],
      "invocationRefs": [{ "contractField": "invocations", "index": 0 }],
      "operands": [
        { "slot": "<plan-file>", "required": true, "description": "the plan file under review" },
        { "slot": "[--nonce <n>]", "required": false, "description": "the flow dispatch nonce — the plain-argument lane onto the AW_REVIEW_NONCE seam (round-open prints the value; flag and a non-empty env must agree)" }
      ],
      "guardrails": [
        { "value": "read-only sandbox — codex cannot edit, create or delete a file", "enforcement": "enforced", "source": "bin/codex-review.sh" },
        { "value": "runs on the pinned model at max effort", "enforcement": "enforced", "condition": "unless CODEX_PROBE=1 relaxes the guard for a throwaway probe", "source": "bin/codex-review.sh" },
        { "value": "a successful review appends one receipt line the review-state gate reads", "enforcement": "enforced", "condition": "a receipt write failure warns and the review still succeeds — the tree then reads un-receipted", "source": "capability.json roles.review.contract.receipt" }
      ],
      "customHooks": ["CODEX_PROBE"]
    },
    {
      "key": "review.code",
      "kind": "primary",
      "role": "review",
      "submode": "code",
      "purpose": "Review the uncommitted working-tree change set, precomputed in full for codex.",
      "whenToUse": [
        "a finished segment heading into its review round",
        "a second opinion on real code before the commit ask"
      ],
      "whenNotTo": ["a clean tree — the wrapper exits before spending a run"],
      "invocationRefs": [{ "contractField": "invocations", "index": 1 }],
      "operands": [
        { "slot": "[--nonce <n>]", "required": false, "description": "the flow dispatch nonce — the plain-argument lane onto the AW_REVIEW_NONCE seam (round-open prints the value; flag and a non-empty env must agree)" },
        { "slot": "[extra focus...]", "required": false, "description": "extra focus words appended to the review directive" }
      ],
      "guardrails": [
        { "value": "read-only sandbox — codex cannot edit, create or delete a file", "enforcement": "enforced", "source": "bin/codex-review.sh" },
        { "value": "an oversized change set rides via a git-dir temp file, never truncated", "enforcement": "enforced", "source": "bin/codex-review.sh" },
        { "value": "a successful review appends one receipt line the review-state gate reads", "enforcement": "enforced", "condition": "a receipt write failure warns and the review still succeeds — the tree then reads un-receipted", "source": "capability.json roles.review.contract.receipt" }
      ],
      "customHooks": ["CODEX_PROBE"]
    },
    {
      "key": "CODEX_PROBE",
      "kind": "env-hook",
      "parents": ["exec", "exec.resume-last", "exec.resume", "review.plan", "review.code"],
      "purpose": "Relax the quality guards for a THROWAWAY probe run.",
      "whenToUse": [
        "a probe whose answer cannot depend on model or effort",
        "checking that the wrapper plumbing works at all"
      ],
      "whenNotTo": ["any run whose output informs what ships — a probe never attests"],
      "descriptor": "CODEX_PROBE=1 codex-review code",
      "guardrails": [
        { "value": "a probe review mints a probe-marked receipt the review-state gate rejects", "enforcement": "enforced", "source": "agent-workflow-kit tools/review-state.mjs" },
        { "value": "on codex-exec it also relaxes the passthrough to the probeRelaxed tier", "enforcement": "enforced", "source": "bin/codex-exec.sh" }
      ]
    }
  ],
  "settings": [
    {
      "key": "CODEX_SERVICE_TIER",
      "kind": "enum",
      "values": ["priority"],
      "default": null,
      "appliesTo": ["codex-exec", "codex-review"],
      "effect": "codex service tier; 'priority' (catalog display name Fast) = ~1.5x token speed at a 2.5x credit rate on gpt-5.6-sol — quality-neutral (same model), live-probed 2026-07-05. Unset/empty ⇒ no service_tier flag (standard tier). SPEND KNOB: enabling it is a consented per-host act, never a default. codex itself accepts any -c service_tier string silently, so the wrapper validates the value."
    },
    {
      "key": "CODEX_HARD_TIMEOUT",
      "kind": "integer",
      "min": 1,
      "max": 86400,
      "default": null,
      "appliesTo": ["codex-exec", "codex-review"],
      "effect": "hard wall-clock cap in seconds via timeout(1); built-in default 3600 (codex-exec) / 1800 (codex-review)."
    },
    {
      "key": "CODEX_REVIEW_MAX_TOTAL_BYTES",
      "kind": "integer",
      "min": 1,
      "max": 100000000,
      "default": "1500000",
      "appliesTo": ["codex-review"],
      "effect": "codex-review code: above this assembled-payload size (bytes) the diff rides via a git-dir temp file instead of inline — never truncated."
    }
  ],
  "networkHosts": ["chatgpt.com", "*.chatgpt.com"],
  "writableDirs": [{ "env": "CODEX_HOME", "default": "~/.codex" }],
  "detect": {
    "installed": {
      "env": "CODEX_CLI_BRIDGE_DIR",
      "default": "~/.claude/skills/codex-cli-bridge",
      "file": "SKILL.md"
    }
  },
  "cost": "subscription",
  "quota": { "kind": "subscription", "finite": true },
  "provenance": { "author": "sabaiway", "source": "github:sabaiway/agent-workflow" }
}
