Skip to main content

Plugin and Engine

$.plugin names the plugin. plugin.register lets a mod refuse another module. engine.create builds $ and lets a mod add a noun. A plugin ships the types of its noun in the .d.ts file that types names in plugin.json.

Return { refuse } from plugin.register to keep a module out. The types file is named in plugin.json.

Official page: Mods Reference. Source: the program (types-2.1.304.d.ts).

Example​

This hook keeps user mods out.

on('plugin.register', { tier: 'user' }, () => ({ refuse: 'managed only' }))

This engine.create hook adds a noun.

on('engine.create', async ($, e, next) => {
const built = await next(e)
return { ...built, voice: { say: async (text) => {} } }
})

Members of the Plugin Noun​

ItemStatusWhat it doesHow it worksWhere it can be used
$.plugin.nameDocumentedThe name from plugin.json. Debug-log and $.ui.log lines carry it.Type string.Anywhere in the module (a plain value).
$.plugin.rootDocumentedThe plugin's directory (the one holding plugin.json), absolute.Type string.Anywhere in the module (a plain value).

Events​

ItemStatusWhat it doesHow it worksWhere it can be used
plugin.registerDocumentedFires once for each hooks module about to join the chain, at load and at reload. Core allows by default.Input PluginRegisterInput. Result PluginRegisterResult: { allow: true } or { refuse }. A refused module never joins. A judge that fails is skipped and the module joins.Hook via on('plugin.register', ...).
engine.createDocumentedRuns while $ is built, once per load or reload of this plugin, before any other hook of it. next(e) resolves to $ built so far.Input EngineCreateInput. Result EngineCreateResult. A step may add nouns to $. Outside user it may also withhold nouns. It fails and the plugin unloads if it replaces another plugin's noun.Hook via on('engine.create', ...).

Types​

ItemStatusWhat it is forShape and limits
CoreEngineInterfaceDocumentedThe plugin's identity (plugin) and the nouns core adds to $ as the innermost step of the engine.create fold.A finished $ has every core noun that no outer step withheld and every noun that plugins added.
EngineCreateInputDocumentedThe input of engine.create.Field plugins: the modules this fold builds, first outermost (managed plugins first, so an organization plugin's withholding wins). At a first load it is all plugins. At a reload it is this plugin only. Write the hook after next: const built = await next(e).
EngineCreateResultDocumentedWhat an engine.create hook returns: $ as built so far with this plugin's nouns added, less any it withheld.EngineInterface plus a record of nouns. Every declared noun is optional here.
EngineInterfaceDocumented$, the first parameter of every hook. Frozen.A plugin adds a noun by declaration merging: declare module "claude-code" { interface EngineInterface { voice: Voice } }.
EngineInterfaceBuiltDocumentedWhat next(e) resolves to at engine.create: $ as the steps beneath built it.Open to nouns no declaration names yet. A withheld noun is a stub on it.
NoEngineInterfaceDocumentedWhat an engine.create hook gets as $: nothing.Every property reads as never, so $.model inside the hook is a compile error.
INSTRUCTION_FILE_KINDSDocumentedEvery tier an instruction file can belong to.["managed", "user", "project", "local", "memory"]
InstructionFileDocumentedOne instruction file behind the claudeMd block.path (absolute), kind, content (comments and front matter already stripped), and parent? (the file whose @ import brought this one).
InstructionFileKindDocumentedThe tier of an instruction file.One of the values of INSTRUCTION_FILE_KINDS.
PluginOptionsDocumentedA plugin's options as register(on, options) gets them: the values of its userConfig fields, defaults filled in.A read-only record of string, number, boolean, or string list. Stored in pluginConfigs[<plugin>].options of settings.
PluginRegisterInputDocumentedThe input of plugin.register: one hooks module about to load. Every field is pinned.name, tier (never core), root, version?, provenance (<name>@<marketplace>, <name>@inline for --plugin-dir, <name>@builtin), and uses.
PluginRegisterResultDocumentedWhat a plugin.register hook returns.{ allow: true } lets the module load. { refuse: reason } stops it. The debug log names the plugin and the reason.
PluginRegisterUsesDocumentedWhat a hooks module uses, as the host scanned its source. These are the lists claude plugin validate prints.events (the patterns of the on calls), calls (noun.method), env? (names in $.env.get and $.env.set), state? ({ plugin, key }). A module that spells on, $, $.env, or a $.state reference in a non-literal way does not load.
PluginStampDocumentedWhose element: the plugin whose hook drew it, stamped by the runtime.Field plugin. Two plugins under one hover.scope string never share a group.
PluginStateDocumentedThe named values plugins keep in the session ($.state), by plugin name and key. Empty by default.A plugin declares its keys by declaration merging. Example: interface PluginState { swarm: { workers: Worker[] } }.