Provider: Codex CLI adapter behind AgentProvider — research-pinned spec (supersedes #2) #87

Closed
opened 2026-07-10 01:58:56 +02:00 by dominik.polakovics · 4 comments

Context

Supersedes #2 (closed as superseded — its triage history remains the record for the attach decision and the #6 seam refactor). That issue predates the provider-seam hardening wave this one builds on: ADR-0033 (provider-declared attribution markers, #75), ADR-0034 (per-provider login sessions #77, generic per-provider host config #78), ADR-0035 (lab-owned context-file names + skills index for skills-less providers, #79), and #80 (two-tier conformance suite + provider-authoring checklist — implementing now, lands before this issue starts).

Definition of done = #80's bar: pass the Tier 1 hermetic conformance suite + run the Tier 2 live spikes, evidenced by a committed compat record, following the provider-authoring checklist.

Carried forward from #2's triage (still binding):

  • No deep link. OpenAI remote-connections requires the desktop app as pairing host; there is no per-session URL. The adapter omits DeepLinker; instance rows show the copyable tmux-attach affordance.
  • Binary deployment is #74 (nixpkgs ships codex 0.133.0, already in the host store).

Decisions from the 2026-07-10 grill:

  1. One phased issue (spike → implement → conform), not a spike/impl split.
  2. Spawn posture: full access, never ask — parity with claude-code's --permission-mode auto; isolation is the host's job (service user + worktree), not the agent sandbox's.
  3. Per-session config rides argv -c overrides first; the global ~/.codex/config.toml is touched only for settings an override verifiably cannot carry.
  4. Auth: ChatGPT OAuth redirect (AuthFlowOAuthRedirect) with SSH port-forward instructions; API-key flow out of scope.
  5. Incogni: defensive ScrubPatterns now, reconciled against live ground truth (tighten/extend, never just delete).
  6. LiveSignals omitted in v1 (honest degradation, ADR-0020); codex's notify/hooks findings are recorded in the compat record as the follow-up route.
  7. Context file: AGENTS.local.md via fallback config + a global $CODEX_HOME/AGENTS.md bridge (see Seeding).

Research basis: online docs sweep of 2026-07-10 (developers.openai.com/codex CLI/config/auth/hooks/sandbox references + upstream issues). Facts below marked (spike N) are unverified against the pinned binary and appear in the live-spike checklist.

Design

Spawn

codex --ask-for-approval never --sandbox danger-full-access \
      -c commit_attribution="" \
      -c 'project_doc_fallback_filenames=["AGENTS.local.md"]' \
      [--model M] [-c model_reasoning_effort=E] [PROMPT]
  • Trailing positional initial prompt is official CLI behavior; empty prompt appends nothing (the seam's pinned shape).
  • --ask-for-approval never is documented: no approval prompts ever. danger-full-access avoids the two known workspace-write traps for lab sessions: network off by default (breaks labctl/git push) and writes confined to cwd (a linked worktree's commits write to the shared git dir outside cwd).
  • Model catalog pinned from the live binary at implementation time (spike 1). July-2026 candidates: gpt-5.5 (default candidate), gpt-5.6-sol / gpt-5.6-terra / gpt-5.6-luna; do not pin slugs retiring 2026-07-23 (gpt-5.1-codex*, gpt-5.2-codex, …). Efforts: minimal|low|medium|high (+xhigh where the model supports it (spike 2)), default medium, applied via -c model_reasoning_effort=.
  • SpawnOptions(): none declared in v1.

Auth

  • AuthFlow{Kind: oauth-redirect}; Instructions carries the headless recipe (documented upstream): ssh -L 1455:localhost:1455 <host>, run login, open the printed URL in the local browser.
  • LoginStart drives codex login inside the per-provider login session (ADR-0034 naming, tmuxx.IsLoginSession) and scrapes the authorize URL (spike 5: which stream it prints on); LoginSubmitCode returns a typed not-supported error (redirect flows have no pasted code); completion is detected by forced AuthStatus polling over codex login status (exit 0 = logged in; non-zero value (spike 5)).
  • Logout = codex logout + forced status refresh (seam contract: success decided from status, not exit code). Credentials live in $CODEX_HOME/auth.json (default ~/.codex).
  • Known upstream hazard: Ctrl-C cannot exit the login screen under tmux with keyboard-enhancement (openai/codex#23820) (spike 5).

Workspace seeding (SeedMeta + SeedWorkspace)

  • ContextFileName: "AGENTS.local.md" (#79 hard rule: lab-owned, never repo-tracked).
  • Discovery wiring is the adapter's job and is double-pathed, because project_doc_fallback_filenames is fallback-only per directory level — a repo-committed AGENTS.md at the worktree root would silently skip the fallback:
    1. -c project_doc_fallback_filenames=["AGENTS.local.md"] (covers repos without their own AGENTS.md), and
    2. a lab-managed $CODEX_HOME/AGENTS.md bridge whose sole content instructs: if AGENTS.local.md exists at the workspace root, read and follow it — the global file is always concatenated regardless of repo files, so lab context survives a tracked AGENTS.md.
      Both couplings live-verified end-to-end, including against a repo that tracks its own AGENTS.md (spike 9).
  • NativeSkillDiscovery: false → the seeder appends the ADR-0035 skills index to the context file. Spike note: the TUI now has a /skills command — check whether 0.133+ has native skill discovery from a seedable path; if so, flip to native (spike 8b).
  • ExcludeEntries cover every seeded path; SeededPathPatterns stay narrower (guard never rejects a repo's own tracked codex config).
  • ScrubPatterns (BRE∩RE2 dialect, #75): defensive shapes for the documented attribution default Co-authored-by: Codex <noreply@openai.com> plus generated-with-Codex variants, shipped as the adapter's conformance marker samples; reconciled against Tier 2 ground truth (spike 10).
  • Incogni source-level disable (D15 §9 measure 1): -c commit_attribution="" in the spawn argv (upstream: commit_attribution config backs the codex_git_commit feature's co-author trailer).
  • SeedWorkspace stays minimal (config rides argv). One candidate exception: directory trust. Whether -c 'projects."<worktree>".trust_level="trusted"' satisfies the first-run trust prompt is undocumented (spike 3); only if it fails does SeedWorkspace fall back to a guarded append of the [projects] entry to ~/.codex/config.toml.

Chat surface

  • LocateTranscript: newest rollout under $CODEX_HOME/sessions/YYYY/MM/DD/rollout-<ts>-<uuid>.jsonl whose session_meta.cwd matches the worktree (cwd is recorded; codex resume --last is cwd-scoped upstream).
  • ReadTranscript: map the rollout JSONL (session_meta; response_item subtypes message/function_call/function_call_output/reasoning; event_msg task_started/task_complete/agent_message/token_count; turn_context) into the universal schema — reasoning → text+Thinking, function_call(+output) → tool chips, task events → lifecycle/state.
  • Clear/epoch obligation: /new carries CommandRoleClear. Whether /new opens a new rollout file (identity rotates for free) or clears in place (adapter synthesizes an epoch-qualified path) is (spike 4).
  • Reply: tmux send-keys. Upstream: Enter mid-turn steers the current turn (input is injected, not dropped) — reply-while-working is legal with no typed drop error. Multi-line delivery (bracketed paste vs Ctrl+J newlines) (spike 7).
  • Interrupt: single Esc. Ctrl-C is a quit hazard (conflicting upstream sources; some versions exit immediately) — the recipe must never emit it; double-Esc triggers backtrack/fork on an empty composer, hazard-check both (spike 6).
  • Commands: curated catalog; /new (role clear, ChatSafe), picker-opening commands (/resume, /fork, /model, /permissions, …) ship ChatSafe: false. Note upstream rename /approvals/permissions.
  • Dialogs: none answerable in v1 (never-ask posture + no structured question tool); unknown shapes degrade to Answerable: false + tmux-attach hint.
  • Optional capabilities omitted: DeepLinker (no web surface), LiveSignals (no verified structured channel in v1; compat record documents notify = agent-turn-complete only, and the 2026 hooks system incl. PermissionRequest (spike 8) as the follow-up route), ConnectingReporter (nothing to connect).

Plan (phased, one issue)

  1. Tier 2 discovery spikes against a logged-in codex CLI on the lab host (login as the lab service user; binary via #74). Answers land in the committed compat record with real samples (rollout JSONL excerpts, keystroke recipes, login transcript, attribution ground truth).
  2. Implement internal/provider/codex against the pinned couplings; register the provider; keep core grep-clean.
  3. Conformance: add the adapter to #80's Tier 1 registration table and pass in CI; re-run the Tier 2 recipe hazard checks; commit the compat record per the checklist.

Live-spike checklist (each answer → compat record)

  1. Default model slug + live model/effort catalog on the pinned binary (/status, /model).
  2. xhigh effort support per model; the rumored -m model[effort] bracket syntax — real?
  3. -c 'projects."<path>".trust_level="trusted"' as trust pre-grant — works? (else SeedWorkspace config-append fallback)
  4. /new: new rollout file (rotation) vs in-place clear (epoch synthesis required).
  5. Login: URL output stream (stdout/stderr), codex login status exit codes, tmux login-screen Ctrl-C bug (#23820) workaround.
  6. Interrupt hazards on the pinned version: Esc, double-Esc backtrack, Ctrl-C quit behavior.
  7. Reply injection via tmux send-keys: bracketed paste, Ctrl+J newlines, steer-vs-queue mid-turn.
  8. Hooks availability in 0.133 (PermissionRequest et al.) — record only, for the LiveSignals follow-up. 8b: /skills — native skill discovery? From a seedable path?
  9. Context-file wiring end-to-end: project_doc_fallback_filenames present + fallback semantics on 0.133; global $CODEX_HOME/AGENTS.md bridge verified against a repo WITH a tracked AGENTS.md.
  10. Attribution ground truth: commits/PRs with the git feature on/off; -c commit_attribution="" verified; ScrubPatterns reconciled.
  11. TERM under tmux (tmux-256color vs xterm-256color; OSC 11 timeout issue #22761).

Acceptance

  • A repo with provider: codex runs manual + AFK sessions end to end (seed prompt as trailing argv positional; tracker-agnostic labctl seed vocabulary unchanged).
  • Tier 1 conformance passes in CI via the #80 registration table; Tier 2 evidenced by the committed compat record.
  • Incogni parity: no attribution at the source (commit_attribution=""), the adapter's ScrubPatterns strip its own marker samples through the union path, pre-push guard clean.
  • Core stays adapter-agnostic: no codex references outside internal/provider/codex (grep-clean).
  • ADR records the adapter's notable choices: sandbox posture parity, argv-first config, the global AGENTS.md bridge, LiveSignals deferral.

Out of scope

  • LiveSignals / hook-based live signals (follow-up issue once spike 8 pins hook availability).
  • API-key auth (AuthFlowAPIKey has no mechanism behind it; separate issue if wanted).
  • Embedded remote interface; any DeepLinker work.
  • Binary deployment (#74) and the conformance suite itself (#80).

Sequencing

needs-triage until #80 merges — its suite + checklist are this issue's definition of done, so it starts after. At re-triage, expected ready-for-human: every fragile coupling needs a live logged-in codex session, which an AFK agent on this host cannot drive.

## Context Supersedes #2 (closed as superseded — its triage history remains the record for the attach decision and the #6 seam refactor). That issue predates the provider-seam hardening wave this one builds on: ADR-0033 (provider-declared attribution markers, #75), ADR-0034 (per-provider login sessions #77, generic per-provider host config #78), ADR-0035 (lab-owned context-file names + skills index for skills-less providers, #79), and #80 (two-tier conformance suite + provider-authoring checklist — implementing now, lands before this issue starts). **Definition of done = #80's bar**: pass the Tier 1 hermetic conformance suite + run the Tier 2 live spikes, evidenced by a committed compat record, following the provider-authoring checklist. Carried forward from #2's triage (still binding): - **No deep link.** OpenAI remote-connections requires the desktop app as pairing host; there is no per-session URL. The adapter omits `DeepLinker`; instance rows show the copyable tmux-attach affordance. - Binary deployment is #74 (nixpkgs ships `codex` 0.133.0, already in the host store). Decisions from the 2026-07-10 grill: 1. One phased issue (spike → implement → conform), not a spike/impl split. 2. Spawn posture: **full access, never ask** — parity with claude-code's `--permission-mode auto`; isolation is the host's job (service user + worktree), not the agent sandbox's. 3. Per-session config rides **argv `-c` overrides first**; the global `~/.codex/config.toml` is touched only for settings an override verifiably cannot carry. 4. Auth: **ChatGPT OAuth redirect** (`AuthFlowOAuthRedirect`) with SSH port-forward instructions; API-key flow out of scope. 5. Incogni: **defensive ScrubPatterns now, reconciled against live ground truth** (tighten/extend, never just delete). 6. **LiveSignals omitted in v1** (honest degradation, ADR-0020); codex's `notify`/hooks findings are recorded in the compat record as the follow-up route. 7. Context file: **`AGENTS.local.md` via fallback config + a global `$CODEX_HOME/AGENTS.md` bridge** (see Seeding). Research basis: online docs sweep of 2026-07-10 (developers.openai.com/codex CLI/config/auth/hooks/sandbox references + upstream issues). Facts below marked *(spike N)* are unverified against the pinned binary and appear in the live-spike checklist. ## Design ### Spawn ``` codex --ask-for-approval never --sandbox danger-full-access \ -c commit_attribution="" \ -c 'project_doc_fallback_filenames=["AGENTS.local.md"]' \ [--model M] [-c model_reasoning_effort=E] [PROMPT] ``` - Trailing positional initial prompt is official CLI behavior; empty prompt appends nothing (the seam's pinned shape). - `--ask-for-approval never` is documented: no approval prompts ever. `danger-full-access` avoids the two known workspace-write traps for lab sessions: network off by default (breaks `labctl`/`git push`) and writes confined to cwd (a linked worktree's commits write to the shared git dir *outside* cwd). - Model catalog pinned from the live binary at implementation time *(spike 1)*. July-2026 candidates: `gpt-5.5` (default candidate), `gpt-5.6-sol` / `gpt-5.6-terra` / `gpt-5.6-luna`; do not pin slugs retiring 2026-07-23 (`gpt-5.1-codex*`, `gpt-5.2-codex`, …). Efforts: `minimal|low|medium|high` (+`xhigh` where the model supports it *(spike 2)*), default `medium`, applied via `-c model_reasoning_effort=`. - `SpawnOptions()`: none declared in v1. ### Auth - `AuthFlow{Kind: oauth-redirect}`; `Instructions` carries the headless recipe (documented upstream): `ssh -L 1455:localhost:1455 <host>`, run login, open the printed URL in the local browser. - `LoginStart` drives `codex login` inside the per-provider login session (ADR-0034 naming, `tmuxx.IsLoginSession`) and scrapes the authorize URL *(spike 5: which stream it prints on)*; `LoginSubmitCode` returns a typed not-supported error (redirect flows have no pasted code); completion is detected by forced `AuthStatus` polling over `codex login status` (exit 0 = logged in; non-zero value *(spike 5)*). - `Logout` = `codex logout` + forced status refresh (seam contract: success decided from status, not exit code). Credentials live in `$CODEX_HOME/auth.json` (default `~/.codex`). - Known upstream hazard: Ctrl-C cannot exit the login screen under tmux with keyboard-enhancement (openai/codex#23820) *(spike 5)*. ### Workspace seeding (SeedMeta + SeedWorkspace) - `ContextFileName: "AGENTS.local.md"` (#79 hard rule: lab-owned, never repo-tracked). - Discovery wiring is the adapter's job and is double-pathed, because `project_doc_fallback_filenames` is **fallback-only per directory level** — a repo-committed `AGENTS.md` at the worktree root would silently skip the fallback: 1. `-c project_doc_fallback_filenames=["AGENTS.local.md"]` (covers repos without their own AGENTS.md), and 2. a lab-managed `$CODEX_HOME/AGENTS.md` bridge whose sole content instructs: *if `AGENTS.local.md` exists at the workspace root, read and follow it* — the global file is always concatenated regardless of repo files, so lab context survives a tracked AGENTS.md. Both couplings live-verified end-to-end, including against a repo that tracks its own `AGENTS.md` *(spike 9)*. - `NativeSkillDiscovery: false` → the seeder appends the ADR-0035 skills index to the context file. Spike note: the TUI now has a `/skills` command — check whether 0.133+ has native skill discovery from a seedable path; if so, flip to native *(spike 8b)*. - `ExcludeEntries` cover every seeded path; `SeededPathPatterns` stay narrower (guard never rejects a repo's own tracked codex config). - `ScrubPatterns` (BRE∩RE2 dialect, #75): defensive shapes for the documented attribution default `Co-authored-by: Codex <noreply@openai.com>` plus generated-with-Codex variants, shipped as the adapter's conformance marker samples; reconciled against Tier 2 ground truth *(spike 10)*. - Incogni source-level disable (D15 §9 measure 1): `-c commit_attribution=""` in the spawn argv (upstream: `commit_attribution` config backs the `codex_git_commit` feature's co-author trailer). - `SeedWorkspace` stays minimal (config rides argv). One candidate exception: directory trust. Whether `-c 'projects."<worktree>".trust_level="trusted"'` satisfies the first-run trust prompt is undocumented *(spike 3)*; only if it fails does `SeedWorkspace` fall back to a guarded append of the `[projects]` entry to `~/.codex/config.toml`. ### Chat surface - `LocateTranscript`: newest rollout under `$CODEX_HOME/sessions/YYYY/MM/DD/rollout-<ts>-<uuid>.jsonl` whose `session_meta.cwd` matches the worktree (cwd is recorded; `codex resume --last` is cwd-scoped upstream). - `ReadTranscript`: map the rollout JSONL (`session_meta`; `response_item` subtypes `message`/`function_call`/`function_call_output`/`reasoning`; `event_msg` `task_started`/`task_complete`/`agent_message`/`token_count`; `turn_context`) into the universal schema — reasoning → text+Thinking, function_call(+output) → tool chips, task events → lifecycle/state. - Clear/epoch obligation: `/new` carries `CommandRoleClear`. Whether `/new` opens a new rollout file (identity rotates for free) or clears in place (adapter synthesizes an epoch-qualified path) is *(spike 4)*. - `Reply`: tmux send-keys. Upstream: Enter mid-turn *steers* the current turn (input is injected, not dropped) — reply-while-working is legal with no typed drop error. Multi-line delivery (bracketed paste vs Ctrl+J newlines) *(spike 7)*. - `Interrupt`: single Esc. **Ctrl-C is a quit hazard** (conflicting upstream sources; some versions exit immediately) — the recipe must never emit it; double-Esc triggers backtrack/fork on an empty composer, hazard-check both *(spike 6)*. - `Commands`: curated catalog; `/new` (role clear, ChatSafe), picker-opening commands (`/resume`, `/fork`, `/model`, `/permissions`, …) ship `ChatSafe: false`. Note upstream rename `/approvals` → `/permissions`. - Dialogs: none answerable in v1 (never-ask posture + no structured question tool); unknown shapes degrade to `Answerable: false` + tmux-attach hint. - Optional capabilities omitted: `DeepLinker` (no web surface), `LiveSignals` (no verified structured channel in v1; compat record documents `notify` = `agent-turn-complete` only, and the 2026 hooks system incl. `PermissionRequest` *(spike 8)* as the follow-up route), `ConnectingReporter` (nothing to connect). ## Plan (phased, one issue) 1. **Tier 2 discovery spikes** against a logged-in codex CLI on the lab host (login as the lab service user; binary via #74). Answers land in the committed compat record with real samples (rollout JSONL excerpts, keystroke recipes, login transcript, attribution ground truth). 2. **Implement `internal/provider/codex`** against the pinned couplings; register the provider; keep core grep-clean. 3. **Conformance**: add the adapter to #80's Tier 1 registration table and pass in CI; re-run the Tier 2 recipe hazard checks; commit the compat record per the checklist. ## Live-spike checklist (each answer → compat record) 1. Default model slug + live model/effort catalog on the pinned binary (`/status`, `/model`). 2. `xhigh` effort support per model; the rumored `-m model[effort]` bracket syntax — real? 3. `-c 'projects."<path>".trust_level="trusted"'` as trust pre-grant — works? (else SeedWorkspace config-append fallback) 4. `/new`: new rollout file (rotation) vs in-place clear (epoch synthesis required). 5. Login: URL output stream (stdout/stderr), `codex login status` exit codes, tmux login-screen Ctrl-C bug (#23820) workaround. 6. Interrupt hazards on the pinned version: Esc, double-Esc backtrack, Ctrl-C quit behavior. 7. Reply injection via tmux send-keys: bracketed paste, Ctrl+J newlines, steer-vs-queue mid-turn. 8. Hooks availability in 0.133 (`PermissionRequest` et al.) — record only, for the LiveSignals follow-up. 8b: `/skills` — native skill discovery? From a seedable path? 9. Context-file wiring end-to-end: `project_doc_fallback_filenames` present + fallback semantics on 0.133; global `$CODEX_HOME/AGENTS.md` bridge verified against a repo WITH a tracked `AGENTS.md`. 10. Attribution ground truth: commits/PRs with the git feature on/off; `-c commit_attribution=""` verified; ScrubPatterns reconciled. 11. TERM under tmux (`tmux-256color` vs `xterm-256color`; OSC 11 timeout issue #22761). ## Acceptance - A repo with `provider: codex` runs manual + AFK sessions end to end (seed prompt as trailing argv positional; tracker-agnostic `labctl` seed vocabulary unchanged). - Tier 1 conformance passes in CI via the #80 registration table; Tier 2 evidenced by the committed compat record. - Incogni parity: no attribution at the source (`commit_attribution=""`), the adapter's ScrubPatterns strip its own marker samples through the union path, pre-push guard clean. - Core stays adapter-agnostic: no codex references outside `internal/provider/codex` (grep-clean). - ADR records the adapter's notable choices: sandbox posture parity, argv-first config, the global AGENTS.md bridge, LiveSignals deferral. ## Out of scope - LiveSignals / hook-based live signals (follow-up issue once spike 8 pins hook availability). - API-key auth (`AuthFlowAPIKey` has no mechanism behind it; separate issue if wanted). - Embedded remote interface; any `DeepLinker` work. - Binary deployment (#74) and the conformance suite itself (#80). ## Sequencing `needs-triage` until #80 merges — its suite + checklist are this issue's definition of done, so it starts after. At re-triage, expected `ready-for-human`: every fragile coupling needs a live logged-in codex session, which an AFK agent on this host cannot drive.
Author
Owner

This was generated by AI during triage.

Amendment: auth flow → device-code (maintainer direction, 2026-07-10)

Decision 4 changes: device-code authorization replaces the ChatGPT OAuth localhost redirect. Lab normally runs on a server; the redirect flow needs an SSH port-forward to localhost:1455, while device auth needs only a browser anywhere and a one-time code. Verified live on the pinned binary (codex-cli 0.133.0, scratch CODEX_HOME):

  • codex login --device-auth exists and prints, on stdout: the URL https://auth.openai.com/codex/device and a one-time code (XXXX-XXXXX, 15-minute expiry).
  • codex login status while logged out: Not logged in, exit 1 (spike 5's non-zero value, now pinned).

Spec deltas:

  • AuthFlow presents the device-auth recipe; the SSH port-forward instructions are dropped.
  • LoginStart drives codex login --device-auth in the ADR-0034 login session and scrapes URL + one-time code from stdout (stream verified).
  • LoginSubmitCode stays a typed not-supported error — the code is entered browser-side at the printed URL, never pasted into the CLI.
  • Completion detection unchanged: poll codex login status (exit 1 = logged out confirmed; exit 0 output shape still to pin once logged in).
  • Spike 5 narrows to: post-login status output/exit, and the tmux Ctrl-C login-screen hazard (openai/codex#23820) under the device flow.

Host ground truth (2026-07-10): codex on this host is authenticated only for the human operator's account, not the lab service user (/var/lib/lab/.codex has no auth.json). Tier-2 spikes requiring auth need a lab-user login first — the device flow above is the recipe.

> *This was generated by AI during triage.* ## Amendment: auth flow → device-code (maintainer direction, 2026-07-10) Decision 4 changes: **device-code authorization replaces the ChatGPT OAuth localhost redirect.** Lab normally runs on a server; the redirect flow needs an SSH port-forward to localhost:1455, while device auth needs only a browser anywhere and a one-time code. Verified live on the pinned binary (codex-cli 0.133.0, scratch `CODEX_HOME`): - `codex login --device-auth` exists and prints, on **stdout**: the URL `https://auth.openai.com/codex/device` and a one-time code (`XXXX-XXXXX`, 15-minute expiry). - `codex login status` while logged out: `Not logged in`, exit **1** (spike 5's non-zero value, now pinned). Spec deltas: - `AuthFlow` presents the device-auth recipe; the SSH port-forward instructions are dropped. - `LoginStart` drives `codex login --device-auth` in the ADR-0034 login session and scrapes URL + one-time code from stdout (stream verified). - `LoginSubmitCode` stays a typed not-supported error — the code is entered browser-side at the printed URL, never pasted into the CLI. - Completion detection unchanged: poll `codex login status` (exit 1 = logged out confirmed; exit 0 output shape still to pin once logged in). - Spike 5 narrows to: post-login `status` output/exit, and the tmux Ctrl-C login-screen hazard (openai/codex#23820) under the device flow. Host ground truth (2026-07-10): codex on this host is authenticated only for the human operator's account, not the lab service user (`/var/lib/lab/.codex` has no `auth.json`). Tier-2 spikes requiring auth need a lab-user login first — the device flow above is the recipe.
Author
Owner

This was generated by AI during triage.

Amendment 2: Tier-2 spike results — all 11 live-spike questions answered (2026-07-10)

Codex is now authenticated for the lab service user (auth.json in $CODEX_HOME; codex login statusLogged in using ChatGPT, exit 0 — spike 5's remaining shape, now pinned). All checklist items were run live against the pinned binary (codex-cli 0.133.0) on this host, headless via codex exec plus a real TUI driven over tmux. Answers below are ground truth for the compat record; each supersedes the corresponding (spike N) marker in the spec.

Spike 1–2 — models & efforts

  • Picker catalog on 0.133 with a ChatGPT account: gpt-5.5 (default) and gpt-5.4-mini, both with efforts low / medium (default) / high / xhigh. No minimal tier.
  • codex debug models renders the catalog as machine-readable JSON (slugs, display names, default + supported reasoning levels) — pin the adapter's catalog from this, not TUI scraping. It also lists internal codex-auto-review (visibility-filter before surfacing).
  • gpt-5.6-terra / gpt-5.6-luna exist server-side but are rejected with "requires a newer version of Codex" on 0.133; gpt-5.6-sol and gpt-5.1-codex are rejected outright. An invalid model fails at request time with an API 400 — there is no client-side catalog validation.
  • The rumored -m model[effort] bracket syntax is refuted: the string is passed verbatim as the slug and 400s. Effort rides -c model_reasoning_effort= (verified high and xhigh end-to-end; the exec banner echoes the resolved effort).
  • Quirk: codex exec defaults to reasoning effort: none in its banner; the TUI defaults to medium. Spawns should pass the effort explicitly.

Spike 3 — trust pre-grant

  • -c 'projects."<path>".trust_level="trusted"' does not suppress the first-run trust prompt — the prompt appears even with explicit --ask-for-approval never --sandbox workspace-write.
  • The fallback works: appending [projects."<path>"]\ntrust_level = "trusted" to ~/.codex/config.toml suppresses the prompt. SeedWorkspace must do the guarded config append; the argv route is dead for trust.
  • Related: codex auto-writes trust entries for directories after codex exec runs in them — the adapter's config guard must tolerate codex mutating config.toml on its own.

Spike 4 — /new

Rotates. /new opens a fresh rollout JSONL with a new session id (old file untouched, TUI prints a codex resume <old-id> hint). Clear/epoch identity comes for free; no synthesized epoch path needed. Locate-by-newest-cwd-match works (both files carry the cwd in session_meta). Note: the filename timestamp is local time; payload timestamps are UTC.

Spike 5 — login (device flow re-verified)

  • codex login --device-auth re-verified against the real $CODEX_HOME: URL + one-time code print on stdout.
  • Status shapes both pinned: logged out Not logged in / exit 1; logged in Logged in using ChatGPT / exit 0.
  • The tmux login-screen Ctrl-C bug is moot given the Ctrl-C findings below: the recipe never emits Ctrl-C anywhere, and the ADR-0034 login session is disposable.

Spike 6 — interrupt hazards

  • Single Esc mid-turn interrupts cleanly ("Conversation interrupted — tell the model what to do differently"), composer intact; the working footer itself documents esc to interrupt. In the rollout this lands as event_msg/turn_aborted with reason:"interrupted" — a clean lifecycle marker for the reader.
  • Esc on an idle empty composer arms "esc again to edit previous message"; a second Esc opens the backtrack/edit overlay. It does not kill the session; q exits back to the composer. The recipe must not emit Esc when idle (interrupt is only legal while working), and q is the recovery if the overlay is ever entered.
  • Ctrl-C on the idle composer quits codex immediately — no confirmation. The hazard is confirmed at its worst; no recipe may ever emit Ctrl-C.

Spike 7 — reply injection

  • Bracketed paste (tmux paste-buffer -p) lands multi-line text in the composer without submitting; Enter then submits it as one message. Ctrl+J also inserts a literal newline. Both recipes verified.
  • Mid-turn reply is queue-with-steer: the TUI shows "Messages to be submitted after next tool call (press esc to interrupt and send immediately)", and the queued message was delivered in the same turn (both markers arrived). No typed-drop error exists.
  • Burst hazard (recipe rule): a slash command and its Enter must be separate send-keys calls with a delay — sent in one burst, the command text merges with subsequent input instead of executing.

Spike 8 / 8b — hooks & skills

  • Hooks are stable and enabled in 0.133 (codex features: hooks stable true, plus plugin_hooks). Event vocabulary present in the binary: SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, Stop, SubagentStop, PreCompact, PermissionRequest, with hook_event_name / stop_hook_active payload keys. The LiveSignals follow-up has a real substrate; legacy notify (agent-turn-complete) also still present.
  • /skills: native skills exist (SKILL.md format, $CODEX_HOME/skills/, system skills preinstalled) — but discovery is global-only. Planted marker skills in <repo>/.codex/skills/ and <repo>/.agents/skills/ were not discovered; only the $CODEX_HOME/skills/ marker was. No per-workspace seedable path ⇒ NativeSkillDiscovery: false stands; the ADR-0035 context-file skills index stays.

Spike 9 — context-file wiring (all three legs verified)

  1. Repo without AGENTS.md: -c 'project_doc_fallback_filenames=["AGENTS.local.md"]' → content read (marker surfaced). The key exists and works on 0.133.
  2. Repo with tracked AGENTS.md: fallback silently skipped, exactly the trap the spec predicted — only the tracked file's marker surfaced.
  3. Global $CODEX_HOME/AGENTS.md bridge ("if AGENTS.local.md exists at the workspace root, read and follow it"): codex read AGENTS.local.md at runtime via a tool call and followed it, tracked AGENTS.md notwithstanding. The double-path design is confirmed end-to-end.

Spike 10 — attribution

  • Ground truth from a real codex-authored commit: no Co-authored-by trailer, no attribution of any kind — the commit message is verbatim. The codex_git_commit feature is removed (off) in 0.133.
  • commit_attribution is an unknown config field on 0.133: silently ignored normally, hard error under --strict-config. Spec delta: drop -c commit_attribution="" from the spawn argv. ScrubPatterns stay as defensive conformance samples only.

Spike 11 — TERM / terminal

  • Lab tmux default-terminal is tmux-256color; codex TUI renders and runs fine under it across many starts — no OSC 11 hang observed.
  • codex doctor flags TERMINFO unreadable under the nix profile paths (cosmetic here; worth a compat-record note). tmux extended-keys is off on this host.
  • TUI shows an update banner (0.133.0 → 0.144.1) at startup — scraping must tolerate leading banner noise.

New findings outside the checklist

  • workspace-write mounts .git read-only — git commits are impossible in codex's workspace-write sandbox even with .git inside cwd (a third trap alongside network-off and cwd-confined writes; escape hatch -c 'sandbox_workspace_write.writable_roots=[...]' exists). The full-access, never-ask posture (decision 2) is reconfirmed with stronger evidence.
  • codex exec announces "Reading additional input from stdin..." when stdin is a pipe — spawn recipes should keep the prompt as the argv positional and not leave a piped stdin dangling.
  • codex doctor gives a one-shot diagnostic (auth, state DB integrity, terminal) — useful in the compat record and for support tooling.

Spec deltas from this round

  1. Spawn argv: remove -c commit_attribution="" (unknown field; attribution is absent at source in 0.133).
  2. SeedWorkspace: trust must be granted via guarded config.toml append (the -c route is confirmed dead) — the spec's fallback becomes the primary.
  3. Model catalog: pin from codex debug models; v1 catalog = gpt-5.5 (default, effort default medium) + gpt-5.4-mini, efforts low/medium/high/xhigh; always pass effort explicitly on spawn.
  4. Chat recipes: interrupt = single Esc only while working; never Ctrl-C anywhere; never Esc on idle composer (backtrack overlay; q recovers); slash commands typed and submitted as separate keystroke bursts.
  5. Transcript reader: /new = file rotation (no epoch synthesis); map turn_aborted(reason=interrupted) to the interrupted lifecycle state; filename timestamps are local, payload UTC.

Sequencing note: #80 (conformance suite + checklist, this issue's definition-of-done bar) has merged, and the host now has an authenticated codex for the lab user — both former blockers are gone. The original ready-for-human expectation rested on "an AFK agent cannot drive a live logged-in codex session"; this triage session just drove all of the fragile couplings from exactly that seat, so that rationale is obsolete. Re-triage decision (state label) pending maintainer direction.

> *This was generated by AI during triage.* ## Amendment 2: Tier-2 spike results — all 11 live-spike questions answered (2026-07-10) Codex is now authenticated for the lab service user (`auth.json` in `$CODEX_HOME`; `codex login status` → `Logged in using ChatGPT`, exit **0** — spike 5's remaining shape, now pinned). All checklist items were run live against the pinned binary (codex-cli 0.133.0) on this host, headless via `codex exec` plus a real TUI driven over tmux. Answers below are ground truth for the compat record; each supersedes the corresponding *(spike N)* marker in the spec. ### Spike 1–2 — models & efforts - Picker catalog on 0.133 with a ChatGPT account: **`gpt-5.5`** (default) and **`gpt-5.4-mini`**, both with efforts **low / medium (default) / high / xhigh**. No `minimal` tier. - `codex debug models` renders the catalog as machine-readable JSON (slugs, display names, default + supported reasoning levels) — pin the adapter's catalog from this, not TUI scraping. It also lists internal `codex-auto-review` (visibility-filter before surfacing). - `gpt-5.6-terra` / `gpt-5.6-luna` exist server-side but are rejected with "requires a newer version of Codex" on 0.133; `gpt-5.6-sol` and `gpt-5.1-codex` are rejected outright. An invalid model fails at request time with an API 400 — there is no client-side catalog validation. - The rumored `-m model[effort]` bracket syntax is **refuted**: the string is passed verbatim as the slug and 400s. Effort rides `-c model_reasoning_effort=` (verified `high` and `xhigh` end-to-end; the exec banner echoes the resolved effort). - Quirk: `codex exec` defaults to `reasoning effort: none` in its banner; the TUI defaults to medium. Spawns should pass the effort explicitly. ### Spike 3 — trust pre-grant - `-c 'projects."<path>".trust_level="trusted"'` does **not** suppress the first-run trust prompt — the prompt appears even with explicit `--ask-for-approval never --sandbox workspace-write`. - The fallback works: appending `[projects."<path>"]\ntrust_level = "trusted"` to `~/.codex/config.toml` suppresses the prompt. **`SeedWorkspace` must do the guarded config append; the argv route is dead for trust.** - Related: codex **auto-writes** trust entries for directories after `codex exec` runs in them — the adapter's config guard must tolerate codex mutating `config.toml` on its own. ### Spike 4 — `/new` **Rotates.** `/new` opens a fresh rollout JSONL with a new session id (old file untouched, TUI prints a `codex resume <old-id>` hint). Clear/epoch identity comes for free; no synthesized epoch path needed. Locate-by-newest-cwd-match works (both files carry the cwd in `session_meta`). Note: the **filename** timestamp is local time; payload timestamps are UTC. ### Spike 5 — login (device flow re-verified) - `codex login --device-auth` re-verified against the real `$CODEX_HOME`: URL + one-time code print on **stdout**. - Status shapes both pinned: logged out `Not logged in` / exit 1; logged in `Logged in using ChatGPT` / exit 0. - The tmux login-screen Ctrl-C bug is moot given the Ctrl-C findings below: the recipe never emits Ctrl-C anywhere, and the ADR-0034 login session is disposable. ### Spike 6 — interrupt hazards - **Single Esc mid-turn interrupts cleanly** ("Conversation interrupted — tell the model what to do differently"), composer intact; the working footer itself documents `esc to interrupt`. In the rollout this lands as `event_msg`/`turn_aborted` with `reason:"interrupted"` — a clean lifecycle marker for the reader. - Esc on an **idle empty** composer arms "esc again to edit previous message"; a second Esc opens the backtrack/edit overlay. It does not kill the session; `q` exits back to the composer. The recipe must not emit Esc when idle (interrupt is only legal while working), and `q` is the recovery if the overlay is ever entered. - **Ctrl-C on the idle composer quits codex immediately — no confirmation.** The hazard is confirmed at its worst; no recipe may ever emit Ctrl-C. ### Spike 7 — reply injection - Bracketed paste (tmux `paste-buffer -p`) lands multi-line text in the composer without submitting; Enter then submits it as one message. Ctrl+J also inserts a literal newline. Both recipes verified. - Mid-turn reply is **queue-with-steer**: the TUI shows "Messages to be submitted after next tool call (press esc to interrupt and send immediately)", and the queued message was delivered in the same turn (both markers arrived). No typed-drop error exists. - Burst hazard (recipe rule): a slash command and its Enter must be **separate** `send-keys` calls with a delay — sent in one burst, the command text merges with subsequent input instead of executing. ### Spike 8 / 8b — hooks & skills - Hooks are **stable and enabled** in 0.133 (`codex features`: `hooks stable true`, plus `plugin_hooks`). Event vocabulary present in the binary: `SessionStart`, `UserPromptSubmit`, `PreToolUse`, `PostToolUse`, `Stop`, `SubagentStop`, `PreCompact`, `PermissionRequest`, with `hook_event_name` / `stop_hook_active` payload keys. The LiveSignals follow-up has a real substrate; legacy `notify` (`agent-turn-complete`) also still present. - `/skills`: native skills exist (SKILL.md format, `$CODEX_HOME/skills/`, system skills preinstalled) — but discovery is **global-only**. Planted marker skills in `<repo>/.codex/skills/` and `<repo>/.agents/skills/` were not discovered; only the `$CODEX_HOME/skills/` marker was. No per-workspace seedable path ⇒ **`NativeSkillDiscovery: false` stands; the ADR-0035 context-file skills index stays.** ### Spike 9 — context-file wiring (all three legs verified) 1. Repo without `AGENTS.md`: `-c 'project_doc_fallback_filenames=["AGENTS.local.md"]'` → content read (marker surfaced). The key exists and works on 0.133. 2. Repo **with** tracked `AGENTS.md`: fallback silently skipped, exactly the trap the spec predicted — only the tracked file's marker surfaced. 3. Global `$CODEX_HOME/AGENTS.md` bridge ("if AGENTS.local.md exists at the workspace root, read and follow it"): codex read `AGENTS.local.md` at runtime via a tool call and followed it, tracked `AGENTS.md` notwithstanding. The double-path design is confirmed end-to-end. ### Spike 10 — attribution - Ground truth from a real codex-authored commit: **no `Co-authored-by` trailer, no attribution of any kind** — the commit message is verbatim. The `codex_git_commit` feature is `removed` (off) in 0.133. - `commit_attribution` is an **unknown config field** on 0.133: silently ignored normally, hard error under `--strict-config`. **Spec delta: drop `-c commit_attribution=""` from the spawn argv.** ScrubPatterns stay as defensive conformance samples only. ### Spike 11 — TERM / terminal - Lab tmux `default-terminal` is `tmux-256color`; codex TUI renders and runs fine under it across many starts — no OSC 11 hang observed. - `codex doctor` flags TERMINFO unreadable under the nix profile paths (cosmetic here; worth a compat-record note). tmux `extended-keys` is off on this host. - TUI shows an update banner (0.133.0 → 0.144.1) at startup — scraping must tolerate leading banner noise. ### New findings outside the checklist - **workspace-write mounts `.git` read-only** — git commits are impossible in codex's workspace-write sandbox even with `.git` inside cwd (a *third* trap alongside network-off and cwd-confined writes; escape hatch `-c 'sandbox_workspace_write.writable_roots=[...]'` exists). The **full-access, never-ask posture (decision 2) is reconfirmed with stronger evidence**. - `codex exec` announces "Reading additional input from stdin..." when stdin is a pipe — spawn recipes should keep the prompt as the argv positional and not leave a piped stdin dangling. - `codex doctor` gives a one-shot diagnostic (auth, state DB integrity, terminal) — useful in the compat record and for support tooling. ### Spec deltas from this round 1. Spawn argv: **remove** `-c commit_attribution=""` (unknown field; attribution is absent at source in 0.133). 2. `SeedWorkspace`: trust **must** be granted via guarded `config.toml` append (the `-c` route is confirmed dead) — the spec's fallback becomes the primary. 3. Model catalog: pin from `codex debug models`; v1 catalog = `gpt-5.5` (default, effort default medium) + `gpt-5.4-mini`, efforts low/medium/high/xhigh; always pass effort explicitly on spawn. 4. Chat recipes: interrupt = single Esc only while working; never Ctrl-C anywhere; never Esc on idle composer (backtrack overlay; `q` recovers); slash commands typed and submitted as separate keystroke bursts. 5. Transcript reader: `/new` = file rotation (no epoch synthesis); map `turn_aborted(reason=interrupted)` to the interrupted lifecycle state; filename timestamps are local, payload UTC. Sequencing note: #80 (conformance suite + checklist, this issue's definition-of-done bar) has merged, and the host now has an authenticated codex for the lab user — both former blockers are gone. The original `ready-for-human` expectation rested on "an AFK agent cannot drive a live logged-in codex session"; this triage session just drove all of the fragile couplings from exactly that seat, so that rationale is obsolete. Re-triage decision (state label) pending maintainer direction.
Author
Owner

This was generated by AI during triage.

Agent Brief

Category: enhancement
Summary: Implement the Codex CLI adapter behind AgentProvider, to #80's conformance bar, per the pinned spec in this issue.

This brief is a pointer-contract: the issue body (research-pinned spec) + Amendment 1 (device-auth) + Amendment 2 (Tier-2 spike results) together are the authoritative specification. Every (spike N) marker in the body is superseded by Amendment 2's ground truth; where body and amendments conflict, the amendments win. Key deltas the implementer must honor:

  • Spawn argv without -c commit_attribution="" (unknown field on 0.133; attribution is absent at source).
  • Auth = device-code flow (codex login --device-auth, URL + one-time code scraped from stdout; LoginSubmitCode returns typed not-supported; status shapes: exit 1 "Not logged in" / exit 0 "Logged in using ChatGPT").
  • Trust pre-grant via -c is dead: SeedWorkspace does a guarded [projects."<worktree>"] trust_level = "trusted" append to ~/.codex/config.toml, tolerant of codex's own auto-written entries.
  • Model catalog pinned from codex debug models: gpt-5.5 (default; effort default medium) + gpt-5.4-mini, efforts low/medium/high/xhigh; effort always passed explicitly via -c model_reasoning_effort=; no bracket syntax.
  • /new rotates the rollout file (new session id) — no epoch synthesis; map turn_aborted(reason="interrupted") to the interrupted lifecycle state; rollout filename timestamps are local time, payload timestamps UTC.
  • Chat recipes: interrupt = single Esc only while a turn is working; never emit Ctrl-C (immediate quit, no confirmation) and never Esc on an idle composer (backtrack overlay; q recovers); slash command text and its Enter are separate paced key bursts; multi-line replies via bracketed paste (or Ctrl+J newlines); mid-turn replies are queued-after-next-tool-call — legal, no drop error.
  • Context file: AGENTS.local.md via -c 'project_doc_fallback_filenames=["AGENTS.local.md"]' plus the lab-managed global $CODEX_HOME/AGENTS.md bridge (both legs live-verified, including against a repo with a tracked AGENTS.md).
  • NativeSkillDiscovery: false (0.133 discovers skills only from global $CODEX_HOME/skills/, no per-workspace path) → seeder appends the ADR-0035 skills index.
  • Optional capabilities omitted in v1: DeepLinker, LiveSignals (hooks are stable in 0.133 with SessionStart/PreToolUse/PostToolUse/Stop/etc. — record in compat.md as the follow-up route), ConnectingReporter.

Acceptance criteria (= issue body's Acceptance section, restated):

  • A repo with provider: codex runs manual + AFK sessions end to end (prompt as trailing argv positional; stdin not left as a dangling pipe).
  • Tier 1 conformance passes in CI via #80's registration table.
  • Tier 2 evidenced by a committed compat record per the provider-authoring checklist, with real samples (rollout excerpts, keystroke recipes, login transcript, attribution ground truth — Amendment 2 is the source material, re-verified where the checklist demands).
  • Incogni parity: no attribution at source on 0.133; adapter ScrubPatterns (defensive) strip its own marker samples through the union path; pre-push guard clean.
  • Core stays adapter-agnostic: no codex references outside the codex provider package (grep-clean).
  • ADR records the notable choices: sandbox posture parity, argv-first config with the config-append trust exception, the global AGENTS.md bridge, LiveSignals deferral.

Out of scope: unchanged from the issue body (LiveSignals implementation, API-key auth, DeepLinker/remote interface, #74 binary deployment, #80 suite itself).

Environment note for the implementing agent: codex 0.133.0 is on PATH and authenticated for the lab user; live re-verification runs are possible from the lab seat (drive the TUI via tmux; keep prompts trivial; codex's workspace-write sandbox blocks git writes — see Amendment 2).

> *This was generated by AI during triage.* ## Agent Brief **Category:** enhancement **Summary:** Implement the Codex CLI adapter behind `AgentProvider`, to #80's conformance bar, per the pinned spec in this issue. This brief is a pointer-contract: the **issue body (research-pinned spec) + Amendment 1 (device-auth) + Amendment 2 (Tier-2 spike results)** together are the authoritative specification. Every *(spike N)* marker in the body is superseded by Amendment 2's ground truth; where body and amendments conflict, the amendments win. Key deltas the implementer must honor: - Spawn argv **without** `-c commit_attribution=""` (unknown field on 0.133; attribution is absent at source). - Auth = **device-code flow** (`codex login --device-auth`, URL + one-time code scraped from stdout; `LoginSubmitCode` returns typed not-supported; status shapes: exit 1 "Not logged in" / exit 0 "Logged in using ChatGPT"). - Trust pre-grant via `-c` is dead: `SeedWorkspace` does a guarded `[projects."<worktree>"] trust_level = "trusted"` append to `~/.codex/config.toml`, tolerant of codex's own auto-written entries. - Model catalog pinned from `codex debug models`: `gpt-5.5` (default; effort default medium) + `gpt-5.4-mini`, efforts low/medium/high/xhigh; effort always passed explicitly via `-c model_reasoning_effort=`; no bracket syntax. - `/new` rotates the rollout file (new session id) — no epoch synthesis; map `turn_aborted(reason="interrupted")` to the interrupted lifecycle state; rollout filename timestamps are local time, payload timestamps UTC. - Chat recipes: interrupt = single Esc only while a turn is working; **never emit Ctrl-C** (immediate quit, no confirmation) and never Esc on an idle composer (backtrack overlay; `q` recovers); slash command text and its Enter are separate paced key bursts; multi-line replies via bracketed paste (or Ctrl+J newlines); mid-turn replies are queued-after-next-tool-call — legal, no drop error. - Context file: `AGENTS.local.md` via `-c 'project_doc_fallback_filenames=["AGENTS.local.md"]'` **plus** the lab-managed global `$CODEX_HOME/AGENTS.md` bridge (both legs live-verified, including against a repo with a tracked `AGENTS.md`). - `NativeSkillDiscovery: false` (0.133 discovers skills only from global `$CODEX_HOME/skills/`, no per-workspace path) → seeder appends the ADR-0035 skills index. - Optional capabilities omitted in v1: `DeepLinker`, `LiveSignals` (hooks are stable in 0.133 with SessionStart/PreToolUse/PostToolUse/Stop/etc. — record in compat.md as the follow-up route), `ConnectingReporter`. **Acceptance criteria** (= issue body's Acceptance section, restated): - [ ] A repo with `provider: codex` runs manual + AFK sessions end to end (prompt as trailing argv positional; stdin not left as a dangling pipe). - [ ] Tier 1 conformance passes in CI via #80's registration table. - [ ] Tier 2 evidenced by a committed compat record per the provider-authoring checklist, with real samples (rollout excerpts, keystroke recipes, login transcript, attribution ground truth — Amendment 2 is the source material, re-verified where the checklist demands). - [ ] Incogni parity: no attribution at source on 0.133; adapter ScrubPatterns (defensive) strip its own marker samples through the union path; pre-push guard clean. - [ ] Core stays adapter-agnostic: no codex references outside the codex provider package (grep-clean). - [ ] ADR records the notable choices: sandbox posture parity, argv-first config with the config-append trust exception, the global AGENTS.md bridge, LiveSignals deferral. **Out of scope:** unchanged from the issue body (LiveSignals implementation, API-key auth, DeepLinker/remote interface, #74 binary deployment, #80 suite itself). Environment note for the implementing agent: codex 0.133.0 is on PATH and authenticated for the lab user; live re-verification runs are possible from the lab seat (drive the TUI via tmux; keep prompts trivial; codex's workspace-write sandbox blocks git writes — see Amendment 2).
Author
Owner

This was generated by AI while landing a PR.

Landing audit — PR #91 (afk/87): PASS

Verification signal relied on: Forgejo Actions CI — ci / native success (run #96, 4m45s). Per this repo's gate model I relied on that green rather than re-running go test/lint; the compat record notes its own LAB_COMPAT_LIVE=1 probes passed against the real binary on the build host.

Checks:

  • Open, non-draft. Title is Conventional Commits (feat(provider): …).
  • AFK contract: head afk/87, body carries a working Closes #87. ✓
  • Mergeable into main — no conflicts (merge-tree clean).
  • Seam changes are additive and provider-neutral: AuthFlowDeviceCode, ErrLoginCodeUnsupported, and the optional LoginCodeReporter capability (advertised by type-assertion like ConnectingReporter/DeepLinker); httpapi echoes user_code and maps the sentinel to 409 with no concrete-provider coupling; the SPA auth card gains a descriptor-driven device-code branch. Existing adapters/fakes untouched.
  • codex adapter is package-isolated — TestCoreAttributionNeutrality exempts it with the same rationale as claudecode; no codex coupling outside the adapter + composition root.
  • Spawn argv matches the pinned design (--ask-for-approval never --sandbox danger-full-access, -c values as single argv elements).

Intentional deviations from this issue's original spec — both documented in the PR body as evidence-based/maintainer amendments, not defects:

  1. Auth flow is device-code, not the originally-specified oauth-redirect (maintainer amendment).
  2. No -c commit_attribution="" — unknown config key on codex 0.133 (hard-errors under --strict-config); attribution is absent at source anyway.

Verdict: PASS. Awaiting explicit free-text merge go-ahead before merging.

> *This was generated by AI while landing a PR.* **Landing audit — PR #91 (`afk/87`): PASS** **Verification signal relied on:** Forgejo Actions CI — `ci / native` **success** (run #96, 4m45s). Per this repo's gate model I relied on that green rather than re-running `go test`/lint; the compat record notes its own `LAB_COMPAT_LIVE=1` probes passed against the real binary on the build host. **Checks:** - Open, non-draft. Title is Conventional Commits (`feat(provider): …`). - AFK contract: head `afk/87`, body carries a working `Closes #87`. ✓ - Mergeable into `main` — no conflicts (merge-tree clean). - Seam changes are additive and provider-neutral: `AuthFlowDeviceCode`, `ErrLoginCodeUnsupported`, and the optional `LoginCodeReporter` capability (advertised by type-assertion like `ConnectingReporter`/`DeepLinker`); httpapi echoes `user_code` and maps the sentinel to 409 with no concrete-provider coupling; the SPA auth card gains a descriptor-driven `device-code` branch. Existing adapters/fakes untouched. - `codex` adapter is package-isolated — `TestCoreAttributionNeutrality` exempts it with the same rationale as `claudecode`; no codex coupling outside the adapter + composition root. - Spawn argv matches the pinned design (`--ask-for-approval never --sandbox danger-full-access`, `-c` values as single argv elements). **Intentional deviations from this issue's original spec — both documented in the PR body as evidence-based/maintainer amendments, not defects:** 1. Auth flow is **device-code**, not the originally-specified `oauth-redirect` (maintainer amendment). 2. **No `-c commit_attribution=""`** — unknown config key on codex 0.133 (hard-errors under `--strict-config`); attribution is absent at source anyway. Verdict: **PASS.** Awaiting explicit free-text merge go-ahead before merging.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Cloonar/coding-lab#87
No description provided.