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.
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.