Turning it on, briefly
The skill is gated behind CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 on Claude Code 2.1.260 or later. In the desktop app that means one block in ~/.claude/settings.json:
{
"env": {
"CLAUDE_CODE_ENABLE_FUNCTION_HOOKS": "1"
}
}Type / in a session and plugin-authoring is in the list. The full setup, the plugin folder layout, and a tested plugin to copy are in the secret redactor install guide. The background on hooks themselves is in the complete hooks guide.
What the skill is
Inside the 2.1.260 binary the skill describes itself as the way to "write or debug a Claude Code plugin made of function hooks." It is not a code generator bolted on the side; it is an orientation note that loads into the session before Claude writes a plugin, and it tells Claude four things: what a function hook plugin is, where the exact contract for the running build is written down, how to run a plugin under development, and where the engine reports what it refused. Ray Amjad's September 2026 walkthrough shows the effect: one sentence describing a transcript secret redactor produced a working 300-line plugin, and a request for a deployment status row produced a live panel beneath the prompt with a hide button.
The contract the skill hands Claude is short enough to state:
- →A plugin is a folder with a manifest. Its function hooks live in one module named by
hooks/hooks.jsonundermodules, exportingregister(on, options). - →Every hook has the shape
($, e, next).$is the engine interface,eis the event's input as a plain value, andnext(e)continues to the other plugins and then the engine. Returning without callingnextanswers for itself; callingnextwith a changed event rewrites what the rest of the chain sees. - →The module runs in an environment of its own, with no DOM and no Node. Everything outside it is reached through
$. JSX is available withhas the factory. - →The types are the reference.
/plugin-typeswrites them from the running build, and the skill tells Claude not to guess at an event's input or a method on$.
What it unlocks
The events cover tool calls and their descriptions, the prompt as submitted, the system prompt's sections, what the interface draws, the turn's start and completion, the session's start, skills, and subagents. The engine interface adds the verbs. Together they make the following buildable from a description, and several were built on camera in the video or verified by community testers on the proposal thread.
| Capability | Primitive | Example |
|---|---|---|
| Guard a tool | tool.call returning deny | Refuse destructive database commands or force pushes, with the reason sent to the model |
| Rewrite a tool call | tool.call with next and a changed event | Swap npm for pnpm, add a flag, route a fetch through a proxy |
| Answer a tool yourself | tool.call returning result | Serve a cached page instead of refetching; replace the built-in search with a preferred provider |
| Rewrite or drop a prompt | prompt.submit | Redact secrets; add context from a knowledge base; refuse a prompt with a reason |
| Draw in the interface | ui.render with $.ui.resolve and JSX | A deployment status row with stage and elapsed time and a hide button; hidden values revealed on hover in the desktop app |
| Ask the user | $.ui.ask | Offer to split a file that has grown past a thousand lines before editing it; gate a newsletter send behind a confirmation |
| Register a tool the model can call | $.tool.register plus a matched tool.call hook | A tool listed as mcp__<plugin>__<name> that the plugin serves itself |
| Call a model from a hook | $.model.complete, classify, fork | Summarise the finished turn with a small model, then speak it with $.audio.speak |
| Wake a quiet session | session.start plus $.clock.every and $.prompt.submit | An inbox folder watcher that turns dropped text files into prompts, verified by a community proof of concept |
| Remember across sessions | $.store | Counters, caches, and preferences; not secrets, since the store is a file on disk |
| See everything | on("*") | One function that forwards every event to an audit log |
| Show state without a turn | $.ui.status, $.ui.toast, $.ui.log | A pinned status line, a passing notice, a dim transcript line that the model never reads |
Preview, with the rough edges stated
Six prompts to try
Each of these is the whole message. The skill prefers an outcome and a constraint over an implementation. Asking it to interview first, as the video does for the deployment row, produces better plugins for anything with a visual component.
/plugin-authoring Make a plugin that blocks any Bash command which deletes a Supabase project or branch, drops a table, or force pushes without a lease. Deny with a one-line reason the model can act on. Log every deny with $.ui.log.
/plugin-authoring Make a plugin that rewrites every Bash command starting with npm to use pnpm instead, and shows a toast the first time it does so in a session.
/plugin-authoring Make a plugin that caches WebFetch results in $.store for one hour, keyed by URL, and answers the tool call from the cache when a fresh copy exists. Include a way to bypass the cache when the prompt says "refetch".
/plugin-authoring Interview me first, then build a plugin that shows the current Vercel deployment for this repo in a row under the prompt: stage, elapsed time, and a button to hide the row. Keep finished deploys visible for an hour.
/plugin-authoring Make a plugin that asks me with $.ui.ask whether to split a file into smaller modules whenever an Edit or Write targets a file longer than 1,000 lines, and passes the edit through untouched if I say no.
/plugin-authoring On turn.complete, send the turn's answer to a Haiku model for a two sentence summary and speak it with $.audio.speak. Skip turns shorter than 200 characters.
The video's closing suggestion is the one with the most leverage: point the skill at an existing CLAUDE.md and ask which of its rules could become hooks. A rule that lives in a hook no longer depends on the model's attention.
The working loop
- Describe the outcome with
/plugin-authoring. Claude reads the skill, runs/plugin-typesif the declarations are stale, and writes the folder. - Validate with the bundled binary:
claude plugin validate <folder> --json. The notes list what the module hooks and which$calls it makes, which is the quickest check that the engine sees what was meant. - Load with
/reload-pluginsin the session, orclaude --plugin-dir <folder>in a terminal, where saving a file reloads the module. - Read the debug log when nothing seems to happen. Anthropic's note is blunt that a plugin that seems to do nothing has usually been told why there: a module it did not load, a hook that threw or overran its budget, a drawing that did not validate.
- Share the folder through a git repository or a private marketplace once it holds. Older builds ignore the
moduleskey, so the rest of the plugin still loads for teammates who have not turned the preview on.
FAQ
Why is /plugin-authoring not in my slash command list?+
It is gated behind the function hooks preview. Set CLAUDE_CODE_ENABLE_FUNCTION_HOOKS to 1, most simply through the env key in the user settings file, and the skill appears in the slash command list. Claude Code 2.1.260 or later is required.
Does the skill write plugins for the terminal or the desktop app?+
Both. The plugin runs inside the Claude Code binary, which the terminal and the desktop app share. Drawing hooks receive a surface field that says whether the terminal or the desktop is rendering, and the element tables differ per surface, so a plugin that draws should check which one it is on.
Can a plugin the skill writes be shared with a team?+
Yes. A plugin is a folder with a manifest, and Anthropic's plugin documentation covers distributing plugins through a git repository or a private marketplace. A team member needs the same preview flag set to load the function hook module; older builds skip the modules key and load the rest of the plugin.
Sources
- The
plugin-authoringskill and the/plugin-typesdeclarations shipped inside Claude Code 2.1.260 - Alice Poteat, Function Hooks - make plugins 10x more powerful, anthropics/claude-code issue #91870, September 3, 2026, and the community test reports in its thread
- Anthropic, Create plugins and Plugins reference (Claude Code documentation)
- Anthropic, Hooks reference (Claude Code documentation)
- cc-function-hooks-poc, a community proof of concept on Claude Code 2.1.261
- Ray Amjad, Anthropic Just Dropped the Biggest Claude Code Update Yet, YouTube, September 2026

