Repository navigation
[developer-review-engine-evals-v1] 2 — A Harbor trial runs Codex by subscription login, next to Claude Code #1652
Description
Tier: 1
Project: cli
Type: feat
Objectives
O1. A Harbor task image installs the Codex CLI at the same pinned version the evaluation already grades with, next to Claude Code, and the image build checks the installed version; a test of the converted task's image definition asserts both installs and both version checks.
O2. A Harbor trial run with the Codex adapter logs in from the operator's Codex subscription: the harbor run process's environment carries the token in CODEX_ACCESS_TOKEN, which the operator fills from the host Codex login the way resolveCodexAccessToken reads it; the Python agent reads it only from its own environment, passes it only on standard input to codex login --with-access-token inside the container, which stages it into the container's own Codex home, and starts the agent process with that Codex home and no access-token variable; a test with a fake Codex binary asserts the login command, its standard input and the agent's environment.
O3. A Codex trial refuses to start, with a reason naming the missing login, when no subscription access token is found; no API-key variable is read or forwarded on either adapter; a test asserts the refusal and that no variable ending in API_KEY reaches the container.
O4. The Harbor agent passes the requested adapter to the trial instead of always Claude Code, the trial accepts claude-code and codex, and the network allowlist for a Codex task names the Codex subscription hosts, starting from api.openai.com and chatgpt.com, while a Claude Code task keeps api.anthropic.com only; tests assert the agent command line and both allowlists.
O5. The Claude Code path is unchanged: the existing Harbor task, practice-fix and agent tests pass without edits to their Claude expectations.
Documentation
apps/cli/specs/evals.md— the "Layer-G role trials in Harbor" section, the allowed hosts and the forwarded login variables (O1, O2, O4, O5)apps/cli/src/lib/worker-boundary.ts—resolveCodexAccessTokenand the Codex login-with-access-token step this task reuses (O2, O3)apps/cli/src/lib/dispatch.ts— why a staged Codex home alone authenticates and an access-token variable on the same process breaks it (O2)apps/cli/src/lib/dev-review-eval/vinaya_harbor_agent.py— the agent's login forwarding and trial command (O2, O3, O4)
Planner's rationale
Boundary — Let a Harbor trial run the Vinaya role on Codex by subscription login, with the same task, trial, grader and report contracts. It does NOT add the Engine backend, read results, or change how Claude Code logs in. Pinned files: apps/cli/src/lib/dev-review-eval/harbor-tasks.ts, apps/cli/src/lib/dev-review-eval/harbor-trial.ts, apps/cli/src/lib/dev-review-eval/vinaya_harbor_agent.py, apps/cli/tests/eval/harbor-tasks.test.ts, apps/cli/tests/eval/harbor-practice-fixes.test.ts, apps/cli/specs/evals.md, .changeset/harbor-codex-subscription.md. Out: the review loop's worker boundary and dispatch code, which are read, not edited; the results reader; step one's own adapter list, which already holds Codex.
reader-resolvable-prose: code comments, READMEs and specs carry no Issue or pull-request numbers and no tranche slugs.
doc-claims: every AEG:CLAIM line in a changed file is kept true in the same commit, the allowed-hosts claim included.
Sizing — One verification story: a converted task image and the agent let a Codex trial log in by subscription and reach only its hosts, and Claude is unchanged. Passes the four too-big tests: one story, one agent, seven pinned files, one failure mode (Codex cannot log in or reaches the wrong hosts). Size M.
Project(s) + blast radius — Project: cli. Evaluation library only; no shared package edited.
Dependency rationale — Conflicts-with: #1643, #1651, #1653, #1654, #1655, #1656 — every one of these also edits the evaluation library directory, which the directory-overlap gate serializes within one milestone; the reasons for the file-level edges follow. It conflicts with the source-citation held-out task, which also pins harbor-tasks.ts, harbor-tasks.test.ts and apps/cli/specs/evals.md. No file-level conflict with the results-reader task: they share only apps/cli/specs/evals.md. The Engine-backend task of this tranche depends on this one: both pin harbor-trial.ts, vinaya_harbor_agent.py, harbor-tasks.test.ts and harbor-practice-fixes.test.ts.
Traps to avoid — Do NOT read or forward any API key; subscription only, on both adapters. Do NOT set the Codex access-token variable on the agent process; stage the Codex home and pass only that. Do NOT pass the token on the command line; feed it to the login command's standard input, as the review loop does. Do NOT widen Claude's allowlist; the allowlist is per adapter. Do NOT invent a Codex version; reuse the pinned grading version. Keep the AGENT_ALLOWED_HOSTS AEG:CLAIM in apps/cli/specs/evals.md true. The install hook runs as root while the trial runs as the image's user tester with its home at /home/tester; the staged Codex home must be owned and writable by tester, since the Codex CLI writes its sessions there. A new test file needs one line in an apps/cli/tests/ci-shards/shard-N.txt.
Suggested agent-class — high: credential staging across a container boundary, where a wrong variable leaks a token or breaks login.
Stop-and-escalate — Stop if staging the Codex login needs a change to the review loop's worker boundary or dispatch code; name the function. Run the login in the agent's existing install hook, which already runs commands in the container as root before the trial starts.
Docs to keep coherent — apps/cli/specs/evals.md (bound to the evaluation library).
Premises
apps/cli/src/lib/dev-review-eval/harbor-trial.tscontainsexport const HARBOR_TRIAL_ADAPTERS = ['claude-code'] as constapps/cli/src/lib/dev-review-eval/vinaya_harbor_agent.pycontains"--backend standalone --adapter claude-code",apps/cli/src/lib/dev-review-eval/vinaya_harbor_agent.pycontainsSUBSCRIPTION_ENV = ("CLAUDE_FORCE_OAUTH", "CLAUDE_CODE_OAUTH_TOKEN")apps/cli/src/lib/dev-review-eval/harbor-tasks.tscontainsexport const AGENT_ALLOWED_HOSTS = ['api.anthropic.com'] as constapps/cli/src/lib/dev-review-eval/step-one.tscontainsexport const GRADING_CODEX_PACKAGE = '@openai/codex@0.160.0'apps/cli/src/lib/worker-boundary.tscontainsexport function resolveCodexAccessToken(
Surface
in: apps/cli/src/lib/dev-review-eval, apps/cli/tests/eval, apps/cli/specs, apps/cli/tests/ci-shards, .changeset
out: harness, processes, packages, apps/log-server
Parts
Part 1 (O1) — Task images install and check the pinned Codex CLI beside Claude Code.
Part 2 (O2, O3) — The Codex subscription login is staged into the container's Codex home, and a missing login refuses.
Part 3 (O4) — The agent passes the adapter; the trial accepts both; the allowlist follows the adapter.
Part 4 (O5) — The Claude Code expectations stay unchanged.
Test plan
cd apps/cli && bun test --timeout=30000 tests/eval/harbor-tasks.test.ts → 0 fail; image installs both CLIs; Codex allowlist and Claude allowlist asserted; agent command carries the adapter
cd apps/cli && bun test --timeout=30000 tests/eval/harbor-practice-fixes.test.ts → 0 fail; fake Codex login gets the token on standard input; agent env has the Codex home and no token or API-key variable
cd apps/cli && bun test --timeout=30000 tests/ci-shards.test.ts → 0 fail
[principal] One Harbor practice trial of a development case with the Codex adapter, logged in by subscription only: it completes and is graded, and the Principal verifies live which Codex subscription hosts the trial reached, starting from api.openai.com and chatgpt.com; any host the allowlist lacks or does not need is reported in the pull request.
Stop conditions
- Staging the Codex login needs a change to the review loop's worker boundary or dispatch code.
Origin
Principal-directed, 2026-10-25: evaluations run on Claude Code and Codex, by subscription login only, never an API key. A Harbor trial today runs Claude Code only, logged in from its subscription token; no container login path exists for Codex.
Activity
daniboomerang commentedon Oct 28, 2026
Brief hash: d8c1037cf323d2f0ab44e4f932f6c8729d7bc2d18602ec685439f377646f9f33
For: [model] (coding-agent CLI on a dev machine, dispatched locally, unattended)
Reason: Suggested agent-class — high: credential staging across a container boundary, where a wrong variable leaks a token or breaks login.
Owner: the Principal
Goal: A Harbor trial runs Codex by subscription login, next to Claude Code
Project: cli
Tier: 1
Closes #1652
You are the AEG Developer. Run
bun apps/cli/src/index.ts doctrine --role developer --printand read its output first. Mandatory.Objectives
O1. A Harbor task image installs the Codex CLI at the same pinned version the evaluation already grades with, next to Claude Code, and the image build checks the installed version; a test of the converted task's image definition asserts both installs and both version checks.
O2. A Harbor trial run with the Codex adapter logs in from the operator's Codex subscription: the
harbor runprocess's environment carries the token inCODEX_ACCESS_TOKEN, which the operator fills from the host Codex login the wayresolveCodexAccessTokenreads it; the Python agent reads it only from its own environment, passes it only on standard input tocodex login --with-access-tokeninside the container, which stages it into the container's own Codex home, and starts the agent process with that Codex home and no access-token variable; a test with a fake Codex binary asserts the login command, its standard input and the agent's environment.O3. A Codex trial refuses to start, with a reason naming the missing login, when no subscription access token is found; no API-key variable is read or forwarded on either adapter; a test asserts the refusal and that no variable ending in
API_KEYreaches the container.O4. The Harbor agent passes the requested adapter to the trial instead of always Claude Code, the trial accepts
claude-codeandcodex, and the network allowlist for a Codex task names the Codex subscription hosts, starting fromapi.openai.comandchatgpt.com, while a Claude Code task keepsapi.anthropic.comonly; tests assert the agent command line and both allowlists.O5. The Claude Code path is unchanged: the existing Harbor task, practice-fix and agent tests pass without edits to their Claude expectations.
Documentation
apps/cli/specs/evals.md— the "Layer-G role trials in Harbor" section, the allowed hosts and the forwarded login variables (O1, O2, O4, O5)apps/cli/src/lib/worker-boundary.ts—resolveCodexAccessTokenand the Codex login-with-access-token step this task reuses (O2, O3)apps/cli/src/lib/dispatch.ts— why a staged Codex home alone authenticates and an access-token variable on the same process breaks it (O2)apps/cli/src/lib/dev-review-eval/vinaya_harbor_agent.py— the agent's login forwarding and trial command (O2, O3, O4)Premises
Checked against the code when this task Issue was cut, and again against the default branch at dispatch — facts, not claims.
apps/cli/src/lib/dev-review-eval/harbor-trial.tscontainsexport const HARBOR_TRIAL_ADAPTERS = ['claude-code'] as constapps/cli/src/lib/dev-review-eval/vinaya_harbor_agent.pycontains"--backend standalone --adapter claude-code",apps/cli/src/lib/dev-review-eval/vinaya_harbor_agent.pycontainsSUBSCRIPTION_ENV = ("CLAUDE_FORCE_OAUTH", "CLAUDE_CODE_OAUTH_TOKEN")apps/cli/src/lib/dev-review-eval/harbor-tasks.tscontainsexport const AGENT_ALLOWED_HOSTS = ['api.anthropic.com'] as constapps/cli/src/lib/dev-review-eval/step-one.tscontainsexport const GRADING_CODEX_PACKAGE = '@openai/codex@0.160.0'apps/cli/src/lib/worker-boundary.tscontainsexport function resolveCodexAccessToken(2. Context — read before doing anything
developer-review-engine-evals-v1, task 2, Issue [developer-review-engine-evals-v1] 2 — A Harbor trial runs Codex by subscription login, next to Claude Code #1652. Branchtask/developer-review-engine-evals-v1/2.Depends-on: —,Conflicts-with: #1643, #1651, #1653, #1654, #1655, #1656.b9c63aae32df154af0c90bda2fb9e0b2e1d8352c— the checkout's HEAD equaled the remote default branch, and no pinned file below carried an uncommitted change, when these facts were read.apps/cli/src/lib/dev-review-eval/harbor-tasks.ts,apps/cli/src/lib/dev-review-eval/harbor-trial.ts,apps/cli/src/lib/dev-review-eval/vinaya_harbor_agent.py,apps/cli/tests/eval/harbor-tasks.test.ts,apps/cli/tests/eval/harbor-practice-fixes.test.ts,apps/cli/specs/evals.md,.changeset/harbor-codex-subscription.md. Out: the review loop's worker boundary and dispatch code, which are read, not edited; the results reader; step one's own adapter list, which already holds Codex.reader-resolvable-prose: code comments, READMEs and specs carry no Issue or pull-request numbers and no tranche slugs.doc-claims: every AEG:CLAIM line in a changed file is kept true in the same commit, the allowed-hosts claim included.AGENT_ALLOWED_HOSTSAEG:CLAIM inapps/cli/specs/evals.mdtrue. The install hook runs as root while the trial runs as the image's usertesterwith its home at/home/tester; the staged Codex home must be owned and writable bytester, since the Codex CLI writes its sessions there. A new test file needs one line in anapps/cli/tests/ci-shards/shard-N.txt.3. Technical dependencies
Dependency rationale —
Conflicts-with: #1643, #1651, #1653, #1654, #1655, #1656— every one of these also edits the evaluation library directory, which the directory-overlap gate serializes within one milestone; the reasons for the file-level edges follow. It conflicts with the source-citation held-out task, which also pinsharbor-tasks.ts,harbor-tasks.test.tsandapps/cli/specs/evals.md. No file-level conflict with the results-reader task: they share onlyapps/cli/specs/evals.md. The Engine-backend task of this tranche depends on this one: both pinharbor-trial.ts,vinaya_harbor_agent.py,harbor-tasks.test.tsandharbor-practice-fixes.test.ts.4. Technical surface map
Create:
Modify:
Out of surface: harness, processes, packages, apps/log-server — a change there, or to any path no Surface
in:glob covers, is still published: the review-loop driver records each such path in the pull request body's beyond-Surface block, and the reviewers judge it like any change.Premise pins
Premise:
5. Pre-flight checks
Step 0 (mandatory, verbatim):
origin/main; branch suffix literal-matches the task id.bun apps/cli/src/index.ts task run), the driver has already run the dispatch-readiness gate plus, on this repository toolchain, its own fuller derivation from its own unsandboxed process before dispatching you (re-derived at render time: it was ready), and dispatches you only when that verdict is READY — a NOT READY verdict refuses the turn before it starts, so being dispatched is the verdict: look for no file and run neither script, whose ownghcall fails inside your sandbox. Working manually, with no driver behind you, fall back toroles/developer.md's own items 3/5/7 prose — each a complete, hand-run forge check in its own right.On any failure: STOP and report.
6. Numbered parts — publish once with
publish_changeswhen every Part is done, thenopen_pull_requestPart 1 (O1): Task images install and check the pinned Codex CLI beside Claude Code.
Files (touches @attalabs/vinaya):
The pre-push hook runs the affected suite on your one push and refuses it on failure — do not run it yourself per Part.
Part 2 (O2, O3): The Codex subscription login is staged into the container's Codex home, and a missing login refuses.
Part 3 (O4): The agent passes the adapter; the trial accepts both; the allowlist follows the adapter.
Part 4 (O5): The Claude Code expectations stay unchanged.
7. Documentation-update list
8. Verification before claiming done
run_checksand CI provide the authoritative results. Do not hand-run or paste static-gate commands. Working manually, run this repository's declared typecheck, lint/format, build, and documentation-gate commands yourself.bun apps/cli/src/index.ts doctrine --role developer --printgenuinely satisfied; use the controller'srun_checksresult, hooks, and CI as gate evidence.9. Test Plan
10. Stop conditions
Stop-and-escalate — Stop if staging the Codex login needs a change to the review loop's worker boundary or dispatch code; name the function. Run the login in the agent's existing install hook, which already runs commands in the container as root before the trial starts.
11. Constraints
12. Deliverable
[developer-review-engine-evals-v1] 2 — A Harbor trial runs Codex by subscription login, next to Claude Codeopen_pull_requesttool (title and body); publish your commits withpublish_changesand update the body withupdate_pull_request_body/refresh_evidence— you hold nogh/git pushcredential.publish_changes, when every Part is done; then open the pull request withopen_pull_request. Publish again only to answer review findings or a red gate — a refused hook, a failing check, a merge conflict.bun apps/cli/src/index.ts doctrine --template pr-report --print), withCloses #1652at the top of the header block. This brief stays frozen on the task Issue and never rides in the body.run_checksand CI run it.git diff origin/main...HEAD --statas context only; Surface is judged by the driver'ssurface-scopecheck, never by this hand-run diff. Token use needs no report — the Vinaya log records it.daniboomerang commentedon Oct 28, 2026
The dev-review-loop paused: escalation — the Developer reported the task blocked (tooling_unavailable): The enforced addressedFindingIds enum permits only R1-CR-1, so it cannot report the required R2-CR-1; the controller must update the response schema. — Fixed R2-CR-1 in commit 8572d15; publication and controller checks passed, but the ….
No pull request exists yet for this task, so the pause is recorded on this Issue instead.
A Principal ruling is needed before this can continue. Post it as a comment on this Issue whose FIRST line is exactly this marker — the second number is the ordinal, and it must exceed the one this pause recorded:
Then continue with:
The Operator's own
task_resumeclears this pause too, reading that same ruling from this Issue;task_cancelends it instead.daniboomerang commentedon Oct 28, 2026
Decision: proceed. Report this turn as completed.
The round-2 code review raised R2-CR-1 (the image lacks the Codex sandbox dependency), and commit 8572d15 fixes it. This round's turn-result schema still offers only
R1-CR-1foraddressedFindingIds: the controller did not refresh the finding list after round 2, which is a controller defect, not yours. FilladdressedFindingIdswith the id the schema offers, and state insummarythat the change addresses R2-CR-1 at 8572d15. The reviewers judge the new head in full. No objective, Surface or scope change.