Repository navigation
Fix(harness): Loop-launched agents reach only the loop's tools, and a halted Developer reports instead of posting #1677
Description
Tier: 1
Project: vinaya
Type: fix
Objectives
O1. A loop-launched Codex role (Developer, code reviewer, security reviewer) reaches no ChatGPT-account connector: the staged config.toml that harness/adapters/agents/codex/config.ts generates sets apps = false, plugins = false and remote_plugin = false under [features], so the only MCP tools the role holds are the loop's own vinaya_dev_tools server.
O2. A loop-launched Claude Code role holds no account connector either: its launch already passes --strict-mcp-config with the loop's own MCP config; a test pins that a Claude role's tool list carries only the loop's MCP server, and if Claude Code's claude.ai connectors still load under that flag, the launch also sets the environment switch that disables them.
O3. The brief template's Autonomy rule (aeg-root/templates/brief-template.md) tells a halted Developer to report the blocker in its turn result (the loop posts it), not to post a PR or Issue comment; no other doctrine file under aeg-root tells a dispatched Developer to post a comment itself. The manual merge-gate flow's comment instructions, for a Developer helping merge by hand, are not a dispatched turn and stay unchanged.
O4. The parity test (harness/adapters/agents/parity.test.ts) and the agent fixtures that embed the staged config.toml are updated in the same change, and the parity test fails when any of the three Codex feature lines is removed.
Documentation
None
Premises
harness/adapters/agents/codex/config.ts contains 'hooks = true',
harness/adapters/agents/claude-code/settings.ts contains '--strict-mcp-config',
aeg-root/templates/brief-template.md contains and when you halt, record the blocker in a PR comment or an Issue comment rather than waiting interactively for input.
Planner's rationale
Boundary — What a loop-launched agent can reach beyond the loop's own tools, and the doctrine line that sent it looking. On a real v2 run the Codex Developer held Codex's ChatGPT-account GitHub connector: github.fetch_issue succeeded and github.add_comment_to_issue was stopped only by Codex's approval policy. Its staged config listed vinaya_dev_tools alone, so the reach came from the account's apps, which the staged [features] block leaves on (codex features list reports apps, plugins and remote_plugin enabled). It tried to post because the brief template's Autonomy rule tells a halted Developer to record the blocker in a comment. Pinned files: harness/adapters/agents/codex/config.ts, harness/adapters/agents/claude-code/settings.ts, harness/adapters/agents/parity.test.ts, aeg-root/templates/brief-template.md. Out: aeg-root/aeg-manual-flow.md (the manual merge-gate flow), the loop's own MCP server and its tool list, the sandbox and network settings, the user's own ~/.codex/config.toml and Claude settings, the v1/v2 flow files, and the importers that only read the generated config or the template: apps/cli/tests/sandbox-conformance, processes/vinaya/executing, processes/vinaya/tests/recovery, packages/aeg-core/src (none needs an edit; their tests must still pass).
Traps to avoid — Do NOT edit the user's home config; the switches go only into the staged per-run config. Do NOT remove or rename a vinaya_dev_tools tool. Confirm each feature key against the installed Codex with codex features list before relying on it; a key that does not exist must not be written. Update every fixture that embeds the staged config.toml (search harness/adapters/agents/fixtures for multi_agent = true), never by loosening the assertion. For Claude, prove the claim with a launch-shape test rather than assuming --strict-mcp-config covers account connectors. Do NOT cite Issue or PR numbers in code comments or doctrine.
Suggested agent-class — mid: a config generator, its fixtures, one doctrine line.
Stop-and-escalate — Stop if disabling apps or plugins also removes the vinaya_dev_tools server or any built-in tool the role's grants allow; report which.
Docs to keep coherent — no-doc-surface: the staged agent config is internal; the one doctrine change is the template line itself.
doc-claims: the change adds no doc claim binding and edits no line a claim cites.
reader-resolvable-prose: the rewritten Autonomy sentence names the turn result and the loop in plain words, with no Issue, PR or tranche reference.
retired-vocabulary: the sentence uses only current terms (turn result, loop, blocker).
doctrine-portability: the sentence names no machine path, vendor product or tool binary.
doctrine-no-procedures: the sentence states a rule (where a blocker is reported), not a step-by-step procedure.
workspace-escape: the sentence names no path outside the repository.
quoted-command: the sentence quotes no command.
Surface
in: harness, aeg-root
out: apps, packages, processes, .github, .claude, .agents
Parts
Part 1 (O1) — The Codex config generator writes apps = false, plugins = false, remote_plugin = false under [features].
Part 2 (O2) — A Claude launch-shape test pins that only the loop's MCP server is reachable; the launch disables account connectors if the test shows they load.
Part 3 (O3) — The Autonomy rule says to report the blocker in the turn result; no other aeg-root file tells a dispatched Developer to post a comment.
Part 4 (O4) — Parity test and fixtures updated; each new feature line is mutation-checked.
Test plan
cd harness && bun test adapters/agents/parity.test.ts → all pass
bun run typecheck → exit 0
bunx biome check harness → 0 errors
git diff main --stat → only paths under harness and aeg-root
- [principal] Start any Codex task with
task run --agent codex --runner atta-engine: nogithub.*call appears in the driver log, the run's stagedconfig.toml(engine-runs/<task>/generated/developer/config.toml) containsapps = false,plugins = falseandremote_plugin = false, and a halted turn reports its blocker without attempting a comment.
Stop conditions
- A connector switch also removes the loop's own server or an allowed built-in tool.
- A Codex feature key named here does not exist in the installed Codex.
Origin
Backlog fix, 2026-10-28, from a real Codex v2 run that halted on a stop condition: the Developer read the Issue through Codex's ChatGPT-account GitHub connector and tried to post a comment, refused only by Codex's approval policy. It tried because the brief template's Autonomy rule asks for a comment; it could because the staged Codex config leaves account apps and plugins on.
Activity
daniboomerang commentedon Oct 28, 2026
Brief hash: f2c4aa6ab54b42c5c5c7e5fd7fef03dc725a54944e195a720c0f12eb2c75da80
For: [model] (coding-agent CLI on a dev machine, dispatched locally, unattended)
Reason: Suggested agent-class — mid: a config generator, its fixtures, one doctrine line.
Owner: the Principal
Goal: Fix(harness): Loop-launched agents reach only the loop's tools, and a halted Developer reports instead of posting
Project: ** vinaya
Tier: 1
Closes #1677
You are the AEG Developer. Run
bun apps/cli/src/index.ts doctrine --role developer --printand read its output first. Mandatory.Objectives
O1. A loop-launched Codex role (Developer, code reviewer, security reviewer) reaches no ChatGPT-account connector: the staged
config.tomlthatharness/adapters/agents/codex/config.tsgenerates setsapps = false,plugins = falseandremote_plugin = falseunder[features], so the only MCP tools the role holds are the loop's ownvinaya_dev_toolsserver.O2. A loop-launched Claude Code role holds no account connector either: its launch already passes
--strict-mcp-configwith the loop's own MCP config; a test pins that a Claude role's tool list carries only the loop's MCP server, and if Claude Code's claude.ai connectors still load under that flag, the launch also sets the environment switch that disables them.O3. The brief template's Autonomy rule (
aeg-root/templates/brief-template.md) tells a halted Developer to report the blocker in its turn result (the loop posts it), not to post a PR or Issue comment; no other doctrine file underaeg-roottells a dispatched Developer to post a comment itself. The manual merge-gate flow's comment instructions, for a Developer helping merge by hand, are not a dispatched turn and stay unchanged.O4. The parity test (
harness/adapters/agents/parity.test.ts) and the agent fixtures that embed the stagedconfig.tomlare updated in the same change, and the parity test fails when any of the three Codex feature lines is removed.Documentation
None — no normative external source governs this task.
Premises
Checked against the code when this task Issue was cut, and again against the default branch at dispatch — facts, not claims.
harness/adapters/agents/codex/config.tscontains'hooks = true',harness/adapters/agents/claude-code/settings.tscontains'--strict-mcp-config',aeg-root/templates/brief-template.mdcontainsand when you halt, record the blocker in a PR comment or an Issue comment rather than waiting interactively for input.2. Context — read before doing anything
task/issue-1677.Depends-on: —,Conflicts-with: —.0760599f0e992618a8719c5c2bdcb088b975325f— the checkout's HEAD equaled the remote default branch, and no pinned file below carried an uncommitted change, when these facts were read.github.fetch_issuesucceeded andgithub.add_comment_to_issuewas stopped only by Codex's approval policy. Its staged config listedvinaya_dev_toolsalone, so the reach came from the account's apps, which the staged[features]block leaves on (codex features listreportsapps,pluginsandremote_pluginenabled). It tried to post because the brief template's Autonomy rule tells a halted Developer to record the blocker in a comment. Pinned files:harness/adapters/agents/codex/config.ts,harness/adapters/agents/claude-code/settings.ts,harness/adapters/agents/parity.test.ts,aeg-root/templates/brief-template.md. Out:aeg-root/aeg-manual-flow.md(the manual merge-gate flow), the loop's own MCP server and its tool list, the sandbox and network settings, the user's own~/.codex/config.tomland Claude settings, the v1/v2 flow files, and the importers that only read the generated config or the template:apps/cli/tests/sandbox-conformance,processes/vinaya/executing,processes/vinaya/tests/recovery,packages/aeg-core/src(none needs an edit; their tests must still pass).vinaya_dev_toolstool. Confirm each feature key against the installed Codex withcodex features listbefore relying on it; a key that does not exist must not be written. Update every fixture that embeds the stagedconfig.toml(searchharness/adapters/agents/fixturesformulti_agent = true), never by loosening the assertion. For Claude, prove the claim with a launch-shape test rather than assuming--strict-mcp-configcovers account connectors. Do NOT cite Issue or PR numbers in code comments or doctrine.3. Technical dependencies
Dependency rationale — none: this single-fix Issue declares no
Depends-onorConflicts-withedge.4. Technical surface map
Create:
Modify:
Out of surface: apps, packages, processes, .github, .claude, .agents — 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): The Codex config generator writes
apps = false,plugins = false,remote_plugin = falseunder[features].Files (touches the repo root):
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): A Claude launch-shape test pins that only the loop's MCP server is reachable; the launch disables account connectors if the test shows they load.
Part 3 (O3): The Autonomy rule says to report the blocker in the turn result; no other
aeg-rootfile tells a dispatched Developer to post a comment.Part 4 (O4): Parity test and fixtures updated; each new feature line is mutation-checked.
7. Documentation-update list
.vinaya/doc-ownersderivation matched zero bindings against this task's surface — no mechanically-derived doc updates. Confirm no additional doc artifact applies before treating this list as final.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
task run --agent codex --runner atta-engine: nogithub.*call appears in the driver log, the run's stagedconfig.toml(engine-runs/<task>/generated/developer/config.toml) containsapps = false,plugins = falseandremote_plugin = false, and a halted turn reports its blocker without attempting a comment.10. Stop conditions
Stop-and-escalate — Stop if disabling
appsorpluginsalso removes thevinaya_dev_toolsserver or any built-in tool the role's grants allow; report which.11. Constraints
12. Deliverable
Fix(harness): Loop-launched agents reach only the loop's tools, and a halted Developer reports instead of postingopen_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 #1677at 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.