Plugins can install code that intercepts tool calls and repaints parts of the terminal interface.
A full plugin hook API that can substitute terminal rendering is present; nothing overrides anything unless a loaded module declares a handler.
What's wrong with this entry?
A plugin can load a hook module that receives a $ object exposing event chains and host capabilities, letting it intercept tool calls, prompts and agent turns, and substitute the props Claude Code uses to draw its own interface. Message rendering was rewritten so that named draw sites can be targeted individually, and modules run inside their own sandboxed globals so host objects and host stack frames never reach plugin code. Nothing switches this on or off, and a site is only overridden when a loaded module declares a handler for it, so a stock install behaves and renders exactly as before.
- Event chains available on
$aretool.call,tool.describe,prompt.submit,prompt.section,agent.spawn,turn.start,turn.step,turn.completeandui.render, withPreToolUsealso carried by the same dispatch layer. - Capabilities on
$aremodel.complete,mcp.call,audio.playandaudio.speak, thesession.*group,tool.listandtool.register,ui.toast,ui.status,ui.logandui.notice,fs.readFile,fs.writeFile,fs.listDir,fs.existsandfs.stat,store.get,store.set,store.deleteandstore.keys, andhttp.fetch. - Each capability enforces its own policy check rather than deferring to one shared permission switch.
- Every call runs its handler chain and fails if nothing at the bottom of the chain terminates it, reporting
no core at the bottom of the chain (the site did not install one and the call supplied none). - The draw sites a
ui.renderhandler can target areUserMessage,AssistantMessage,ToolUse,ToolResult,TurnDuration,Spinner,InfoNotice,SessionModeandAskUserQuestion. - Modules execute against a replacement set of globals: AbortController and AbortSignal, TextEncoder and TextDecoder limited to UTF-8, URL and URLSearchParams, atob and btoa, a hand-written structuredClone,
crypto.subtle.digest,randomUUIDandgetRandomValues,performance.now, and classic-runtime JSX helpers that emitJSX element <markers. - Errors thrown by the host are re-thrown as errors belonging to the plugin's own environment, with stack frames outside the plugin directory trimmed away.
- The hook runtime ships as a bundled worker whose path now appears in build metadata alongside version, build time and git sha.
- A module that fails to load is reported as
plugin_function_hooks_loadwith a declaration-failed reason.
/$bunfs/root/src/plugins/functionHooks/hooks-worker/hooks-worker.js, no core at the bottom of the chain (the site did not install one and the call supplied none), JSX element <
Strings lifted out of the shipped bundle, so the claim above can be checked against them.