Technical Documentation: anthropics/claude-code
ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference
Overview (`README.md`)
Claude Code
[
Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows -- all through natural language commands. Use it in your terminal, IDE, or tag @claude on Github.
Learn more in the official documentation.
Get started
[!NOTE]
Installation via npm is deprecated. Use one of the recommended methods below.
For more installation options, uninstall steps, and troubleshooting, see the setup documentation.
Install Claude Code:
MacOS/Linux (Recommended):
bashcurl -fsSL https://claude.ai/install.sh | bashHomebrew (MacOS/Linux):
bashbrew install --cask claude-codeWindows (Recommended):
powershellirm https://claude.ai/install.ps1 | iexWinGet (Windows):
powershellwinget install Anthropic.ClaudeCodeNPM (Deprecated):
bashnpm install @anthropic-ai/claude-codeNavigate to your project directory and run
claude.
Plugins
This repository includes several Claude Code plugins that extend functionality with custom commands and agents. See the plugins directory for detailed documentation on available plugins.
Reporting Bugs
We welcome your feedback. Use the /bug command to report issues directly within Claude Code, or file a GitHub issue.
Connect on Discord
Join the Claude Developers Discord to connect with other developers using Claude Code. Get help, share feedback, and discuss your projects with the community.
Data collection, usage, and retention
When you use Claude Code, we collect feedback, which includes usage data (such as code acceptance or rejections), associated conversation data, and user feedback submitted via the /bug command.
How we use your data
See our data usage policies.
Privacy safeguards
We have implemented several safeguards to protect your data, including limited retention periods for sensitive information, restricted access to user session data, and clear policies against using feedback for model training.
For full details, please review our Commercial Terms of Service and Privacy Policy.
Overview (`mods/README.md`)
Mods
A mod is a Claude Code plugin whose behaviour lives in a hooks module: oneregister(on, options) entry that hooks the engine's events as functions($, e, next). These four ship inside Claude Code; this folder is their
source, published as it is built into the binary.
| Mod | What it does | Seated |
|---|---|---|
sec-default |
Keeps an organization's classic hooks, prompt content, managed settings, tool policy, permission rules and pinned environment out of reach of the plugins a person installs; adds no policy of its own. | Outermost, on a machine with managed settings or a managed-mcp.json, or for a Team or Enterprise organization, and from then on for the session, unless managed prependPlugins says otherwise |
diff |
/diff: the session's uncommitted changes in a pane beside the transcript, file by file with their hunks, refreshed as Claude edits files and runs commands. |
Built in |
telemetry |
Hooks $.telemetry's two events (log, mark), adding the noun in the engine.create fold where the engine has none, so a built-in plugin can record an event as a first-party analytics row, sent in batches; refuses installed plugins; sends nothing wherever Claude Code's analytics are off. |
Built in |
agents-md |
AGENTS.md as project instructions, by one option: loaded where the project has no CLAUDE.md of its own (claude-md-or-agents-md, the default) or beside it (claude-md-and-agents-md), placed and framed exactly as the engine places CLAUDE.md, nested ones on a Read; or the project's and the person's instruction files dropped and the organization's kept (managed-only); or CLAUDE.md alone, as the engine reads it (claude-md). |
Built in |
Each folder is a complete plugin: .claude-plugin/plugin.json, ahooks/hooks.json naming the module, and TypeScript under hooks/ typed
against the declarations /plugin-types writes (import type … from 'claude-code'), kept here in types/. To read one running from source:
claude --plugin-dir mods/diffTesting
A mod's tests are in its tests/ folder, and run with
claude plugin test mods/diffA test gets the engine's own $ and a plugin's on. Each call on $ is one
the engine makes, through every hook of the mod loaded as it ships. The hooks
the test registers with on sit beneath the mod, where the rest of the world
would be, and nothing is beneath them: a call they leave unanswered throws,
naming its event.
A test file is named for what it covers under hooks/ (register.test.ts
beside hooks/register.ts, git.test.ts beside hooks/git/), and holds its
imports, the tier the mod loads in, and one describe titled with that name;
what several tests share sits under tests/fixtures/, one export a file.
import { describe, expect, mock, test, tier } from 'claude-code/testing'
tier('builtin')
describe('register', () => {
test('outside a git repository /diff says so, opens nothing', async ($, on) => {
const opened: string[] = []
mock.clock(on)
on('session.start', ($, e) => ({ cwd: e.cwd }))
on('command.register', ($, e) => ({ value: { command: e.name } }))
on('process.run', () => ({
value: { exitCode: 128, stdout: '', stderr: 'fatal: not a git repository' },
}))
on('ui.open', ($, e, next) => {
opened.push(e.id)
return next(e)
})
await $.session.start({ surface: 'terminal', isInteractive: true, cwd: '/work' })
const { text } = await $.command.run({
command: 'diff',
args: '',
origin: { kind: 'composer' },
})
expect(text).toContain("isn't in a git repository")
expect(opened).toEqual([])
})
})The kit's mock answers the world beneath the mod from memory, noun by noun,
each member a plain function over on registering hooks where the test calls
it: mock.env(on, variables) for $.env, mock.store(on, entries) for$.store, and mock.clock(on) for $.clock, whose advance(ms) resolves
every wait the mod asked for ($.clock.sleep, after, every) as the clock
crosses it. To see what a dispatch does before it answers, start it
unawaited, await clock.settle(), then look: the clock stays where it was.$.ui.press({ plugin, key }) presses a Button the test rendered, as a
click in the terminal does.
tsc -p mods/tsconfig.json typechecks every mod's hooks and tests againsttypes/ and each mod's own types/ contract.
Composing mods: noun contracts
A mod that adds a noun to $ in the engine.create fold owns that noun's
types, and keeps them in one place: its types/index.d.ts, a declaration
file with no imports that exports the types the noun is made of, each named
for the noun, and declares the noun on EngineInterface in claude-code
(telemetry/types/index.d.ts exports Telemetry, TelemetryLogEntry,TelemetryMarkEntry and the rest, and declares $.telemetry).
- The contract is the only declaration of the noun. The mod's own hooks
import its types from the folder (import type { Telemetry } from '../types'), and the value itsengine.createhook returns is checked
againstEngineInterface['telemetry'], so the implementation cannot drift
from what callers read. - A mod that calls another's noun reads the same file and never copies it:
mods/tsconfig.jsonincludes*/types/**/*.d.ts, so$.telemetry.log(…)
indifftypes againsttelemetry's contract as it stands, and a helper
that must name one of its types imports it from that folder by path. - A test of a mod that calls another's noun seats a provider for it, an inline
plugin whoseengine.createhook adds the noun, and answers the calls the
way it answers the engine's:on('telemetry.log', ($, e) => ({ value: undefined }))runs above the provider's own method, itsetyped by the
contract. With no provider loaded the$build refuses the hook, naming the
noun nobody provides.
A plugin outside this repository that depends on a mod's noun points its
tsconfig include at that mod's types/ folder for now; once the engine
writes the contracts of the plugins a session has installed, /plugin-types
will put them beside claude-code.d.ts and the include goes away.
Early access: hooks modules load only where function hooks are enabled, and
the API these mods are written against may change between releases without
notice. They are not listed in this repository's marketplace; the copies that
matter are the ones already in your Claude Code.
Overview (`plugins/README.md`)
Claude Code Plugins
This directory contains some official Claude Code plugins that extend functionality through custom commands, agents, and workflows. These are examples of what's possible with the Claude Code plugin system—many more plugins are available through community marketplaces.
What are Claude Code Plugins?
Claude Code plugins are extensions that enhance Claude Code with custom slash commands, specialized agents, hooks, and MCP servers. Plugins can be shared across projects and teams, providing consistent tooling and workflows.
Learn more in the official plugins documentation.
Plugins in This Directory
| Name | Description | Contents |
|---|---|---|
| agent-sdk-dev | Development kit for working with the Claude Agent SDK | Command: /new-sdk-app - Interactive setup for new Agent SDK projectsAgents: agent-sdk-verifier-py, agent-sdk-verifier-ts - Validate SDK applications against best practices |
| claude-opus-4-5-migration | Migrate code and prompts from Sonnet 4.x and Opus 4.1 to Opus 4.5 | Skill: claude-opus-4-5-migration - Automated migration of model strings, beta headers, and prompt adjustments |
| code-review | Automated PR code review using multiple specialized agents with confidence-based scoring to filter false positives | Command: /code-review - Automated PR review workflowAgents: 5 parallel Sonnet agents for CLAUDE.md compliance, bug detection, historical context, PR history, and code comments |
| commit-commands | Git workflow automation for committing, pushing, and creating pull requests | Commands: /commit, /commit-push-pr, /clean_gone - Streamlined git operations |
| explanatory-output-style | Adds educational insights about implementation choices and codebase patterns (mimics the deprecated Explanatory output style) | Hook: SessionStart - Injects educational context at the start of each session |
| feature-dev | Comprehensive feature development workflow with a structured 7-phase approach | Command: /feature-dev - Guided feature development workflowAgents: code-explorer, code-architect, code-reviewer - For codebase analysis, architecture design, and quality review |
| frontend-design | Create distinctive, production-grade frontend interfaces that avoid generic AI aesthetics | Skill: frontend-design - Auto-invoked for frontend work, providing guidance on bold design choices, typography, animations, and visual details |
| hookify | Easily create custom hooks to prevent unwanted behaviors by analyzing conversation patterns or explicit instructions | Commands: /hookify, /hookify:list, /hookify:configure, /hookify:helpAgent: conversation-analyzer - Analyzes conversations for problematic behaviorsSkill: writing-rules - Guidance on hookify rule syntax |
| learning-output-style | Interactive learning mode that requests meaningful code contributions at decision points (mimics the unshipped Learning output style) | Hook: SessionStart - Encourages users to write meaningful code (5-10 lines) at decision points while receiving educational insights |
| plugin-dev | Comprehensive toolkit for developing Claude Code plugins with 7 expert skills and AI-assisted creation | Command: /plugin-dev:create-plugin - 8-phase guided workflow for building pluginsAgents: agent-creator, plugin-validator, skill-reviewerSkills: Hook development, MCP integration, plugin structure, settings, commands, agents, and skill development |
| pr-review-toolkit | Comprehensive PR review agents specializing in comments, tests, error handling, type design, code quality, and code simplification | Command: /pr-review-toolkit:review-pr - Run with optional review aspects (comments, tests, errors, types, code, simplify, all)Agents: comment-analyzer, pr-test-analyzer, silent-failure-hunter, type-design-analyzer, code-reviewer, code-simplifier |
| ralph-wiggum | Interactive self-referential AI loops for iterative development. Claude works on the same task repeatedly until completion | Commands: /ralph-loop, /cancel-ralph - Start/stop autonomous iteration loopsHook: Stop - Intercepts exit attempts to continue iteration |
| security-guidance | Security reminder hook that warns about potential security issues when editing files | Hook: PreToolUse - Monitors 9 security patterns including command injection, XSS, eval usage, dangerous HTML, pickle deserialization, and os.system calls |
Installation
These plugins are included in the Claude Code repository. To use them in your own projects:
- Install Claude Code globally:
npm install @anthropic-ai/claude-code- Navigate to your project and run Claude Code:
claude- Use the
/plugincommand to install plugins from marketplaces, or configure them in your project's.claude/settings.json.
For detailed plugin installation and configuration, see the official documentation.
Plugin Structure
Each plugin follows the standard Claude Code plugin structure:
plugin-name/
├── .claude-plugin/
│ └── plugin.json # Plugin metadata
├── commands/ # Slash commands (optional)
├── agents/ # Specialized agents (optional)
├── skills/ # Agent Skills (optional)
├── hooks/ # Event handlers (optional)
├── .mcp.json # External tool configuration (optional)
└── README.md # Plugin documentationContributing
When adding new plugins to this directory:
- Follow the standard plugin structure
- Include a comprehensive README.md
- Add plugin metadata in
.claude-plugin/plugin.json - Document all commands and agents
- Provide usage examples
Learn More
Overview (`examples/mdm/README.md`)
MDM Deployment Examples
Example templates for deploying Claude Code managed settings through Jamf, Iru (Kandji), Intune, or Group Policy. Use these as starting points — adjust them to fit your needs.
All templates encode the same minimal example (permissions.disableBypassPermissionsMode). See the settings reference for the full list of keys, and ../settings for more complete example configurations.
Templates
[!WARNING]
These examples are community-maintained templates which may be unsupported or incorrect. You are responsible for the correctness of your own deployment configuration.
| File | Use with |
|---|---|
managed-settings.json |
Any platform. Deploy to the system config directory. |
macos/com.anthropic.claudecode.plist |
Jamf or Iru (Kandji) Custom Settings payload. Preference domain: com.anthropic.claudecode. |
macos/com.anthropic.claudecode.mobileconfig |
Full configuration profile for local testing or MDMs that take a complete profile. |
windows/Set-ClaudeCodePolicy.ps1 |
Intune Platform scripts. Writes managed-settings.json to C:\Program Files\ClaudeCode\. |
windows/ClaudeCode.admx + en-US/ClaudeCode.adml |
Group Policy or Intune Import ADMX. Writes HKLM\SOFTWARE\Policies\ClaudeCode\Settings (REG_SZ, single-line JSON). |
Tips
- Replace the placeholder
PayloadUUIDandPayloadOrganizationvalues in the.mobileconfigwith your own (uuidgen) - Before deploying to your fleet, test on a single machine and confirm
/statuslists the source under Setting sources — e.g.Enterprise managed settings (plist)on macOS orEnterprise managed settings (HKLM)on Windows - Settings deployed this way sit at the top of the precedence order and cannot be overridden by users
Full Documentation
See https://code.claude.com/docs/en/settings#settings-files for complete documentation on managed settings and settings precedence.
Overview (`examples/settings/README.md`)
Settings Examples
Example Claude Code settings files, primarily intended for organization-wide deployments. Use these as starting points — adjust them to fit your needs.
These may be applied at any level of the settings hierarchy, though certain properties only take effect if specified in enterprise settings (e.g. strictKnownMarketplaces, allowManagedHooksOnly, allowManagedPermissionRulesOnly).
Configuration Examples
[!WARNING]
These examples are community-maintained snippets which may be unsupported or incorrect. You are responsible for the correctness of your own settings configuration.
| Setting | settings-lax.json |
settings-strict.json |
settings-bash-sandbox.json |
|---|---|---|---|
Disable --dangerously-skip-permissions |
✅ | ✅ | |
| Block plugin marketplaces | ✅ | ✅ | |
Block user and project-defined permission allow / ask / deny |
✅ | ✅ | |
| Block user and project-defined hooks | ✅ | ||
| Deny web fetch and search tools | ✅ | ||
| Bash tool requires approval | ✅ | ||
| Bash tool must run inside of sandbox | ✅ |
Tips
- Consider merging snippets of the above examples to reach your desired configuration
- Settings files must be valid JSON
- Before deploying configuration files to your organization, test them locally by applying to
managed-settings.json,settings.jsonorsettings.local.json - The
sandboxproperty only applies to theBashtool; it does not apply to other tools (like Read, Write, WebSearch, WebFetch, MCPs), hooks, or internal commands
Deploying via MDM
To distribute these settings as enterprise-managed policy through Jamf, Iru (Kandji), Intune, or Group Policy, see the deployment templates in ../mdm.
HIPAA deployments
For an organization that has the HIPAA configuration applied, settings-hipaa.json and managed-mcp-hipaa.json are a fuller managed-settings.json and managed-mcp.json pair with sandboxing, a network allowlist, credential protections, and local data retention. README-hipaa.md explains each choice and what to edit before deploying.
Full Documentation
See https://code.claude.com/docs/en/settings for complete documentation on all available managed settings.
Overview (`mods/agents-md/README.md`)
agents-md
AGENTS.md read the way Claude Code reads CLAUDE.md, as a plugin, under
one option, instructionFiles:
claude-md: onlyCLAUDE.mdis loaded, by the engine, as today. The plugin
adds nothing.claude-md-or-agents-md(the default): a project with no instruction files
of its own gets itsAGENTS.mdfiles instead, loaded exactly where and howCLAUDE.mdwould be. "Of its own" is read off what the engine loaded for
the context: aCLAUDE.md,.claude/CLAUDE.mdorCLAUDE.local.mdin any
directory from the root down to the working directory leaves the whole
project to the engine, and the plugin stays out (the organization's managed
file, the person's~/.claude/CLAUDE.md, a.claude/rulesfile and an
added directory'sCLAUDE.mddo not count, as the nested walk does not see
them either). With none, everyAGENTS.mdand.claude/AGENTS.mdon that
path joins the instruction files the engine renders, and aReadunder a
subdirectory attaches that directory'sAGENTS.mdunless aCLAUDE.md
there claims it.claude-md-and-agents-md: everyAGENTS.mdis loaded besideCLAUDE.md,
up and down the tree; a fileCLAUDE.mdalready@-imports, or is a link
to, is not loaded a second time (compared by path, then by content).managed-only: the project's checked-in and private instruction files and
the person's own are dropped from the context; the organization's managedCLAUDE.mdand the engine's memory stay. The engine's nestedCLAUDE.md
attachments onReadare not an event yet and still arrive. (The engine'sclaudeMdExcludessetting also exists, for user, project and local files,
and applies to theAGENTS.mdfiles this plugin reads too.)
How the files reach the model is the engine's doing, not the plugin's:prompt.context hands a hook the instruction files behind claudeMd
({ path, kind, content, parent? }, kinds managed, user, project,local, memory, in load order) and a hook answers the list changed. The
engine then renders claudeMd from the answered files with its own preamble
and framing, announces them by name, and keeps only the managed ones for an
agent that omits project instructions (Explore, Plan, a custom agent withomitClaudeMd). So an AGENTS.md this plugin adds as a project file is, to
everything downstream, a project instruction file: same place in the context,
same framing, same omission rules, same announcement. An organization's
prepended plugin on prompt.context sits above this one and has the last
word on the files.
hooks/register.ts is the module; everything under hooks/ is its parts,
importing claude-code and one another alone. tests/ runs underclaude plugin test .
Setting the option
As a built-in its option is the /config row "Project instructions", a
picker over the four values, each described there. By hand it is
{
"pluginConfigs": {
"agents-md@builtin": {
"options": { "instructionFiles": "claude-md-and-agents-md" }
}
}
}in user settings (~/.claude/settings.json), --settings, or managed
settings; a project's .claude/settings.json is not read for plugin
options. Changing it reloads the module, and the next context the engine
builds (the next turn after the reload, a new conversation, /clear, a
compaction) carries the new mode's files. A hand-typed value outside the
four is told once in the transcript and reads as the default. /plugin
lists the plugin among the built-ins, where a person can turn it off; with
it off the engine reads CLAUDE.md alone. No hooks setting or CLI mode turns
it off (disableAllHooks, allowManagedHooksOnly and --bare govern
settings hooks and installed plugins, not built-ins); where the engine loads
no instruction files (--bare without --add-dir, --safe-mode,CLAUDE_CODE_DISABLE_CLAUDE_MDS) its walk finds none and it adds none,CLAUDE.md and AGENTS.md alike.
The option was first keyed projectInstructions, with the values claude,agents-fallback, both and none. A value still stored under that key is
honoured for now while instructionFiles reads as its default: none asmanaged-only, claude as claude-md, agents-fallback asclaude-md-or-agents-md, both as claude-md-and-agents-md, any other
value as claude-md (which adds nothing, never as the default, which loadsAGENTS.md); the first session.start of a load says in the transcript how
it was read. Once instructionFiles is set to anything but its default, the
old key is not read and the transcript says to remove it.
Run from this folder instead (claude --plugin-dir mods/agents-md), the
same entry is keyed "agents-md".
What it hooks
| event | what the hook does |
|---|---|
session.start |
in every mode: passes the start straight through and floats the usage row for the configured mode, never awaited; the first start of a load logs how a stored projectInstructions value is read. The session's start never waits on this plugin |
prompt.context |
under claude-md-or-agents-md and claude-md-and-agents-md: walks $.fs.ancestors for the AGENTS.md files above the working directory and answers them as project instruction files, each @ import its own entry after its file, each placed where a project file of its directory stands (root first, before the first deeper project file, else after the last project file, before memory); files the engine already holds by path or by content are left out; under claude-md-or-agents-md it answers nothing when the project has a CLAUDE.md of its own (among the handed files, else found by a $.fs.ancestors walk, so a CLAUDE.md the engine loaded and then withheld still counts), and names the files it loaded in the debug log ($.ui.log with to: "debug": no CLAUDE.md found; AGENTS.md loaded: , nothing in the transcript) once, and again after a move to another project root; handed unknown files (a hook above rewrote the claudeMd text) it adds nothing; the first context of a load sends the load row (counts) and the feature mark; under managed-only (matcher: a project, local or user file present): answers the list without those kinds |
agent.spawn on fork: true |
under claude-md-or-agents-md and claude-md-and-agents-md: a fork the Agent tool starts shares its parent's prompt prefix, so the parent loop's delivered nested files are copied to the fork's loop and not attached to it again (a run that resumes a fork is passed on untouched, the fork keeping the set its own loop was given; a /fork or /subtask fork does not raise agent.spawn yet and starts from an empty set, as every fork did before; a fork started in the same tool batch as a Read inherits that Read's file although its prefix holds a placeholder for it) |
tool.call on Read |
under claude-md-or-agents-md and claude-md-and-agents-md, for a file under the session's project root ($.session.root(), read live, so /cd, a host's directory change and worktree moves are followed and a moved root starts the delivered sets and the fallback decision over; a file elsewhere gets nothing, as the engine attaches no nested CLAUDE.md there; and nothing anywhere in a run where the engine attaches nothing to a turn, --bare with its CLAUDE_CODE_SIMPLE or CLAUDE_CODE_DISABLE_ATTACHMENTS, read on every Read through $.env.get as the engine reads them on every turn): walks only the directories strictly between the root and the read file ($.fs.ancestors with below: root, as the engine walks only those for a nested CLAUDE.md, never up to the filesystem root again) and attaches their AGENTS.md files not yet given to that agent loop, not already among the context's instruction files (by path or, for a project file, by text) and not claimed by a CLAUDE.md of the same directory (or imported by one), as context after the tool result, framed Contents of : byte for byte as the engine frames a nested CLAUDE.md, whatever its size; each file once per loop and conversation (the context's recomputation after a compaction or /clear starts the count over), the context's files never; a Read that attached files sends the nested row. A ~ or ~/ path is read under the home directory as the Read tool reads it |
What it calls on `$`
fs.ancestors (with each found file's parts: the file and its imports
apart; with below on a Read; it finds nothing on a thin client, whose
workspace files are remote, as the engine's own walk does), session.root,session.cwd, env.get (HOME and USERPROFILE, once per load, the
profile first on a Windows spelling of the working directory, so a ~/ path
the model hands a Read resolves where the Read tool reads it; CLAUDE_CODE_SIMPLE
and CLAUDE_CODE_DISABLE_ATTACHMENTS on every Read), ui.log,telemetry.log and telemetry.mark.
$.telemetry is the telemetry plugin's noun; where that
plugin is not seated the calls find no noun and are dropped without a trace,
and nothing else changes.
What it logs
Counts and closed choices only; no path and no file text. Each row goes
through $.telemetry.log, so it exists only where the telemetry plugin
does:
| event | when | properties |
|---|---|---|
agents_md_mode |
once per fresh load, at session.start |
mode (claude-md | claude-md-or-agents-md | claude-md-and-agents-md | managed-only), is_interactive |
agents_md_load |
the first context of a load, under claude-md-or-agents-md and claude-md-and-agents-md |
mode, file_count (AGENTS.md files handed to the engine), import_count (their @ imports), total_content_length, yielded (claude-md-or-agents-md stood down for a CLAUDE.md of the project's own), walk_failed; with it one $.telemetry.mark for feature agents_md: ok, or sad with reason walk_failed |
agents_md_nested |
a Read that attached nested files | mode, file_count |
Where it still differs from CLAUDE.md
All of these apply only to the modes that load AGENTS.md,claude-md-or-agents-md (the default) and claude-md-and-agents-md. Each
names a loader fact a plugin cannot reach through the events it has today.
- Nested files attach on a text
Readonly. The engine also attaches a
directory'sCLAUDE.mdfor a file@-mentioned in the prompt, for the
IDE's opened file or selection, and for theReadtool's notebook, image
and PDF results. - A nested file the plugin attaches is not registered in the loop's
read-file state, so after a compaction the engine does not restore it
among the recently read files (the plugin attaches it again at the nextReadunder that directory instead), and a change to it mid-session is
not re-announced. /cdcarries the new tree'sCLAUDE.mdin its own notice; the plugin's
files for the new tree arrive in the same next request through the
engine's instructions announcement instead.- Paths compare by spelling; the engine resolves a symlinked alias of the
working directory before deciding a file is inside it. --add-dirdirectories contribute noAGENTS.md, where the engine can
load theirCLAUDE.md./memoryand the#shortcut do not knowAGENTS.mdfiles, and the
engine's own initial-load row does not count them (this plugin'sagents_md_loadrow does).- An
@import outside the working directory inside anAGENTS.mdis
honoured only once the approval the engine asks for aCLAUDE.md's
external imports has been given (without it the import is left out, as aCLAUDE.md's is); the approval dialog itself is raised forCLAUDE.md
imports alone. - A subagent that is not a fork gets a nested
AGENTS.mdat its own firstReadunder that directory even when its parent's loop was already given
it; the engine does not hand such a subagent the nestedCLAUDE.mdagain.
A fork matches the engine on both sides.
Testing
claude plugin test mods/agents-mdtests/register.test.ts covers the default mode: a project with AGENTS.md
alone gets it as a project instruction file and one debug-log line naming
it, with nothing in the transcript, a project with a CLAUDE.md of its own is
left to the engine without a walk, a failed walk leaves the context as handed,
and the start hands $.telemetry the mode row alone where a test seats a
provider for that noun, and goes on untouched where none is seated.
Overview (`mods/diff/README.md`)
diff
The diff pane as a plugin: /diff opens the session's uncommitted changes
beside the transcript, one row per changed file and every file's hunks
beneath, and closes it again; each toggle leaves Diff panel shown orDiff panel hidden in the transcript. The header, the file list and its
toggles stay put while the wheel moves the hunks under them three rows a
tick, or the list a file a tick while the wheel is over a list longer than
its eight rows (the plugin answers the pane's ui.scroll itself); a row's
click puts that file's hunks at the top; the list also scrolls under the
built-in's list keys (ctrl+up/ctrl+down, opt+up/opt+down), andctrl+x b moves the comparison base on, as the built-in's chord does: both
through Buttons that declare the engine's own actions. The pane refreshes
as Claude edits and runs shell commands, and while it is open it polls
the repository's HEAD so a commit or checkout made elsewhere shows too.
The main loop's first successful edit of a session opens the pane by
itself, as the built-in panel opens on its first checkpoint: where the
layout docks it beside the transcript (the fullscreen layout, which each
drawing's viewport says), the terminal is wide enough (144 columns when
the person never chose, 110 when they kept it open before; a person who
closed it is left alone) and file checkpointing is on; a subagent's edit
opens nothing, and where the surface does not say, nothing opens by
itself. A docked pane fetches before it opens, as the built-in panel
primes its data, so it never lands on Loading diff…; an open the engine
leaves waiting undrawn is withdrawn, so no later resize seats it, and the
next edit asks again. An open answered no-surface (nothing is attached
that draws it yet, as before a host's page attaches) is kept instead:/diff says so, nothing polls or refreshes while no one sees the pane, and
its first drawing reads the repository again and counts it shown. A session
resumed or continued whose transcript already holds such an edit opens the
pane on the same terms as soon as the width is known, as the built-in opens
on the history it restores.
Under the fullscreen layout a terminal under 110 columns gets the
built-in's line asking for a wider one and nothing opens. Without that
layout (CLAUDE_CODE_NO_FLICKER=0, which /diff learns from the command'spresentation) the pane opens inline at any width, focused and as tall
as its content (the open's rows), in the built-in dialog's shape: the
title, the count, five file rows at a time round the selected one (❯,
where the focus ring starts; the plugin follows the ring's walk throughui.focus and re-centres the rows as the built-in does), the key hints;
Enter shows that file's hunks alone,
Escape backs out to the list and then closes, leaving Diff dialog dismissed; toasts show while it is up, as beside the docked pane. A file's
ask button arms that file: its hunks ride the next prompt as context, once.
The pane compares the working tree against HEAD, split at the session's
start (the default; the start the engine gives in $.session.usage(), so a
resumed session keeps its first and /clear begins anew), against HEAD
plainly, or against the merge-base with
the default branch; the base line under the header names a base other than
the session's, and the choice is kept per repository in the plugin's store.
A picker shows one earlier turn's edits instead of the working tree, read
from the session's messages. Files that changed before the session started
(by their timestamp, among the paths already dirty when the pane first
read the repository), and noise (lockfiles, generated and test files), are
listed apart and folded until asked for; a rename lists as git prints it.
Outside a git repository /diff says so and does nothing else.
Git runs when the built-in panel's would: nothing at the session's start;
one git rev-parse, in the directory the session started in, when /diff
or the first edit a pane has room to open on first needs the repository
(an answer of no repository is kept too, until /clear or /resume
forgets it); and the working tree is read only by a fetch for a pane that
is open, after an edit that landed or a shell command that ran. The one
read the built-in has no counterpart for is a git status at a pane's
first fetch, which stands in for the change time the built-in dates a
moved file by.
hooks/register.ts is the module; everything under hooks/ is its parts.
What it hooks
| event | what the hook does |
|---|---|
session.start |
Binds the engine once and registers /diff (a session where another /diff is listed leaves the plugin idle); asks nothing of the repository, which /diff or the first edit pins when it comes; off its dispatch, reads the transcript, and for a resumed session whose turns edited opens the pane as the first edit would. |
ui.render of PromptHint |
Reads the terminal's width and whether its layout docks a pane, which decide whether the first edit opens the pane. |
ui.render of Pane |
Draws the pane: docked, the header, base line, source picker, file list and toggles over the window of hunks; inline, the dialog. |
command.run of diff |
Pins the repository when none is, opens or closes the pane (focused and closing on Escape without the fullscreen layout), says which, and remembers the choice. |
ui.close of the pane |
Backs out of the dialog's detail view instead of closing; else remembers the person's close as /diff's. |
ui.scroll of the pane |
Docked, moves the hunks under the pinned header and list (three rows a wheel tick, a page a page key), or the list when the wheel is over it, and keeps the engine's window still. |
ui.focus in the pane |
In the dialog's list, selects the file the ring lands on, re-centres the five rows on it, and lands the ring where that row now sits. |
command.run of clear, resume |
Closes the pane and forgets the session's state, the pinned repository with it. |
tool.call of Edit, Write, NotebookEdit |
After an edit that landed (not refused, not failed), refreshes an open pane; the main loop's first such edit opens it, pinning the repository then if the terminal has the room and checkpointing is on. |
tool.call of Bash, PowerShell |
After a command that was not refused, failed and interrupted ones too, refreshes an open pane. |
prompt.submit |
Adds the armed file's hunks to the prompt's context and disarms. |
What it calls on `$`
clock.after, clock.every, clock.now, command.register, env.get
(CLAUDE_CODE_DISABLE_FILE_CHECKPOINTING), fs.list, fs.read, fs.stat,process.run (git, read-only), session.id, session.messages,settings.read, store.get, store.set, telemetry.log, telemetry.mark,ui.close, ui.invalidate, ui.log, ui.open, ui.resolve, ui.status.
$.telemetry is the telemetry plugin's noun; where it is absent the rows
are dropped and nothing else changes.
Try it
claude --plugin-dir /path/to/diffthen /diff inside a git repository with a modified file.
Overview (`mods/sec-default/README.md`)
sec-default
The security default for organizations. Function hooks give every plugin a
say on every event, in chain order, and the plugins a person installs sit
in the user tier, beneath the organization's prepend tier and above its
append tier. Some of what an organization sets today (its classic hooks,
its managed CLAUDE.md and rules, its settings, its MCP allowlist, the deny
rules in force on its machines) was never within a person's reach before
function hooks; seated outermost, this plugin keeps exactly those out of the
user tier's reach and adds no policy of its own. Everything else passes
through untouched.
It has three moves and nothing else: continue past the user tier
(next.to(e, "append")), refuse a user-tier caller or module by name
({ deny } when next.origin.tier is user, { refuse } when a module's
pinned e.tier is), or pass (next(e)). A subject's provenance is the
event's pinned e.provider; policy is read through$.settings.read({ source: "policy" }), one read serving a burst of tool
calls; both fail closed, so an unreadable policy counts as a policy in force.
hooks/register.ts is the module; hooks/policy/ reads the managed
settings it decides by.
The rows
| event | from the outermost seat |
|---|---|
classic.* |
Continue past the user tier: the organization's settings hooks see the engine's input and their answer stands. |
prompt.section, prompt.context, prompt.attachment, skill.prompt, attribution.text |
Continue past the user tier: managed CLAUDE.md, rules and policy skills, and what the engine injects for the model beside them (a settings hook's note, the instruction files, a mode's reminder), are not a person's plugin's to reword at these events. A person's plugins keep prompt.submit and its additive context. This does not cover the variables that turn off CLAUDE.md loading: a person's plugin or settings can set CLAUDE_CODE_DISABLE_CLAUDE_MDS, CLAUDE_CODE_SIMPLE or CLAUDE_CODE_SAFE_MODE, and no CLAUDE.md loads, the managed one included. |
session.append |
For a row the engine injects for the model (the attachment and hook-context doors: a reminder, a settings hook's context), for a compaction's rows (the compaction door: its summary and boundary), for a skill's body as a call of the Skill tool hands it over (the tool-message door, that tool's rows alone, since the row does not say whose skill it is) and for a note an organization's plugin appends, continue past the user tier: the row is kept as made, so what passed prompt.attachment whole is not blanked or reworded on its way into the conversation. For a skill the hold does that much and no more: it stops rewording of the row in transit. A person's tool.call hook can still answer for a Skill call or swap input.skill, as it can for any tool; allowManagedModsOnly closes that. Every other row (a prompt, a response, a tool result, another tool's message, a delivery, a command's row, a notice, a note of a person's plugin, and a note the engine itself makes, a Stop hook's feedback among them) passes as the chain leaves it. What is held of a hook is its verdict and the context it adds; the words a hook's block feeds back to the model are such an engine-made note. |
session.compact |
Continue past the user tier, whole: a conversation a person's plugin answers in place of a compaction is never installed, so the conversation a compaction leaves is the engine's or the organization's own making, and its summary is stored as made (the session.append row). A person's own compaction hook does not run where this plugin is seated; a plugin of theirs may still ask for a compaction, which the engine then makes. |
prompt.compose |
Continue past the user tier: the system prompt's list of sections is what the organization's tiers, the built-ins and the engine's own composition make it. A person's plugin neither drops, reorders nor rewrites a section, nor changes the facts the list is composed from, nor answers a list of its own in its place. The engine raises this event only when some loaded plugin hooks it, so where this plugin is seated every render of the system prompt runs the chain. |
settings.read |
Continue past the user tier: no user hook rewrites what any caller reads as settings, this plugin's own policy reads included. |
tool.describe, command.describe, agent.offer, agent.spawn |
When the subject's pinned e.provider.tier is prepend or append (a policy-installed plugin, the managed folder, a policy MCP server), continue past the user tier; a subject provided by user, builtin or core passes. |
tool.register |
A caller in prepend or append continues past the user tier. A user-tier caller is refused by name while managed settings hold allowedMcpServers (set at all, empty included). With no allowlist, one is still refused whose tool, called mcp____<tool>, would read as a tool of a server the organization delivers: a managedMcpServers entry, or a server of the enterprise managed-mcp.json, which the policy read names under that key. So is one whose name reads as a plugin the organization seats itself (prependPlugins, appendPlugins, or an id managed enabledPlugins turns on, by true or by a version list, as the engine reads an entry), or as an MCP server such a plugin's own manifest declares, which the engine spells under the plugin's scope (mcp__plugin__<server>__). A user-tier plugin keeps its own name exactly when the id the engine recorded for it (<name>@<marketplace>: the settings key the loader resolved, never the plugin's manifest) is one managed enabledPlugins turn on, compared as the engine compares ids (NFC, then lower case). That is how an organization's own plugin registers its tools where the engine leaves it in the user tier: only a copy read in place from a local folder marketplace that managed settings name is vouched for, so a plugin from a remote marketplace (git, GitHub, npm) can never be vouched for in this release, and neither is one a version list turns on. For an organization that means such a plugin runs among a person's plugins in the chain, not ahead of them, and keeps its tools by this exemption alone. A plugin loaded with --plugin-dir is always <name>@inline and never matches; nor does a same-named plugin from another marketplace, one whose name only folds to the organization's, or an id policy lists only in prependPlugins or appendPlugins. A person who registers a marketplace of their own under the organization's marketplace name gets an equal id, and so the exemption: it gives that plugin what every plugin had before this hold existed, and strictKnownMarketplaces in managed settings closes it today by allowing no other marketplace source. The mod hears a plugin's id at its admission, so after a load that seats the mod afresh while other plugins stay seated (a load that folds again, as a policy change mid-session can cause) the organization's own plugin is refused its name until the session restarts. A plugin's own MCP servers are connected by the engine from its manifest, not registered through tool.register, so they are unaffected. An id's name is everything before its last at-sign, as the engine parts ids, so a scoped @scope/name@npm counts. A managed-mcp.json that is present and cannot be read whole names nobody: the policy read marks it (managedMcpServersUnreadable) and every such registration is refused while it stands, its servers never taken for none; the only other reader of the mark is tool.list (the next row), so a person's plugins still load and still set what is not pinned. A server the file names and the engine dropped with a warning is still named; a warning about a server that loads is no failure. Names are compared folded, as a model reads them (spelled as the engine spells a name inside a tool's name, every character outside letters, digits, - and _ a _ and nothing normalized; then lower case, every run of - and _ one _; a seated plugin counts under its name composed and decomposed, since the engine spells its tools from its manifest's own form): a plugin named as the server in any case or with other separators, one whose name and tool together spell it, and one whose tool's own name folds to nothing, is refused. A server whose name folds to nothing (no letter or digit in it) cannot be told from any name, so while the policy names one every user-tier registration is refused. The engine pins the tool's name at this event (a hook beneath that hands on another name fails, and the chain goes on without it), so the name judged is the name registered. Otherwise it passes. |
tool.list |
The tools of the organization's managed MCP servers, of the plugins it seats itself and of the MCP servers those plugins' own manifests declare (told by the name whole, as the engine spells it inside a tool's name: mcp__<server>__, never by a fold, so another server whose name only begins like the organization's is not taken for it; a seated plugin and its own servers, under its scope mcp__plugin__, fold to fold as the registration check compares, so policy may list its id in another letter case, and another plugin whose name begins with the seated one's and a - or _ reads the same) are listed as the organization's tiers listed them; every other tool as the user tier left it. Where the server file cannot be read, every mcp__ tool counts as the organization's. With no policy to read, or a refusal from either listing, the organization's listing stands whole. |
tool.check |
A deny, an ask a settings rule, a classic hook, a setting's own check or an organization's ceiling on the tool stands behind, an ask a host answers in the person's place and an ask a built-in or an organization's hook put to a person, hold whole over the user tier: when a person's plugin rewrote the verdict it was handed without tightening it (a more permissive decision, or the same decision under another reason or with what it names changed), the dispatch is run again past the user tier, and unless the chain's answer is the stricter, that verdict, if it is a deny or names what stands behind it or who it is put to, is the answer as the engine gave it. See Deny rules hold. Every other verdict passes as the chain left it. |
ui.log |
A line a plugin in prepend or append logs, this one's included, continues past the user tier: no user hook rewrites or drops it, and none runs inside the hook that logged it. Every other line passes. |
env.get |
A read by a plugin in prepend or append continues past the user tier: no user hook answers what the organization's own plugin reads. Every other read passes. |
env.set |
A write by a plugin in prepend or append continues past the user tier, whatever the variable: no user hook rewrites or drops what the organization's own plugin sets. A variable managed settings set in env (its name in any case) is pinned, and so are CLAUDE_CODE_PROCESS_WRAPPER where they name a launcher with processWrapper and, always, the nine variables that move where policy and sign-in are read from or how policy's tiers compose (CLAUDE_CODE_MANAGED_SETTINGS_PATH, CLAUDE_CODE_REMOTE_SETTINGS_PATH, CLAUDE_CODE_MOCK_REMOTE_SETTINGS, CLAUDE_CODE_DISABLE_ADMIN_ENV_UNION, CLAUDE_CONFIG_DIR, CLAUDE_SECURESTORAGE_CONFIG_DIR, USE_LOCAL_OAUTH, USE_STAGING_OAUTH and CLAUDE_LOCAL_OAUTH_API_BASE, which choose the server sign-in goes to; all nine on every build), and, on every build too, ten variables that can load code into a child the engine starts (LD_PRELOAD, LD_LIBRARY_PATH, LD_AUDIT, DYLD_INSERT_LIBRARIES, DYLD_LIBRARY_PATH, DYLD_FRAMEWORK_PATH, BASH_ENV, ENV, ZDOTDIR, NODE_OPTIONS): setting or unsetting it, a user-tier caller is refused by name and a built-in's write continues past the user tier. Any other variable is a person's plugin's to set. With no policy to read, every variable counts as pinned. allowModsToOverrideDenyRules does not unpin. See Pinned variables. |
plugin.register |
A hooks module in the user tier (one a person installed, named with --plugin-dir, or keeps in their mods folder) is refused while managed settings set this plugin's allowManagedModsOnly option; otherwise it passes. Modules in prepend, append and builtin are never asked about. |
| everything else | Passes: prompt.submit, turn.*, tool.call, command.run, command.register, command.list, agent.register, config.*, prompt.fill, prompt.suggest, prompt.edit, prompt.read, session.* but session.append and session.compact, ui.* but ui.log, fs.*, http.fetch, process.run, store.*, clock.*, model.*, mcp.call, audio.*, agent.list, engine.create. |
Options an administrator sets
Two, in managed settings, under this plugin's own pluginConfigs entry,
keyed by the id the CLI builds the plugin in under (only this spelling of the
id is read):
{
"pluginConfigs": {
"cc-plugin-sec-default@builtin": {
"options": { "allowManagedModsOnly": true }
}
}
}allowManagedModsOnly: only the mods the organization deploys through
managed settings, and the ones built into Claude Code, load. A hooks module
a person installed, named with --plugin-dir or keeps in their mods folder
is refused whenever it loads or reloads (one already running when the option
is set keeps running until then), with one line that names it: mods are limited to your organization's by policy (allowManagedModsOnly); was not loaded
(in the debug log, and on screen where the session hot-reloads the mod's
folder). A plain -p run has it in the debug log alone; the mod is still
not loaded. Settings hooks, status lines and /goal are not touched by it.
- The decision reads the tier the CLI pins on the module and nothing the
module says of itself: a person's copy carrying an organization mod's name
is still in theusertier and is refused. - Refused means nothing of the module joins: no hook, no tool, no command.
Its top-level code has run once by then, in the closed context every hooks
module is evaluated in, with no call on$served. - Only managed settings are read (
$.settings.read({ source: "policy" })):
the same entry in a person's, a project's or a--settingsfile neither
turns it on nor off. On unless absent orfalse, so a mistyped"true"or1still locks. A value the settings schema rejects (null, an object),
here or in any otherpluginConfigsentry, makes the CLI ignore the wholepluginConfigskey with a settings warning, and the option reads as unset. - It fails closed: when the read of managed settings is refused (a hook beneath
denies it) or this plugin's hook fails, its.catchrefuses the module,
with the same line, and names the failure in the debug log; so a policy
that cannot be read keeps every person's mod out at load. Where this plugin
is not seated there is no such rule, and mods load as they do without it. - Where managed settings define
prependPlugins, that list must name this
plugin (next section) for the option to apply. claude plugin testis not covered: it runs a mod's tests in an engine of
their own and loads nothing into a session.
allowModsToOverrideDenyRules: the plugins a person installs may answer
over a settings deny rule on tool.check, as they could before this plugin
held deny rules, and over every other deny, an ask rule, a classic hook's
ask, a setting's own ask or an ask a host or a person answers with it: the one option
covers all that holds there. Off unless it is the
literal true; an option that reads as unset leaves them holding. See
Deny rules hold.
What it hooks
classic.*, prompt.section, prompt.context, prompt.attachment,prompt.compose, skill.prompt,attribution.text, session.append, session.compact, settings.read, tool.describe, command.describe,agent.offer, agent.spawn, tool.register, tool.list, tool.check,ui.log, env.get, env.set, plugin.register.
Hooking tool.check has a cost: the engine raises that event only when some
loaded plugin hooks it, so where this plugin is seated every tool call now
runs the tool.check chain, where before only a session with such a plugin
did. So has hooking ui.log, env.get and env.set: each such call of any
plugin's now runs a chain, and an env.set from outside the organization's tiers waits on
the policy read.
What it calls on `$`
settings.read, and ui.log: to the debug log, and for the one line a
person reads when something held over a plugin of theirs. It continues to
the append tier with next.to, which only a plugin in a managed tier may
do.
Deny rules hold
On tool.check any hook may answer any verdict, so a plugin a person
installs to stop the permission prompts (() => ({ decision: "allow" }))
would also lift a deny rule, an ask rule or a PreToolUse hook's ask, a
managed one included, the read block's ask on a shell command, and the ask a
host was to answer. Where this plugin is seated it does not:
- The hook first runs the chain as it is. If no link that may hold a
person's plugin rewrote the verdict handed up to it (a more permissive
decision, or the same decision under another reason, rule or hook; a
tightening is no rewrite), the answer passes: nothing of the person's
changed anything, and a plugin that only listens, or only tightens, adds no
run of its own.
This is read offnext.trace, whose tiers the engine pins: a link that never
callednextis measured against a deny, and since the engine lists
neighbouring plugins that share a worker as one batch under its first
member's tier, aprependentry beneath this plugin counts as well as auserone. Whether a person's plugin did the rewriting is never settled
here, only by the next step. - Otherwise it runs the dispatch once more with the user tier left out
(next.to(e, "append")). That verdict never passed through a person's
plugin, so neither the decision nor the rule it names can have been
rewritten or erased, and a plugin that answered without callingnext
changes nothing: the rules are evaluated in this run. The two runs differ
by the user tier alone, so where they differ and the chain's answer is not
the stricter, the user tier rewrote it. A deny is returned in place of the
chain's answer whatever decided it; an ask, when it names what decided it,
a settings rule (rule), a classic hook (hook), a setting whose own
check asked (setting) or an organization's ask cap on the tool
(ceiling), or names who answers it (decider: a host, or a person a
built-in or an organization's hook put it to). It is returned
whole, so the reason this event answers, which a person reads in the
prompt and the engine writes into a refusal, is the engine's, and what it
names is still named. (The refusal then enters the conversation as a tool
result, a row a person's plugin may still reword atsession.append.) A
stricter answer of theirs (a deny over an ask) stands. - Any rule, any classic hook, any such setting and any such cap counts,
whoever configured it: a verdict carries the rule as written, the hook's
event, the setting's key and the cap, never where any was read from. A
deny holds unnamed because
it can stand in front of such an ask: lifted, the call would run with nobody
asked. An ask that names none of them and that the person answers at a
dialog (the mode's own, a check of the engine's own that no setting turns
on) is not held. - A person: a hook that answers
askwithdecider: "person"keeps the
call from the classifier's allow. Made by a built-in or an organization's
hook, that ask holds, so a person's plugin neither allows it nor turns it
back into a plain ask. A person's own plugin may ask a person too, over a
verdict that does not hold, and over a host's ask by changing only itsdeciderto"person": that is a tightening and passes. Any other change
to a host's ask stays held. As for any hook's ask, a rule for the whole tool
is not kept; a narrower rule the person saves is theirs and settles nothing
while the hook asks. - The setting the engine names today is the read block's
(permissions.blockReadsOutsideWorkingDirectories), for the two asks the
block keeps for the person: about a shell command that reads outside the
working directories, and, while the block is on, about a command the model
wants run outside the sandbox, which is what holds its reads in. The file
tools refuse such a read outright, and a deny holds as it is. - A host: where the permission callback of the program that runs the session
answers its asks (an SDK host'scan_use_tool, a permission prompt tool;
a cloud session's host is one), the engine's own ask says so
(decider: "host"), in every loop of the process, a subagent's included,
and only where the host would be asked. Such an ask holds, the mode's own
too: it goes on to whatever the mode puts between an ask and the host
(auto mode's classifier) and then to the callback, as it would with no
plugin loaded. An evaluation the engine has not classified is held. - Where no host can be asked on an evaluation, it names none, and a
person's plugin's allow answers as it does with no host. That is a closed
list, pinned by a test: an in-process teammate's own function (under a
headless leader its ask is cancelled or never answered); the comment
auto-edit's own checks (one that is not an allow ends in a notice); the
observer's gate (an ask there is a deny); a fork, subtask, workflow or
forked command that has no session function of its own; and a skill's
inline shell command where no hand-off exists, since an ask then fails
the render. With a hand-off, in auto mode, that command's ask is left to
the model's own call, which the host is asked about: it holds. - An ask that is certain to be refused with nobody asked names no host, so
a person's plugin's allow answers it as it does in a session no host
runs: underdontAsk, in a loop no prompt can show in (a background
agent's; in auto mode there, with no chain, the plugin's allow comes
before the classifier, as it does on main), once a permission prompt
tool's server has left the session. An ask only a dialog on this computer
can show holds under a prompt tool and on a served call: the engine denies
it there, and a plugin's allow does not turn that deny into an allow.
What is not certain holds: every other mode, a
Chrome tool's ask underdontAsk(a site grant sends it on), and, where
the host is set to be asked again after every allow auto mode's
classifier gives, a loop no prompt can show in. - A call this computer runs for a cloud session names that session as its
host: its ask goes there and holds. Serving marks nothing for this
computer's own session: its calls name a host only if one answers them. - The two hosts the engine knows to show the question to the person on a
card (the IDE pane, the desktop app's Code tab) are that person's dialog
and are not named. The session's start says which it is, once, for the
hold and for the card alike; nothing written later changes it. Only the
host's own request is such a card: a permission prompt tool's question
holds in a pane too. The
entrypoint is asserted by the start environment, not proven: whoever sets
the environment a session is spawned with can claim a pane. - An organization's plugin (prepend or append) or a built-in that allows
over a deny rule takes part in both runs, so its answer stands (a prepended
one that loosens is what brings the second run about, so its hooks run
twice on such a call). The mode's own ask
that a person's plugin turns into an allow, with nothing named behind it
and the person the one who would have been asked, stands: that is what such
a plugin is for. tool.checkpins the question (tool,input,tool_use_id), so no hook
can have the rules evaluated on one command and another run; a rewrite
belongs totool.call, which runs before any of this.- The person is told once for each name and kind in a session, in the
transcript and the debug log:tried to lift a deny rule in your settings from a <tool> call (<rule>); the deny rule holds over the plugins you install (allowModsToOverrideDenyRules), ortried to rewordwhere
the decision was kept and its words or its rule were not. The kinds area deny rule,an ask rule,a <event> hook's ask,a <key> setting's ask,a host's askanda refusal(a deny that names no rule); only the two rule kinds
carryin your settingsand a rule. Plugins the
engine ran as one
batch are named together, as it names them (audit+easy). A plain-p
run has it in the debug log alone; the call is still denied, or asked
about, with its own message. The line goes past the user tier (theui.log
row): a hook of theirs that heard it would run inside this plugin's owntool.checkhook, and the engine leaves a hook out of whatever is raised
from inside it. - What this does not reach: a held ask is still an ask, so whatever answers
asks for the person answers it, a classicPermissionRequesthook of
theirs included (allowManagedHooksOnlyis the control for those). Nor an
ask of the engine's own check that no setting turns on (a dangerous
removal's): at a dialog the verdict does not tell it from the mode's own,
so a person's plugin may still answer it there. Nor a session nobody
answers asks for (a plain-prun, where an ask is refused): the mode's
own ask is a person's plugin's to allow there. Nor a hosted session where
this plugin is not seated: a person's plugin answers the mode's ask there
as it does at a dialog. Nor an ask an organization's own plugin answers
without passing on the engine's verdict: it names nothing unless that
plugin names it. - It does not reach a person's classic
PreToolUsehook that allows
either: the engine then raises no ask at all,tool.checknever runs, and
the host is not asked. That is the same with no plugin loaded. - If the hook itself fails, its
.catchanswers from the one run it can
read: a verdict no plugin of the person's rewrote stands, one they
tightened included; one they rewrote, or a run that rejected, is refused
in this plugin's own words, since the rules and hooks were never consulted.
An organization that wants the plugins its people install to override deny
rules, and all else that holds with them, says so in managed settings, under
this plugin's own options:
{
"pluginConfigs": {
"cc-plugin-sec-default@builtin": {
"options": { "allowModsToOverrideDenyRules": true }
}
}
}Only the managed source is read ($.settings.read({ source: "policy" })),
so the same key in a person's, a project's or a local settings file, or in--settings, is never consulted; only the literal true counts, and a
policy that cannot be read leaves them all holding. So does a policy no
administrator composed: where the only policy is a document the person can
write themselves (the Windows HKCU hive), or a remote policy the server
has not yet confirmed this session, the option is not taken from it.
That policy still holds what it holds; it grants nothing.
Pinned variables
$.env.set writes the session's own environment. A variable managed
settings set in env is the organization's to decide, so this plugin
refuses a person's plugin that sets or unsets one (the env.set row). It
refuses the same of the launcher's variable where policy names a launcher,
and, on every build and whatever managed settings hold, of the nine
variables that move where policy and sign-in are read from: a write of one
would point a later load or launch at another policy. An
organization's own plugin's reads, writes and log lines continue past the
user tier's hooks (the env.get, env.set and ui.log rows).
It refuses the same of ten variables that can load code into a child the
engine starts, a managed hook's command among them: the loader's
(LD_PRELOAD, LD_LIBRARY_PATH, LD_AUDIT, DYLD_INSERT_LIBRARIES,DYLD_LIBRARY_PATH, DYLD_FRAMEWORK_PATH), a shell's start file
(BASH_ENV, ENV, ZDOTDIR) and the runtime's options (NODE_OPTIONS).
Each reaches some children, not all: BASH_ENV a bash that is not
interactive, ENV an interactive shell in sh mode, NODE_OPTIONS a Node
child, and macOS drops the DYLD_ names for protected binaries.
That pin is a list, not a boundary. A person's plugin can start a process
as the person by other roads, and other variables steer a child too
(PATH, the home variables, a credential file's path). The pin keeps the
organization's hook commands and tools from being re-pointed by accident
or by a careless plugin, not by a hostile one.
- At a load, from the first admission until the set serves, an op a plugin
makes (one it left running between the load's steps too) is raised through
the plugins admitted so far, this one first: a pinned variable is
refused to a person'splugin.registerhook then as at any later time. - What this does not reach: a variable that managed
envdoes not set and
that is not among those names is a person's plugin's to write, and the
children the engine starts afterwards (Bash, an MCP server,$.process.run,
a person's own hook) start from the environment as written. - A hook the organization defines is the exception: one in managed settings,
one of a plugin managed settings install, and the managed status line and
file suggestion commands. A plugin counts as one managed settings install
only when it is read in place from a folder those settings name; a plugin
they merely enable by id, loaded from a copy on the person's machine (a
marketplace download, or the person's own folder under that id), is not
treated as the organization's, for its hooks or for its writes. The
organization's hook's command starts from the environment, and is
wrapped in theCLAUDE_CODE_SHELL_PREFIX, as they stood before any write a
person's plugin made with$.env.setin this process: a variable such a
plugin set or deleted reads as it did before, absent if it was absent. A
managed HTTP hook's header variables are read the same way, and so is the
time allowed to the hooks that run as a session ends. What an
organization's plugin, or one built into the CLI, writes still reaches the
hook, also where it writes a variable a person's plugin wrote first; a
value a later settings reload puts over the person's plugin's value stands
too. A write counts as the organization's only when no person's plugin
stands behind it. A write made while serving a person's plugin, or in a
call a person's plugin raised, is a person's; so is an organization's
write whose value a hook of a person's plugin changed before it was made. - A person still decides the environment Claude Code starts in (
PATH,LD_PRELOAD,CLAUDE_CODE_SHELL_PREFIXare theirs to set before launch,
and in their own settings files), and a managed hook starts from that
environment like every other child. The same holds for the proxy and
certificate, credential, provider and home variables (HTTPS_PROXY,NODE_EXTRA_CA_CERTS,ANTHROPIC_API_KEY,HOMEand their like): they are
not pinned, because a person sets the same ones in their own settings and
shell, so a pin onenv.setwould not close that road. Where that road is
closed, the engine closes it for a plugin too, with or without this
plugin seated: in a session that asks its organization for its settings (a
Cowork cloud session), a plugin that is not built in sets or unsets only a
variable the filters on every settingsenvwould let a person's own
settings file set there, and any other write (the proxy and certificate
variables among them) is held and answered{ deny }. A plugin the
container's managed settings enable is held alike: the session may be able
to write that file. So is a write, or an unset, of a name any settings tier
above the person's sets there (the project's, the local, a--settings
file's or the organization's own settingsenv), and a built-in's own
write in three corners: the built-in serves a plugin that is not built in,
it writes from a dispatch such a plugin raised, or it writes beneath a call
some hook rewrote, since who rewrote it cannot be told. An organization
pins the variables its hooks rely on by setting them in managedenv. An
organization's plugin's$.env.getis answered past the user tier's hooks,
with the environment as written.
Where it is seated
The CLI seats it first in the prepend tier wherever hooks modules load on a
machine with managed settings or a managed-mcp.json, or for a Team or
Enterprise organization,
unless managed settings define prependPlugins: then that list is the
whole prepend tier, and the organization names sec-default@builtin in it
at the position it wants, e.g. "prependPlugins": ["acme-guard@acme-tools", "sec-default@builtin"], or leaves it out. Once seated by the machine's
managed settings or by the plan, it stays seated until the session ends: a
plan that reads differently at a later reload (a token variable a plugin
set, an apiKeyHelper that appeared in a person's settings, another
sign-in) does not unseat it. How a person signs in before a launch is
theirs, so a seat that rests on the plan alone follows the sign-in at the
next launch; managed settings on the machine are what hold it there. The
organization's own prependPlugins list still decides at every reload,
with one exception: a Cowork cloud session that asks its organization for
its managed settings seats it by default, and there a prependPlugins list
that leaves it out does not unseat it. The only such list a session there
can hold is a file's in its container, which the session can write as well
as its environment can, so it may add a hold and never lift one. That
default ends once the organization's 200 has set nothing, the server
has named a Pro or Max plan for the launch's login and the host's plan
variable agrees: it is then known that nothing seats it, as in the
terminal, and a policy served later brings it back. It
is a plugin folder like any
other, but its one move that matters, next.to, is refused outside a
managed tier, so loading it with --plugin-dir seats a plugin that can
only pass.
Overview (`mods/telemetry/README.md`)
telemetry
Plugin analytics as a plugin: its hooks on telemetry.log andtelemetry.mark are what those two events do, built over the nouns itsengine.create step is handed, and a gate above them serves the plugins
built into Claude Code alone: a call from a plugin a person installed or an
administrator listed is refused with a reason (the host stamps every call
with the plugin that raised it, next.origin, and the gate reads its tier).
On an engine that has no $.telemetry of its own the same step adds the
noun, so the calls exist there too. An entry names where it goes with to:anthropic, the default, is this mod's; one for collector, the telemetry
collector an operator configured, is passed on beneath untouched, and to
is never part of a row.$.telemetry.log({ event, props }) queues one event as one first-party
row, tengu_plugin_<event>; $.telemetry.mark({ feature, kind, reason?, props? }) marks one use of a feature as the CLI's own feature events do,tengu_feature_<kind> with a feature_name and the mark's properties
beside it. Both resolve once the row is queued. Rows go out in batches: one
POST to the event-logging ingest with the session's own credential
($.session.authorize(), resolved for each batch) a few seconds after the
first row was queued, at once when a hundred wait, and when the session
ends; a batch the ingest refuses with a server error, a timeout or a rate
limit is tried once more. A session with no first-party credential, or an
ingest that still refuses, drops the batch; each outcome is one line in the
debug log.
Each row carries what the CLI's own rows carry, gathered through $ once
a session: an event id, the install's device id and the signed-in account's
ids from the CLI's global config, the session's id, model, client type,
entrypoint and interactivity, and an env block (platform and
architecture from one uname probe, terminal, shell, package managers and
runtimes, CI and GitHub Actions, the remote container, the deployment, the
Linux distribution and kernel, WSL, the working directory's version
control, and the engine's version, base version and build time from$.session.version(), left empty on an engine that does not answer it),
with the repository's remote hash beside the row's properties. What the
engine alone knows (its runtime's version, the process's memory, the
request's betas, the subscription tier, the calling agent) is not on $,
and those columns stay empty.
It sends nothing wherever the CLI's own analytics are off: underDISABLE_TELEMETRY, CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC orDO_NOT_TRACK, in a test run, on any third-party provider (Bedrock,
Vertex, Foundry and kin) the host does not manage, on a cloud gateway
(the environment's switch or the managed policy's login pins), and on a
deployment with its own OAuth URL. Each is read through $.env and$.settings before every batch, so a session that has since moved to a
third-party provider or a gateway sends nothing more; when the switches
cannot be read, nothing is sent either. The row's user_type is ant
when USER_TYPE says so, else external.
Nothing free-form reaches a row. An event name and every property key is a
snake_case token; a value is a finite number, a boolean, or a Choice (a
string named together with the list it is chosen from), under log andmark alike; mark takes ok, sad or bad, with a reason required on
the last two and refused on the first. An entry that breaks a rule is
refused before anything is queued. Of the environment, a variable whose
value is a secret, or names a person or a host, is read for whether it is
set and nothing more; a shell is its basename from a closed list.
hooks/register.ts is the module; types/index.d.ts is the noun's contract,
the one declaration of $.telemetry that this mod's hooks, a mod calling the
noun and a test answering it all read.
What it hooks
telemetry.*, the gate: a caller in the built-in tier (or the engine) goes
on, any other is refused, and a gate that throws refuses too.telemetry.log and telemetry.mark, beneath the gate: the entry is checked
and its row queued, the hook answering { value }, or { deny } with the
reason for an entry that breaks a rule, so the caller's promise rejects
naming it. engine.create: the sender is built over await next(e), and
the step hands up { ...{ telemetry }, ...beneath }: what is beneath is
spread last, so its own telemetry stands where it has one and this mod's
is added where it has none; nothing beneath is replaced.session.start, to learn whether a person is at the prompt; session.end,
to send what still waits.
What it calls on `$`
session.authorize, session.id, session.model, session.surfaces,session.cwd, session.repo, settings.read, env.get (the switches and
the describing variables, by literal name), fs.read, fs.list,fs.exists, process.run (one sh -c of uname and command -v),clock.after, clock.sleep, http.fetch and ui.log (to the debug log),
each on the interface the fold handed it.
Where it runs, whom it serves
This plugin is seated by the CLI itself, on every build whose own analytics
are on, and nowhere else; it serves the plugins bundled with the CLI and
refuses every other caller. It is not meant to be installed or loaded with--plugin-dir; the folder has a manifest so it reads like every other
plugin, not so it can stand alone. A built-in that calls $.telemetry
where this one is absent finds no such noun, or, on an engine with the noun
of its own, one whose calls queue nothing; either way that is "no analytics
here".
Overview (`plugins/agent-sdk-dev/README.md`)
Agent SDK Development Plugin
A comprehensive plugin for creating and verifying Claude Agent SDK applications in Python and TypeScript.
Overview
The Agent SDK Development Plugin streamlines the entire lifecycle of building Agent SDK applications, from initial scaffolding to verification against best practices. It helps you quickly start new projects with the latest SDK versions and ensures your applications follow official documentation patterns.
Features
Command: `/new-sdk-app`
Interactive command that guides you through creating a new Claude Agent SDK application.
What it does:
- Asks clarifying questions about your project (language, name, agent type, starting point)
- Checks for and installs the latest SDK version
- Creates all necessary project files and configuration
- Sets up proper environment files (.env.example, .gitignore)
- Provides a working example tailored to your use case
- Runs type checking (TypeScript) or syntax validation (Python)
- Automatically verifies the setup using the appropriate verifier agent
Usage:
/new-sdk-app my-project-nameOr simply:
/new-sdk-appThe command will interactively ask you:
- Language choice (TypeScript or Python)
- Project name (if not provided)
- Agent type (coding, business, custom)
- Starting point (minimal, basic, or specific example)
- Tooling preferences (npm/yarn/pnpm or pip/poetry)
Example:
/new-sdk-app customer-support-agent
# → Creates a new Agent SDK project for a customer support agent
# → Sets up TypeScript or Python environment
# → Installs latest SDK version
# → Verifies the setup automaticallyAgent: `agent-sdk-verifier-py`
Thoroughly verifies Python Agent SDK applications for correct setup and best practices.
Verification checks:
- SDK installation and version
- Python environment setup (requirements.txt, pyproject.toml)
- Correct SDK usage and patterns
- Agent initialization and configuration
- Environment and security (.env, API keys)
- Error handling and functionality
- Documentation completeness
When to use:
- After creating a new Python SDK project
- After modifying an existing Python SDK application
- Before deploying a Python SDK application
Usage:
The agent runs automatically after /new-sdk-app creates a Python project, or you can trigger it by asking:
"Verify my Python Agent SDK application"
"Check if my SDK app follows best practices"Output:
Provides a comprehensive report with:
- Overall status (PASS / PASS WITH WARNINGS / FAIL)
- Critical issues that prevent functionality
- Warnings about suboptimal patterns
- List of passed checks
- Specific recommendations with SDK documentation references
Agent: `agent-sdk-verifier-ts`
Thoroughly verifies TypeScript Agent SDK applications for correct setup and best practices.
Verification checks:
- SDK installation and version
- TypeScript configuration (tsconfig.json)
- Correct SDK usage and patterns
- Type safety and imports
- Agent initialization and configuration
- Environment and security (.env, API keys)
- Error handling and functionality
- Documentation completeness
When to use:
- After creating a new TypeScript SDK project
- After modifying an existing TypeScript SDK application
- Before deploying a TypeScript SDK application
Usage:
The agent runs automatically after /new-sdk-app creates a TypeScript project, or you can trigger it by asking:
"Verify my TypeScript Agent SDK application"
"Check if my SDK app follows best practices"Output:
Provides a comprehensive report with:
- Overall status (PASS / PASS WITH WARNINGS / FAIL)
- Critical issues that prevent functionality
- Warnings about suboptimal patterns
- List of passed checks
- Specific recommendations with SDK documentation references
Workflow Example
Here's a typical workflow using this plugin:
- Create a new project:
/new-sdk-app code-reviewer-agent- Answer the interactive questions:
Language: TypeScript
Agent type: Coding agent (code review)
Starting point: Basic agent with common featuresAutomatic verification:
The command automatically runsagent-sdk-verifier-tsto ensure everything is correctly set up.Start developing:
# Set your API key
echo "ANTHROPIC_API_KEY=your_key_here" > .env
# Run your agent
npm start- Verify after changes:
"Verify my SDK application"Installation
This plugin is included in the Claude Code repository. To use it:
- Ensure Claude Code is installed
- The plugin commands and agents are automatically available
Best Practices
- Always use the latest SDK version:
/new-sdk-appchecks for and installs the latest version - Verify before deploying: Run the verifier agent before deploying to production
- Keep API keys secure: Never commit
.envfiles or hardcode API keys - Follow SDK documentation: The verifier agents check against official patterns
- Type check TypeScript projects: Run
npx tsc --noEmitregularly - Test your agents: Create test cases for your agent's functionality
Resources
Troubleshooting
Type errors in TypeScript project
Issue: TypeScript project has type errors after creation
Solution:
- The
/new-sdk-appcommand runs type checking automatically - If errors persist, check that you're using the latest SDK version
- Verify your
tsconfig.jsonmatches SDK requirements
Python import errors
Issue: Cannot import from claude_agent_sdk
Solution:
- Ensure you've installed dependencies:
pip install -r requirements.txt - Activate your virtual environment if using one
- Check that the SDK is installed:
pip show claude-agent-sdk
Verification fails with warnings
Issue: Verifier agent reports warnings
Solution:
- Review the specific warnings in the report
- Check the SDK documentation references provided
- Warnings don't prevent functionality but indicate areas for improvement
Author
Ashwin Bhat ([email protected])
Version
1.0.0
Overview (`plugins/claude-opus-4-5-migration/README.md`)
Claude Opus 4.5 Migration Plugin
Migrate your code and prompts from Sonnet 4.x and Opus 4.1 to Opus 4.5.
Overview
This skill updates your code and prompts to be compatible with Opus 4.5. It automates the migration process, handling model strings, beta headers, and other configuration details. If you run into any issues with Opus 4.5 after migration, you can continue using this skill to adjust your prompts.
Usage
"Migrate my codebase to Opus 4.5"Learn More
Refer to our prompting guide for best practices on prompting Claude models.
Authors
William Hu ([email protected])
Overview (`plugins/code-review/README.md`)
Code Review Plugin
Automated code review for pull requests using multiple specialized agents with confidence-based scoring to filter false positives.
Overview
The Code Review Plugin automates pull request review by launching multiple agents in parallel to independently audit changes from different perspectives. It uses confidence scoring to filter out false positives, ensuring only high-quality, actionable feedback is posted.
Commands
`/code-review`
Performs automated code review on a pull request using multiple specialized agents.
What it does:
- Checks if review is needed (skips closed, draft, trivial, or already-reviewed PRs)
- Gathers relevant CLAUDE.md guideline files from the repository
- Summarizes the pull request changes
- Launches 4 parallel agents to independently review:
- Agents #1 & #2: Audit for CLAUDE.md compliance
- Agent #3: Scan for obvious bugs in changes
- Agent #4: Analyze git blame/history for context-based issues
- Scores each issue 0-100 for confidence level
- Filters out issues below 80 confidence threshold
- Outputs review (to terminal by default, or as PR comment with
--commentflag)
Usage:
/code-review [--comment]Options:
--comment: Post the review as a comment on the pull request (default: outputs to terminal only)
Example workflow:
# On a PR branch, run locally (outputs to terminal):
/code-review
# Post review as PR comment:
/code-review --comment
# Claude will:
# - Launch 4 review agents in parallel
# - Score each issue for confidence
# - Output issues ≥80 confidence (to terminal or PR depending on flag)
# - Skip if no high-confidence issues foundFeatures:
- Multiple independent agents for comprehensive review
- Confidence-based scoring reduces false positives (threshold: 80)
- CLAUDE.md compliance checking with explicit guideline verification
- Bug detection focused on changes (not pre-existing issues)
- Historical context analysis via git blame
- Automatic skipping of closed, draft, or already-reviewed PRs
- Links directly to code with full SHA and line ranges
Review comment format:
## Code review
Found 3 issues:
1. Missing error handling for OAuth callback (CLAUDE.md says "Always handle OAuth errors")
https://github.com/owner/repo/blob/abc123.../src/auth.ts#L67-L72
2. Memory leak: OAuth state not cleaned up (bug due to missing cleanup in finally block)
https://github.com/owner/repo/blob/abc123.../src/auth.ts#L88-L95
3. Inconsistent naming pattern (src/conventions/CLAUDE.md says "Use camelCase for functions")
https://github.com/owner/repo/blob/abc123.../src/utils.ts#L23-L28Confidence scoring:
- 0: Not confident, false positive
- 25: Somewhat confident, might be real
- 50: Moderately confident, real but minor
- 75: Highly confident, real and important
- 100: Absolutely certain, definitely real
False positives filtered:
- Pre-existing issues not introduced in PR
- Code that looks like a bug but isn't
- Pedantic nitpicks
- Issues linters will catch
- General quality issues (unless in CLAUDE.md)
- Issues with lint ignore comments
Installation
This plugin is included in the Claude Code repository. The command is automatically available when using Claude Code.
Best Practices
Using `/code-review`
- Maintain clear CLAUDE.md files for better compliance checking
- Trust the 80+ confidence threshold - false positives are filtered
- Run on all non-trivial pull requests
- Review agent findings as a starting point for human review
- Update CLAUDE.md based on recurring review patterns
When to use
- All pull requests with meaningful changes
- PRs touching critical code paths
- PRs from multiple contributors
- PRs where guideline compliance matters
When not to use
- Closed or draft PRs (automatically skipped anyway)
- Trivial automated PRs (automatically skipped)
- Urgent hotfixes requiring immediate merge
- PRs already reviewed (automatically skipped)
Workflow Integration
Standard PR review workflow:
# Create PR with changes
# Run local review (outputs to terminal)
/code-review
# Review the automated feedback
# Make any necessary fixes
# Optionally post as PR comment
/code-review --comment
# Merge when readyAs part of CI/CD:
# Trigger on PR creation or update
# Use --comment flag to post review comments
/code-review --comment
# Skip if review already existsRequirements
- Git repository with GitHub integration
- GitHub CLI (
gh) installed and authenticated - CLAUDE.md files (optional but recommended for guideline checking)
Troubleshooting
Review takes too long
Issue: Agents are slow on large PRs
Solution:
- Normal for large changes - agents run in parallel
- 4 independent agents ensure thoroughness
- Consider splitting large PRs into smaller ones
Too many false positives
Issue: Review flags issues that aren't real
Solution:
- Default threshold is 80 (already filters most false positives)
- Make CLAUDE.md more specific about what matters
- Consider if the flagged issue is actually valid
No review comment posted
Issue: /code-review runs but no comment appears
Solution:
Check if:
- PR is closed (reviews skipped)
- PR is draft (reviews skipped)
- PR is trivial/automated (reviews skipped)
- PR already has review (reviews skipped)
- No issues scored ≥80 (no comment needed)
Link formatting broken
Issue: Code links don't render correctly in GitHub
Solution:
Links must follow this exact format:
https://github.com/owner/repo/blob/[full-sha]/path/file.ext#L[start]-L[end]- Must use full SHA (not abbreviated)
- Must use
#Lnotation - Must include line range with at least 1 line of context
GitHub CLI not working
Issue: gh commands fail
Solution:
- Install GitHub CLI:
brew install gh(macOS) or see GitHub CLI installation - Authenticate:
gh auth login - Verify repository has GitHub remote
Tips
- Write specific CLAUDE.md files: Clear guidelines = better reviews
- Include context in PRs: Helps agents understand intent
- Use confidence scores: Issues ≥80 are usually correct
- Iterate on guidelines: Update CLAUDE.md based on patterns
- Review automatically: Set up as part of PR workflow
- Trust the filtering: Threshold prevents noise
Configuration
Adjusting confidence threshold
The default threshold is 80. To adjust, modify the command file at commands/code-review.md:
Filter out any issues with a score less than 80.Change 80 to your preferred threshold (0-100).
Customizing review focus
Edit commands/code-review.md to add or modify agent tasks:
- Add security-focused agents
- Add performance analysis agents
- Add accessibility checking agents
- Add documentation quality checks
Technical Details
Agent architecture
- 2x CLAUDE.md compliance agents: Redundancy for guideline checks
- 1x bug detector: Focused on obvious bugs in changes only
- 1x history analyzer: Context from git blame and history
- Nx confidence scorers: One per issue for independent scoring
Scoring system
- Each issue independently scored 0-100
- Scoring considers evidence strength and verification
- Threshold (default 80) filters low-confidence issues
- For CLAUDE.md issues: verifies guideline explicitly mentions it
GitHub integration
Uses gh CLI for:
- Viewing PR details and diffs
- Fetching repository data
- Reading git blame and history
- Posting review comments
Author
Boris Cherny ([email protected])
Version
1.0.0
Overview (`plugins/commit-commands/README.md`)
Commit Commands Plugin
Streamline your git workflow with simple commands for committing, pushing, and creating pull requests.
Overview
The Commit Commands Plugin automates common git operations, reducing context switching and manual command execution. Instead of running multiple git commands, use a single slash command to handle your entire workflow.
Commands
`/commit`
Creates a git commit with an automatically generated commit message based on staged and unstaged changes.
What it does:
- Analyzes current git status
- Reviews both staged and unstaged changes
- Examines recent commit messages to match your repository's style
- Drafts an appropriate commit message
- Stages relevant files
- Creates the commit
Usage:
/commitExample workflow:
# Make some changes to your code
# Then simply run:
/commit
# Claude will:
# - Review your changes
# - Stage the files
# - Create a commit with an appropriate message
# - Show you the commit statusFeatures:
- Automatically drafts commit messages that match your repo's style
- Follows conventional commit practices
- Avoids committing files with secrets (.env, credentials.json)
- Includes Claude Code attribution in commit message
`/commit-push-pr`
Complete workflow command that commits, pushes, and creates a pull request in one step.
What it does:
- Creates a new branch (if currently on main)
- Stages and commits changes with an appropriate message
- Pushes the branch to origin
- Creates a pull request using
gh pr create - Provides the PR URL
Usage:
/commit-push-prExample workflow:
# Make your changes
# Then run:
/commit-push-pr
# Claude will:
# - Create a feature branch (if needed)
# - Commit your changes
# - Push to remote
# - Open a PR with summary and test plan
# - Give you the PR URL to reviewFeatures:
- Analyzes all commits in the branch (not just the latest)
- Creates comprehensive PR descriptions with:
- Summary of changes (1-3 bullet points)
- Test plan checklist
- Claude Code attribution
- Handles branch creation automatically
- Uses GitHub CLI (
gh) for PR creation
Requirements:
- GitHub CLI (
gh) must be installed and authenticated - Repository must have a remote named
origin
`/clean_gone`
Cleans up local branches that have been deleted from the remote repository.
What it does:
- Lists all local branches to identify [gone] status
- Identifies and removes worktrees associated with [gone] branches
- Deletes all branches marked as [gone]
- Provides feedback on removed branches
Usage:
/clean_goneExample workflow:
# After PRs are merged and remote branches are deleted
/clean_gone
# Claude will:
# - Find all branches marked as [gone]
# - Remove any associated worktrees
# - Delete the stale local branches
# - Report what was cleaned upFeatures:
- Handles both regular branches and worktree branches
- Safely removes worktrees before deleting branches
- Shows clear feedback about what was removed
- Reports if no cleanup was needed
When to use:
- After merging and deleting remote branches
- When your local branch list is cluttered with stale branches
- During regular repository maintenance
Installation
This plugin is included in the Claude Code repository. The commands are automatically available when using Claude Code.
Best Practices
Using `/commit`
- Review the staged changes before committing
- Let Claude analyze your changes and match your repo's commit style
- Trust the automated message, but verify it's accurate
- Use for routine commits during development
Using `/commit-push-pr`
- Use when you're ready to create a PR
- Ensure all your changes are complete and tested
- Claude will analyze the full branch history for the PR description
- Review the PR description and edit if needed
- Use when you want to minimize context switching
Using `/clean_gone`
- Run periodically to keep your branch list clean
- Especially useful after merging multiple PRs
- Safe to run - only removes branches already deleted remotely
- Helps maintain a tidy local repository
Workflow Integration
Quick commit workflow:
# Write code
/commit
# Continue developmentFeature branch workflow:
# Develop feature across multiple commits
/commit # First commit
# More changes
/commit # Second commit
# Ready to create PR
/commit-push-prMaintenance workflow:
# After several PRs are merged
/clean_gone
# Clean workspace ready for next featureRequirements
- Git must be installed and configured
- For
/commit-push-pr: GitHub CLI (gh) must be installed and authenticated - Repository must be a git repository with a remote
Troubleshooting
`/commit` creates empty commit
Issue: No changes to commit
Solution:
- Ensure you have unstaged or staged changes
- Run
git statusto verify changes exist
`/commit-push-pr` fails to create PR
Issue: gh pr create command fails
Solution:
- Install GitHub CLI:
brew install gh(macOS) or see GitHub CLI installation - Authenticate:
gh auth login - Ensure repository has a GitHub remote
`/clean_gone` doesn't find branches
Issue: No branches marked as [gone]
Solution:
- Run
git fetch --pruneto update remote tracking - Branches must be deleted from the remote to show as [gone]
Tips
- Combine with other tools: Use
/commitduring development, then/commit-push-prwhen ready - Let Claude draft messages: The commit message analysis learns from your repo's style
- Regular cleanup: Run
/clean_goneweekly to maintain a clean branch list - Review before pushing: Always review the commit message and changes before pushing
Author
Anthropic ([email protected])
Version
1.0.0
Overview (`plugins/explanatory-output-style/README.md`)
Explanatory Output Style Plugin
This plugin recreates the deprecated Explanatory output style as a SessionStart
hook.
WARNING: Do not install this plugin unless you are fine with incurring the token
cost of this plugin's additional instructions and output.
What it does
When enabled, this plugin automatically adds instructions at the start of each
session that encourage Claude to:
- Provide educational insights about implementation choices
- Explain codebase patterns and decisions
- Balance task completion with learning opportunities
How it works
The plugin uses a SessionStart hook to inject additional context into every
session. This context instructs Claude to provide brief educational explanations
before and after writing code, formatted as:
`★ Insight ─────────────────────────────────────`
[2-3 key educational points]
`─────────────────────────────────────────────────`Usage
Once installed, the plugin activates automatically at the start of every
session. No additional configuration is needed.
The insights focus on:
- Specific implementation choices for your codebase
- Patterns and conventions in your code
- Trade-offs and design decisions
- Codebase-specific details rather than general programming concepts
Migration from Output Styles
This plugin replaces the deprecated "Explanatory" output style setting. If you
previously used:
{
"outputStyle": "Explanatory"
}You can now achieve the same behavior by installing this plugin instead.
More generally, this SessionStart hook pattern is roughly equivalent to
CLAUDE.md, but it is more flexible and allows for distribution through plugins.
Note: Output styles that involve tasks besides software development, are better
expressed as
subagents, not as
SessionStart hooks. Subagents change the system prompt while SessionStart hooks
add to the default system prompt.
Managing changes
- Disable the plugin - keep the code installed on your device
- Uninstall the plugin - remove the code from your device
- Update the plugin - create a local copy of this plugin to personalize this
plugin- Hint: Ask Claude to read
https://docs.claude.com/en/docs/claude-code/plugins.md and set it up for
you!
- Hint: Ask Claude to read
Overview (`plugins/feature-dev/README.md`)
Feature Development Plugin
A comprehensive, structured workflow for feature development with specialized agents for codebase exploration, architecture design, and quality review.
Overview
The Feature Development Plugin provides a systematic 7-phase approach to building new features. Instead of jumping straight into code, it guides you through understanding the codebase, asking clarifying questions, designing architecture, and ensuring quality—resulting in better-designed features that integrate seamlessly with your existing code.
Philosophy
Building features requires more than just writing code. You need to:
- Understand the codebase before making changes
- Ask questions to clarify ambiguous requirements
- Design thoughtfully before implementing
- Review for quality after building
This plugin embeds these practices into a structured workflow that runs automatically when you use the /feature-dev command.
Command: `/feature-dev`
Launches a guided feature development workflow with 7 distinct phases.
Usage:
/feature-dev Add user authentication with OAuthOr simply:
/feature-devThe command will guide you through the entire process interactively.
The 7-Phase Workflow
Phase 1: Discovery
Goal: Understand what needs to be built
What happens:
- Clarifies the feature request if it's unclear
- Asks what problem you're solving
- Identifies constraints and requirements
- Summarizes understanding and confirms with you
Example:
You: /feature-dev Add caching
Claude: Let me understand what you need...
- What should be cached? (API responses, computed values, etc.)
- What are your performance requirements?
- Do you have a preferred caching solution?Phase 2: Codebase Exploration
Goal: Understand relevant existing code and patterns
What happens:
- Launches 2-3
code-exploreragents in parallel - Each agent explores different aspects (similar features, architecture, UI patterns)
- Agents return comprehensive analyses with key files to read
- Claude reads all identified files to build deep understanding
- Presents comprehensive summary of findings
Agents launched:
- "Find features similar to [feature] and trace implementation"
- "Map the architecture and abstractions for [area]"
- "Analyze current implementation of [related feature]"
Example output:
Found similar features:
- User authentication (src/auth/): Uses JWT tokens, middleware pattern
- Session management (src/session/): Redis-backed, 24hr expiry
- API security (src/api/middleware/): Rate limiting, CORS
Key files to understand:
- src/auth/AuthService.ts:45 - Core authentication logic
- src/middleware/authMiddleware.ts:12 - Request authentication
- src/config/security.ts:8 - Security configurationPhase 3: Clarifying Questions
Goal: Fill in gaps and resolve all ambiguities
What happens:
- Reviews codebase findings and feature request
- Identifies underspecified aspects:
- Edge cases
- Error handling
- Integration points
- Backward compatibility
- Performance needs
- Presents all questions in an organized list
- Waits for your answers before proceeding
Example:
Before designing the architecture, I need to clarify:
1. OAuth provider: Which OAuth providers? (Google, GitHub, custom?)
2. User data: Store OAuth tokens or just user profile?
3. Existing auth: Replace current auth or add alongside?
4. Sessions: Integrate with existing session management?
5. Error handling: How to handle OAuth failures?Critical: This phase ensures nothing is ambiguous before design begins.
Phase 4: Architecture Design
Goal: Design multiple implementation approaches
What happens:
- Launches 2-3
code-architectagents with different focuses:- Minimal changes: Smallest change, maximum reuse
- Clean architecture: Maintainability, elegant abstractions
- Pragmatic balance: Speed + quality
- Reviews all approaches
- Forms opinion on which fits best for this task
- Presents comparison with trade-offs and recommendation
- Asks which approach you prefer
Example output:
I've designed 3 approaches:
Approach 1: Minimal Changes
- Extend existing AuthService with OAuth methods
- Add new OAuth routes to existing auth router
- Minimal refactoring required
Pros: Fast, low risk
Cons: Couples OAuth to existing auth, harder to test
Approach 2: Clean Architecture
- New OAuthService with dedicated interface
- Separate OAuth router and middleware
- Refactor AuthService to use common interface
Pros: Clean separation, testable, maintainable
Cons: More files, more refactoring
Approach 3: Pragmatic Balance
- New OAuthProvider abstraction
- Integrate into existing AuthService
- Minimal refactoring, good boundaries
Pros: Balanced complexity and cleanliness
Cons: Some coupling remains
Recommendation: Approach 3 - gives you clean boundaries without
excessive refactoring, and fits your existing architecture well.
Which approach would you like to use?Phase 5: Implementation
Goal: Build the feature
What happens:
- Waits for explicit approval before starting
- Reads all relevant files identified in previous phases
- Implements following chosen architecture
- Follows codebase conventions strictly
- Writes clean, well-documented code
- Updates todos as progress is made
Notes:
- Implementation only starts after you approve
- Follows patterns discovered in Phase 2
- Uses architecture designed in Phase 4
- Continuously tracks progress
Phase 6: Quality Review
Goal: Ensure code is simple, DRY, elegant, and functionally correct
What happens:
- Launches 3
code-revieweragents in parallel with different focuses:- Simplicity/DRY/Elegance: Code quality and maintainability
- Bugs/Correctness: Functional correctness and logic errors
- Conventions/Abstractions: Project standards and patterns
- Consolidates findings
- Identifies highest severity issues
- Presents findings and asks what you want to do:
- Fix now
- Fix later
- Proceed as-is
- Addresses issues based on your decision
Example output:
Code Review Results:
High Priority Issues:
1. Missing error handling in OAuth callback (src/auth/oauth.ts:67)
2. Memory leak: OAuth state not cleaned up (src/auth/oauth.ts:89)
Medium Priority:
1. Could simplify token refresh logic (src/auth/oauth.ts:120)
2. Consider extracting OAuth config validation
All tests pass. Code follows project conventions.
What would you like to do?Phase 7: Summary
Goal: Document what was accomplished
What happens:
- Marks all todos complete
- Summarizes:
- What was built
- Key decisions made
- Files modified
- Suggested next steps
Example:
Feature Complete: OAuth Authentication
What was built:
- OAuth provider abstraction supporting Google and GitHub
- OAuth routes and middleware integrated with existing auth
- Token refresh and session integration
- Error handling for all OAuth flows
Key decisions:
- Used pragmatic approach with OAuthProvider abstraction
- Integrated with existing session management
- Added OAuth state to prevent CSRF
Files modified:
- src/auth/OAuthProvider.ts (new)
- src/auth/AuthService.ts
- src/routes/auth.ts
- src/middleware/authMiddleware.ts
Suggested next steps:
- Add tests for OAuth flows
- Add more OAuth providers (Microsoft, Apple)
- Update documentationAgents
`code-explorer`
Purpose: Deeply analyzes existing codebase features by tracing execution paths
Focus areas:
- Entry points and call chains
- Data flow and transformations
- Architecture layers and patterns
- Dependencies and integrations
- Implementation details
When triggered:
- Automatically in Phase 2
- Can be invoked manually when exploring code
Output:
- Entry points with file:line references
- Step-by-step execution flow
- Key components and responsibilities
- Architecture insights
- List of essential files to read
`code-architect`
Purpose: Designs feature architectures and implementation blueprints
Focus areas:
- Codebase pattern analysis
- Architecture decisions
- Component design
- Implementation roadmap
- Data flow and build sequence
When triggered:
- Automatically in Phase 4
- Can be invoked manually for architecture design
Output:
- Patterns and conventions found
- Architecture decision with rationale
- Complete component design
- Implementation map with specific files
- Build sequence with phases
`code-reviewer`
Purpose: Reviews code for bugs, quality issues, and project conventions
Focus areas:
- Project guideline compliance (CLAUDE.md)
- Bug detection
- Code quality issues
- Confidence-based filtering (only reports high-confidence issues ≥80)
When triggered:
- Automatically in Phase 6
- Can be invoked manually after writing code
Output:
- Critical issues (confidence 75-100)
- Important issues (confidence 50-74)
- Specific fixes with file:line references
- Project guideline references
Usage Patterns
Full workflow (recommended for new features):
/feature-dev Add rate limiting to API endpointsLet the workflow guide you through all 7 phases.
Manual agent invocation:
Explore a feature:
"Launch code-explorer to trace how authentication works"Design architecture:
"Launch code-architect to design the caching layer"Review code:
"Launch code-reviewer to check my recent changes"Best Practices
- Use the full workflow for complex features: The 7 phases ensure thorough planning
- Answer clarifying questions thoughtfully: Phase 3 prevents future confusion
- Choose architecture deliberately: Phase 4 gives you options for a reason
- Don't skip code review: Phase 6 catches issues before they reach production
- Read the suggested files: Phase 2 identifies key files—read them to understand context
When to Use This Plugin
Use for:
- New features that touch multiple files
- Features requiring architectural decisions
- Complex integrations with existing code
- Features where requirements are somewhat unclear
Don't use for:
- Single-line bug fixes
- Trivial changes
- Well-defined, simple tasks
- Urgent hotfixes
Requirements
- Claude Code installed
- Git repository (for code review)
- Project with existing codebase (workflow assumes existing code to learn from)
Troubleshooting
Agents take too long
Issue: Code exploration or architecture agents are slow
Solution:
- This is normal for large codebases
- Agents run in parallel when possible
- The thoroughness pays off in better understanding
Too many clarifying questions
Issue: Phase 3 asks too many questions
Solution:
- Be more specific in your initial feature request
- Provide context about constraints upfront
- Say "whatever you think is best" if truly no preference
Architecture options overwhelming
Issue: Too many architecture options in Phase 4
Solution:
- Trust the recommendation—it's based on codebase analysis
- If still unsure, ask for more explanation
- Pick the pragmatic option when in doubt
Tips
- Be specific in your feature request: More detail = fewer clarifying questions
- Trust the process: Each phase builds on the previous one
- Review agent outputs: Agents provide valuable insights about your codebase
- Don't skip phases: Each phase serves a purpose
- Use for learning: The exploration phase teaches you about your own codebase
Author
Sid Bidasaria ([email protected])
Version
1.0.0
Overview (`plugins/frontend-design/README.md`)
Frontend Design Plugin
Generates distinctive, production-grade frontend interfaces that avoid generic AI aesthetics.
What It Does
Claude automatically uses this skill for frontend work. Creates production-ready code with:
- Bold aesthetic choices
- Distinctive typography and color palettes
- High-impact animations and visual details
- Context-aware implementation
Usage
"Create a dashboard for a music streaming app"
"Build a landing page for an AI security startup"
"Design a settings panel with dark mode"Claude will choose a clear aesthetic direction and implement production code with meticulous attention to detail.
Learn More
See the Frontend Aesthetics Cookbook for detailed guidance on prompting for high-quality frontend design.
Authors
Prithvi Rajasekaran ([email protected])
Alexander Bricken ([email protected])
Overview (`plugins/hookify/README.md`)
Hookify Plugin
Easily create custom hooks to prevent unwanted behaviors by analyzing conversation patterns or from explicit instructions.
Overview
The hookify plugin makes it simple to create hooks without editing complex hooks.json files. Instead, you create lightweight markdown configuration files that define patterns to watch for and messages to show when those patterns match.
Key features:
- 🎯 Analyze conversations to find unwanted behaviors automatically
- 📝 Simple markdown configuration files with YAML frontmatter
- 🔍 Regex pattern matching for powerful rules
- 🚀 No coding required - just describe the behavior
- 🔄 Easy enable/disable without restarting
Quick Start
1. Create Your First Rule
/hookify Warn me when I use rm -rf commandsThis analyzes your request and creates .claude/hookify.warn-rm.local.md.
2. Test It Immediately
No restart needed! Rules take effect on the very next tool use.
Ask Claude to run a command that should trigger the rule:
Run rm -rf /tmp/testYou should see the warning message immediately!
Usage
Main Command: /hookify
With arguments:
/hookify Don't use console.log in TypeScript filesCreates a rule from your explicit instructions.
Without arguments:
/hookifyAnalyzes recent conversation to find behaviors you've corrected or been frustrated by.
Helper Commands
List all rules:
/hookify:listConfigure rules interactively:
/hookify:configureEnable/disable existing rules through an interactive interface.
Get help:
/hookify:helpRule Configuration Format
Simple Rule (Single Pattern)
.claude/hookify.dangerous-rm.local.md:
---
name: block-dangerous-rm
enabled: true
event: bash
pattern: rm\s+-rf
action: block
---
⚠️ **Dangerous rm command detected!**
This command could delete important files. Please:
- Verify the path is correct
- Consider using a safer approach
- Make sure you have backupsAction field:
warn: Shows warning but allows operation (default)block: Prevents operation from executing (PreToolUse) or stops session (Stop events)
Advanced Rule (Multiple Conditions)
.claude/hookify.sensitive-files.local.md:
---
name: warn-sensitive-files
enabled: true
event: file
action: warn
conditions:
- field: file_path
operator: regex_match
pattern: \.env$|credentials|secrets
- field: new_text
operator: contains
pattern: KEY
---
🔐 **Sensitive file edit detected!**
Ensure credentials are not hardcoded and file is in .gitignore.All conditions must match for the rule to trigger.
Event Types
bash: Triggers on Bash tool commandsfile: Triggers on Edit, Write, MultiEdit toolsstop: Triggers when Claude wants to stop (for completion checks)prompt: Triggers on user prompt submissionall: Triggers on all events
Pattern Syntax
Use Python regex syntax:
| Pattern | Matches | Example |
|---|---|---|
rm\s+-rf |
rm -rf | rm -rf /tmp |
console\.log\( |
console.log( | console.log("test") |
(eval|exec)\( |
eval( or exec( | eval("code") |
\.env$ |
files ending in .env | .env, .env.local |
chmod\s+777 |
chmod 777 | chmod 777 file.txt |
Tips:
- Use
\sfor whitespace - Escape special chars:
\.for literal dot - Use
|for OR:(foo|bar) - Use
.*to match anything - Set
action: blockfor dangerous operations - Set
action: warn(or omit) for informational warnings
Examples
Example 1: Block Dangerous Commands
---
name: block-destructive-ops
enabled: true
event: bash
pattern: rm\s+-rf|dd\s+if=|mkfs|format
action: block
---
🛑 **Destructive operation detected!**
This command can cause data loss. Operation blocked for safety.
Please verify the exact path and use a safer approach.This rule blocks the operation - Claude will not be allowed to execute these commands.
Example 2: Warn About Debug Code
---
name: warn-debug-code
enabled: true
event: file
pattern: console\.log\(|debugger;|print\(
action: warn
---
🐛 **Debug code detected**
Remember to remove debugging statements before committing.This rule warns but allows - Claude sees the message but can still proceed.
Example 3: Require Tests Before Stopping
---
name: require-tests-run
enabled: false
event: stop
action: block
conditions:
- field: transcript
operator: not_contains
pattern: npm test|pytest|cargo test
---
**Tests not detected in transcript!**
Before stopping, please run tests to verify your changes work correctly.This blocks Claude from stopping if no test commands appear in the session transcript. Enable only when you want strict enforcement.
Advanced Usage
Multiple Conditions
Check multiple fields simultaneously:
---
name: api-key-in-typescript
enabled: true
event: file
conditions:
- field: file_path
operator: regex_match
pattern: \.tsx?$
- field: new_text
operator: regex_match
pattern: (API_KEY|SECRET|TOKEN)\s*=\s*["']
---
🔐 **Hardcoded credential in TypeScript!**
Use environment variables instead of hardcoded values.Operators Reference
regex_match: Pattern must match (most common)contains: String must contain patternequals: Exact string matchnot_contains: String must NOT contain patternstarts_with: String starts with patternends_with: String ends with pattern
Field Reference
For bash events:
command: The bash command string
For file events:
file_path: Path to file being editednew_text: New content being added (Edit, Write)old_text: Old content being replaced (Edit only)content: File content (Write only)
For prompt events:
user_prompt: The user's submitted prompt text
For stop events:
- Use general matching on session state
Management
Enable/Disable Rules
Temporarily disable:
Edit the .local.md file and set enabled: false
Re-enable:
Set enabled: true
Or use interactive tool:
/hookify:configureDelete Rules
Simply delete the .local.md file:
rm .claude/hookify.my-rule.local.mdView All Rules
/hookify:listInstallation
This plugin is part of the Claude Code Marketplace. It should be auto-discovered when the marketplace is installed.
Manual testing:
cc --plugin-dir /path/to/hookifyRequirements
- Python 3.7+
- No external dependencies (uses stdlib only)
Troubleshooting
Rule not triggering:
- Check rule file exists in
.claude/directory (in project root, not plugin directory) - Verify
enabled: truein frontmatter - Test regex pattern separately
- Rules should work immediately - no restart needed
- Try
/hookify:listto see if rule is loaded
Import errors:
- Ensure Python 3 is available:
python3 --version - Check hookify plugin is installed
Pattern not matching:
- Test regex:
python3 -c "import re; print(re.search(r'pattern', 'text'))" - Use unquoted patterns in YAML to avoid escaping issues
- Start simple, then add complexity
Hook seems slow:
- Keep patterns simple (avoid complex regex)
- Use specific event types (bash, file) instead of "all"
- Limit number of active rules
Contributing
Found a useful rule pattern? Consider sharing example files via PR!
Future Enhancements
- Severity levels (error/warning/info distinctions)
- Rule templates library
- Interactive pattern builder
- Hook testing utilities
- JSON format support (in addition to markdown)
License
MIT License
Overview (`plugins/learning-output-style/README.md`)
Learning Style Plugin
This plugin combines the unshipped Learning output style with explanatory functionality as a SessionStart hook.
Note: This plugin differs from the original unshipped Learning output style by also incorporating all functionality from the explanatory-output-style plugin, providing both interactive learning and educational insights.
WARNING: Do not install this plugin unless you are fine with incurring the token cost of this plugin's additional instructions and the interactive nature of learning mode.
What it does
When enabled, this plugin automatically adds instructions at the start of each session that encourage Claude to:
- Learning Mode: Engage you in active learning by requesting meaningful code contributions at decision points
- Explanatory Mode: Provide educational insights about implementation choices and codebase patterns
Instead of implementing everything automatically, Claude will:
- Identify opportunities where you can write 5-10 lines of meaningful code
- Focus on business logic and design choices where your input truly matters
- Prepare the context and location for your contribution
- Explain trade-offs and guide your implementation
- Provide educational insights before and after writing code
How it works
The plugin uses a SessionStart hook to inject additional context into every session. This context instructs Claude to adopt an interactive teaching approach where you actively participate in writing key parts of the code.
When Claude requests contributions
Claude will ask you to write code for:
- Business logic with multiple valid approaches
- Error handling strategies
- Algorithm implementation choices
- Data structure decisions
- User experience decisions
- Design patterns and architecture choices
When Claude won't request contributions
Claude will implement directly:
- Boilerplate or repetitive code
- Obvious implementations with no meaningful choices
- Configuration or setup code
- Simple CRUD operations
Example interaction
Claude: I've set up the authentication middleware. The session timeout behavior is a security vs. UX trade-off - should sessions auto-extend on activity, or have a hard timeout?
In auth/middleware.ts, implement the handleSessionTimeout() function to define the timeout behavior.
Consider: auto-extending improves UX but may leave sessions open longer; hard timeouts are more secure but might frustrate active users.
You: [Write 5-10 lines implementing your preferred approach]
Educational insights
In addition to interactive learning, Claude will provide educational insights about implementation choices using this format:
`★ Insight ─────────────────────────────────────`
[2-3 key educational points about the codebase or implementation]
`─────────────────────────────────────────────────`These insights focus on:
- Specific implementation choices for your codebase
- Patterns and conventions in your code
- Trade-offs and design decisions
- Codebase-specific details rather than general programming concepts
Usage
Once installed, the plugin activates automatically at the start of every session. No additional configuration is needed.
Migration from Output Styles
This plugin combines the unshipped "Learning" output style with the deprecated "Explanatory" output style. It provides an interactive learning experience where you actively contribute code at meaningful decision points, while also receiving educational insights about implementation choices.
If you previously used the explanatory-output-style plugin, this learning plugin includes all of that functionality plus interactive learning features.
This SessionStart hook pattern is roughly equivalent to CLAUDE.md, but it is more flexible and allows for distribution through plugins.
Managing changes
- Disable the plugin - keep the code installed on your device
- Uninstall the plugin - remove the code from your device
- Update the plugin - create a local copy of this plugin to personalize it
- Hint: Ask Claude to read https://docs.claude.com/en/docs/claude-code/plugins.md and set it up for you!
Philosophy
Learning by doing is more effective than passive observation. This plugin transforms your interaction with Claude from "watch and learn" to "build and understand," ensuring you develop practical skills through hands-on coding of meaningful logic.
Overview (`plugins/plugin-dev/README.md`)
Plugin Development Toolkit
A comprehensive toolkit for developing Claude Code plugins with expert guidance on hooks, MCP integration, plugin structure, and marketplace publishing.
Overview
The plugin-dev toolkit provides seven specialized skills to help you build high-quality Claude Code plugins:
- Hook Development - Advanced hooks API and event-driven automation
- MCP Integration - Model Context Protocol server integration
- Plugin Structure - Plugin organization and manifest configuration
- Plugin Settings - Configuration patterns using .claude/plugin-name.local.md files
- Command Development - Creating slash commands with frontmatter and arguments
- Agent Development - Creating autonomous agents with AI-assisted generation
- Skill Development - Creating skills with progressive disclosure and strong triggers
Each skill follows best practices with progressive disclosure: lean core documentation, detailed references, working examples, and utility scripts.
Guided Workflow Command
/plugin-dev:create-plugin
A comprehensive, end-to-end workflow command for creating plugins from scratch, similar to the feature-dev workflow.
8-Phase Process:
- Discovery - Understand plugin purpose and requirements
- Component Planning - Determine needed skills, commands, agents, hooks, MCP
- Detailed Design - Specify each component and resolve ambiguities
- Structure Creation - Set up directories and manifest
- Component Implementation - Create each component using AI-assisted agents
- Validation - Run plugin-validator and component-specific checks
- Testing - Verify plugin works in Claude Code
- Documentation - Finalize README and prepare for distribution
Features:
- Asks clarifying questions at each phase
- Loads relevant skills automatically
- Uses agent-creator for AI-assisted agent generation
- Runs validation utilities (validate-agent.sh, validate-hook-schema.sh, etc.)
- Follows plugin-dev's own proven patterns
- Guides through testing and verification
Usage:
/plugin-dev:create-plugin [optional description]
# Examples:
/plugin-dev:create-plugin
/plugin-dev:create-plugin A plugin for managing database migrationsUse this workflow for structured, high-quality plugin development from concept to completion.
Skills
1. Hook Development
Trigger phrases: "create a hook", "add a PreToolUse hook", "validate tool use", "implement prompt-based hooks", "${CLAUDE_PLUGIN_ROOT}", "block dangerous commands"
What it covers:
- Prompt-based hooks (recommended) with LLM decision-making
- Command hooks for deterministic validation
- All hook events: PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification
- Hook output formats and JSON schemas
- Security best practices and input validation
- ${CLAUDE_PLUGIN_ROOT} for portable paths
Resources:
- Core SKILL.md (1,619 words)
- 3 example hook scripts (validate-write, validate-bash, load-context)
- 3 reference docs: patterns, migration, advanced techniques
- 3 utility scripts: validate-hook-schema.sh, test-hook.sh, hook-linter.sh
Use when: Creating event-driven automation, validating operations, or enforcing policies in your plugin.
2. MCP Integration
Trigger phrases: "add MCP server", "integrate MCP", "configure .mcp.json", "Model Context Protocol", "stdio/SSE/HTTP server", "connect external service"
What it covers:
- MCP server configuration (.mcp.json vs plugin.json)
- All server types: stdio (local), SSE (hosted/OAuth), HTTP (REST), WebSocket (real-time)
- Environment variable expansion (${CLAUDE_PLUGIN_ROOT}, user vars)
- MCP tool naming and usage in commands/agents
- Authentication patterns: OAuth, tokens, env vars
- Integration patterns and performance optimization
Resources:
- Core SKILL.md (1,666 words)
- 3 example configurations (stdio, SSE, HTTP)
- 3 reference docs: server-types (~3,200w), authentication (~2,800w), tool-usage (~2,600w)
Use when: Integrating external services, APIs, databases, or tools into your plugin.
3. Plugin Structure
Trigger phrases: "plugin structure", "plugin.json manifest", "auto-discovery", "component organization", "plugin directory layout"
What it covers:
- Standard plugin directory structure and auto-discovery
- plugin.json manifest format and all fields
- Component organization (commands, agents, skills, hooks)
- ${CLAUDE_PLUGIN_ROOT} usage throughout
- File naming conventions and best practices
- Minimal, standard, and advanced plugin patterns
Resources:
- Core SKILL.md (1,619 words)
- 3 example structures (minimal, standard, advanced)
- 2 reference docs: component-patterns, manifest-reference
Use when: Starting a new plugin, organizing components, or configuring the plugin manifest.
4. Plugin Settings
Trigger phrases: "plugin settings", "store plugin configuration", ".local.md files", "plugin state files", "read YAML frontmatter", "per-project plugin settings"
What it covers:
- .claude/plugin-name.local.md pattern for configuration
- YAML frontmatter + markdown body structure
- Parsing techniques for bash scripts (sed, awk, grep patterns)
- Temporarily active hooks (flag files and quick-exit)
- Real-world examples from multi-agent-swarm and ralph-wiggum plugins
- Atomic file updates and validation
- Gitignore and lifecycle management
Resources:
- Core SKILL.md (1,623 words)
- 3 examples (read-settings hook, create-settings command, templates)
- 2 reference docs: parsing-techniques, real-world-examples
- 2 utility scripts: validate-settings.sh, parse-frontmatter.sh
Use when: Making plugins configurable, storing per-project state, or implementing user preferences.
5. Command Development
Trigger phrases: "create a slash command", "add a command", "command frontmatter", "define command arguments", "organize commands"
What it covers:
- Slash command structure and markdown format
- YAML frontmatter fields (description, argument-hint, allowed-tools)
- Dynamic arguments and file references
- Bash execution for context
- Command organization and namespacing
- Best practices for command development
Resources:
- Core SKILL.md (1,535 words)
- Examples and reference documentation
- Command organization patterns
Use when: Creating slash commands, defining command arguments, or organizing plugin commands.
6. Agent Development
Trigger phrases: "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "autonomous agent"
What it covers:
- Agent file structure (YAML frontmatter + system prompt)
- All frontmatter fields (name, description, model, color, tools)
- Description format with
blocks for reliable triggering - System prompt design patterns (analysis, generation, validation, orchestration)
- AI-assisted agent generation using Claude Code's proven prompt
- Validation rules and best practices
- Complete production-ready agent examples
Resources:
- Core SKILL.md (1,438 words)
- 2 examples: agent-creation-prompt (AI-assisted workflow), complete-agent-examples (4 full agents)
- 3 reference docs: agent-creation-system-prompt (from Claude Code), system-prompt-design (~4,000w), triggering-examples (~2,500w)
- 1 utility script: validate-agent.sh
Use when: Creating autonomous agents, defining agent behavior, or implementing AI-assisted agent generation.
7. Skill Development
Trigger phrases: "create a skill", "add a skill to plugin", "write a new skill", "improve skill description", "organize skill content"
What it covers:
- Skill structure (SKILL.md with YAML frontmatter)
- Progressive disclosure principle (metadata → SKILL.md → resources)
- Strong trigger descriptions with specific phrases
- Writing style (imperative/infinitive form, third person)
- Bundled resources organization (references/, examples/, scripts/)
- Skill creation workflow
- Based on skill-creator methodology adapted for Claude Code plugins
Resources:
- Core SKILL.md (1,232 words)
- References: skill-creator methodology, plugin-dev patterns
- Examples: Study plugin-dev's own skills as templates
Use when: Creating new skills for plugins or improving existing skill quality.
Installation
Install from claude-code-marketplace:
/plugin install plugin-dev@claude-code-marketplaceOr for development, use directly:
cc --plugin-dir /path/to/plugin-devQuick Start
Creating Your First Plugin
Plan your plugin structure:
- Ask: "What's the best directory structure for a plugin with commands and MCP integration?"
- The plugin-structure skill will guide you
Add MCP integration (if needed):
- Ask: "How do I add an MCP server for database access?"
- The mcp-integration skill provides examples and patterns
Implement hooks (if needed):
- Ask: "Create a PreToolUse hook that validates file writes"
- The hook-development skill gives working examples and utilities
Development Workflow
The plugin-dev toolkit supports your entire plugin development lifecycle:
┌─────────────────────┐
│ Design Structure │ → plugin-structure skill
│ (manifest, layout) │
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ Add Components │
│ (commands, agents, │ → All skills provide guidance
│ skills, hooks) │
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ Integrate Services │ → mcp-integration skill
│ (MCP servers) │
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ Add Automation │ → hook-development skill
│ (hooks, validation)│ + utility scripts
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ Test & Validate │ → hook-development utilities
│ │ validate-hook-schema.sh
└──────────┬──────────┘ test-hook.sh
│ hook-linter.shFeatures
Progressive Disclosure
Each skill uses a three-level disclosure system:
- Metadata (always loaded): Concise descriptions with strong triggers
- Core SKILL.md (when triggered): Essential API reference (~1,500-2,000 words)
- References/Examples (as needed): Detailed guides, patterns, and working code
This keeps Claude Code's context focused while providing deep knowledge when needed.
Utility Scripts
The hook-development skill includes production-ready utilities:
# Validate hooks.json structure
./validate-hook-schema.sh hooks/hooks.json
# Test hooks before deployment
./test-hook.sh my-hook.sh test-input.json
# Lint hook scripts for best practices
./hook-linter.sh my-hook.shWorking Examples
Every skill provides working examples:
- Hook Development: 3 complete hook scripts (bash, write validation, context loading)
- MCP Integration: 3 server configurations (stdio, SSE, HTTP)
- Plugin Structure: 3 plugin layouts (minimal, standard, advanced)
- Plugin Settings: 3 examples (read-settings hook, create-settings command, templates)
- Command Development: 10 complete command examples (review, test, deploy, docs, etc.)
Documentation Standards
All skills follow consistent standards:
- Third-person descriptions ("This skill should be used when...")
- Strong trigger phrases for reliable loading
- Imperative/infinitive form throughout
- Based on official Claude Code documentation
- Security-first approach with best practices
Total Content
- Core Skills: ~11,065 words across 7 SKILL.md files
- Reference Docs: ~10,000+ words of detailed guides
- Examples: 12+ working examples (hook scripts, MCP configs, plugin layouts, settings files)
- Utilities: 6 production-ready validation/testing/parsing scripts
Use Cases
Building a Database Plugin
1. "What's the structure for a plugin with MCP integration?"
→ plugin-structure skill provides layout
2. "How do I configure an stdio MCP server for PostgreSQL?"
→ mcp-integration skill shows configuration
3. "Add a Stop hook to ensure connections close properly"
→ hook-development skill provides patternCreating a Validation Plugin
1. "Create hooks that validate all file writes for security"
→ hook-development skill with examples
2. "Test my hooks before deploying"
→ Use validate-hook-schema.sh and test-hook.sh
3. "Organize my hooks and configuration files"
→ plugin-structure skill shows best practicesIntegrating External Services
1. "Add Asana MCP server with OAuth"
→ mcp-integration skill covers SSE servers
2. "Use Asana tools in my commands"
→ mcp-integration tool-usage reference
3. "Structure my plugin with commands and MCP"
→ plugin-structure skill provides patternsBest Practices
All skills emphasize:
✅ Security First
- Input validation in hooks
- HTTPS/WSS for MCP servers
- Environment variables for credentials
- Principle of least privilege
✅ Portability
- Use ${CLAUDE_PLUGIN_ROOT} everywhere
- Relative paths only
- Environment variable substitution
✅ Testing
- Validate configurations before deployment
- Test hooks with sample inputs
- Use debug mode (
claude --debug)
✅ Documentation
- Clear README files
- Documented environment variables
- Usage examples
Contributing
This plugin is part of the claude-code-marketplace. To contribute improvements:
- Fork the marketplace repository
- Make changes to plugin-dev/
- Test locally with
cc --plugin-dir - Create PR following marketplace-publishing guidelines
Version
0.1.0 - Initial release with seven comprehensive skills and three validation agents
Author
Daisy Hollman ([email protected])
License
MIT License - See repository for details
Note: This toolkit is designed to help you build high-quality plugins. The skills load automatically when you ask relevant questions, providing expert guidance exactly when you need it.
Overview (`plugins/pr-review-toolkit/README.md`)
PR Review Toolkit
A comprehensive collection of specialized agents for thorough pull request review, covering code comments, test coverage, error handling, type design, code quality, and code simplification.
Overview
This plugin bundles 6 expert review agents that each focus on a specific aspect of code quality. Use them individually for targeted reviews or together for comprehensive PR analysis.
Agents
1. comment-analyzer
Focus: Code comment accuracy and maintainability
Analyzes:
- Comment accuracy vs actual code
- Documentation completeness
- Comment rot and technical debt
- Misleading or outdated comments
When to use:
- After adding documentation
- Before finalizing PRs with comment changes
- When reviewing existing comments
Triggers:
"Check if the comments are accurate"
"Review the documentation I added"
"Analyze comments for technical debt"2. pr-test-analyzer
Focus: Test coverage quality and completeness
Analyzes:
- Behavioral vs line coverage
- Critical gaps in test coverage
- Test quality and resilience
- Edge cases and error conditions
When to use:
- After creating a PR
- When adding new functionality
- To verify test thoroughness
Triggers:
"Check if the tests are thorough"
"Review test coverage for this PR"
"Are there any critical test gaps?"3. silent-failure-hunter
Focus: Error handling and silent failures
Analyzes:
- Silent failures in catch blocks
- Inadequate error handling
- Inappropriate fallback behavior
- Missing error logging
When to use:
- After implementing error handling
- When reviewing try/catch blocks
- Before finalizing PRs with error handling
Triggers:
"Review the error handling"
"Check for silent failures"
"Analyze catch blocks in this PR"4. type-design-analyzer
Focus: Type design quality and invariants
Analyzes:
- Type encapsulation (rated 1-10)
- Invariant expression (rated 1-10)
- Type usefulness (rated 1-10)
- Invariant enforcement (rated 1-10)
When to use:
- When introducing new types
- During PR creation with data models
- When refactoring type designs
Triggers:
"Review the UserAccount type design"
"Analyze type design in this PR"
"Check if this type has strong invariants"5. code-reviewer
Focus: General code review for project guidelines
Analyzes:
- CLAUDE.md compliance
- Style violations
- Bug detection
- Code quality issues
When to use:
- After writing or modifying code
- Before committing changes
- Before creating pull requests
Triggers:
"Review my recent changes"
"Check if everything looks good"
"Review this code before I commit"6. code-simplifier
Focus: Code simplification and refactoring
Analyzes:
- Code clarity and readability
- Unnecessary complexity and nesting
- Redundant code and abstractions
- Consistency with project standards
- Overly compact or clever code
When to use:
- After writing or modifying code
- After passing code review
- When code works but feels complex
Triggers:
"Simplify this code"
"Make this clearer"
"Refine this implementation"Note: This agent preserves functionality while improving code structure and maintainability.
Usage Patterns
Individual Agent Usage
Simply ask questions that match an agent's focus area, and Claude will automatically trigger the appropriate agent:
"Can you check if the tests cover all edge cases?"
→ Triggers pr-test-analyzer
"Review the error handling in the API client"
→ Triggers silent-failure-hunter
"I've added documentation - is it accurate?"
→ Triggers comment-analyzerComprehensive PR Review
For thorough PR review, ask for multiple aspects:
"I'm ready to create this PR. Please:
1. Review test coverage
2. Check for silent failures
3. Verify code comments are accurate
4. Review any new types
5. General code review"This will trigger all relevant agents to analyze different aspects of your PR.
Proactive Review
Claude may proactively use these agents based on context:
- After writing code → code-reviewer
- After adding docs → comment-analyzer
- Before creating PR → Multiple agents as appropriate
- After adding types → type-design-analyzer
Installation
Install from your personal marketplace:
/plugins
# Find "pr-review-toolkit"
# InstallOr add manually to settings if needed.
Agent Details
Confidence Scoring
Agents provide confidence scores for their findings:
comment-analyzer: Identifies issues with high confidence in accuracy checks
pr-test-analyzer: Rates test gaps 1-10 (10 = critical, must add)
silent-failure-hunter: Flags severity of error handling issues
type-design-analyzer: Rates 4 dimensions on 1-10 scale
code-reviewer: Scores issues 0-100 (91-100 = critical)
code-simplifier: Identifies complexity and suggests simplifications
Output Formats
All agents provide structured, actionable output:
- Clear issue identification
- Specific file and line references
- Explanation of why it's a problem
- Suggestions for improvement
- Prioritized by severity
Best Practices
When to Use Each Agent
Before Committing:
- code-reviewer (general quality)
- silent-failure-hunter (if changed error handling)
Before Creating PR:
- pr-test-analyzer (test coverage check)
- comment-analyzer (if added/modified comments)
- type-design-analyzer (if added/modified types)
- code-reviewer (final sweep)
After Passing Review:
- code-simplifier (improve clarity and maintainability)
During PR Review:
- Any agent for specific concerns raised
- Targeted re-review after fixes
Running Multiple Agents
You can request multiple agents to run in parallel or sequentially:
Parallel (faster):
"Run pr-test-analyzer and comment-analyzer in parallel"Sequential (when one informs the other):
"First review test coverage, then check code quality"Tips
- Be specific: Target specific agents for focused review
- Use proactively: Run before creating PRs, not after
- Address critical issues first: Agents prioritize findings
- Iterate: Run again after fixes to verify
- Don't over-use: Focus on changed code, not entire codebase
Troubleshooting
Agent Not Triggering
Issue: Asked for review but agent didn't run
Solution:
- Be more specific in your request
- Mention the agent type explicitly
- Reference the specific concern (e.g., "test coverage")
Agent Analyzing Wrong Files
Issue: Agent reviewing too much or wrong files
Solution:
- Specify which files to focus on
- Reference the PR number or branch
- Mention "recent changes" or "git diff"
Integration with Workflow
This plugin works great with:
- build-validator: Run build/tests before review
- Project-specific agents: Combine with your custom agents
Recommended workflow:
- Write code → code-reviewer
- Fix issues → silent-failure-hunter (if error handling)
- Add tests → pr-test-analyzer
- Document → comment-analyzer
- Review passes → code-simplifier (polish)
- Create PR
Contributing
Found issues or have suggestions? These agents are maintained in:
- User agents:
~/.claude/agents/ - Project agents:
.claude/agents/in claude-cli-internal
License
MIT
Author
Daisy ([email protected])
Quick Start: Just ask for review and the right agent will trigger automatically!
Overview (`plugins/ralph-wiggum/README.md`)
Ralph Wiggum Plugin
Implementation of the Ralph Wiggum technique for iterative, self-referential AI development loops in Claude Code.
What is Ralph?
Ralph is a development methodology based on continuous AI agent loops. As Geoffrey Huntley describes it: "Ralph is a Bash loop" - a simple while true that repeatedly feeds an AI agent a prompt file, allowing it to iteratively improve its work until completion.
The technique is named after Ralph Wiggum from The Simpsons, embodying the philosophy of persistent iteration despite setbacks.
Core Concept
This plugin implements Ralph using a Stop hook that intercepts Claude's exit attempts:
# You run ONCE:
/ralph-loop "Your task description" --completion-promise "DONE"
# Then Claude Code automatically:
# 1. Works on the task
# 2. Tries to exit
# 3. Stop hook blocks exit
# 4. Stop hook feeds the SAME prompt back
# 5. Repeat until completionThe loop happens inside your current session - you don't need external bash loops. The Stop hook in hooks/stop-hook.sh creates the self-referential feedback loop by blocking normal session exit.
This creates a self-referential feedback loop where:
- The prompt never changes between iterations
- Claude's previous work persists in files
- Each iteration sees modified files and git history
- Claude autonomously improves by reading its own past work in files
Quick Start
/ralph-loop "Build a REST API for todos. Requirements: CRUD operations, input validation, tests. Output <promise>COMPLETE</promise> when done." --completion-promise "COMPLETE" --max-iterations 50Claude will:
- Implement the API iteratively
- Run tests and see failures
- Fix bugs based on test output
- Iterate until all requirements met
- Output the completion promise when done
Commands
/ralph-loop
Start a Ralph loop in your current session.
Usage:
/ralph-loop "<prompt>" --max-iterations <n> --completion-promise "<text>"Options:
--max-iterations <n>- Stop after N iterations (default: unlimited)--completion-promise <text>- Phrase that signals completion
/cancel-ralph
Cancel the active Ralph loop.
Usage:
/cancel-ralphPrompt Writing Best Practices
1. Clear Completion Criteria
❌ Bad: "Build a todo API and make it good."
✅ Good:
Build a REST API for todos.
When complete:
- All CRUD endpoints working
- Input validation in place
- Tests passing (coverage > 80%)
- README with API docs
- Output: <promise>COMPLETE</promise>2. Incremental Goals
❌ Bad: "Create a complete e-commerce platform."
✅ Good:
Phase 1: User authentication (JWT, tests)
Phase 2: Product catalog (list/search, tests)
Phase 3: Shopping cart (add/remove, tests)
Output <promise>COMPLETE</promise> when all phases done.3. Self-Correction
❌ Bad: "Write code for feature X."
✅ Good:
Implement feature X following TDD:
1. Write failing tests
2. Implement feature
3. Run tests
4. If any fail, debug and fix
5. Refactor if needed
6. Repeat until all green
7. Output: <promise>COMPLETE</promise>4. Escape Hatches
Always use --max-iterations as a safety net to prevent infinite loops on impossible tasks:
# Recommended: Always set a reasonable iteration limit
/ralph-loop "Try to implement feature X" --max-iterations 20
# In your prompt, include what to do if stuck:
# "After 15 iterations, if not complete:
# - Document what's blocking progress
# - List what was attempted
# - Suggest alternative approaches"Note: The --completion-promise uses exact string matching, so you cannot use it for multiple completion conditions (like "SUCCESS" vs "BLOCKED"). Always rely on --max-iterations as your primary safety mechanism.
Philosophy
Ralph embodies several key principles:
1. Iteration > Perfection
Don't aim for perfect on first try. Let the loop refine the work.
2. Failures Are Data
"Deterministically bad" means failures are predictable and informative. Use them to tune prompts.
3. Operator Skill Matters
Success depends on writing good prompts, not just having a good model.
4. Persistence Wins
Keep trying until success. The loop handles retry logic automatically.
When to Use Ralph
Good for:
- Well-defined tasks with clear success criteria
- Tasks requiring iteration and refinement (e.g., getting tests to pass)
- Greenfield projects where you can walk away
- Tasks with automatic verification (tests, linters)
Not good for:
- Tasks requiring human judgment or design decisions
- One-shot operations
- Tasks with unclear success criteria
- Production debugging (use targeted debugging instead)
Real-World Results
- Successfully generated 6 repositories overnight in Y Combinator hackathon testing
- One $50k contract completed for $297 in API costs
- Created entire programming language ("cursed") over 3 months using this approach
Learn More
- Original technique: https://ghuntley.com/ralph/
- Ralph Orchestrator: https://github.com/mikeyobrien/ralph-orchestrator
For Help
Run /help in Claude Code for detailed command reference and examples.
Overview (`plugins/security-guidance/README.md`)
security-guidance
Security review for Claude-generated code. Three layers:
- Pattern warnings — instant regex-based reminders on
Edit/Writefor ~25 known-dangerous patterns (yaml.load,torch.load(weights_only=False),pickle.loadon untrusted data, rawinnerHTML, hardcoded secrets, etc.). - LLM diff review — when Claude finishes a turn, the plugin sends the diff to a fast LLM call (Opus 4.7 by default) and feeds high-severity findings back to Claude so it can fix them before you see the response.
- Agentic commit review — on
git commit, an SDK-driven reviewer reads related files (Read/Grep/Glob) to trace data flow across the codebase, catching multi-file vulnerabilities pattern matching misses (IDOR, auth bypass, cross-file SSRF).
Findings cover common web-vulnerability classes — injection, XSS, SSRF, hardcoded secrets, IDOR, auth bypass, unsafe deserialization, and path traversal among others.
Install
/plugin install security-guidance@claude-plugins-officialMarketplace ships enabled by default in Claude Code — no setup beyond having the CLI itself.
Prerequisites
- Claude Code CLI ≥ v2.1.144
- Python 3.8+ on
PATH(python3,python, orpy -3— the plugin picks the first that works) - A working API path (subscription, API key, or 3P provider config)
Configuration
All configuration is via environment variables. None are required for default behavior.
Selecting a model
# 1P / gateway: a canonical model id
SECURITY_REVIEW_MODEL=claude-opus-4-7 # default
# Bedrock: use the inference-profile id
SECURITY_REVIEW_MODEL=us.anthropic.claude-opus-4-7
# Vertex: use the Vertex date-tag form
SECURITY_REVIEW_MODEL=claude-opus-4-7@20260218SECURITY_REVIEW_MODEL controls the LLM diff review. SG_AGENTIC_MODEL (same syntax) controls the agentic commit reviewer; defaults to the same model.
Enabling/disabling layers
| Variable | Default | What it does |
|---|---|---|
SECURITY_GUIDANCE_DISABLE=1 |
unset | Kill switch — disables the entire plugin |
ENABLE_PATTERN_RULES=0 |
on | Disable layer 1 (regex pattern warnings) |
ENABLE_CODE_SECURITY_REVIEW=0 |
on | Disable all LLM reviews (Stop hook + commit/push) |
ENABLE_STOP_REVIEW=0 |
on | Disable only the Stop-hook diff review, keeping commit/push reviews. Useful for multi-agent / shared-worktree setups where another agent can move HEAD between a worker's turns |
ENABLE_COMMIT_REVIEW=0 |
on | Disable layer 3 (agentic commit review) |
Higher-recall mode
SG_DUAL_OR=on # default offRuns two parallel review calls and unions the findings. Catches a few percentage points more vulnerabilities in our testing, at roughly 2× the API cost per review. Most users don't need it.
Org-specific policies
Drop a claude-security-guidance.md in any of:
~/.claude/claude-security-guidance.md— user-wide rules/.claude/claude-security-guidance.md— project rules, intended to be committed/.claude/claude-security-guidance.local.md— local overrides, intended to be.gitignore'd
All three are loaded and concatenated into the LLM diff review's prompt in the order user → project → project-local. If the combined size exceeds the 8 KB prompt budget, the tail is truncated, so user-wide rules are kept and project-local rules are dropped first. The agentic commit reviewer (layer 3) does not currently read this file. Example:
# Acme security rules
- All SELECTs against the `customers` or `orders` tables MUST go through `db.replica`,
never `db.primary`. Primary is for writes only.
- Background jobs must not use the user-context auth token; they get
service-account creds from `jobs.get_service_account()`.
- Calls to `requests.get(url)` with a user-controlled `url` need
the SSRF-allowlist wrapper at `acme.net.safe_request`.Built-in rules cover common web-vulnerability classes without it — claude-security-guidance.md is for things specific to your codebase that the model can't infer.
Privacy and data handling
The plugin sends data to a model endpoint to perform its reviews. Specifically, each Stop-hook diff review transmits the changed file paths, the diff hunks, and the relevant file contents in the diff; each agentic commit review additionally transmits any files the reviewer pulls in via Read/Grep/Glob while tracing data flow. Your claude-security-guidance.md contents (user, project, and local) are appended to the prompt on every review, so don't put secrets in it.
Where that data goes depends on your Claude Code configuration:
- Default (Anthropic API / subscription): sent to
api.anthropic.comand handled under Anthropic's Commercial Terms and Privacy Policy. - LLM gateway (
ANTHROPIC_BASE_URLset): sent to your gateway URL instead. The gateway operator's terms apply. - 3rd-party providers (Bedrock / Vertex / Foundry / Mantle): sent to your configured provider endpoint. The provider's data-handling terms apply (e.g., AWS / GCP / Azure).
The plugin writes its own debug log to ~/.claude/security/log.txt (override with SECURITY_GUIDANCE_DEBUG_LOG). The log contains diffstate metadata and finding categories — no full file contents or model prompts — and rotates at 1 MB. Nothing is uploaded.
Limitations
This is a best-effort assistive tool, not a guarantee. Treat findings as suggestions, not as a substitute for human code review, SAST/DAST, dependency scanning, or pen-testing. The reviewer can miss vulnerabilities, produce false positives, and may behave differently across codebases, languages, and model versions. No warranty is provided — use is subject to Anthropic's Commercial Terms.
Troubleshooting
Plugin doesn't seem to fire — check that ~/.claude/claude-security-guidance.md (or hook activity) shows in debug logs. Run Claude Code with --debug-file /tmp/claude/debug.txt and grep for security_reminder_hook. The plugin also writes its own log to ~/.claude/security/log.txt.
Review never finds anything — verify your API path works. On 3P providers, check SECURITY_REVIEW_MODEL is set to a provider-specific id (not a bare claude-opus-4-7). On LLM gateways, check the gateway's logs for POST /v1/messages traffic from the plugin.
Too many false positives — drop SECURITY_REVIEW_MODEL to a cheaper model (claude-sonnet-4-6) and re-evaluate; if precision is the priority, stay on Opus 4.7.
Want to silence a specific finding — add a comment to the line explaining why it's safe; the LLM reviewer treats inline justifications as exclusions. For systemic exclusions, document them in your claude-security-guidance.md.
Reporting issues
Open an issue on the security-guidance plugin repo with:
- The Claude Code CLI version (
claude --version) - Provider setup (1P / Bedrock / Vertex / LLM gateway / etc.)
- A minimal repro diff
- The relevant section of
~/.claude/security/log.txt
Overview (`examples/gateway/aws/README.md`)
Claude apps gateway on AWS
Reference deployment artifacts for running Claude apps gateway on AWS with
Amazon Bedrock as the upstream: ECS on Fargate or EKS, Amazon RDS for
PostgreSQL, AWS Secrets Manager, and IAM-role auth to Bedrock.
These files are provided as a working example rather than a supported production
deployment. Adapt them to your own environment.
- Walkthrough: https://code.claude.com/docs/en/claude-apps-gateway-on-aws
- Related: AWS-maintained samples for various customer environments at
https://github.com/aws-samples/anthropic-on-aws/tree/main/claude-apps-gateway
| File | Purpose |
|---|---|
setup.sh |
Scripts the walkthrough end to end via the aws CLI |
Dockerfile |
Runtime image for the claude gateway binary (bakes in gateway.yaml) |
gateway.yaml.example |
Gateway config template, AWS-shaped (Bedrock upstream, Okta IdP) |
terraform/ |
Provisions the full architecture (two-pass apply — see terraform/README.md) |
Overview (`examples/gateway/gcp/README.md`)
Claude Gateway on Google Cloud
Reference deployment artifacts for running Claude Gateway on GCP with Agent
Platform (formerly Vertex AI) as the upstream: Cloud Run or GKE, Cloud SQL for
PostgreSQL, Secret Manager, and service-account auth to Agent Platform.
These files are provided as a working example rather than a supported production
deployment. Adapt them to your own environment.
| File | Purpose |
|---|---|
setup.sh |
Scripts the walkthrough end to end via gcloud |
Dockerfile |
Runtime image for the claude gateway binary |
gateway.yaml.example |
Gateway config template, GCP-shaped (Agent Platform upstream, Google Workspace IdP) |
terraform/ |
Provisions the full architecture (two-pass apply — see terraform/README.md) |
Overview (`examples/gateway/aws/terraform/README.md`)
Claude apps gateway — Terraform (ECS Fargate)
Terraform equivalent of ../setup.sh. Lets end-users provision and manage
the gateway with terraform apply. Covers the same scope (walkthrough §1–7,
ECS track): security groups → task + execution IAM roles → ECR repository →
private-subnet RDS for PostgreSQL → Secrets Manager secrets → ECS Fargate
service behind an internal ALB. The VPC and private subnets are walkthrough
prerequisites, passed in as variables — unlike the GCP example, no network is
created here.
Files
| File | Purpose |
|---|---|
versions.tf |
Provider pins (aws, random) |
variables.tf |
All inputs (defaults match setup.sh's) |
main.tf |
Resources |
outputs.tf |
ALB DNS name + zone ID, image, roles, DB endpoint |
terraform.tfvars.example |
Copy to terraform.tfvars and edit |
Prerequisites
../gateway.yamlcreated and FULLY filled in — copy the template first:cp ../gateway.yaml.example ../gateway.yaml, then replace everyREPLACE_ME
(Terraform reads this file and enforces noREPLACE_MEvia a precondition).
Unlike the GCP example there is no placeholder-first-pass: the config is
baked into the image, andpublic_urlis your own internal hostname,
which you choose up front (you already hold its ACM certificate).gateway.yamlis gitignored; the committed template isgateway.yaml.example.- The prebuilt linux-x64
claudebinary at../claude— the Claude Code
release binary, which includes thegatewaysubcommand (see the
walkthrough).
See../setup.sh'sDIST_URL/DIST_SHA256download path for a
checksum-verified fetch. - A VPC with two+ private subnets in different AZs and NAT egress, an ACM
certificate for your internal gateway hostname, and Bedrock model access
enabled in the console (cross-regionus.anthropic.*profiles need it in each
region the profile spans), with the one-time use case form submitted. - A remote backend for shared use (see below). State holds secrets — never commit it.
Deploy
Terraform creates the ECR repository but does not build/push the image, so
the apply is two passes: a targeted apply to create the repo, then build/push,
then the full apply.
/* Detailed source-code truncated for AI context efficiency. */Set in terraform.tfvars:
region,vpc_id,private_subnet_ids,corporate_cidracm_certificate_arn— the certificate for your internal gateway hostname
(gateway.yaml'spublic_urlhost), served by the ALB's HTTPS listenerimage_tag(after building/pushing — step 2 above). The repo enforces
immutable tags, so agateway.yamledit means a rebuild under a new
tag and animage_tagbump (../setup.shautomates this by tagging<version>-cfg<sha8-of-gateway.yaml>)oidc_client_secret— required (the ECS tasks injectlatestof this
secret at start; with no version they fail withResourceInitializationError). Terraform creates the secret + version from it.
Tear down
Tear down a trial with terraform destroy: set deletion_protection = false,
run terraform apply to record that on RDS and the ALB (and to flip RDS toskip_final_snapshot — the provider checks the value in state, not config,
so destroy would still refuse otherwise), then terraform destroy.
The same switch drives the Secrets Manager recovery window: the three secrets
have fixed names, and a secret deleted with the default 30-day recovery
window keeps its name reserved — a later terraform apply would fail with a
name conflict until the window elapses. With deletion_protection = false the
destroy deletes them immediately (recovery_window_in_days = 0). If you
destroyed a deployment that still had deletion_protection = true (or tore
down an older copy of this module), clear the scheduled deletions before
re-applying:
for s in gateway-postgres-url gateway-jwt-secret gateway-oidc-client-secret; do
aws secretsmanager delete-secret --secret-id "$s" --force-delete-without-recovery
doneGuard rails
Tuned so accidental deletion is hard but greenfield teardown stays easy:
deletion_protection = true(variable, default true) on RDS and the ALB —
blocks accidental deletion; setfalsewhen you intend toterraform destroy.
The same switch controls RDSskip_final_snapshot, so a protected instance
always leaves a final snapshot.- ECR tags are immutable and scanned on push — a deployed tag can never
be silently re-pointed at different bytes. For production, also restrict push
rights on the repo to your CI / image-promotion pipeline rather than operator
credentials. - The IAM roles carry only the walkthrough's least-privilege documents: Bedrock
invoke on the Anthropic model ARNs (task role) andsecretsmanager:GetSecretValue
on exactly the three secrets this module creates (by ARN) plus the AWS-managed
ECS execution policy (execution role). Inline policies are scoped to these
roles, so nothing else in the account is touched. - TLS everywhere it terminates: the ALB listener pins
ELBSecurityPolicy-TLS13-1-2-2021-06(no TLS 1.0/1.1), and the store
connection usessslmode=verify-fullagainst the RDS CA bundle baked into
the image, withrds.force_ssl=1enforcing TLS server-side.
Private access
The ALB is internal with ip_address_type = "ipv4" (a dual-stack internal
ALB publishes public-range AAAA records, which the CLI's /login
private-network check rejects), and its security group admits onlycorporate_cidr on 443. Reaching it from on-prem requires your existing
routing into the VPC (Direct Connect / VPN) — operator / network-team-owned
plumbing this module does not create.
After the apply, give developers a privately resolvable hostname: in a Route 53
private hosted zone, alias the host of gateway.yaml's public_url to the ALB
(alb_dns_name / alb_zone_id outputs). The ALB's own *.elb.amazonaws.com
name can't carry your ACM certificate, so use your own name.
The tasks run in the private subnets with no public IP; all egress (Bedrock,
the IdP, Secrets Manager, ECR, CloudWatch Logs) goes through the NAT gateway.
To keep Bedrock traffic off the public path, create a bedrock-runtime
interface VPC endpoint and point the upstream's base_url at it (see../gateway.yaml.example); the IdP still needs internet egress.
Remote state (recommended for teams)
Add a backend so state is shared and locked (and out of git):
# backend.tf
terraform {
backend "s3" {
bucket = "<your-tf-state-bucket>"
key = "claude-gateway/ecs"
region = "us-east-1"
use_lockfile = true # S3-native locking (Terraform >= 1.10); or set dynamodb_table
}
}After deploy
terraform output alb_dns_name/alb_zone_id— create the Route 53 alias.- Register
/oauth/callbackon the Okta OIDC web app and make sure../gateway.yamlpublic_urlmatches the host you aliased. - Notes: Terraform does not build the image. To ship a new gateway version or
a config edit, rerun the docker build/push under a new tag and bumpimage_tag— secrets-only rotations roll the service without a rebuild (the
task definition stamps a hash of the managed secret values), but agateway.yamledit reaches the container only through the rebuilt image.
Overview (`examples/gateway/gcp/terraform/README.md`)
Claude Gateway — Terraform (Cloud Run)
Terraform equivalent of ../setup.sh. Lets end-users provision and manage
the gateway with terraform apply. Covers the same scope (walkthrough §1–7): APIs →
service account + IAM → Artifact Registry repo → VPC + Private Services Access →
private-IP Cloud SQL (PG16) → secrets → Cloud Run with Direct VPC egress.
Files
| File | Purpose |
|---|---|
versions.tf |
Provider pins (google, random) |
variables.tf |
All inputs (defaults match setup.sh's) |
main.tf |
Resources |
outputs.tf |
Service URL, OAuth redirect URI, SA, DB info |
terraform.tfvars.example |
Copy to terraform.tfvars and edit |
Prerequisites
../gateway.yamlcreated and filled in — copy the template first:cp ../gateway.yaml.example ../gateway.yaml, then replace everyREPLACE_ME
(Terraform reads this file and enforces noREPLACE_MEvia a precondition).
Leavepublic_urlat its placeholder for the first apply; set it to therun.appURL (theservice_urloutput) or your LB hostname and re-apply.gateway.yamlis gitignored; the committed template isgateway.yaml.example.- A remote backend for shared use (see below). State holds secrets — never commit it.
Deploy
Terraform creates the Artifact Registry repo but does not build/push the
image, so the apply is two passes: a targeted apply to create the repo, then
build/push, then the full apply.
cp terraform.tfvars.example terraform.tfvars # edit it
terraform init
# 1. Create just the Artifact Registry repo (the -target warning is expected):
terraform apply -target=google_artifact_registry_repository.repo
# 2. Download the public Claude Code linux-x64 release binary (it includes the
# `gateway` subcommand; the Dockerfile picks it up at gcp/claude), verify its
# sha256 against the release manifest, then build and push the image:
BASE="https://downloads.claude.ai/claude-code-releases"
VERSION="$(curl -fsSL --proto '=https' "${BASE}/latest")"
curl -fL --proto '=https' --proto-redir '=https' -o ../claude \
"${BASE}/${VERSION}/linux-x64/claude"
WANT="$(curl -fsSL --proto '=https' "${BASE}/${VERSION}/manifest.json" \
| tr -d '[:space:]' | grep -oE '"linux-x64"[^}]*' | grep -oE '[a-f0-9]{64}' | head -1)"
[ "$(openssl dgst -sha256 ../claude | awk '{print $NF}')" = "${WANT}" ] \
&& echo "sha256 OK" || { echo "checksum mismatch" >&2; rm -f ../claude; }
gcloud auth configure-docker us-east5-docker.pkg.dev --quiet
docker build --platform=linux/amd64 --provenance=false \
-f ../Dockerfile -t "us-east5-docker.pkg.dev/<project>/claude-gateway/gateway:${VERSION}" ..
docker push "us-east5-docker.pkg.dev/<project>/claude-gateway/gateway:${VERSION}"
# 3. Full apply:
terraform apply(../setup.sh §3 automates the same download-and-verify.)
Set in terraform.tfvars:
project_id,regionimage_tag(after building/pushing — step 2 above)oidc_client_secret— required (the Cloud Run service mountslatestof
this secret; with no version the deploy fails). Terraform creates the
secret + version from it.invoker_iam_disabled/allow_unauthenticated— the gateway runs its own
OIDC, so the Cloud Run invoker IAM check must be opened or disabled.
Preferred:invoker_iam_disabled = true(noallUsersbinding; works
under Domain Restricted Sharing). Fallback:allow_unauthenticated = true
grantsallUsersrun.invoker— fine on a normal org, but DRS orgs rejectallUsers(set itfalsethere, since an LB does not bypass the IAM
check). If both paths are blocked by org policy, use the GKE track.ingress— defaults to internal-only (no public URL). Claude Code's/login
only accepts gateway hosts on private addresses, so public ingress cannot serve
clients; the two-pass OAuth bootstrap must be completed from inside the VPC (or a
PSC-connected corp network). See "Private access" below.
Tear down a trial with terraform destroy: set deletion_protection = false,
run terraform apply to record that in state (the provider checks the value in
state, not config, so destroy would still refuse otherwise), then terraform destroy. The destroy will stop at the VPC network
because the Private Services Access peering is intentionally left in place
(deletion_policy = ABANDON — see Guard rails below); finish by deleting the
peering manually once the Cloud SQL instance is gone, then re-run destroy:
gcloud services vpc-peerings delete --service=servicenetworking.googleapis.com \
--network=cc-gateway-vpc --project=<project>
terraform destroyGuard rails
Tuned so accidental deletion is hard but greenfield teardown stays easy:
deletion_protection = true(variable, default true) on Cloud SQL and Cloud Run —
blocks accidental deletion; setfalsewhen you intend toterraform destroy.disable_on_destroy = falseon APIs — tearing down config never disables APIs.deletion_policy = ABANDONon the PSA peering — never tears down the
service-networking peering automatically (it's shared by every private-IP
service on the VPC). On the dedicated VPC this module creates, that meansterraform destroystops at the network step; delete the peering manually
per the teardown note above.- IAM uses non-authoritative
_memberresources, so other project/secret bindings
are never clobbered.
Private access (internal ingress) — the default
By default the service has no public URL (ingress = "INGRESS_TRAFFIC_INTERNAL_ONLY"),
and there is no public-ingress option: Claude Code's /login rejects gateway hosts that
resolve to public addresses, so public exposure cannot serve clients. Reach the service
from inside the VPC, or via the private-access plumbing below.
With internal-only ingress, public_url stays the run.app URL (Google-managed cert) —
no load balancer or your own certificate required. But internal ingress alone does
not let corporate on-prem clients reach run.app; that needs operator /
network-team-owned plumbing that Cloud Run does not create for you (validate it's in
place before relying on internal ingress):
- A Private Service Connect endpoint for Google APIs (an internal VIP in the VPC).
- A Cloud DNS private zone for
run.appresolving*.run.appto that endpoint IP. - On-prem routing to the endpoint over Cloud VPN / Interconnect.
This is normally managed centrally in the network/hub project, so the module does not
provision it. See Private networking and Cloud Run.
For a greenfield trial without this plumbing, complete the OAuth bootstrap from inside
the VPC — e.g. a browser proxied through an in-VPC VM (SSH SOCKS tunnel over IAP).
For a custom internal hostname or your own TLS cert, useINGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER and front the service with your own internal
Application Load Balancer (also not provisioned by this module).
Remote state (recommended for teams)
Add a backend so state is shared and locked (and out of git):
# backend.tf
terraform {
backend "gcs" {
bucket = "<your-tf-state-bucket>"
prefix = "claude-gateway/cloudrun"
}
}After deploy
terraform output service_url/oauth_redirect_uri.- Register the redirect URI on the Google OAuth client and make sure
../gateway.yamlpublic_urlmatches the host. - Notes: Terraform does not build the image. To ship a new gateway version,
rerun the docker build/push under a new tag and bumpimage_tag— a bare
re-apply under an unchanged tag does not roll a new revision (Cloud Run
resolves the tag to a digest only at revision creation, and an unchangedimageattribute means no new revision).
Overview (`plugins/plugin-dev/skills/command-development/README.md`)
Command Development Skill
Comprehensive guidance on creating Claude Code slash commands, including file format, frontmatter options, dynamic arguments, and best practices.
Overview
This skill provides knowledge about:
- Slash command file format and structure
- YAML frontmatter configuration fields
- Dynamic arguments ($ARGUMENTS, $1, $2, etc.)
- File references with @ syntax
- Bash execution with !` syntax
- Command organization and namespacing
- Best practices for command development
- Plugin-specific features (${CLAUDE_PLUGIN_ROOT}, plugin patterns)
- Integration with plugin components (agents, skills, hooks)
- Validation patterns and error handling
Skill Structure
SKILL.md (~2,470 words)
Core skill content covering:
Fundamentals:
- Command basics and locations
- File format (Markdown with optional frontmatter)
- YAML frontmatter fields overview
- Dynamic arguments ($ARGUMENTS and positional)
- File references (@ syntax)
- Bash execution (!` syntax)
- Command organization patterns
- Best practices and common patterns
- Troubleshooting
Plugin-Specific:
- ${CLAUDE_PLUGIN_ROOT} environment variable
- Plugin command discovery and organization
- Plugin command patterns (configuration, template, multi-script)
- Integration with plugin components (agents, skills, hooks)
- Validation patterns (argument, file, resource, error handling)
References
Detailed documentation:
frontmatter-reference.md: Complete YAML frontmatter field specifications
- All field descriptions with types and defaults
- When to use each field
- Examples and best practices
- Validation and common errors
plugin-features-reference.md: Plugin-specific command features
- Plugin command discovery and organization
- ${CLAUDE_PLUGIN_ROOT} environment variable usage
- Plugin command patterns (configuration, template, multi-script)
- Integration with plugin agents, skills, and hooks
- Validation patterns and error handling
Examples
Practical command examples:
simple-commands.md: 10 complete command examples
- Code review commands
- Testing commands
- Deployment commands
- Documentation generators
- Git integration commands
- Analysis and research commands
plugin-commands.md: 10 plugin-specific command examples
- Simple plugin commands with scripts
- Multi-script workflows
- Template-based generation
- Configuration-driven deployment
- Agent and skill integration
- Multi-component workflows
- Validated input commands
- Environment-aware commands
When This Skill Triggers
Claude Code activates this skill when users:
- Ask to "create a slash command" or "add a command"
- Need to "write a custom command"
- Want to "define command arguments"
- Ask about "command frontmatter" or YAML configuration
- Need to "organize commands" or use namespacing
- Want to create commands with file references
- Ask about "bash execution in commands"
- Need command development best practices
Progressive Disclosure
The skill uses progressive disclosure:
- SKILL.md (~2,470 words): Core concepts, common patterns, and plugin features overview
- References (~13,500 words total): Detailed specifications
- frontmatter-reference.md (~1,200 words)
- plugin-features-reference.md (~1,800 words)
- interactive-commands.md (~2,500 words)
- advanced-workflows.md (~1,700 words)
- testing-strategies.md (~2,200 words)
- documentation-patterns.md (~2,000 words)
- marketplace-considerations.md (~2,200 words)
- Examples (~6,000 words total): Complete working command examples
- simple-commands.md
- plugin-commands.md
Claude loads references and examples as needed based on task.
Command Basics Quick Reference
File Format
---
description: Brief description
argument-hint: [arg1] [arg2]
allowed-tools: Read, Bash(git:*)
---
Command prompt content with:
- Arguments: $1, $2, or $ARGUMENTS
- Files: @path/to/file
- Bash: !`command here`Locations
- Project:
.claude/commands/(shared with team) - Personal:
~/.claude/commands/(your commands) - Plugin:
plugin-name/commands/(plugin-specific)
Key Features
Dynamic arguments:
$ARGUMENTS- All arguments as single string$1,$2,$3- Positional arguments
File references:
@path/to/file- Include file contents
Bash execution:
!command`` - Execute and include output
Frontmatter Fields Quick Reference
| Field | Purpose | Example |
|---|---|---|
description |
Brief description for /help | "Review code for issues" |
allowed-tools |
Restrict tool access | Read, Bash(git:*) |
model |
Specify model | sonnet, opus, haiku |
argument-hint |
Document arguments | [pr-number] [priority] |
disable-model-invocation |
Manual-only command | true |
Common Patterns
Simple Review Command
---
description: Review code for issues
---
Review this code for quality and potential bugs.Command with Arguments
---
description: Deploy to environment
argument-hint: [environment] [version]
---
Deploy to $1 environment using version $2Command with File Reference
---
description: Document file
argument-hint: [file-path]
---
Generate documentation for @$1Command with Bash Execution
---
description: Show Git status
allowed-tools: Bash(git:*)
---
Current status: !`git status`
Recent commits: !`git log --oneline -5`Development Workflow
Design command:
- Define purpose and scope
- Determine required arguments
- Identify needed tools
Create file:
- Choose appropriate location
- Create
.mdfile with command name - Write basic prompt
Add frontmatter:
- Start minimal (just description)
- Add fields as needed (allowed-tools, etc.)
- Document arguments with argument-hint
Test command:
- Invoke with
/command-name - Verify arguments work
- Check bash execution
- Test file references
- Invoke with
Refine:
- Improve prompt clarity
- Handle edge cases
- Add examples in comments
- Document requirements
Best Practices Summary
- Single responsibility: One command, one clear purpose
- Clear descriptions: Make discoverable in
/help - Document arguments: Always use argument-hint
- Minimal tools: Use most restrictive allowed-tools
- Test thoroughly: Verify all features work
- Add comments: Explain complex logic
- Handle errors: Consider missing arguments/files
Status
Completed enhancements:
- ✓ Plugin command patterns (${CLAUDE_PLUGIN_ROOT}, discovery, organization)
- ✓ Integration patterns (agents, skills, hooks coordination)
- ✓ Validation patterns (input, file, resource validation, error handling)
Remaining enhancements (in progress):
- Advanced workflows (multi-step command sequences)
- Testing strategies (how to test commands effectively)
- Documentation patterns (command documentation best practices)
- Marketplace considerations (publishing and distribution)
Maintenance
To update this skill:
- Keep SKILL.md focused on core fundamentals
- Move detailed specifications to references/
- Add new examples/ for different use cases
- Update frontmatter when new fields added
- Ensure imperative/infinitive form throughout
- Test examples work with current Claude Code
Version History
v0.1.0 (2025-01-15):
- Initial release with basic command fundamentals
- Frontmatter field reference
- 10 simple command examples
- Ready for plugin-specific pattern additions
Overview (`plugins/plugin-dev/skills/plugin-structure/README.md`)
Plugin Structure Skill
Comprehensive guidance on Claude Code plugin architecture, directory layout, and best practices.
Overview
This skill provides detailed knowledge about:
- Plugin directory structure and organization
plugin.jsonmanifest configuration- Component organization (commands, agents, skills, hooks)
- Auto-discovery mechanisms
- Portable path references with
${CLAUDE_PLUGIN_ROOT} - File naming conventions
Skill Structure
SKILL.md (1,619 words)
Core skill content covering:
- Directory structure overview
- Plugin manifest (plugin.json) fields
- Component organization patterns
- ${CLAUDE_PLUGIN_ROOT} usage
- File naming conventions
- Auto-discovery mechanism
- Best practices
- Common patterns
- Troubleshooting
References
Detailed documentation for deep dives:
manifest-reference.md: Complete
plugin.jsonfield reference- All field descriptions and examples
- Path resolution rules
- Validation guidelines
- Minimal vs. complete manifest examples
component-patterns.md: Advanced organization patterns
- Component lifecycle (discovery, activation)
- Command organization patterns
- Agent organization patterns
- Skill organization patterns
- Hook organization patterns
- Script organization patterns
- Cross-component patterns
- Best practices for scalability
Examples
Three complete plugin examples:
minimal-plugin.md: Simplest possible plugin
- Single command
- Minimal manifest
- When to use this pattern
standard-plugin.md: Well-structured production plugin
- Multiple components (commands, agents, skills, hooks)
- Complete manifest with metadata
- Rich skill structure
- Integration between components
advanced-plugin.md: Enterprise-grade plugin
- Multi-level organization
- MCP server integration
- Shared libraries
- Configuration management
- Security automation
- Monitoring integration
When This Skill Triggers
Claude Code activates this skill when users:
- Ask to "create a plugin" or "scaffold a plugin"
- Need to "understand plugin structure"
- Want to "organize plugin components"
- Need to "set up plugin.json"
- Ask about "${CLAUDE_PLUGIN_ROOT}" usage
- Want to "add commands/agents/skills/hooks"
- Need "configure auto-discovery" help
- Ask about plugin architecture or best practices
Progressive Disclosure
The skill uses progressive disclosure to manage context:
- SKILL.md (~1600 words): Core concepts and workflows
- References (~6000 words): Detailed field references and patterns
- Examples (~8000 words): Complete working examples
Claude loads references and examples only as needed based on the task.
Related Skills
This skill works well with:
- hook-development: For creating plugin hooks
- mcp-integration: For integrating MCP servers (when available)
- marketplace-publishing: For publishing plugins (when available)
Maintenance
To update this skill:
- Keep SKILL.md lean and focused on core concepts
- Move detailed information to references/
- Add new examples/ for common patterns
- Update version in SKILL.md frontmatter
- Ensure all documentation uses imperative/infinitive form
Overview (`plugins/plugin-dev/skills/hook-development/scripts/README.md`)
Hook Development Utility Scripts
These scripts help validate, test, and lint hook implementations before deployment.
validate-hook-schema.sh
Validates hooks.json configuration files for correct structure and common issues.
Usage:
./validate-hook-schema.sh path/to/hooks.jsonChecks:
- Valid JSON syntax
- Required fields present
- Valid hook event names
- Proper hook types (command/prompt)
- Timeout values in valid ranges
- Hardcoded path detection
- Prompt hook event compatibility
Example:
cd my-plugin
./validate-hook-schema.sh hooks/hooks.jsontest-hook.sh
Tests individual hook scripts with sample input before deploying to Claude Code.
Usage:
./test-hook.sh [options] <hook-script> <test-input.json>Options:
-v, --verbose- Show detailed execution information-t, --timeout N- Set timeout in seconds (default: 60)--create-sample <event-type>- Generate sample test input
Example:
# Create sample test input
./test-hook.sh --create-sample PreToolUse > test-input.json
# Test a hook script
./test-hook.sh my-hook.sh test-input.json
# Test with verbose output and custom timeout
./test-hook.sh -v -t 30 my-hook.sh test-input.jsonFeatures:
- Sets up proper environment variables (CLAUDE_PROJECT_DIR, CLAUDE_PLUGIN_ROOT)
- Measures execution time
- Validates output JSON
- Shows exit codes and their meanings
- Captures environment file output
hook-linter.sh
Checks hook scripts for common issues and best practices violations.
Usage:
./hook-linter.sh <hook-script.sh> [hook-script2.sh ...]Checks:
- Shebang presence
set -euo pipefailusage- Stdin input reading
- Proper error handling
- Variable quoting (injection prevention)
- Exit code usage
- Hardcoded paths
- Long-running code detection
- Error output to stderr
- Input validation
Example:
# Lint single script
./hook-linter.sh ../examples/validate-write.sh
# Lint multiple scripts
./hook-linter.sh ../examples/*.shTypical Workflow
Write your hook script
bashvim my-plugin/scripts/my-hook.shLint the script
bash./hook-linter.sh my-plugin/scripts/my-hook.shCreate test input
bash./test-hook.sh --create-sample PreToolUse > test-input.json # Edit test-input.json as neededTest the hook
bash./test-hook.sh -v my-plugin/scripts/my-hook.sh test-input.jsonAdd to hooks.json
bash# Edit my-plugin/hooks/hooks.jsonValidate configuration
bash./validate-hook-schema.sh my-plugin/hooks/hooks.jsonTest in Claude Code
bashclaude --debug
Tips
- Always test hooks before deploying to avoid breaking user workflows
- Use verbose mode (
-v) to debug hook behavior - Check the linter output for security and best practice issues
- Validate hooks.json after any changes
- Create different test inputs for various scenarios (safe operations, dangerous operations, edge cases)
Common Issues
Hook doesn't execute
Check:
- Script has shebang (
#!/bin/bash) - Script is executable (
chmod +x) - Path in hooks.json is correct (use
${CLAUDE_PLUGIN_ROOT})
Hook times out
- Reduce timeout in hooks.json
- Optimize hook script performance
- Remove long-running operations
Hook fails silently
- Check exit codes (should be 0 or 2)
- Ensure errors go to stderr (
>&2) - Validate JSON output structure
Injection vulnerabilities
- Always quote variables:
"$variable" - Use
set -euo pipefail - Validate all input fields
- Run the linter to catch issues
--- METRICS ---
- Files Extracted: 29
- Estimated Token Budget: ~48968 tokens
- Canonical Reference: https://codewiki.google/github.com/anthropics/claude-code