Skip to content

Mods reference

Lookup tables for Claude Code mods - files, the on() function, every event, mods API namespaces, render sites, elements, limits, settings and commands.

This is the lookup page for mods: files, the hook function, events, API namespaces, render sites, elements, limits and settings, current as of Claude Code v2.1.290 for the CLI and Desktop app. For explanations and worked examples, follow the links to the guide pages.

Note: The authoritative reference is the TypeScript declarations Claude Code writes into your mod's .claude-plugin/types/ folder on each load (see /docs/plugins/mods/create). A copy lives at mods/types/claude-code.d.ts in the anthropics/claude-code GitHub repository, but may lag your installed version. When anything disagrees, trust your local types.

Files

FileRequiredContents
.claude-plugin/plugin.jsonYesStandard plugin manifest. No mod-specific required fields
hooks/hooks.jsonYesmodules: an array with one path (relative to this file) to the hooks module, e.g. "modules": ["./register.js"]. May also contain settings hooks under hooks
Hooks module, e.g. hooks/register.jsYesES module exporting register(on, options). Extensions: .js, .mjs, .cjs, .jsx, .ts, .mts, .cts, .tsx
Type declarations, e.g. types/index.d.ts, named by types in the manifestWhen using $.state or adding an API namespaceDeclares PluginState values and any added namespace
*.test.ts, *.test.tsxNoTests for claude plugin test

register receives on and options. options carries the plugin's userConfig values with defaults applied.

The on function

on(eventName, [matcher], hook)   // returns a registration with .catch(handler)

The optional matcher filters on event fields; see /docs/plugins/mods/events. .catch sets an error handler for that one hook.

Hook argumentMeaning
$The mods API. Always write calls in full, e.g. $.fs.read('notes.md')
eEvent input, deeply frozen. Pass a modified copy to next to change it
next(e)Calls later hooks then Claude Code's behaviour; resolves to the result
next.signalAbortSignal fired when the event is abandoned
next.origin{ plugin, tier } of whoever fired the event. Claude Code is { plugin: 'engine', tier: 'core' }. Mod tiers: prepend, user, append, builtin
next.budgetms (total time limit) and remainingMs
next.to(e, tier)Skip ahead to append, builtin or core. Only for mods in prependPlugins or appendPlugins
next.error, next.calledIn .catch only. next.error.kind is throw or timeout, next.error.message the text; next.called is true if the failed hook had called next

Events

Hooks on turn.step and process.spawn are async generators; all others are async functions. In the "Can return" column, next(e) means pass through, next({ ...e, x }) means pass a modified copy, and a bare object means answer without calling next.

Tools

EventFiresCan return
tool.callA tool is about to runnext(e), { deny: reason }, { result }
tool.checkClaude Code decides whether a call may run, after tool.call and PreToolUse hooks. next(e) resolves to the decision so far{ decision }: allow, ask or deny
tool.describeOnce per tool, when its description is first sent{ description }, optionally isDeferred: true (behind tool search) or false (load upfront)

Prompts and what Claude reads

EventFiresCan return
prompt.submitA prompt is submittednext({ ...e, text }), next({ ...e, context }), { drop: reason }
prompt.fill, prompt.suggestText is about to enter the prompt box as a draft or dim suggestionnext(e) with changed text
prompt.editThe user edits the prompt boxnext(e)
prompt.composeA system prompt is rendered{ sections }: ordered { id, text, scope }
prompt.sectionOnce per named system-prompt section (e.name matches the id){ text } or { text: null } to omit
prompt.contextOnce per conversation, for context sent with the first message{ blocks }
prompt.attachmentClaude Code adds its own message for Claude, such as a reminder. e.type is the kind; e.detail holds source facts for declared kinds{ text } or { text: null }
prompt.mentionA file @-mentioned in a prompt is about to be read (v2.1.290+)next({ ...e, path }) or { deny: reason }
skill.promptA skill's text is expanded{ text }
attribution.textCommit or PR attribution text is composed{ text }

Commands and configuration

EventFiresCan return
command.runA command is about to run{ text }, {}, next(e)
command.describeOnce per command for the list{ description, argumentHint, isHidden }
config.setA /config row is about to changenext({ ...e, value }), { deny: reason }
config.describeOnce per /config row{ label, description, isHidden }

Turns

EventFiresCan return
turn.startA turn beginsnext(e)
turn.stepOne model request is about to be sentyield* next(e), next({ ...e, model }), next({ ...e, effort })
turn.completeA turn endednext(e), or { text } for a line under the answer

Session

EventFiresCan return
session.startOnce per loaded mod before the first prompt, and after a reload of that mod. Not after /clear, /resume or /branchnext(e)
session.endSession ends, or /clear, /resume, /branch runs. e.reason: clear, resume, logout, prompt_input_exit, other (/branch reports resume)next(e)
session.compactConversation about to be compacted{ skip: reason }
session.receiveA message arrives from another agent or session{ consumed: reason }
session.sendA message is about to go to another agent or session{ isDelivered: false, reason }
session.appendOnce per stored conversation row (prompt, response block, tool result, notice)next({ ...e, message }) to rewrite content
session.attach, session.detachAnother app connects or disconnectsnext(e)
session.measureAfter each turn, and when a plan limit's percentage changesnext(e)

Subagents

EventFiresCan return
agent.offerA subagent type is offered to Claude{ isOffered: false }
agent.spawnA subagent or agent-team teammate is about to start (e.isTeammate for teammates)next({ ...e, model }), { deny: reason }

Interface

EventFires
ui.renderA render site is about to be drawn
ui.resolveOnce per app, render site and mod when mods load; produces the element table $.ui.resolve(e) reads
ui.press, ui.input, ui.selectA mod-drawn Button, Input or Select is used
ui.focus, ui.scrollFocus or scroll position of a pane or the band is about to change
ui.closeA pane is about to close. e.id is the pane; e.origin.kind is plugin, person or unload
ui.messageA Client element posts data to its mod
ui.faultA Client element failed to load, draw or run. e.phase: load, render, run; e.reason: message (v2.1.289+)

Other mods

EventFiresCan return
plugin.registerA hooks module is about to load. e.uses lists its events, API calls (without $., e.g. fs.read), env vars and state, as validate prints them{ refuse: reason }
engine.createThe mods API is being built for a modA modified API (to add a namespace; non-user tiers can also withhold one)

Telemetry

EventFiresCan return
telemetry.log, telemetry.markA telemetry record is about to be logged, or a feature use markednext(e), { deny: reason }

In an installed mod, telemetry hooks must use the filter { to: 'collector' }, as in on('telemetry.log', { to: 'collector' }, hook), or validate fails. The * wildcard does not match these events.

Settings hook events and API calls as events

  • Every settings hook event is available as classic.<Event>, for example classic.Stop or classic.PostToolUse. e is that hook's stdin JSON.
  • Every mods API method is also an event named <namespace>.<method>, such as fs.read, model.complete or ui.open. A hook there intercepts calls from mods running after it and can return next(e), { deny: reason } or { value }.

Mods API namespaces

NamespaceMethods and notes
$.pluginname, root
$.uiresolve, invalidate, open, close, panes, focus, scroll, toast, status, log, notice, ask, copy, selection, blit
$.commandregister, run, list
$.toolregister, call, check, list
$.agentregister, spawn, list
$.modelcomplete, fork, classify
$.promptsubmit, read, fill, suggest, compose. submit({ text }) is introduced to Claude as coming from your mod; add asUser: true to send it as the user's words
$.turnabort
$.sessionmessages, cwd, root, model, turns, id, repo, surfaces, usage, version, compact, send, append, authorize. usage() returns { startedAt, context, rateLimits, cost } with context holding tokens, window, percent and rateLimits a list of { kind, percentUsed, resetsAt }
$.configlist, set
$.settingsread
$.envget, set
$.fsread, write, list, exists, stat, ancestors. write is not atomic; use $.store for data several sessions change
$.storeget, set, delete, keys. Key-value store shared by every session on the machine
$.stateget, set, plus helpers atom, read, update, derive, memberOf imported from claude-code
$.clocknow, sleep, after, every
$.httpfetch
$.processrun, spawn
$.mcpcall, connect (connect(server) only for servers your own manifest lists)
$.audioplay, speak
$.telemetrylog, mark (only sent when Claude Code or a built-in mod calls it)

Render sites

Each site is a value of e.component in a ui.render hook. e.surface is terminal or desktop.

Sitee.propse.requestIdDrawn on
Panetitle, isFocused, bodyColumns, placement, scroll, viewThe pane's idTerminal, Desktop
AbovePrompthasSurvey, isWorking, maxRows, bodyColumns, scroll, viewSingle instanceTerminal, Desktop
UserMessagetext, origin, isExpanded, and task or from by originMessage idTerminal, Desktop
AssistantMessageThe reply's textMessage idTerminal, Desktop
ToolUse, ToolResult, ToolGroupTool name, input, resultTool call idTerminal, Desktop
CommandOutputcommand, textMessage idTerminal, Desktop
AskUserQuestionQuestion and optionsTool call idTerminal, Desktop
ToolProgresskindTool call idTerminal
Spinnerword, message, suffix, modeAgent idTerminal, Desktop
TurnDurationword, durationMsMessage idTerminal
InfoNoticetext, commandMessage idTerminal
SessionModemodesSingle instanceTerminal, Desktop
PromptHintisDraft, isWorking, hintSingle instanceTerminal, Desktop

e.viewport has columns, rows and isFullscreen, and is absent until the window is measured. Its rows is the whole window, not your pane.

Sizing your tree:

  • Width of a pane or the band: e.props.bodyColumns.
  • Height of a docked pane (placement: 'dock'): e.props.scroll.bodyRows.
  • Height of an inline pane above the prompt (placement: 'inline'): the pane grows with your tree up to bodyRows. Ask for a different limit with rows on $.ui.open.

Taller trees scroll as a whole.

Elements

Get elements with $.ui.resolve(e). Screenshots and samples are in /docs/plugins/mods/gallery.

ElementMain propsTerminalDesktop
Boxkey, flex layout, gap, padding, margin, width, height, borderStyle, backgroundColor, position, hoverYesYes
Textcolor, backgroundColor, bold, italic, underline, dimColor, inverse, wrapYesYes
Buttonkey, label, onPress, hotkey, plain, dimColor, autoFocus, actionYesYes
Linkhref, labelYesYes
Codesource, language, path, startLine, format, wrapYesYes
Markdowntext, key, dimColor, onLinkPress, pressableLinksYesYes
Inputkey, label, placeholder, value, submitLabel, onSubmit, onInput, autoFocusYesYes
Selectkey, label, options, value, onSelect, autoFocusYesYes
SvgAn SVG document up to 131,072 charactersYes
Clientmodule, keyYesYes
Rasterkey, columns (up to 512), rows (up to 256), cellsYes
ImagePNG or RGBA bytes up to 2 MiB, or a file path; columns and rows up to 255; altYes

Extra Button rules:

  • action names one of Claude Code's keybinding actions; the user's binding for it presses the button when that binding is a chord or modified key.
  • A digit hotkey on a button in the band also fires when the user types that digit alone into an empty prompt and pauses.
  • If two buttons in one drawing share a hotkey, the later one wins.
  • autoFocus accepts only true on any control; omit it otherwise.

Box border styles

borderStyleTerminal drawsTop edge
'single'Thin lines, square corners┌──┐
'double'Double lines╔══╗
'round'Thin lines, rounded corners╭──╮
'bold'Thick lines┏━━┓
'singleDouble'Thin top and bottom, double sides╓──╖
'doubleSingle'Double top and bottom, thin sides╒══╕
'classic'ASCII +, -, |+--+
'arrow'Arrows pointing inward↘↓↓↙
'dashed'Dashed lines, blank corners╌╌
'quote'A ▎ bar on the left onlyBlank

Any other value (a common slip is 'rounded') draws no border.

Limits

Hooks exceeding a time limit are skipped; calls exceeding a size limit are rejected.

LimitValue
A hook's own run time per event (excludes time in next and API calls other than $.clock.sleep)10 s; 50 ms for prompt.edit
.catch handler1 s
All session.end hooks togetherThe SessionEnd hook budget, 1.5 s by default, counted after settings SessionEnd hooks finish
$.process.run timeout30 s default, 10 min max
$.model.complete maxTokens1024 default, up to 64,000 or the model's output limit
$.fs.read, $.fs.write4 MiB per file
Text drawn per treeFirst 100,000 characters
$.store4 MiB of JSON in total
$.session.messages()Newest 4,096 entries
$.ui.invalidate('ui.render') redraws10 per second; 30 in the terminal for the visible pane, expanded band and the hint line. Extra calls coalesce
$.ui.toastShown 4 s unless { timeoutMs } given
A pane opened without user actionPlaced from 144 terminal columns, 110 once the user has opened it themselves
Command, tool, subagent type and pane namesLetters, digits, _, -; up to 64 characters
One claude plugin test test5 s unless the test sets timeoutMs

Settings and environment variables

NameRead fromEffect
CLAUDE_CODE_PLUGIN_DIRSEnvironment, or env in ~/.claude/settings.jsonDirectories to load as --plugin-dir would. Absolute paths separated by : (; on Windows)
CLAUDE_CODE_PLUGIN_DIR_WATCHEnvironment1 makes long-running non-interactive sessions reload --plugin-dir mods on save
prependPlugins, appendPluginsManaged settings (user settings only on machines with no managed settings, for users not signed in on Team or Enterprise)Plugin ids such as acme-guard@acme-tools. Prepended mods run before every user mod, appended after, in listed order
allowManagedModsOnlyManaged, as an option on the built-in guardOnly organisation and built-in mods run their hooks. Users' settings hooks continue
allowModsToOverrideDenyRulesManaged, as an option on the built-in guardLets a user-installed mod approve a call a deny rule refuses
allowManagedHooksOnlyManagedBlocks hooks and installed mods that are not the organisation's
disableAllHooksAny settings fileIn managed settings, nothing from installed plugins runs. In your own settings, organisation-managed items keep running
disableSideloadFlagsManagedRejects --plugin-dir and --plugin-url at startup
pluginConfigsUser or manageduserConfig values for a mod, keyed by plugin id (acme-guard@acme-tools) or name@inline for --plugin-dir mods

sec-default@builtin (shown as cc-plugin-sec-default) is the built-in guard. It loads ahead of user-installed mods on machines with managed settings or for users signed in on Team or Enterprise. If managed prependPlugins is set, the guard loads only if that list names it, at that position. Its source is in mods/sec-default in the anthropics/claude-code repository.

Commands

CommandDoes
/pluginShows a line such as 1 mod active · edit-meter when a non-built-in mod has loaded
claude plugin validate <dir>Reports errors, handled events and API calls. --strict treats warnings as errors; --json prints machine-readable output
claude plugin test [dir]Runs every .test.ts/.test.tsx under the directory (default: current). Exit 1 on failure
claude --plugin-dir <dir>Loads a plugin for one session and hot-reloads the module on save. Repeatable
/reload-pluginsReloads plugins now