Three agent fields attach a tool that runs at a fixed moment rather than when the model calls it. Each is one tool reference (tool_id, or an inline tool) or null. A stored tool must be published before you attach it, and publishing the agent pins its version (see versions).
An explicit null detaches a hook. Publish the agent for calls to pick it up.

When each fires

on_enter

The hook runs to completion before the greeting, so the greeting and prompt can read {{userdata.…}} values it just published. Its latency delays the agent’s first word — open the tree with a say if the lookup is slow. After the hook, the agent speaks its greeting; an agent reached by a handoff with no greeting generates an opening line (using the handoff’s instructions) unless the hook already ran generate_reply. If the hook hands off or hangs up, no opening line is spoken.

on_exit

For logging outcomes, posting leads, writing CRM notes. A failure is logged and never affects the caller. On text, what the hook says is saved to the chat (and sent on Telegram or WhatsApp); a chat nobody ends never runs it.

on_user_turn_completed

Runs between the caller finishing and the agent replying — keep it fast. Ending the call or handing off inside it suppresses this agent’s reply (the target answers instead). A hook that fails is logged and the turn continues. With screen share on, the newest frame is already in context when it runs.

Where hooks are refused

All other operations work in hooks. A keypad entry does not fire on_user_turn_completed.

Example: load a CRM record on enter

on_error: "continue" leaves a thinner prompt instead of a failed call when the CRM is down. Tell the prompt to ask rather than guess when a field is blank, and keep fields the lookup might miss out of the greeting (see userdata). For on_user_turn_completed, the tool’s own json_schema must declare user_message as a string parameter, or the tool will not publish.

Next

Operation tree

What a hook tool’s tree can contain.

Userdata

What a hook publishes and who reads it.