All 46 extension events
These are the complete supplied event names. Numbers follow the supplied inventory and make omissions easy to check.
Unless stated otherwise, a notification handler’s returned value does not control the operation.
Resources and session lifecycle
| No. | Event | Payload/use | Supported result |
|---|---|---|---|
| 1 | resources_discover | cwd, startup/reload reason; contribute resource paths | skillPaths, promptPaths, themePaths; requires host dispatch/consumption |
| 2 | session_start | Initial initialized session load | Notification |
| 3 | session_before_switch | Reason new, resume or fork; optional target file | { cancel } |
| 4 | session_switch | Completed switch; reason and previous file | Notification; reconstruct current state |
| 5 | session_before_branch | Selected user-message entry ID | { cancel, skipConversationRestore } |
| 6 | session_branch | Branch completed; previous file | Notification |
| 7 | session_before_compact | Preparation, branch entries, public instructions, signal | { cancel, compaction } |
| 8 | session.compacting | Session ID and messages about to be summarized | { context, prompt, preserveData } |
| 9 | session_compact | Compaction entry and fromExtension | Notification |
| 10 | session_shutdown | Teardown | Cleanup; concurrent bounded handlers |
| 11 | session_before_tree | Tree preparation and signal | { cancel, summary }; summary used only when requested |
| 12 | session_tree | Old/new leaf, optional summary entry and origin | Notification |
skipConversationRestore means the branch proceeds while in-memory conversation restoration is skipped. It is not cancellation.
For the cancelable pre-events, cancellation short-circuits. Otherwise the current generic runner retains the last returned result rather than deep-merging every handler’s object. session.compacting likewise uses the last returned result object; coordinate cooperating extensions.
Seed Desk reconstructs after lifecycle events. Review Desk invalidates pending authority before navigation.
Prompt and provider boundaries
| No. | Event | Payload/use | Supported result |
|---|---|---|---|
| 13 | context | Messages before each model call | Replacement { messages }, chained |
| 14 | before_provider_request | Provider-specific logical payload; request model in context | Return the replacement payload directly |
| 15 | provider_request | Frozen event with final payloadJson | Observation only |
| 16 | after_provider_response | Status, headers, request ID, metadata before stream consumption | Observation only |
| 17 | before_agent_start | Submitted prompt, images, current prompt blocks | Custom message and/or replacement systemPrompt blocks |
| 39 | input | Input text, images and source tag | { handled, text, images }; transforms chain, handled stops |
before_provider_request replacements chain in load order. Provider-specific payloads are not one universal HTTP schema.
provider_request is the final logical JSON after those transforms, not exact transport bytes or headers. Returned values cannot change it. Extension observer errors are isolated and are not a reliable dispatch veto.
An embedding that requires a fail-closed final-payload check uses the awaited SDK onProviderRequest callback; rejection there stops dispatch before extension observers.
The supplied guide identifies devin-agent as a provider that does not fire the request hook. Provider implementation coverage must be checked when relying on these boundaries; no live provider was exercised for the workbook examples.
after_provider_response occurs before the response stream has yielded final assistant usage. Use a completed assistant message, commonly at turn_end, for actual turn token/cost accounting.
input source tags are interactive, rpc and extension. The runner supports all three labels, but that does not mean every host path emits the event. The supplied RPC/ACP prompt implementations do not themselves call emitInput(). Do not use it as a universal inbound-policy gateway.
In typed interactive input flow, naming a session from input can precede the normal first-message title check. That does not imply every initial CLI prompt takes the same path.
Agent, turn and message notifications
| No. | Event | Payload/use | Supported result |
|---|---|---|---|
| 18 | agent_start | Agent-loop start | Notification |
| 19 | agent_end | Messages and optional willContinue | Notification only |
| 20 | session_stop | Main-session settle context, turn/session IDs, last assistant, stop_hook_active, signal | { continue: true, additionalContext } or { decision: "block", reason } |
| 21 | turn_start | Turn index and timestamp | Notification |
| 22 | turn_end | Completed turn message and tool results | Notification; inspect completed usage here |
| 23 | message_start | A message begins | Notification |
| 24 | message_update | Assistant message and streaming event/delta | Notification; keep handlers lightweight |
| 25 | message_end | Detached completed-message snapshot | Notification, not a rewrite hook |
A turn is one assistant response plus its associated tool results. A run can contain several turns and maintenance continuations.
session_stop:
- is awaited at eligible main-session settle;
- does not run for task/subagent sessions;
- requires nonempty continuation context/reason;
- is capped at eight consecutive continuations;
- is deferred when automatic continuation or owner-scoped pending async work means the run is not truly finished;
- can be cancelled through its signal.
Use stop_hook_active to avoid endlessly requesting the same extra pass.
Streaming notifications can be queued/detached relative to other host work. Do not base an authorization protocol on an assumed universal arrival order of every message and UI frame.
Tool execution and approval
| No. | Event | Payload/use | Supported result |
|---|---|---|---|
| 26 | tool_execution_start | Call ID, name, arguments, optional intent | Observation |
| 27 | tool_execution_update | Call identity, arguments and partial result | Observation |
| 28 | tool_execution_end | Call identity, result and error state | Observation |
| 40 | tool_approval_requested | Session/call/tool IDs, optional reason, approval mode | Observation |
| 41 | tool_approval_resolved | Session/call/tool IDs, approved boolean, optional reason | Observation |
| 42 | tool_call | Call identity and normalized input before execution | { block, reason, input } |
| 43 | tool_result | Effective input, content, details and error state | Patch { content, details, isError }, chained |
A tool_execution_start event does not prove the side effect happened; approval may still be pending.
Approval events are emitted when the wrapper reaches a required approval gate and relevant handlers are present. They are not a way to approve by returning a value.
Already-denied calls can short-circuit before tool_call. Schema failures, pre-execution blocks and approval denials do not necessarily traverse the post-execution tool_result path.
tool_call errors/timeouts fail closed. tool_result middleware can change what is reported, not reverse external effects.
Reliability and domain reminders
| No. | Event | Payload/use |
|---|---|---|
| 29 | auto_compaction_start | Reason: threshold, overflow, idle or incomplete; selected action |
| 30 | auto_compaction_end | Action, optional result, aborted/willRetry, optional error/skipped |
| 31 | auto_retry_start | Attempt, maximum attempts, delay, error message and optional error ID |
| 32 | auto_retry_end | Success, attempt, final error and optional retry-error presentation updates |
| 33 | retry_fallback_applied | From/to model selectors and configured role |
| 34 | retry_fallback_succeeded | Fallback model and role that actually succeeded |
| 35 | ttsr_triggered | Rules whose stream matching interrupted generation |
| 36 | todo_reminder | Unfinished todos and reminder attempt information |
| 37 | goal_updated | Current goal or null and optional goal-mode state |
| 38 | credential_disabled | Provider and truncated diagnostic cause for automatic credential soft-disable |
These are observations, not return-value control hooks.
Compaction actions include context-full, remote, handoff, shake and snapcompact in the supplied event type. A skipped or aborted compaction is not a successful summary.
retry_fallback_applied means a candidate was selected. retry_fallback_succeeded distinguishes actual success.
credential_disabled is not fired for every user logout/removal. Startup events can be buffered until runtime initialization; the runner’s buffer is bounded at 32.
Human execution and MCP notifications
| No. | Event | Payload/use | Supported result |
|---|---|---|---|
| 44 | user_bash | Command, cwd and whether !! excludes output from model context | Full replacement { result } |
| 45 | user_python | Code, cwd and whether $$ excludes output from model context | Full replacement { result } |
| 46 | mcp_notification | Raw server name, method and unknown params | Notification |
user_bash concerns human !/!! execution, not every model bash tool or arbitrary pi.exec() call. user_python concerns the corresponding $/$$ user-code path.
The first returned user-execution result replaces default execution. Throwing is not a supported blocking result.
MCP notifications arrive after the manager’s known-method processing. Buffering is bounded at 100 with drop-oldest behavior at the supplied startup boundaries. Validate payloads and do not mistake notifications for durable authority.
Source, snapshot 2026-08-29: packages/coding-agent/src/extensibility/extensions/types.ts, all on overloads; packages/coding-agent/src/extensibility/shared-events.ts; runner.ts; wrapper.ts; packages/coding-agent/src/session/agent-session.ts; packages/coding-agent/src/session/bash-runner.ts; packages/coding-agent/src/modes/rpc/rpc-mode.ts.
Extensions inside those boundaries · Source chapter: extensions/all-46-extension-events. Original evidence remains scoped to its recorded snapshot.