[FEATURE] Consistent hook execution across in-process and pane-based teammate spawn modes

Resolved 💬 3 comments Opened Feb 8, 2026 by anonhostpi Closed Mar 8, 2026

Preflight Checklist

  • [x] I have searched existing requests and this feature hasn't been requested yet
  • [x] This is a single feature request (not multiple features)

Problem Statement

When using Agent Teams, lifecycle hooks fire inconsistently between in-process and pane-based teammate spawn modes:

Hooks that only fire for in-process teammates (not pane-based):

  • SubagentStart, SubagentStop, TeammateIdle, TaskCompleted — these fire in the parent process for in-process teammates but never fire for pane-based teammates (tmux/iTerm2), since the parent's hook system is bypassed entirely.

Hooks that only fire for pane-based teammates (not in-process):

  • SessionStart — pane-based teammates spawn a new CLI process, which fires its own SessionStart during initialization. In-process teammates do not trigger SessionStart because they run within the existing process and SessionStart only fires once at main session startup.

This means any hook-driven workflow — context injection, validation gates, audit logging, setup scripts — silently breaks or behaves differently depending on spawn mode. The behavior difference is undocumented and creates a hidden compatibility gap between platforms (Windows defaults to in-process; macOS/Linux with tmux defaults to pane-based).

Proposed Solution

All teammate lifecycle hooks should fire consistently regardless of spawn backend:

  • SubagentStart, SubagentStop, TeammateIdle, and TaskCompleted should fire in the parent/leader process for pane-based teammates, not just in-process ones.
  • SessionStart should either fire for in-process teammates (as a per-agent event) or be explicitly documented as a session-level-only event with an alternative hook for per-agent initialization.

For pane-based teammates, this could mean:

  • The parent fires these hooks locally even though the teammate runs in a separate process
  • Or the teammate's process communicates lifecycle events back to the parent, which then runs the hooks

The hook input should contain the same fields (agent_id, agent_type, teammate_name, team_name) regardless of spawn mode, so hook scripts don't need to handle platform-specific differences.

Critically, hooks that support context injection must have their output routed to the child process. For SubagentStart, exit code 0 stdout and hookSpecificOutput.additionalContext are used to inject context into the subagent's message stream. When SubagentStart fires in the parent for a pane-based teammate, the hook output must be relayed to the child process so the teammate actually receives the injected context. The same applies to any other hook (SubagentStop, PostToolUse, etc.) whose output is meant to feed back into the agent — if the hook fires in the parent, its output needs a delivery path to the child. Without this, firing the hook in the parent is insufficient for context injection use cases.

Alternative Solutions

Current workaround: Force teammateMode: "in-process" in settings to ensure SubagentStart and other lifecycle hooks fire. This works but sacrifices the process isolation and terminal UI benefits of pane-based mode, and means SessionStart does not fire per-teammate.

Another partial workaround: Use PreToolUse/PostToolUse on the Task tool (which do fire for both modes) and inspect tool_input for name/team_name fields to detect teammate spawns. However, this doesn't cover the full lifecycle — only the initial spawn event.

Priority

High - Significant impact on productivity

Feature Category

Configuration and settings

Use Case Example

  1. I set up a SubagentStart hook that injects role-specific context into teammates based on their name (e.g., teammate named "security-reviewer" gets security guidelines, "tester" gets test standards)
  2. This works perfectly on Windows (in-process mode) — but SessionStart never fires per-teammate
  3. A colleague on macOS with tmux runs the same project — teammates spawn in panes, SubagentStart never fires in the parent, no context is injected — but SessionStart fires in each pane's own process
  4. The teammates behave differently on each platform with no errors or warnings
  5. Even if SubagentStart were fired in the parent for pane-based teammates, the additionalContext output would need to be forwarded to the child process — otherwise the hook runs but the teammate never sees the injected context

Additional Context

Verified by reading the cli.js source (v2.1.37). The relevant code paths:

  • In-process teammates: fx4()zZY()xj6() (async) → LR()STA() fires SubagentStart in parent. Hook output (additionalContext) is pushed into the subagent's message array N before CZ() (the conversation loop) starts — the subagent receives it directly. SessionStart (oM()/RLA()) is NOT called anywhere in this path.
  • Pane-based teammates: fx4()KZY()/YZY() → tmux/iTerm2 pane created → a new claude CLI process starts → that process fires its own SessionStart during initialization. The parent never reaches LR() or STA(). No mechanism exists to relay hook output to the child process.

Summary of hook behavior by spawn mode:

| Hook | In-process (parent) | Pane-based (parent) | Pane-based (child) |
|---|---|---|---|
| SessionStart | No | No | Yes |
| SubagentStart | Yes | No | No |
| SubagentStop | Yes | No | No |
| TeammateIdle | Yes | No | No |
| TaskCompleted | Yes | No | No |
| PreToolUse (Task) | Yes | Yes | N/A |
| PostToolUse (Task) | Yes | Yes | N/A |

The PostToolUse hook for the Task tool fires before SubagentStart for in-process teammates because xj6() is fire-and-forget. This timing relationship is also absent for pane-based teammates.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗