Source Intelligence

DisclaimerUnofficial, and not affiliated with Anthropic. Nearly all of this is read straight out of what ships: npm bundles, captured prompts, published docs. Anthropic's own notes go in verbatim, marked as theirs. The rest is my reading, and every entry carries the strings behind it. If one looks wrong, vote it down and say why.

All of v2.1.242 Home All releases olderv2.1.241 v2.1.243newer
Claude Code v2.1.242

Plugins can ship JavaScript hook modules that run in a shared Bun worker, built but switched off

Not switched on
Useful3 Signal5
Plugins Notable not in their notes

Plugins could ship JavaScript hook modules running in a worker, but loading is refused here.

The whole worker-based plugin hook module runtime is built; tengu_plugin_hooks_modules defaults false and the loader says so.

CLAUDE_CODE_HOOKS_SAME_THREAD
What

A plugin's hooks/hooks.json may now name a JavaScript module that registers hooks in code rather than as shell commands, and that module runs in a background worker thread shared by all plugins, with crash containment, a heartbeat and a broad capability object passed in. Nothing loads in this build: the loader refuses with a message saying the rollout flag is off, the flag tengu_plugin_hooks_modules has a built-in value of false, and no plugin bundled with Claude Code declares a hooks module, so even a server-side switch would only enable third-party plugins.

Details
  • The modules array in hooks.json names exactly one module per plugin, resolved relative to hooks.json and exporting a register function; a second entry is refused.
  • The worker's entry point is baked into the binary as a build constant pointing at an internal hooks worker script, falling back to a relative hooks-worker.ts path when that constant is missing.
  • Host and worker speak a framed protocol covering load, dispatch, build, call, ping and flush, and the host heartbeats the worker.
  • A hook that spins without yielding, or a plugin that repeatedly ignores its abort signal, causes the worker to be respawned and that plugin to be unloaded; repeated crashes that cannot be pinned on one plugin switch hook modules off for the rest of the session.
  • Setting the environment variable CLAUDE_CODE_HOOKS_SAME_THREAD runs hooks in the main process instead of the worker.
  • Each module receives a $ object of named capabilities: $.ui with ask, toast, status, notice, log and resolve; $.model with complete plus classify, which builds its own classifier prompt and maps the reply back to a label; $.store with get, set, delete and keys under a character limit; $.clock with sleep, after and every returning cancellable timers; $.fs with readFile, writeFile, listDir, exists and stat; plus $.http.fetch, $.mcp.call, $.tool.register/list/call, $.agent.spawn, $.prompt.submit and $.audio.play/speak.
  • Arguments are validated per capability and errors name the offending plugin; tool schemas and interface text have size limits, and a hook can claim work whose promise nobody is waiting on.
  • Telemetry is already wired for plugin_function_hooks_load, plugin_function_hooks_worker and plugin_function_hooks_register_tool, with respawns recorded on the worker event and a plugin unloaded by a crash recorded on the load event as "crashed_worker".
  • The same flag also reveals a plugin-types row in the doctor output and in the plugin dialog listing.
Evidence

tengu_plugin_hooks_modules, hooks worker spawned (one for every plugin), hooks.json modules names one hooks module per plugin; a second entry is refused, $.audio.play with loop needs options.signal: the clip repeats until it aborts

Strings lifted out of the shipped bundle, so the claim above can be checked against them.

See this entry in the whole of v2.1.242 →