Skip to content

feat: add AGENT_DEV_CMD / AGENT_REVIEW_CMD per-side overrides (INV-37)#156

Merged
zxkane merged 13 commits into
mainfrom
feat/per-side-agent-cmd
May 26, 2026
Merged

feat: add AGENT_DEV_CMD / AGENT_REVIEW_CMD per-side overrides (INV-37)#156
zxkane merged 13 commits into
mainfrom
feat/per-side-agent-cmd

Conversation

@zxkane
Copy link
Copy Markdown
Owner

@zxkane zxkane commented May 25, 2026

Summary

Adds two operator knobs in lib-agent.sh that let dev and review wrappers run on different agent CLIs in the same project:

  • AGENT_DEV_CMD — defaults to ${AGENT_CMD:-claude}
  • AGENT_REVIEW_CMD — defaults to ${AGENT_CMD:-claude}

Each wrapper sets AGENT_CMD to its side's value immediately after sourcing lib-agent.sh. The AGENT_LAUNCHER claude-only guard generalizes to reject any non-claude side (strictly more permissive than the old single-side check — never rejects a config that previously passed).

The motivating use case: a downstream consumer project wants AGENT_CMD="claude" for heavy dev and AGENT_REVIEW_CMD="agy" for cheaper review.

What's in the PR

  • skills/autonomous-dispatcher/scripts/lib-agent.sh — 7-line init + guard rewrite
  • skills/autonomous-dispatcher/scripts/autonomous-dev.sh — 4-line override block after source lib-agent.sh
  • skills/autonomous-dispatcher/scripts/autonomous-review.sh — 5-line override block (symmetric)
  • skills/autonomous-dispatcher/scripts/autonomous.conf.example — operator-facing comment block with worked example
  • tests/unit/test-lib-agent-per-side-cmd.sh — 14 assertions (PSC-S1..S11): defaults, single-side override, both-side, empty-string, launcher guard ×4, wrapper structural placement
  • docs/pipeline/per-side-agent-cmd.md — spec
  • docs/pipeline/invariants.md — INV-37
  • docs/pipeline/README.md — index entry
  • docs/superpowers/plans/2026-05-25-per-side-agent-cmd.md — implementation plan (kept for traceability)

Backwards compatibility

Existing deployments don't set the new vars. Defaults make both equal to $AGENT_CMD, so behavior is byte-for-byte identical pre/post. Verified: all 7 peer test-lib-agent-*.sh suites still pass.

Spec & invariant

  • docs/pipeline/per-side-agent-cmd.md
  • INV-37 in docs/pipeline/invariants.md

Pipeline-docs gate

Touches lib-agent.sh (watched path), so docs/pipeline/ must also change. Satisfied:

  • docs/pipeline/per-side-agent-cmd.md
  • docs/pipeline/invariants.md (INV-37)
  • docs/pipeline/README.md

Test plan

  • bash tests/unit/test-lib-agent-per-side-cmd.sh — 14/14 PASS
  • All existing tests/unit/test-lib-agent-*.sh regression tests PASS
  • shellcheck -S error on lib-agent.sh + both wrappers + new test
  • bash -n autonomous.conf.example syntax OK
  • CI: unit-tests + shellcheck + pipeline-docs-gate green

Review process

The PR went through /pr-review-toolkit:review-pr with four specialized agents (code-reviewer, pr-test-analyzer, silent-failure-hunter, comment-analyzer). Findings addressed inline:

  • C1 (Critical): stripped podcast-curation private-repo refs from two committed docs (CLAUDE.md "No Private Repo Refs" rule)
  • H1, H2 (High): removed stale lib-agent.sh line numbers from the spec doc (referenced by name instead — survives churn better)
  • M1, M2, M3 (Medium): fixed spec-vs-implementation drift in operator-block placement and PSC-S9/S10 line-window descriptions (+4 / +5 reflecting the actual WHY-rationale comment sizes)

Silent-failure-hunter found 0 critical issues; 2 cosmetic observations (no fix recommended). Test analyzer noted 3 improvement opportunities (rated 5-7) deferred to follow-up.

Future work (filed as suggestions in review, NOT blocking this PR)

  • _LIB_AGENT_AGY_MODEL_WARNED-style WARN-once gate for the (rare) inverse pattern (agy-dev / claude-review with conflicting permission needs) — currently the AGENT_PERMISSION_MODE value is silently dropped on agy side, which is fine for the common pattern but not for the inverse
  • Behavioral test that exercises the AGENT_CMD rebinding actually steers case "$AGENT_CMD" dispatch (PSC-S9/S10 are structural-only)
  • env -i isolation in test sandboxes (mitigates hypothetical dev-box AUTONOMOUS_CONF ambient export)

zxkane added 12 commits May 25, 2026 15:42
Adds:
  - docs/pipeline/per-side-agent-cmd.md — spec for AGENT_DEV_CMD /
    AGENT_REVIEW_CMD operator knobs that let dev and review run on
    different agent CLIs in the same project (e.g. claude for dev,
    agy for review). Naming follows AGENT_DEV_MODEL /
    AGENT_REVIEW_MODEL precedent. Defaults to AGENT_CMD so existing
    deployments are unchanged.
  - docs/pipeline/README.md — index entry.

INV-37 (the precedence rule) is referenced in the spec but lands in
invariants.md as part of the implementation PR.
…spec

Review findings landed inline:
  - A1: clarify AGENT_LAUNCHER guard runs at lib-agent source time,
    BEFORE the wrapper's AGENT_CMD override
  - A3: tighten AGENT_PERMISSION_MODE rationale — claude-only branch
    consumes it; rare inverse pattern (agy-dev / claude-review)
    explicitly deferred
  - Q1: pin override-line placement (immediately after source
    lib-agent, before any other source)
  - Q3: drop step 7 (cross-link in agy-cli-support.md is duplication;
    autonomous.conf.example already covers the deployment pattern)
  - T1: add PSC-S11 (launcher guard with both sides non-claude) so
    refactor can't silently collapse the guard's || into AND

Test count now eleven (S1-S11). No behavior change to the planned
implementation; spec is more precise.
Adds GSTACK REVIEW REPORT section (eng-review CLEARED, 4 issues all
resolved inline). Fixes stale 'ten test cases' reference at step 5
(now eleven, matching the test table).
Bite-sized TDD plan, six tasks with red-green-commit cadence:
  T1 — lib-agent init (2 vars + guard rewrite) + PSC-S1..S8 + S11
  T2 — autonomous-dev.sh override + PSC-S9
  T3 — autonomous-review.sh override + PSC-S10
  T4 — autonomous.conf.example operator block
  T5 — INV-37 in invariants.md
  T6 — final regression + push + PR

Self-review confirms full spec coverage, no placeholders, type
consistency across tasks.
Adds per-side AGENT_CMD overrides to lib-agent.sh. Default to AGENT_CMD
so existing deployments are byte-for-byte unchanged.

The AGENT_LAUNCHER guard is rewritten to read AGENT_DEV_CMD /
AGENT_REVIEW_CMD directly. The new check is strictly more permissive
than the old one — it rejects the same set of bad configs (any
non-claude side with launcher set) plus correctly accepts the new
'both sides claude' default case via the per-side path.

Tests: PSC-S1..S8 + S11 (defaults, single-side override, both-side,
empty-string fallback, launcher guard 4 ways). PSC-S9/S10 (wrapper
structural placement) land in Tasks 2 and 3.

Existing test-lib-agent-*.sh suites all pass — zero regressions.
… placeholders

Code-quality review nit: shellcheck SC2034 (declared but not used) on
the two wrapper-path variables. They're consumed by PSC-S9 / PSC-S10
which land in Tasks 2 and 3 of the plan; defining them here keeps the
test scaffolding in one place across all three tasks.

Add an explanatory comment + 'shellcheck disable=SC2034' so a default-
severity shellcheck run is clean without changing what the variables
mean to a human reader.
…urce

Adds AGENT_CMD=$AGENT_DEV_CMD immediately after source lib-agent.sh so
the case statements in run_agent / resume_agent dispatch to the
dev-side CLI when the operator has set per-side overrides. Default
behavior (no overrides) is unchanged because AGENT_DEV_CMD defaults
to $AGENT_CMD inside lib-agent.sh.

Test: PSC-S9 asserts the line lands within 2 lines of the source
statement so a future refactor can't accidentally move it past code
that consumes $AGENT_CMD (earliest consumer is line 177).
Spec-compliance review surfaced an internal inconsistency in the plan:
Step 2.4 specs a 3-line WHY-rationale comment before AGENT_CMD=
"$AGENT_DEV_CMD", but Step 2.1's awk window of "+2" only allowed 1
intervening line, forcing one or the other to be sacrificed.

Resolve by restoring the spec'd 3-line comment (it carries useful
WHY-documentation that justifies the override pattern for future
maintainers) and widening the awk window to "+4". The window is still
tight enough to catch a refactor that moves the override past the
first $AGENT_CMD consumer (line 177 was the original concern).
…ent source

Mirrors the dev-side change. AGENT_CMD=$AGENT_REVIEW_CMD lands
immediately after source lib-agent.sh so the run_agent dispatch and
the 'Reviewed HEAD: ... agent X' trailer (line ~636) report the
review-side CLI correctly.

Test: PSC-S10 asserts placement structurally with a +5 line window
(accommodates the 4-line WHY-rationale comment, same as the dev-side
fix in commit 7bea617).
…onf.example

Adds a 17-line operator-facing comment block between the EXTRA_ARGS
declarations and the per-CLI blocks. Includes a worked example for
the 'claude for dev, agy for review' deployment pattern (the
motivating use case) and the AGENT_LAUNCHER constraint reminder.
INV-37 documents the AGENT_DEV_CMD / AGENT_REVIEW_CMD precedence rule
that lets one project run dev and review on different agent CLIs.
Defaults preserve back-compat (both vars fall back to AGENT_CMD via
:- semantics). AGENT_LAUNCHER guard tightens to require both sides
claude.

Anchored to docs/pipeline/per-side-agent-cmd.md (which already exists
on this branch with cross-reference [INV-37] resolved by this commit).
PR-review fixes (Critical + High + Medium):

  C1 (CLAUDE.md No Private Repo Refs): replace 'podcast-curation'
    with 'a downstream consumer project' / 'the motivating use case'
    in two committed docs (per-side-agent-cmd.md failure-mode table
    and the implementation plan PR body example).

  H1: drop stale lib-agent.sh:106-108 line ref for the AGENT_LAUNCHER
    guard (the guard moved during the rewrite); reference by name
    instead so the doc survives churn.

  H2: drop stale ~lines 588, 800 line refs for AGENT_PERMISSION_MODE
    consumption (claude branch consumes it; line numbers were ~12
    off from origin/main and would drift further).

  M1: spec said the operator-block lands 'after AGENT_PERMISSION_MODE,
    before per-CLI blocks' — actual placement (and where the
    autonomous.conf.example edit lands) is after AGENT_*_EXTRA_ARGS
    defaults. Update to match.

  M2 + M3: PSC-S9 / PSC-S10 spec table descriptions said 'at most
    one blank line of separation' / 'immediately after' — actual
    awk windows are +4 (dev, 3-line WHY comment) and +5 (review,
    4-line WHY comment) per the lessons learned during Tasks 2/3.
    Spec table now matches the implementation.

Test plan: 14/14 PSC assertions still pass; all peer test-lib-agent-*
suites still pass; shellcheck clean. (Note: pre-existing private-repo
references in unrelated tracked docs are out of scope per CLAUDE.md
'what I WRITE' clause.)
@zxkane
Copy link
Copy Markdown
Owner Author

zxkane commented May 25, 2026

agy CLI review (Antigravity 2.0, v1.0.2)

I ran the local agy CLI to review this PR (using the same flag set lib-agent.sh uses for AGENT_CMD=agy: agy -p --dangerously-skip-permissions --print-timeout 30m --log-file <path>). agy returned 3 findings; I verified each against the codebase. Two are real regressions this PR enables; one is a pre-existing bug.


Finding 1: AGENT_DEV_EXTRA_ARGS / AGENT_REVIEW_EXTRA_ARGS mapped by stage, not side (HIGH, pre-existing on origin/main, NOT introduced by this PR)

Location: skills/autonomous-dispatcher/scripts/lib-agent.sh:590 (run_agent) and :803 (resume_agent).

# run_agent line 590:
_parse_extra_args AGENT_DEV_EXTRA_ARGS extra_args

# resume_agent line 803:
_parse_extra_args AGENT_REVIEW_EXTRA_ARGS extra_args

Why it's a bug: the variables are named per-side (DEV / REVIEW) but consumed per-stage (run / resume). Call-site reality:

  • autonomous-dev.sh calls both run_agent (lines 337, 531) AND resume_agent (line 447) → dev side picks up AGENT_DEV_EXTRA_ARGS on first run, but AGENT_REVIEW_EXTRA_ARGS on resume
  • autonomous-review.sh calls only run_agent (line 546) → review side picks up AGENT_DEV_EXTRA_ARGS (wrong name)

Status: NOT introduced by this PR — the misnaming exists on origin/main. This PR doesn't touch _parse_extra_args or its call sites. But the misnaming becomes more visible now that per-side CLIs are possible (operators may set AGENT_REVIEW_EXTRA_ARGS=... for an agy review wrapper and find it ignored).

Recommended fix (separate PR): pass an AGENT_SIDE argument to run_agent/resume_agent and select the EXTRA_ARGS variable dynamically. Or rename the vars to AGENT_RUN_EXTRA_ARGS / AGENT_RESUME_EXTRA_ARGS to match what they actually do (with backwards-compat aliases). File as a separate issue.


Finding 2: _pgid_has_agent_process reads shared $AGENT_CMD — false-negative liveness under split config (HIGH, newly enabled by this PR)

Location: skills/autonomous-dispatcher/scripts/lib-dispatch.sh:1276

_pgid_has_agent_process() {
  ...
  local agent_cmd="${AGENT_CMD:-claude}"
  ...
  if [[ "$comm" == *"$agent_cmd"* ]]; then
    return 0
  fi
  ...
}

Why it's a regression: the helper is shared by dev_near_success (caller at line 1234) and review_near_success (caller at line 1371). When the dispatcher tick runs with the project's default AGENT_CMD=claude, but the review wrapper has been spawned with AGENT_CMD=agy (via the new AGENT_REVIEW_CMD=agy override), the substring match *claude* against the agy process's comm fails, falsely classifying the live wrapper as DEAD.

Pre-PR: impossible — there was no way for dev and review to run different CLIs.
Post-PR: real failure mode for any project that adopts AGENT_REVIEW_CMDAGENT_DEV_CMD.

Recommended fix: callers know which side they're checking. Pass the per-side CLI as an argument:

# In dev_near_success:
_pgid_has_agent_process "$pid" "${AGENT_DEV_CMD:-${AGENT_CMD:-claude}}"

# In review_near_success:
_pgid_has_agent_process "$pid" "${AGENT_REVIEW_CMD:-${AGENT_CMD:-claude}}"

# In _pgid_has_agent_process:
_pgid_has_agent_process() {
  local pgid="$1"
  local agent_cmd="${2:-${AGENT_CMD:-claude}}"
  ...
}

Finding 3: is_session_completed AGENT_CMD-gate reads shared var — wrong CLI under split config (MEDIUM, newly enabled by this PR)

Location: skills/autonomous-dispatcher/scripts/lib-dispatch.sh:530

is_session_completed() {
  ...
  [ "${AGENT_CMD:-claude}" = "claude" ] || return 1
  ...
}

Why it's a regression: the function only handles claude's JSON log format (documented at lines 503-528). The gate at line 530 conservatively returns 1 (false) for non-claude CLIs so the dispatcher falls through to normal stale-detection. Under split config (AGENT_CMD=claude AGENT_DEV_CMD=codex):

  • Dispatcher's $AGENT_CMD is still claude (the project default)
  • Gate passes (claude == claude)
  • Function tries to parse /tmp/agent-${PROJECT_ID}-issue-N.log
  • But the dev wrapper actually ran codex → log is codex JSONL, not claude JSON
  • Parser misinterprets

Recommended fix: gate on the dev-side CLI:

local dev_cmd="${AGENT_DEV_CMD:-${AGENT_CMD:-claude}}"
[ "$dev_cmd" = "claude" ] || return 1

Note: this function is dev-side-only (it parses the dev wrapper's log, called from Step 4 of dispatcher-tick). Review-side has no analogous parsing path.


Verdict

This PR's lib-agent.sh + wrapper changes are correct for the typical (no-override) deployment. But Findings 2 + 3 are dispatcher-side coupling points that the PR's per-side feature exposes. Without fixing them, the first project to adopt AGENT_REVIEW_CMD=agy will hit false-negative liveness checks (Finding 2) and may hit log-parser misinterpretation under AGENT_DEV_CMD=codex (Finding 3).

Recommendation: hold this PR; address Findings 2+3 in this same PR (estimated +30 lines code, +2 test cases, ~30 minutes). Finding 1 is pre-existing and out of scope here — file as a separate issue.

agy conversation id: 56746887-b20e-4b6c-accb-c54fc3dd441b (for resume).

…-completed (agy review #156)

Address Findings 2 + 3 from the agy CLI review of PR #156. The
dispatcher tick does not source lib-agent.sh and so cannot inherit
the wrapper-level AGENT_CMD override (added by this same PR for
run_agent/resume_agent dispatch). Two helpers in lib-dispatch.sh
need explicit per-side awareness:

Finding 2 — _pgid_has_agent_process now accepts an optional 2nd
argument: the per-side CLI to match against process comms in the
group. Callers updated:

  dev_near_success    → "${AGENT_DEV_CMD:-${AGENT_CMD:-claude}}"
  review_near_success → "${AGENT_REVIEW_CMD:-${AGENT_CMD:-claude}}"

Empty/missing 2nd arg falls back to AGENT_CMD for back-compat with
existing single-arg callers and test mocks. Without this, a project
running AGENT_REVIEW_CMD=agy would have its live agy review process
classified as DEAD by the dispatcher's *claude* substring match.

Finding 3 — is_session_completed gates on the dev-side CLI
(${AGENT_DEV_CMD:-${AGENT_CMD:-claude}}) because it parses the dev
wrapper's log file. Without this, a project with AGENT_DEV_CMD=codex
and the dispatcher's AGENT_CMD=claude default would attempt to parse
codex JSONL with claude rules, producing wrong completion-state
verdicts.

Test plan:
  - new tests/unit/test-pgid-has-agent-process.sh — 9 assertions
    covering per-side arg, fallback, back-compat 1-arg call,
    bad-PGID guards. Spawns a child via cp /bin/sleep + setsid so
    its comm matches a chosen name.
  - extends tests/unit/test-is-session-completed.sh with TC-WH-005b:
    3 assertions covering AGENT_DEV_CMD ≠ AGENT_CMD split config.
  - all existing peer tests still pass (test-dev-near-success,
    test-dispatcher-review-near-success, test-is-session-completed,
    test-is-session-completed-end-ts).

Spec: docs/pipeline/per-side-agent-cmd.md gains a §Dispatcher-side
coupling section. INV-37 Consumer field extended to name the two
dispatcher-side reads. Test-cases doc at
docs/test-cases/dispatcher-per-side-cmd-coupling.md tracks the
fixes.
@zxkane
Copy link
Copy Markdown
Owner Author

zxkane commented May 26, 2026

Findings 2 + 3 addressed in commit 7675a90

Pushed a fix commit to this branch addressing Findings 2 + 3 from the agy review above.

What changed

Finding 2_pgid_has_agent_process now accepts an optional 2nd argument (per-side CLI override). Empty/missing falls back to $AGENT_CMD for back-compat.

  • dev_near_success calls with ${AGENT_DEV_CMD:-${AGENT_CMD:-claude}}
  • review_near_success calls with ${AGENT_REVIEW_CMD:-${AGENT_CMD:-claude}}

Finding 3is_session_completed gates on ${AGENT_DEV_CMD:-${AGENT_CMD:-claude}} (function parses the dev wrapper's log).

Tests:

  • New tests/unit/test-pgid-has-agent-process.sh — 9 assertions (TC-PSC-COUP-01a..d). Spawns a controlled child via cp /bin/sleep $TMPDIR/fake-agy && setsid so its comm matches the test name.
  • Extended tests/unit/test-is-session-completed.sh with TC-WH-005b — 3 assertions for split-CLI config.
  • All peer tests still pass.

Spec/doc:

  • docs/pipeline/per-side-agent-cmd.md — new §Dispatcher-side coupling section
  • docs/pipeline/invariants.md — INV-37 Consumer field extended to name both dispatcher-side reads
  • New test-cases doc at docs/test-cases/dispatcher-per-side-cmd-coupling.md

Finding 1 (pre-existing AGENT_*_EXTRA_ARGS mapped by stage not side) is NOT addressed in this PR — it's a pre-existing bug on origin/main with a different fix shape (likely AGENT_SIDE parameter to run_agent/resume_agent). Will file as a separate issue.

Verification

  • bash tests/unit/test-pgid-has-agent-process.sh — 9/9 PASS
  • bash tests/unit/test-is-session-completed.sh — 17/17 PASS
  • Full unit suite — all PASS, zero regressions
  • shellcheck -S error clean on lib-dispatch.sh + new test file

@zxkane
Copy link
Copy Markdown
Owner Author

zxkane commented May 26, 2026

agy re-review (after commit 7675a90)

Re-ran the local agy CLI to re-review after pushing the fix commit. agy resumed the prior conversation (56746887-b20e-4b6c-accb-c54fc3dd441b) and returned:

Verdict: CLEARED

The fixes in commit 7675a90 are correct and complete. They successfully resolve Findings 2 + 3 without introducing regressions.

Verified by agy:

  1. Finding 2 resolved cleanly at lib-dispatch.sh:1290 (local agent_cmd="${2:-${AGENT_CMD:-claude}}"); callers dev_near_success / review_near_success correctly pass ${AGENT_DEV_CMD:-...} / ${AGENT_REVIEW_CMD:-...}.
  2. Finding 3 resolved cleanly at lib-dispatch.sh:534 (local _dev_cmd="${AGENT_DEV_CMD:-${AGENT_CMD:-claude}}").
  3. Back-compat: 1-arg calls to _pgid_has_agent_process and unset AGENT_DEV_CMD configs fall back to $AGENT_CMD / claude as expected.
  4. Sweep check: agy grepped lib-dispatch.sh + dispatcher-tick.sh for $AGENT_CMD references and confirms no other dispatcher-side reads exist. (dispatcher-tick.sh has zero AGENT_CMD references; all reads in lib-dispatch.sh are now per-side.)
  5. Test coverage: TC-PSC-COUP-01a..d and TC-WH-005b correctly exercise the new behaviors. All unit tests pass.
  6. Shellcheck: clean.
  7. Comments: accurately mirror new behavior.

Finding 1 (AGENT_*_EXTRA_ARGS mapped by stage not side) remains flagged as pre-existing on origin/main. As noted in the prior comment, that's out of scope for this PR — different fix shape (likely an AGENT_SIDE parameter to run_agent/resume_agent). Will file as a separate issue.

PR is ready for merge from agy's perspective. CI green (Unit Tests + ShellCheck + pipeline-docs gate all pass).

@zxkane zxkane merged commit efffbba into main May 26, 2026
3 checks passed
@zxkane zxkane deleted the feat/per-side-agent-cmd branch May 26, 2026 02:20
zxkane added a commit that referenced this pull request May 26, 2026
…ide overrides (#158)

Adds AGENT_DEV_LAUNCHER and AGENT_REVIEW_LAUNCHER operator knobs that
let dev and review wrappers each have their own launcher prefix. Both
default to \${AGENT_LAUNCHER:-} so existing deployments are byte-for-
byte unchanged.

INV-38 documents the precedence rule. The single INV-37 'both sides
claude' launcher guard is replaced by two independent per-side guards:
each side's launcher is gated on THAT side's AGENT_CMD. Strictly more
permissive than the INV-37 form.

The motivating use case: a project with AGENT_CMD=claude +
AGENT_DEV_LAUNCHER=cc-bridge (Bedrock dev) + AGENT_REVIEW_CMD=kiro (no
launcher needed for review). Pre-INV-38 was blocked by INV-37's both-
sides-claude check. Post-INV-38 works.

Includes:
  - skills/autonomous-dispatcher/scripts/lib-agent.sh — init + per-
    side argv tokenization mirroring the existing AGENT_LAUNCHER eval;
    two per-side guards replace the single guard
  - skills/autonomous-dispatcher/scripts/autonomous-dev.sh —
    AGENT_LAUNCHER_ARGV rebind to AGENT_DEV_LAUNCHER_ARGV after the
    existing AGENT_CMD rebind from #156
  - skills/autonomous-dispatcher/scripts/autonomous-review.sh —
    symmetric rebind
  - skills/autonomous-dispatcher/scripts/autonomous.conf.example —
    operator-facing comment block with worked example + caveat about
    the kiro --trust-all-tools stage-vs-side gotcha (pre-existing)
  - tests/unit/test-lib-agent-per-side-launcher.sh — 14 assertions
    (PSL-S1..S10): defaults, fallback, per-side override, per-side
    guard pass/fail with RC=1 lock, structural placement
  - tests/unit/test-lib-agent-per-side-cmd.sh — PSC-S7/S8/S11 needles
    updated to match the new per-side error messages
  - docs/pipeline/per-side-launcher.md — full spec
  - docs/pipeline/invariants.md — INV-38
  - docs/pipeline/README.md — index entry

agy CLI review CLEARED with clean sweep — no other AGENT_LAUNCHER
reads exist on the dispatcher side.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant