Skip to content

fix(status): keep pi subagent panes working - #184

Closed
aserper wants to merge 1 commit into
raine:mainfrom
aserper:fix/pi-scoped-status
Closed

fix(status): keep pi subagent panes working#184
aserper wants to merge 1 commit into
raine:mainfrom
aserper:fix/pi-scoped-status

Conversation

@aserper

@aserper aserper commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Pi status extensions pass the emitting process id via --from-pid
  • a child Pi done event is kept as working while a parent Pi ancestor is still alive; a top-level Pi done stays done
  • the guard is stateless and Linux-only (reads /proc), matching the existing multiplexer::tmux::process_ancestors helper

Bug

Pi runs subagents as separate pi processes in the same tmux pane and loads the same status extension in parent and child. Both fire identical agent_start / agent_end hooks, and the events carry no run or parent id, so a child subagent finishing was indistinguishable from the parent finishing and marked the pane done early.

With no id in the event, the process tree is the only signal available to tell them apart: a top-level Pi has no Pi ancestor, a subagent Pi does.

Tests

  • cargo test --bin workmux process_tree --quiet
  • cargo test --bin workmux set_window_status --quiet
  • cargo test --quiet

Two related fixes that were previously bundled here have been split into their own PRs:

@raine

raine commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Thanks. How come all this logic is needed for Pi?

Pi runs subagents as separate `pi` processes in the same tmux pane and
loads the same status extension in parent and child. Both fire identical
`agent_start` / `agent_end` hooks, and the events carry no run or parent
id, so a child finishing was indistinguishable from the parent finishing
and marked the pane done early.

The extension now passes the emitting process id with `--from-pid`. A
top-level Pi has no Pi ancestor, so `done` stays `done`; a child Pi has a
live parent Pi ancestor, so its `done` is kept as `working` until the
parent completes. The guard is stateless and Linux-only (reads `/proc`),
matching the existing `multiplexer::tmux::process_ancestors` helper.
@aserper

aserper commented Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

The root issue is that Pi runs subagents as separate pi processes in the same tmux pane, and loads the same status extension in both parent and child. Both fire identical agent_start / agent_end hooks, and the events don't carry a run or parent id — so when a child subagent finishes, it's indistinguishable from the parent finishing, and the pane gets marked done early. With no id in the event, the process tree is the only signal I could find to tell them apart: a top-level Pi has no Pi ancestor, a subagent Pi does.

That said, this PR had ended up bundling two unrelated fixes — a tmux command-drift preserve and an atomic-write temp-file fix. I've split those out into #188 and #189 and slimmed this PR down to just the nested-done guard.

@arthurnw

Copy link
Copy Markdown
Contributor

Pi doesn't actually ship its own subagent functionality though right? Various extensions do this; i don't think there's a universal implementation, though running as a separate process in the same pane is probably a common and reasonable implementation.

@aserper

aserper commented Jul 14, 2026

Copy link
Copy Markdown
Contributor Author

You are correct, but that's how I've seen it implemented in pi and other harnesses as well. There's no "real" multi threading here...

@raine

raine commented Jul 26, 2026

Copy link
Copy Markdown
Owner

I'm a bit confused as to what to do with this PR, found some issues in review:

The process-tree approach works for separate-process Pi subagents on a normal Linux host, but that appears to be narrower than the PR currently suggests.

Current upstream Pi’s example subagent extension does spawn a separate pi process, so this works there. Current OMP, however, creates subagents as AgentSession objects in the same process and reloads extensions for each session. Parent and child therefore pass the same PID, so the child done event still marks the pane done.

The distinction is also lost in workmux sandboxes because the guest RPC sends only the status, and the implementation always treats the process as top-level on macOS and other non-Linux platforms.

Finally, existing installed Pi and OMP extensions will keep calling set-window-status without --from-pid; workmux setup treats any existing extension file as configured, so users would need an explicit reinstall or upgrade path.

@aserper aserper closed this Jul 26, 2026
@aserper

aserper commented Jul 26, 2026

Copy link
Copy Markdown
Contributor Author

After looking through the review findings, I agree that the process-tree approach is too narrow. It works for separate-process Pi subagents on an unsandboxed Linux host, but it cannot reliably handle same-process OMP sessions, sandbox PID namespaces, or other platforms. It would also require an upgrade path for existing installed extensions.

I think this is better handled by the extension launching the nested agent, since it knows whether the session is a child and can disable Workmux status updates there. Closing this rather than adding more Workmux-side heuristics.

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.

3 participants