Skip to content

Fix(harness): Loop-launched agents reach only the loop's tools, and a halted Developer reports instead of posting #1677

Closed

Description

@daniboomerang

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: no github.* call appears in the driver log, the run's staged config.toml (engine-runs/<task>/generated/developer/config.toml) contains apps = false, plugins = false and remote_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

  1. daniboomerang commented on Oct 28, 2026

    @daniboomerang
    MemberAuthor

    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 --print and 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.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 — 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.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.

    2. Context — read before doing anything

    • Backlog Issue: Fix(harness): Loop-launched agents reach only the loop's tools, and a halted Developer reports instead of posting #1677, no tranche. Branch task/issue-1677. Depends-on: —, Conflicts-with: —.
    • Read Issue Fix(harness): Loop-launched agents reach only the loop's tools, and a halted Developer reports instead of posting #1677 in full for the complete rationale — do not re-derive it.
    • Revision: rendered at 0760599f0e992618a8719c5c2bdcb088b975325f — the checkout's HEAD equaled the remote default branch, and no pinned file below carried an uncommitted change, when these facts were read.
    • 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.

    3. Technical dependencies

    Dependency rationale — none: this single-fix Issue declares no Depends-on or Conflicts-with edge.

    4. Technical surface map

    Create:

    • (none — every surface file already exists)

    Modify:

    • aeg-root/aeg-manual-flow.md
    • aeg-root/templates/brief-template.md
    • harness/adapters/agents/claude-code/settings.ts
    • harness/adapters/agents/codex/config.ts
    • harness/adapters/agents/parity.test.ts

    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:

    • aeg-root/aeg-manual-flow.md sha256: e1b5a007c3722650993caa53be40d773568f162c0a1278533c61a84241b05072
    • aeg-root/templates/brief-template.md sha256: f6d4af14ed5abee45ef2bb6244a8bba3713146d3d82d5c0e1b660278fcf54a86
    • harness/adapters/agents/claude-code/settings.ts sha256: de3348e47579fa096d84c380f671a59398ceeed2fbe7892f3f5fef8af1bf4e71
    • harness/adapters/agents/codex/config.ts sha256: f5b22a8247872a7634f003344e7d40b6474ac0b5bf9c25cc7c58a61d7cac3855
    • harness/adapters/agents/parity.test.ts sha256: 027356406726e8cd54e1c3a6365a6849c0eb9dc98b0d0cc9aaee601371e8c183

    5. Pre-flight checks

    Step 0 (mandatory, verbatim):

    bun install --frozen-lockfile --silent
    
    1. Clean status; parent origin/main; branch suffix literal-matches the task id.
    2. Under the review loop (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 own gh call fails inside your sandbox. Working manually, with no driver behind you, fall back to roles/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_changes when every Part is done, then open_pull_request

    1. Part 1 (O1): The Codex config generator writes apps = false, plugins = false, remote_plugin = false under [features].

      Files (touches the repo root):

      • aeg-root/aeg-manual-flow.md
      • aeg-root/templates/brief-template.md
      • harness/adapters/agents/claude-code/settings.ts
      • harness/adapters/agents/codex/config.ts
      • harness/adapters/agents/parity.test.ts

      The pre-push hook runs the affected suite on your one push and refuses it on failure — do not run it yourself per Part.

    2. 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.

    3. 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.

    4. Part 4 (O4): Parity test and fixtures updated; each new feature line is mutation-checked.

    7. Documentation-update list

    .vinaya/doc-owners derivation 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

    • Under the review loop, the controller runs the static gates: the commit hook applies safe format and lint fixes to staged files, typechecks affected packages, and runs the Vinaya checks; the pre-push hook runs the affected suite; run_checks and 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.
    • The pre-push hook runs the affected suite once, on your one push, and refuses it on failure; CI runs the full suite.
    • Every blast-radius consumer named in §4, re-verified by name.
    • The tier checklist in bun apps/cli/src/index.ts doctrine --role developer --print genuinely satisfied; use the controller's run_checks result, hooks, and CI as gate evidence.

    9. 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: no github.* call appears in the driver log, the run's staged config.toml (engine-runs/<task>/generated/developer/config.toml) contains apps = false, plugins = false and remote_plugin = false, and a halted turn reports its blocker without attempting a comment.

    10. 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.

    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.

    11. Constraints

    Autonomy: Do not stop to ask clarifying questions. For any ambiguity not covered by a Section 10 stop condition, choose the most reasonable option consistent with this brief, record the choice in the PR body at open, or in a PR comment after open, and continue. Halt only for the explicit Section 10 stop conditions — and when you halt, record the blocker in a PR comment or an Issue comment rather than waiting interactively for input.

    12. Deliverable

    • PR title (exact): Fix(harness): Loop-launched agents reach only the loop's tools, and a halted Developer reports instead of posting
    • Open the PR only via the open_pull_request tool (title and body); publish your commits with publish_changes and update the body with update_pull_request_body/refresh_evidence — you hold no gh/git push credential.
    • Publish once, with publish_changes, when every Part is done; then open the pull request with open_pull_request. Publish again only to answer review findings or a red gate — a refused hook, a failing check, a merge conflict.
    • PR body = the Developer's PR report (print it with bun apps/cli/src/index.ts doctrine --template pr-report --print), with Closes #1677 at the top of the header block. This brief stays frozen on the task Issue and never rides in the body.
    • Pre-open: tier checklist satisfied. The documentation gate is the controller's — run_checks and CI run it.
    • Include git diff origin/main...HEAD --stat as context only; Surface is judged by the driver's surface-scope check, never by this hand-run diff. Token use needs no report — the Vinaya log records it.
    • Then STOP. Review and Verification are separate invocations.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions