Skip to content

fix(pstack): let Claude Code subagents wait in the foreground (#232, #233) - #239

Merged
mergify[bot] merged 2 commits into
mainfrom
fix/232-233-claude-code-waits
Oct 21, 2026
Merged

mergify[bot] merged 2 commits into
mainfrom
fix/232-233-claude-code-waits

Conversation

@ericlitman

@ericlitman ericlitman commented Oct 21, 2026 •

Copy link
Copy Markdown
Owner

Summary

On Claude Code, a subagent can now wait for a lane's report in the foreground. Every generated lane agent set background: true, which Claude Code honors over a caller's run_in_background: false, so a subagent that needed a lane's result could only poll for it.

 runner/registry/render.ts
-  "background: true",
 plugins/pstack/agents/pstack-<family>-<effort>.md   (25 files, regenerated)
-  background: true
 poteto-mode/references/codex-tools.md
+  ## Waits on Claude Code      (main session vs subagent; watch-pr; one observation window)
 provider-dispatch.md, poteto-mode/SKILL.md:12, playbooks/babysit.md:12, docs/reference.md
+  pointers to that section
 verify-open-pstack/features/recipes.ts
   native-agents: dispatch with run_in_background false, require each report inline

Closes #232. Closes #233.

Evidence

  • Before: on Claude Code 2.1.304, a throwaway agent with background: true, called with run_in_background: false, returned "Async agent launched successfully" with is_backgrounded: true, from the main session and from a subagent at depth 2 (2026-10-20 probe, quoted on Claude lanes default to background, which forces polling when a subagent dispatches dependent work #233).
  • After: on this candidate, loaded with session-only --plugin-dir, a foreground general-purpose subagent dispatched pstack:pstack-opus-low with run_in_background: false:
    Agent call {"type":"general-purpose","bg":false,"parent":"main"}
    task_started {"bg":false,"depth":1}
    Agent call {"type":"pstack:pstack-opus-low","bg":false,"parent":"nested"}
    task_started {"bg":false,"depth":2}
    tool_result nested [Subagent hand-back] ...
    result success "PROBE-NESTED-OK"
    
  • The catalog unit test now fails on a launch-notice result and passes on an inline report.
  • Live gate: pending. This PR changes features/recipes.ts, so it runs from a checkout of this head with --self-test. Features, and why each runs:
    • claude:catalog: its native-agents case dispatches the regenerated lane agents in the foreground and requires their reports inline.
    • claude:skill-invocation:poteto-mode and codex:skill-invocation:poteto-mode: one stand-in per harness for the text changes, since poteto-mode's Platform Adaptation paragraph now points to the new section.
    • project-skill in both harnesses comes with --self-test.

Merge Danger

Door: two-way

Blast Radius: dispatch

A main-session caller that omits run_in_background still starts subagents in the background by default. A caller that asks for the foreground now gets it. The section tells the main session to pass run_in_background: true for fan-outs.

Acceptance criteria

Gate results

On this head:

Command Exit Summary
bun run test 0 505 pass, 0 fail
bun run typecheck 0 strict tsc, three projects
bun run static 0 201 pass, 0 fail
claude plugin validate plugins/pstack 0 Validation passed
bun runner/registry/render.ts --check 0 generated agents current

Review rounds

  • Head 1 (4fb19b7d), Unfret: the TIMEOUT-only rerun would strand a babysit subagent after it fixed a BLOCKER (exit 3 or 4) and pushed (verdict-changing, fixed). The catalog prompt said "both" Agent calls for three agents (fails-loudly, fixed in the same push). The watcher rule did not say it is GitHub-only (fails-loudly, fixed in the same sentence).

Not verified

  • No live case runs the watch-pr wait inside a subagent, or a subagent waiting on its own background lane's receipt. Those are instructions whose mechanics, the Bash timeout and watch-pr's exit 5, already exist.
  • watch-pr checks its deadline only before a sleep that can last 300 s, so one call can still run past 240 s. That script is upstream-derived; any change goes to cursor/plugins first.
  • NOTICE.md's port-authored list leaves out provider-dispatch.md.

Thanks to @tapabratadey for both reports and the measurements behind them.

🤖 Generated with Claude Code

…233)

Every generated lane agent set background: true, which Claude Code
honors over a caller's run_in_background: false, so a subagent could
not wait for a lane's report and polled instead. The generator drops
the field. codex-tools.md now says once how the main session and a
subagent wait on Claude Code, including the PR watcher, and the
other files point there. The catalog live-gate case dispatches its
lanes in the foreground and requires their reports inline.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mergify

mergify Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Merge Protections

🟢 All 2 merge protections satisfied — ready to merge.

Show 2 satisfied protections

🟢 Queue ready pull requests

Automatically queue non-draft pull requests targeting main after verify, Unfret, and live-gate pass on the head and every review thread is resolved.

  • #review-threads-unresolved = 0
  • -draft
  • check-success=Unfret
  • check-success=live-gate
  • check-success=verify

🟢 🚦 Auto-queue

When all merge protections are satisfied and these conditions match, this pull request will be queued automatically.

  • -files~=^\.github/
  • base = main

@ericlitman

Copy link
Copy Markdown
Owner Author

Live evidence: Open Pstack

  • Candidate SHA: 4fb19b7d9fc8c9212aeef7c8aa942d82d94bc8de
  • Base SHA: f7ead75f1639510625b14063cb640c9b69ea4961
  • Result: PASSED — named features verified
  • Self-test: completed in both harnesses
  • Planned sessions: 7 (limit 12)
  • Publisher revision: 4fb19b7d9fc8c9212aeef7c8aa942d82d94bc8de
  • Evidence-set SHA-256: c38338e034f908c08477598aa9e5d12994a5a73c742093feb96e8831f5e6f8f0
  • Installation (claude): CLI 2.1.304 (Claude Code), plugin 1.15.0, candidate 4fb19b7d9fc8c9212aeef7c8aa942d82d94bc8de, tree d3dbf643a9cea357846823af9c614e757094f7bfe90c492c83db6e79c8a5af09.
  • Installation (codex): CLI codex-cli 0.163.0, plugin 1.15.0, candidate 4fb19b7d9fc8c9212aeef7c8aa942d82d94bc8de, tree d3dbf643a9cea357846823af9c614e757094f7bfe90c492c83db6e79c8a5af09.
  • Observation (claude / catalog): surface claude -p stream-json with the candidate plugin-dir; action recipe catalog: consume-sheet, consume-sheet-bounded, native-agents; result passed 28 assertions; ids retained privately; 28 assertions machine-checked; transcript SHA-256 a63199f224f96f5a62ca760fd4daf1816102041a44295dd180bd20f1ff7b3bfe; artifact-set SHA-256 ddd37d8ccdf64751fcf46cfe47343580e8d56a5c7db4af226e77988c5d761716.
  • Observation (claude / skill-invocation:poteto-mode): surface claude -p stream-json with the candidate plugin-dir; action recipe skill-invocation:poteto-mode: invoke; result passed: invoke:exit-0 invoke:skill-loaded invoke:file:result.md; 3 assertions machine-checked; transcript SHA-256 30135b8068c6eb95e5e00f61c117314a6ed9a7f1e6c33bbd151b2d4efbed2f31; artifact-set SHA-256 e9c31db8b1bf57ec795fc83f71f4402844ce9b19d51681676a56e7dc0ef15f06.
  • Observation (claude / project-skill): surface claude -p stream-json with the candidate plugin-dir; action recipe project-skill: doctor; result passed: doctor:exit-0 doctor:skill-loaded doctor:doctor-ran doctor:doctor-canonical-pass; 4 assertions machine-checked; transcript SHA-256 fea97b1f787dc4c94e8f53302f9d955c161211c39670de48eb18cd99e731a2ab; artifact-set SHA-256 269c01ac5d99a1aecba0639465c1732566a94b157be291dead4cb60e7b014cce.
  • Observation (codex / skill-invocation:poteto-mode): surface codex exec --json with the run-owned candidate installation; action recipe skill-invocation:poteto-mode: invoke; result passed: invoke:exit-0 invoke:skill-loaded invoke:file:result.md; 3 assertions machine-checked; transcript SHA-256 7ebc40d21e2678073d6c57bf887c3cf368aa78b112b4910dc408d8544d3d31ff; artifact-set SHA-256 42c48448e9c026434d7d3bfb82a35de5143c21ef2233411676e4a43cee056f98.
  • Observation (codex / project-skill): surface codex exec --json with the run-owned candidate installation; action recipe project-skill: doctor; result passed: doctor:exit-0 doctor:skill-loaded doctor:doctor-ran doctor:doctor-canonical-pass; 4 assertions machine-checked; transcript SHA-256 56e5ae47abea490bc9c60b32f1ca91c8291ef83fceadd37bb4e46e49f8d4da28; artifact-set SHA-256 60168bd542d30fac6b699981d14a8a99645023101664afc8488d3a477af1a183.
  • Policy: every new head requires a fresh run; this verifier does not change PR state, queue, or merge.

@greptile-apps

greptile-apps Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileTier: apex

[Medium impact] The change affects Claude Code users following pstack’s lane and babysit workflows.

The watcher rule needs fixing before merge because it blocks a subagent’s required recheck after a blocker is fixed.

Findings

  1. P1 Watching stops after a fix ▶
  2. P2 Prompt asks for too few ▶

Summary

Removes forced background execution from 25 generated Claude lane agents and lets callers choose how to wait.

  • Claude Code callers choose whether pstack lanes run in the background.
  • Claude Code subagents follow one shared rule for waiting on work.

Acknowledged limits, not new findings:

  • ericlitman notes that watch-pr can exceed 240 seconds because its existing sleep can last 300 seconds; changes belong upstream.
  • ericlitman notes that no live case covers a subagent running watch-pr or waiting on its own background lane receipt.
  • ericlitman notes that NOTICE.md omits provider-dispatch.md from its port-authored list.

This review used source inspection. No tests or live sessions were run.

Reviews (1) · Last reviewed commit: "fix(pstack): let Claude Code subagents w..." · Reviewed by Greptile

Comment thread plugins/pstack/skills/poteto-mode/references/codex-tools.md Outdated
Comment thread .claude/skills/verify-open-pstack/features/recipes.ts Outdated
@unfret-eal

unfret-eal Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

✅ Accepted risk

Accepted by ericlitman: #232 (authority 48fa77b)

🔴 High · TIMEOUT restart loops past merge-queue readiness

Details

Run: GET /unfret/run/panel:2e6d2ec138cd6165da432a1895632c5ac0b03908:Ri3f_Gz2wJx:r7xoPEhwhN8.

@unfret review · @unfret status · @unfret help

@unfret-eal unfret-eal Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛑 3 blocking findings
🔴 High · The three-agent live gate requests only two calls
🔴 High · TIMEOUT-only restart strands babysit after a blocker
🟡 Medium · Origin subagents are routed to the GitHub-only watcher
Check

Comment thread .claude/skills/verify-open-pstack/features/recipes.ts Outdated
Comment thread plugins/pstack/skills/poteto-mode/references/codex-tools.md Outdated
Comment thread plugins/pstack/skills/poteto-mode/references/codex-tools.md Outdated
The wait rule let a subagent rerun watch-pr only after a TIMEOUT exit,
so after it fixed a BLOCKER (exit 3 or 4) and pushed, it stopped
watching, against babysit step 6. It now reruns after a TIMEOUT and
after every push or verdict it acts on, on GitHub only. The catalog
case's prompt asks for all of its Agent calls, now three.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ericlitman

Copy link
Copy Markdown
Owner Author

Live evidence: Open Pstack

  • Candidate SHA: 2e6d2ec138cd6165da432a1895632c5ac0b03908
  • Base SHA: f7ead75f1639510625b14063cb640c9b69ea4961
  • Result: PASSED — named features verified
  • Self-test: completed in both harnesses
  • Planned sessions: 7 (limit 12)
  • Publisher revision: 2e6d2ec138cd6165da432a1895632c5ac0b03908
  • Evidence-set SHA-256: 14d961662fff05b2135a35e9cf1e8cc67d8d5bf78a4a5a42a081f0e654ed02cf
  • Installation (claude): CLI 2.1.304 (Claude Code), plugin 1.15.0, candidate 2e6d2ec138cd6165da432a1895632c5ac0b03908, tree 9fa204429c029116c055d36b91470ab1511b74afebc7cc0b646f252f90914c45.
  • Installation (codex): CLI codex-cli 0.163.0, plugin 1.15.0, candidate 2e6d2ec138cd6165da432a1895632c5ac0b03908, tree 9fa204429c029116c055d36b91470ab1511b74afebc7cc0b646f252f90914c45.
  • Observation (claude / catalog): surface claude -p stream-json with the candidate plugin-dir; action recipe catalog: consume-sheet, consume-sheet-bounded, native-agents; result passed 28 assertions; ids retained privately; 28 assertions machine-checked; transcript SHA-256 016dd776368deae7055ecded695144210f43bc48f53fa3ca6ea6d3b0d1db614f; artifact-set SHA-256 8c08287696610a3d710f339511fa82d985b9b27c60abbf318f79383840516aa9.
  • Observation (claude / skill-invocation:poteto-mode): surface claude -p stream-json with the candidate plugin-dir; action recipe skill-invocation:poteto-mode: invoke; result passed: invoke:exit-0 invoke:skill-loaded invoke:file:result.md; 3 assertions machine-checked; transcript SHA-256 c7a2d41fea4857e2eaa21cda5baf84d7374f0d961265756ea3a3165bf1a0dc2c; artifact-set SHA-256 0fb7dca9b9c9e2584e918f9330cb65835debdb9b876cc4bbc619b164bedf477e.
  • Observation (claude / project-skill): surface claude -p stream-json with the candidate plugin-dir; action recipe project-skill: doctor; result passed: doctor:exit-0 doctor:skill-loaded doctor:doctor-ran doctor:doctor-canonical-pass; 4 assertions machine-checked; transcript SHA-256 5fb70f63c65939785546b3b80fa09521cedfdae4047e4e7282a65001023c3bbf; artifact-set SHA-256 ce754d8898b9812722c54e952c6ad53f2a94ab03c712f85fc393da88e95e365c.
  • Observation (codex / skill-invocation:poteto-mode): surface codex exec --json with the run-owned candidate installation; action recipe skill-invocation:poteto-mode: invoke; result passed: invoke:exit-0 invoke:skill-loaded invoke:file:result.md; 3 assertions machine-checked; transcript SHA-256 69c3cf04e4fe44f905585b6256b14b549e40a17d88ca635e37905f84415175f3; artifact-set SHA-256 6d067b6d3f86d4064cd6b24f861e23c9449ff89e9ea8b99de2649e276406c2a3.
  • Observation (codex / project-skill): surface codex exec --json with the run-owned candidate installation; action recipe project-skill: doctor; result passed: doctor:exit-0 doctor:skill-loaded doctor:doctor-ran doctor:doctor-canonical-pass; 4 assertions machine-checked; transcript SHA-256 f22bce1c26d6d8713cc937cee2a48e9f62fdf191e06c33b1a5d0cec53bc6ef99; artifact-set SHA-256 2c45b55fc0f60efe66eca9840aff56b04f23175c5bb2acf8163cbe8f827dc915.
  • Policy: every new head requires a fresh run; this verifier does not change PR state, queue, or merge.

@unfret-eal unfret-eal Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛑 1 blocking finding
🔴 High · TIMEOUT restart loops past merge-queue readiness
Check

Comment thread plugins/pstack/skills/poteto-mode/references/codex-tools.md
@ericlitman

Copy link
Copy Markdown
Owner Author

Operator waiver for head 2e6d2ec (#232, #233).

The one open blocking finding, "TIMEOUT restart loops past merge-queue readiness", is true and not material. Class: inert.

  • In queued-stack mode watch-pr emits a non-terminal WAITING verdict while the stack sits in the merge queue, and can then exit with TIMEOUT (5). A subagent that follows the wait rule reruns the watcher instead of stopping at babysit's queued-mode stop condition.
  • The consequence is extra observation of a queued PR until the watcher reports COMPLETE on merge. watch-pr only reads: it runs gh api graphql queries, gh pr view and gh run view, with no mutation (scripts/watch-pr/github.ts). Nothing is pushed, merged or posted, and the babysit reaches the same merged end.
  • No consequence is security, secret exposure, data loss, or gate or waiver integrity.
  • The other three findings on this PR were dismissed by the panel on this head.
  • On this head the live gate passed, 7 sessions (evidence comment 6308133603).

@ericlitman

Copy link
Copy Markdown
Owner Author

@Mergifyio refresh

@mergify

mergify Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • ✅ Entered queue — 2026-10-21 04:45 UTC · Rule: default · triggered by merge protections
  • ✅ Checks skipped · PR is already up-to-date
  • ✅ Merged — 2026-10-21 04:45 UTC · at a62bc993f13fe7e7ce3fb472b36b218ce64ce90f · merge

This pull request spent 9 seconds in the queue, including 1 second running CI.

Required conditions to merge

@mergify
mergify Bot merged commit a62bc99 into main Oct 21, 2026
6 checks passed
@mergify

mergify Bot commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

refresh

✅ Pull request refreshed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

1 participant