Codex harness operations
This file is the Codex-facing entry point for Yoke. It references the shared bootstrap contract and lists the narrow safe command surface for Codex sessions.
Shared project rules load from the canonical AGENTS.md. This guide explains Codex-specific operations; it is an ordinary reference, not an additional auto-loaded instruction file.
Each standing rule in AGENTS.md names a deep home under .yoke/docs/agents/rules/ carrying the reasoning, recovery paths, and worked failure modes behind it; AGENTS.md lists which file covers which operation. Read the one that governs an operation before performing it, and read an operation's own --help for its variants and flags.
The ## Simplify — three-axis doctrine section in AGENTS.md defines the shared reuse / quality / efficiency vocabulary, future-concept pull-forward lens, and stage weights used by every authoring step (idea, refine, implement, shepherd, conduct, polish). Codex sessions read it from AGENTS.md; this file does not duplicate it. The doctrine is Yoke-owned and harness-neutral — do not treat any Claude-only built-in as a dependency.
Bootstrap
Native AGENTS.md and the opening hook provide shared startup orientation.
The start hook runs for every source, including forks, clear and compact.
Saved forks register under their own session id. Every registration path,
including the lazy one a tool-call hook drives, needs a saved transcript: a
Codex hook without one never creates or revives a session row, so unsaved
Desktop helper threads stay unregistered while their tool calls still run.
Transcript and usage credential reads honor CODEX_HOME (default ~/.codex).
The generated main_agent packet contains decisions and executable recipes
needed by that role; it is not a copied full schema/topic roster. Explicit
topic depth stays available through yoke packets render --help.
harness_contract separately owns manifest/bootstrap substrate facts.
See the packet reference.
Repo-local skill discovery
Yoke skills live canonically in the hidden directory .agents/skills/yoke/. Codex treats that repo-local .agents/skills tree as a native skill source, so no .codex/skills mirror or plugin install is required for ordinary Yoke work. Codex progressive disclosure loads each skill's frontmatter first and reads the full SKILL.md only when the skill is invoked. Claude requires .claude/skills/yoke, a native discovery symlink to the canonical tree in both source and installed projects. Codex and Cursor discover .agents/skills directly. No regular discovery copies are installed; native symlink support is required. See native discovery.
Approval and sandbox posture
Codex decides whether to stop and ask before running a command from
$CODEX_HOME/config.toml, and it reads no project-local config, so that
machine file is the only place the answer can live. Its defaults ask — and
its default sandbox denies every outbound socket, which is what a local
Postgres control plane listens on, so an unconfigured machine cannot reach
Yoke at all and cannot run the feedback command it is told to fall back to.
The shared harness reconcile writes what Codex needs into that file:
approval_policy and sandbox_mode from the same declaration the launch
plane already passes launched workers, plus a [projects."<checkout>"] trust
entry so Codex does not ask about the directory either. It only writes a key
that is absent, reports rather than overwrites a value you set yourself, and
leaves your model choices in place. It mints checkout hook trust and mirrors
that trust only to lanes with identical hook content. After hook content changes,
run yoke project refresh to install it and renew trust for the new hashes.
Yoke serializes its folder trust, posture, hook trust and owned-setting removal against the resolved configuration file, including symlink aliases. Each update reads current state under the same private lock and atomically replaces the file, preserving permissions and unrelated operator values. Parallel Yoke updates cannot overwrite each other's changes or expose a partial file.
If an update reports Codex config is busy, wait for the other update to finish
and retry the same operation; the message names the resolved target. Do not
delete its lock file to bypass a running writer. For invalid TOML or UTF-8,
repair the named file, then retry. Permission or publication failures name the
target and recovery; a refused update leaves the original configuration intact.
These file updates grant no new sign-in, machine or project approval.
Setup always writes approval_policy = "never" and
sandbox_mode = "danger-full-access", replacing prompting modes.
Unrelated configuration stays in place.
HC-harness-unattended-posture reports the standing posture for every
harness on the machine from saved configuration. Repair setup facets with
yoke doctor run --only harness-setup --fix.
The session check verifies native transcript identity and the newest turn's
approval_policy and sandbox_policy.type for codex-cli and codex-desktop.
Only never plus danger-full-access passes. Saved settings and earlier turns
cannot prove the active mode. Automatic review does not meet Yoke's
unrestricted-permissions requirement.
A restricted mode reports HARNESS_POSTURE_RESTRICTED: select Full Access
in this chat's permissions control and rerun yoke doctor run --session in
a new turn. Managed organization requirements take precedence; ask your
administrator if the mode is unavailable. See OpenAI's
permission documentation.
Missing, unreadable or out-of-window native evidence fails: rerun in a new turn
after it is saved, then start a new chat if necessary.
codex-vscode reports HARNESS_POSTURE_CONFIRM_REQUIRED as a WARN:
confirm Full Access is selected in this Codex VS Code chat before onboarding.
If a yoke command is refused with Operation not permitted, the CLI diagnoses
the harness sandbox denial and names the repair; follow that recovery.
Setup, project install/refresh and lane preparation use the same reconcile. The relay runs it when a harness home appears, covering registered checkouts and their lanes without reinstalling projects. Absent harness homes are never created. A failed facet names its reason and recovery while other facets run; the relay records failures and retries after 15 minutes, or immediately when the list of existing harness homes changes again.
Never wrap yoke in a shell loop or command substitution. An operator
who allows commands starting with yoke is allowing a first word, so
for slug in A B C; do yoke ...; done presents for and asks again — every
call inside it was already permitted, and the composition is what re-prompts.
Run repeated calls as separate plain invocations.
Work-item entry surfaces
Every create selects a workflow and a typed entry surface (web_form, cli, harness_skill, or promotion); the pinned immutable workflow version must allow that surface. /yoke idea drives the registered items.create function through harness_skill, while product forms and operator commands use their own typed surfaces. Dry-run and test-isolated DB targets may omit the surface.
Safe Command Surface
Codex sessions use the shared Yoke operator surface unless the Codex manifest declares a concrete substrate limitation.
Supported entrypoints
| Command | Description |
|---|---|
/yoke idea "title" |
File a new backlog item |
/yoke refine PREFIX-N |
Critique and improve item artifacts (no worktree, no code) |
/yoke implement PREFIX-N |
Drive a pinned implement segment in its registered single worktree lane |
/yoke conduct PREFIX-N |
Drive a pinned generated-task segment via shared dispatch descriptors |
/yoke polish PREFIX-N |
Review and finish implementation in existing worktree |
/yoke usher PREFIX-N [--dry-run] |
Merge/deploy handoff for implemented items; use dry-run first for Codex validation |
Supported downstream paths
Codex supports these downstream paths (derived server-side from the shared Yoke registry, then limited by the Codex manifest only when the manifest declares an explicit limitation):
| Path | Description |
|---|---|
shepherd |
Drive an item through quality-gated lifecycle to ready |
refine |
Critique and improve item artifacts |
implement |
Definition-bound single-lane implementation through review |
dash |
Direct execution from one spec, any size: survey, worktree, verify, merge, evidence |
blitz |
Document-led direct execution from the item's single linked strategy document |
conduct |
Definition-bound task-graph loop that dispatches Engineer / Tester / Architect / Simulator |
polish |
Review and finish implementation in existing worktree |
usher |
Merge and deploy implemented/release items through the top-level operator flow |
Work requiring paths outside this shared delivery-path set still falls back with a clear message. Yoke core derives the path list from the shared registry plus manifest-declared limitations — the harness no longer self-reports capabilities via environment variables.
Limitations
The Codex manifest is the source of truth for substrate limitations and currently declares none on entrypoints or downstream paths. The full operator surface — including /yoke conduct, /yoke resync, /yoke curate, /yoke wrapup, /yoke feed, /yoke strategize, and /yoke charge — is part of Codex's safe surface. Conduct dispatches the same yoke-engineer, yoke-tester, yoke-architect, and yoke-simulator agent bodies as Claude, rendered into Codex custom agents from the canonical agent bodies. The shared dispatch descriptor emits the same task envelope for both harnesses, so phase files name agents through descriptors rather than a Claude-only subagent_type. Result ingestion is parseable on both sides, and tool-call telemetry flows into the same event stream.
The remaining named substrate gap is on the telemetry edge: Codex does not emit a dedicated PostToolUseFailure event for non-Bash tools (Write/Edit/Read). Bash failures on Codex are recovered inside the PostToolUse handler via exit-code parsing, hard-failure text matching, and last-resort transcript reconciliation against tool_use_id ↔ rollout call_id.
Future shared-registry additions inherit to Codex unless a real substrate limitation is declared in the manifest.
Shell differences on Codex
Use the search tool available on the current machine: prefer rg; if it
is absent, use git grep -n 'pattern' or grep -rn 'pattern' <known-dir>.
Do not translate flags mechanically: grep -r is recursive, while rg -r
selects replacement text.
- Enumerate paths; never pass a shell glob. The path-glob guard denies an
unmatched zsh glob before the command runs, and its recovery line names
rg --files. List candidates withgit ls-filesor search a directory you have confirmed exists, and usegrep --includerather than a shell wildcard. - Single-quote the whole pattern. Mixed single/double quoting inside one regex is the most frequent denial here; a single-quoted literal avoids both zsh expansion and the unmatched-quote refusal.
- Run lane tests through
yoke watch pytest -- <bare pytest args>. A barepython3 -m pytestinside.worktrees/<branch>/resolves the main checkout's install: it either fails collection withModuleNotFoundError: yoke_contractsor, worse, passes while testing the wrong source.yoke dev run -- <command>binds any other lane-source command the same way. - Work acquisition takes the explicit item flag:
yoke claims work acquire --item PREFIX-N --reason "...". Other registered adapters have their own grammar; read that operation's--help.
Tool use on Codex
These Codex tool behaviours cost whole turns when they are met for the first time mid-task. All are harness-owned: nothing in Yoke changes them, so the handling is yours.
- Run a long
yokecommand alone in its ownexec_command, and keep thesession_idit returns. A long command shares its call with nothing: no&&chain, no second command after it, no surrounding pipeline. The call returns while the child is still alive, and that returnedsession_idis the only handle to it — continue the SAME session withwrite_stdinuntil the command exits and you have read its outcome. A secondexec_commandbeside a live one spends the shared resource twice and can cancel work the first was about to finish, and a turn that ends before the child exits kills it with no recorded verdict. - Run short blocking checks in the foreground with the default wait,
not a 1-second
yield_time_ms:yoke dev ruff-changed,yoke dev import-checkand file-line checks. - Replace a whole file with one
Updatehunk, and re-read a file after running a formatter.apply_patchmatches context exactly, so a rewrite expressed as many hunks fails on the first line that moved, and every hunk authored against pre-formatter context is stale the moment a formatter, codegen step, or bundle sync rewrites the file. Read the file back and author the next patch against what is actually there.
Identity
The Codex adapter sets these environment variables:
| Variable | Value | Purpose |
|---|---|---|
YOKE_EXECUTOR |
codex |
Identifies this session as a Codex harness |
YOKE_PROVIDER |
openai |
Records the provider for Codex sessions |
YOKE_MODEL |
runtime-resolved | Carries the actual Codex model label (for example gpt-5.4) into session registration |
The opening hook records these as session identity. Yoke core derives supported paths server-side from the shared registry and applies any limitations declared in the Codex manifest — the harness does not set YOKE_SUPPORTED_PATHS. In Codex Desktop, the adapter resolves YOKE_MODEL from the current thread's runtime metadata instead of guessing.
Yoke function-call surface
Yoke control-plane writes (item structured fields, sections, epic-task amendment, DB-claim amendment, claim mutation, QA writes) route through the Yoke function-call surface. Agents call typed function ids (items.structured_field.replace, items.structured_field.append_addendum, items.progress_log.append, workflow_item.epic_task.body_replace, db_claim.amend, claims.work.acquire, etc.); the CLI adapters (yoke items structured-field replace, yoke items structured-field append-addendum, yoke items section upsert, yoke workflow-item epic-task body-replace, yoke db-claim amend, yoke claims work acquire, etc.) construct the matching FunctionCallRequest and dispatch through the same registry. See .yoke/docs/functions/index.md for the envelope, the per-family reference, and the YokeFunctionCalled / DispatcherIdempotencyReplay / DispatcherDownstreamDegraded dispatcher-event schemas.
External tooling (git, pytest, package managers, rg / grep) stays command-shaped under the permanent-boundary classification. Yoke-owned control-plane reads, writes, and checks are function-shaped.
What Codex does NOT own
Codex is a harness adapter, not a replacement for Yoke core. The following remain Yoke-core responsibilities:
- Routing decisions -- steering selects work and pinned workflow bindings select the stage skill; shared Yoke code owns command/path support and Codex declares only substrate limitations
- Canonical telemetry -- session events, lifecycle transitions, and ledger entries come from Yoke core
- Ownership truth -- session claims, releases, and ownership tracking are core-owned
- Safety enforcement -- correctness comes from Yoke core, not from Codex hooks
Codex hooks (when available) are optional enhancements that improve ergonomics and local visibility. They are never the sole safety layer.
Lifecycle & Routing
The canonical lifecycle guide is
.yoke/docs/workflows/lifecycle.md. It explains how immutable
workflow versions own stages, transitions, target-stage gates, policies, and
registered runner bindings. For a live item, read
yoke workflows item get PREFIX-N and then
yoke workflows version get WORKFLOW VERSION; the pinned definition, not the
guide or a workflow-name branch, is the source of truth for which executor
owns the current stage.
Frontier computation lives in .yoke/docs/strategy/charge-frontier.md. Yoke core derives Codex's supported-path set server-side from the shared registry plus any manifest limitations; the adapter does not self-report capabilities via YOKE_SUPPORTED_PATHS.
Related docs
- Command boundaries -- registered skill boundaries and routing
- Charge Frontier -- frontier computation and status-to-adapter map