Hook event 16 of 33

TeammateIdle

Runs when an agent-team teammate is about to go idle after finishing a turn.

Exit code veto
Exit 2 blocks. Exit 2 feeds stderr back so the teammate keeps working; a JSON continue:false field stops it entirely instead, a different outcome from the exit-code path.
Matchers
none
if filter
Does not apply
Docs checked
2026-08-29

Before a teammate goes quiet

Your teammate just finished a turn and is about to sit idle, waiting for the next assignment. That is the moment TeammateIdle fires, before the idle transition happens. There is no matcher, so every configured handler runs. The payload still carries permission_mode, teammate_name, and team_name, but the hooks reference marks the last two as deprecated. Write new hooks against teammate_name.

Two levers with opposite effects

You have two ways to steer a teammate, and they pull in opposite directions. Exit 2 sends the teammate back to work. Whatever you put on stderr becomes feedback, and the teammate keeps going instead of idling. The JSON continue: false with stopReason does the opposite: it stops the teammate entirely, and you see the reason. There is no top-level decision and no event-specific output object, so those two paths are the only things this hook can say. The exit code means not yet. The JSON means done.

Exit 0 and exit 1 let the teammate go idle, unless the JSON stops it.

The mistake most people make first

You want to send a teammate back with a note, so you reach for the shared field because it worked elsewhere: {"continue": false, "stopReason": "lint failed on src/api.ts"}.

The teammate stops. Not idle, stopped, and your note shows up as the reason it stopped. On this event that shared field does the opposite of what you wanted.

The keep-working path is exit 2 with the note on stderr.