mirror of
https://github.com/kochetkov-ma/claude-brewcode.git
synced 2026-09-14 20:16:41 +08:00
v3.4.9: sync creator agents with reference docs, permission-guard Bash support
- hook-creator: 25 events, version history, lifecycle diagrams, channel matrix - agent-creator: 5 new fields, 10 bugs, version history, debugging section - skill-creator: 10 bugs, effort max, CLAUDE_SKILL_DIR fix, limitations - permission-guard: Bash tool matcher, network blocklist, .claude/tmp/ + /tmp/
This commit is contained in:
@@ -6,13 +6,13 @@
|
||||
},
|
||||
"metadata": {
|
||||
"description": "Claude Code plugin suite: brewcode for infinite task execution and brewdoc for documentation tools",
|
||||
"version": "3.4.8"
|
||||
"version": "3.4.9"
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"name": "brewcode",
|
||||
"description": "Brewcode - full-featured development platform for Claude Code: infinite focus tasks, prompt optimization, skill/agent creation, quorum reviews, rules management",
|
||||
"version": "3.4.8",
|
||||
"version": "3.4.9",
|
||||
"category": "productivity",
|
||||
"keywords": [
|
||||
"brewcode",
|
||||
@@ -46,7 +46,7 @@
|
||||
{
|
||||
"name": "brewdoc",
|
||||
"description": "Brewdoc - Claude Code documentation tools: auto-sync for skills/agents/rules, my-claude installation docs, memory optimization, md-to-pdf conversion",
|
||||
"version": "3.4.8",
|
||||
"version": "3.4.9",
|
||||
"category": "productivity",
|
||||
"keywords": [
|
||||
"brewdoc",
|
||||
|
||||
@@ -2,6 +2,21 @@
|
||||
|
||||
---
|
||||
|
||||
## v3.4.9 (2026-03-31)
|
||||
|
||||
### brewcode
|
||||
#### Changed
|
||||
- **hook-creator agent** -- synced with HOOKS-REFERENCE: 14 to 25 events, version history, lifecycle diagrams, channel reliability matrix, expanded matcher patterns, output schemas, async recommendations
|
||||
- **agent-creator agent** -- synced with AGENT-REFERENCE: added `initialPrompt`, `isolation`, `mcpServers`, `color`, `memory` fields; 10 bugs table; version history; architectural limitations; expanded validation checklist (6 to 12 items); debugging section
|
||||
- **skill-creator agent** -- synced with SKILL-REFERENCE: 10 bugs table; version history; `effort` max value; `CLAUDE_SKILL_DIR` version fix (v2.1.69 to v2.1.71); 250-char description truncation; `once` field; architectural limitations
|
||||
- **permission-guard hook** -- added Bash tool to PermissionRequest matcher; network/dangerous command blocklist; restricted `rm` to safe dirs; added `.claude/tmp/`, `/tmp/`, `/private/tmp/` to allowed paths
|
||||
|
||||
#### Added
|
||||
- **Reference auto-sync dependents** -- `dependents` field in reference frontmatter for cascading updates to creator agents
|
||||
- **Downstream tracking** -- each reference document now lists dependent plugin artifacts
|
||||
|
||||
---
|
||||
|
||||
## v3.4.8 (2026-03-30)
|
||||
|
||||
### brewcode
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "brewcode",
|
||||
"version": "3.4.8",
|
||||
"version": "3.4.9",
|
||||
"description": "Brewcode - full-featured development platform for Claude Code: infinite focus tasks, prompt optimization, skill/agent creation, quorum reviews, rules management",
|
||||
"author": {
|
||||
"name": "Maksim Kochetkov",
|
||||
|
||||
@@ -34,12 +34,17 @@ Creates Claude Code agents following Anthropic best practices.
|
||||
name: agent-name # REQ: lowercase letters/hyphens
|
||||
description: "Short description" # REQ: trigger terms, when to delegate
|
||||
model: sonnet # OPT: sonnet|opus|haiku|inherit (default: inherit)
|
||||
effort: high # OPT: low|medium|high|auto (v2.1.78+, plugin agents only)
|
||||
maxTurns: 20 # OPT: max turns before stopping (v2.1.78+, plugin agents only)
|
||||
effort: high # OPT: low|medium|high|auto (v2.1.78+, plugin only)
|
||||
maxTurns: 20 # OPT: max turns before stopping (v2.1.78+, plugin only)
|
||||
tools: Read, Glob, Grep # OPT: comma-separated (omit = inherit all)
|
||||
disallowedTools: Write, Edit # OPT: deny specific tools
|
||||
disallowedTools: Write, Edit # OPT: deny specific tools (v2.1.78+)
|
||||
permissionMode: default # OPT: see Permission Modes table
|
||||
skills: skill1, skill2 # OPT: injected into context at startup
|
||||
color: cyan # OPT: UI color semantics
|
||||
memory: true # OPT: agent-specific MEMORY.md
|
||||
initialPrompt: "Analyze this code" # OPT: first prompt on start (v2.1.69+)
|
||||
isolation: worktree # OPT: isolated git worktree (v2.1.50+)
|
||||
mcpServers: [server1, server2] # OPT: restrict MCP servers
|
||||
hooks: # OPT: lifecycle hooks
|
||||
PreToolUse:
|
||||
- matcher: "Bash"
|
||||
@@ -66,16 +71,21 @@ Detailed instructions for the agent...
|
||||
|
||||
### Optional Fields
|
||||
|
||||
| Field | Values | Default | Description |
|
||||
|-------|--------|---------|-------------|
|
||||
| `model` | `sonnet`, `opus`, `haiku`, `inherit` | `inherit` | Model selection |
|
||||
| `effort` | `low`, `medium`, `high`, `auto` | `inherit` | Override effort level (v2.1.78+, plugin agents only) |
|
||||
| `maxTurns` | integer | unlimited | Max conversation turns before stopping (v2.1.78+, plugin agents only) |
|
||||
| `tools` | comma-separated | All inherited | Allowed tools |
|
||||
| `disallowedTools` | comma-separated | None | Denied tools (removed from inherited) |
|
||||
| `permissionMode` | see below | `default` | Permission handling |
|
||||
| `skills` | comma-separated | None | Injected into context |
|
||||
| `hooks` | YAML structure | None | Lifecycle hooks |
|
||||
| Field | Values | Default | Version | Description |
|
||||
|-------|--------|---------|---------|-------------|
|
||||
| `model` | `sonnet`, `opus`, `haiku`, `inherit` | `inherit` | -- | Model selection |
|
||||
| `effort` | `low`, `medium`, `high`, `auto` | `inherit` | 2.1.78 | Override effort level (plugin agents only) |
|
||||
| `maxTurns` | integer | unlimited | 2.1.78 | Max turns before stopping (plugin agents only) |
|
||||
| `tools` | comma-separated | All inherited | -- | Allowed tools |
|
||||
| `disallowedTools` | comma-separated | None | 2.1.78 | Denied tools (removed from inherited) |
|
||||
| `permissionMode` | see below | `default` | -- | Permission handling |
|
||||
| `skills` | comma-separated | None | -- | Injected into context at startup |
|
||||
| `hooks` | YAML structure | None | -- | Lifecycle hooks |
|
||||
| `color` | `cyan`, `green`, `yellow`, `red`, `magenta` | None | -- | UI color (see Color Semantics) |
|
||||
| `memory` | `true`/`false` | `false` | -- | Agent-specific MEMORY.md; auto-adds Read/Write/Edit |
|
||||
| `initialPrompt` | string | None | 2.1.69 | Text of first prompt sent to agent on start |
|
||||
| `isolation` | `worktree` | None | 2.1.50 | Run agent in isolated git worktree |
|
||||
| `mcpServers` | array of names | All inherited | -- | Restrict which MCP servers agent can access |
|
||||
|
||||
### Permission Modes
|
||||
|
||||
@@ -101,13 +111,21 @@ Detailed instructions for the agent...
|
||||
|
||||
### Hook Events
|
||||
|
||||
| Event | Matcher | When |
|
||||
|-------|---------|------|
|
||||
| `PreToolUse` | Tool name | Before tool execution |
|
||||
| `PostToolUse` | Tool name | After tool execution |
|
||||
| `Stop` | (none) | When agent finishes |
|
||||
| Event | Matcher | When | Level |
|
||||
|-------|---------|------|-------|
|
||||
| `PreToolUse` | Tool name | Before tool execution | Agent frontmatter |
|
||||
| `PostToolUse` | Tool name | After tool execution | Agent frontmatter |
|
||||
| `Stop` | (none) | When agent finishes | Agent frontmatter |
|
||||
| `SubagentStart` | (none) | Before subagent starts | settings.json only |
|
||||
| `SubagentStop` | (none) | Before subagent stops (blockable) | settings.json only |
|
||||
| `PreToolUse:Task` | (none) | Before Task tool call | settings.json only |
|
||||
| `PostToolUse:Task` | (none) | After Task tool completes | settings.json only |
|
||||
| `TaskCreated` | (none) | When task created (Teams, v2.1.84) | settings.json only |
|
||||
| `TeammateIdle` | (none) | Teammate finished task (Teams) | settings.json only |
|
||||
| `TaskCompleted` | (none) | Task completed by teammate (Teams) | settings.json only |
|
||||
|
||||
> Settings-level hooks: `SubagentStart`, `SubagentStop` (configure in `settings.json`)
|
||||
> Agent frontmatter hooks: `PreToolUse`, `PostToolUse`, `Stop` only.
|
||||
> Settings-level hooks affect ALL subagents -- configure in `settings.json` or `plugin/hooks/hooks.json`.
|
||||
|
||||
---
|
||||
|
||||
@@ -156,7 +174,9 @@ claude --agents '{
|
||||
| **File-based communication** | Агенты пишут результаты в файлы, следующий агент читает |
|
||||
| **Agent Teams** (v2.1.33+) | Lead координирует teammates (но teammates тоже не спавнят sub-teammates) |
|
||||
|
||||
> Источники: [Sub-agents docs](https://code.claude.com/docs/en/sub-agents), [#4182](https://github.com/anthropics/claude-code/issues/4182), [#17283](https://github.com/anthropics/claude-code/issues/17283)
|
||||
**Agent Teams** -- lead coordinates teammates via Task API tools: `TaskCreate`, `TaskUpdate`, `TaskList`, `TaskGet`, `TaskOutput`, `TaskStop`. Hook events: `TeammateIdle`, `TaskCompleted`, `TaskCreated` (v2.1.84). One level deep only.
|
||||
|
||||
> Sources: [Sub-agents docs](https://code.claude.com/docs/en/sub-agents), [#4182](https://github.com/anthropics/claude-code/issues/4182), [#17283](https://github.com/anthropics/claude-code/issues/17283)
|
||||
|
||||
---
|
||||
|
||||
@@ -171,16 +191,16 @@ What a subagent receives at runtime (important for system prompt design):
|
||||
| Git status | **Yes** | Basic project state |
|
||||
| Permissions | **Yes** | Override via `permissionMode` |
|
||||
| Tools / MCP servers | **Yes** | Configurable via `tools`/`disallowedTools`/`mcpServers` |
|
||||
| Skills from `skills:` field | **Yes** | Full content injected at startup |
|
||||
| Skills from `skills:` field | **Yes** | Full content injected at startup (not runtime) |
|
||||
| Agent memory (`memory:` field) | **Yes** | First 200 lines of MEMORY.md; auto-adds Read/Write/Edit |
|
||||
| Full Claude Code system prompt | **No** | Replaced with short ~294-token agent prompt |
|
||||
| Parent conversation history | **No** | Clean slate each invocation |
|
||||
| Parent's invoked skills | **No** | Must list explicitly in `skills:` |
|
||||
| Parent's invoked skills | **No** | Must list explicitly in `skills:` field |
|
||||
| Parent's auto memory (`memory/MEMORY.md`) | **No** | Only agent-specific memory |
|
||||
|
||||
> **Design implication:** Don't duplicate CLAUDE.md rules in agent body -- they're already injected. Focus system prompt on agent-specific role, patterns, and checklists.
|
||||
|
||||
> **Known bugs:** [#13627](https://github.com/anthropics/claude-code/issues/13627) -- agent body sometimes not injected via Task tool. [#8395](https://github.com/anthropics/claude-code/issues/8395) -- subagents may ignore user-level CLAUDE.md rules. Workaround: `SubagentStart` hook with `additionalContext`.
|
||||
> **Known bugs:** See [Known Bugs](#known-bugs) section below for full list and workarounds.
|
||||
|
||||
---
|
||||
|
||||
@@ -529,15 +549,93 @@ tools: Read, Glob, Grep, Bash
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
- [ ] `name`: lowercase-hyphens only
|
||||
- [ ] `description`: trigger terms, when to delegate
|
||||
- [ ] `tools`: minimal required set
|
||||
- [ ] System prompt: tables over prose
|
||||
- [ ] Project-specific knowledge included
|
||||
- [ ] `name`: lowercase-hyphens only (`[a-z0-9-]+`)
|
||||
- [ ] `description`: trigger terms + min 3 `<example>` blocks for complex agents
|
||||
- [ ] `tools`: minimal required set (principle of least privilege)
|
||||
- [ ] `disallowedTools`: no conflict with `tools` if both specified
|
||||
- [ ] `model`: matches task complexity (opus=complex, sonnet=standard, haiku=light)
|
||||
- [ ] System prompt: tables over prose, code over text
|
||||
- [ ] Project-specific knowledge included (stack, conventions, commands)
|
||||
- [ ] Checklist (DoD) present at end of system prompt
|
||||
- [ ] READ-ONLY agents have no Write/Edit tools
|
||||
- [ ] No CLAUDE.md rules duplicated in agent body (already injected)
|
||||
- [ ] Unique name in scope (no conflict with existing agents)
|
||||
- [ ] Optimized with `text-optimize` skill
|
||||
|
||||
---
|
||||
|
||||
## Known Bugs
|
||||
|
||||
| Bug | Impact | Status | Workaround |
|
||||
|-----|--------|--------|------------|
|
||||
| [#29423](https://github.com/anthropics/claude-code/issues/29423) | Task subagents don't load CLAUDE.md and rules | Active | Pass rules in `Task(prompt=...)` |
|
||||
| [#29110](https://github.com/anthropics/claude-code/issues/29110) | `bypassPermissions` breaks Write/Edit; worktree loses data | Active | Avoid `bypassPermissions` + `isolation: worktree` combo |
|
||||
| [#19040](https://github.com/anthropics/claude-code/issues/19040) | Session files grow to multi-GB from subagent progress entries | Active | Monitor session file size |
|
||||
| [#31392](https://github.com/anthropics/claude-code/issues/31392) | Global agents `~/.claude/agents/` not discovered | Active (v2.1.70+) | Use project-level or plugin-level agents |
|
||||
| [#27736](https://github.com/anthropics/claude-code/issues/27736) | `skills:` in plugin agent frontmatter not rendered in Task tool | Active | Pre-inject skill content via `Task(prompt=...)` |
|
||||
| [#25834](https://github.com/anthropics/claude-code/issues/25834) | Plugin agent `skills:` doesn't inject content | Active | Inline skill content or use `$BC_PLUGIN_ROOT` path |
|
||||
| [#13627](https://github.com/anthropics/claude-code/issues/13627) | Agent body not injected via Task tool | Closed (NOT PLANNED) | `SubagentStart` hook with `additionalContext` |
|
||||
| [#8395](https://github.com/anthropics/claude-code/issues/8395) | Subagents ignore user-level CLAUDE.md | Closed (NOT PLANNED) | `SubagentStart` hook with `additionalContext` |
|
||||
| [#4182](https://github.com/anthropics/claude-code/issues/4182) | Skill tool unavailable in subagent | By design | Use `skills:` in frontmatter for pre-injection |
|
||||
| [#17283](https://github.com/anthropics/claude-code/issues/17283) | Subagents cannot spawn subagents | By design | Chaining from main conversation |
|
||||
|
||||
---
|
||||
|
||||
## Architectural Limitations
|
||||
|
||||
| Limitation | Description | Workaround |
|
||||
|------------|-------------|------------|
|
||||
| No nested subagents | `SubAgentLoop` excludes `AgentTool` | Chaining, preloaded skills, file-based communication |
|
||||
| No runtime skill injection | Skills injected only at startup | List all needed skills in frontmatter upfront |
|
||||
| No parent history access | Clean context per invocation | Pass context via `Task(prompt=...)` |
|
||||
| Short system prompt | ~294-token agent prompt replaces full Claude Code prompt | Compensate with detailed agent body |
|
||||
| `effort`/`maxTurns` plugin-only | Don't work for project/user agents | Use plugin-level agents |
|
||||
| Plugin agents: no hooks/mcpServers/permissionMode | Security restriction | Copy to `.claude/agents/` for full feature access |
|
||||
| auto mode overrides permissionMode | Frontmatter `permissionMode` ignored in auto mode | Don't use auto mode with custom agents |
|
||||
|
||||
---
|
||||
|
||||
## Version History (Agent Features)
|
||||
|
||||
| Version | Date | Changes |
|
||||
|---------|------|---------|
|
||||
| v2.1.85 | 2026-03-26 | `TaskCreated` hook, WorktreeCreate `type: http` |
|
||||
| v2.1.78 | 2026-03-17 | `effort`, `maxTurns`, `disallowedTools` for plugin agents |
|
||||
| v2.1.74 | 2026-03-12 | Fix: full model IDs in frontmatter; `--agents` flag visibility |
|
||||
| v2.1.73 | 2026-03-11 | Fix: subagent model aliases on Bedrock/Vertex |
|
||||
| v2.1.72 | 2026-03-10 | Restored `model` on Agent tool; deprecated `TaskOutput` |
|
||||
| v2.1.70 | 2026-03-06 | Fix: background subagents invisible after compaction; `agent_id`/`agent_type` in hooks |
|
||||
| v2.1.69 | 2026-03-05 | Agent name in terminal; `initialPrompt` frontmatter; `InstructionsLoaded` hook |
|
||||
| v2.1.63 | ~2026-02-28 | **Task tool renamed to Agent tool.** `Task(...)` works as alias |
|
||||
| v2.1.50 | 2026-02-20 | `isolation: worktree`; `WorktreeCreate`/`WorktreeRemove` hooks |
|
||||
| v2.1.49 | 2026-02-19 | `--worktree` flag; `Ctrl+F` to kill background agents |
|
||||
|
||||
---
|
||||
|
||||
## Debugging
|
||||
|
||||
| Tool | Usage |
|
||||
|------|-------|
|
||||
| `CLAUDE_DEBUG=1` | Env var: full debug output, shows agent prompts |
|
||||
| `Ctrl+O` | Verbose mode in UI: shows agent calls and stdout |
|
||||
| `/agents` | Lists all registered agents with priorities |
|
||||
| Manual `Task()` | `Task(subagent_type="name", prompt="test")` -- direct invocation for testing |
|
||||
|
||||
### Common Problems
|
||||
|
||||
| Problem | Cause | Solution |
|
||||
|---------|-------|----------|
|
||||
| Agent doesn't trigger automatically | Vague description, no trigger words | Add specific trigger terms, `<example>` blocks |
|
||||
| Agent triggers on irrelevant requests | Too broad description | Narrow description, add `<commentary>` conditions |
|
||||
| Agent doesn't see CLAUDE.md rules | Bug [#8395] or [#29423] | `SubagentStart` hook with `additionalContext` |
|
||||
| System prompt not injected | Bug [#13627] | Retry; pass instructions via `Task(prompt=...)` |
|
||||
| Agent can't call skills | By design [#4182] | Use `skills:` in frontmatter for pre-injection |
|
||||
| Agent can't spawn subagent | By design -- `SubAgentLoop` without `AgentTool` | Chaining from main conversation |
|
||||
| `agents/` directory in plugin.json | Causes validation error | Remove from manifest -- auto-discovered by default |
|
||||
| `effort`/`maxTurns` not working | Only available for plugin agents | Move agent to plugin scope |
|
||||
|
||||
---
|
||||
|
||||
## Output
|
||||
|
||||
When creating agent: analysis summary (from parallel agents) -> agent file path -> full content -> validation summary
|
||||
|
||||
+371
-71
@@ -22,7 +22,7 @@ model: opus
|
||||
color: yellow
|
||||
tools: Read, Write, Edit, Glob, Grep, Bash, WebFetch, WebSearch
|
||||
auto-sync: true
|
||||
auto-sync-date: 2026-02-11
|
||||
auto-sync-date: 2026-03-30
|
||||
auto-sync-type: agent
|
||||
---
|
||||
|
||||
@@ -30,6 +30,29 @@ auto-sync-type: agent
|
||||
|
||||
Creates production-quality Claude Code hooks (bash and JS/mjs) with correct message routing, JSON schemas, and fail-safe design.
|
||||
|
||||
> **Reference version:** 2.1.85+ | 25 hook events | 4 hook types (command, http, prompt, agent)
|
||||
|
||||
### Session Lifecycle
|
||||
|
||||
```
|
||||
InstructionsLoaded -> SessionStart -> UserPromptSubmit -> PermissionRequest -> PreToolUse
|
||||
-> [Tool] -> PostToolUse / PostToolUseFailure -> Notification -> Stop -> StopFailure
|
||||
-> PreCompact -> PostCompact -> SessionEnd
|
||||
Background: CwdChanged, FileChanged, ConfigChange
|
||||
```
|
||||
|
||||
### Subagent Lifecycle
|
||||
|
||||
```
|
||||
PreToolUse:Task -> TaskCreated -> SubagentStart -> [work] -> SubagentStop -> PostToolUse:Task
|
||||
```
|
||||
|
||||
### Agent Teams Lifecycle
|
||||
|
||||
```
|
||||
TeammateIdle (exit 0=stop, 1=continue) | TaskCompleted (exit 0=accept, 1=redo)
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
| Goal | Event | Output |
|
||||
@@ -39,6 +62,11 @@ Creates production-quality Claude Code hooks (bash and JS/mjs) with correct mess
|
||||
| Modify input | PreToolUse | `updatedInput` |
|
||||
| Block stop | Stop | `decision:"block"` + `reason` |
|
||||
| Session init | SessionStart | `additionalContext` |
|
||||
| Auto-allow permission | PermissionRequest | `decision: {behavior:"allow"}` |
|
||||
| Post-tool feedback | PostToolUse | `additionalContext` |
|
||||
| Control teammates | TeammateIdle | `{continue: false, stopReason: "..."}` |
|
||||
| React to config change | ConfigChange | Exit code or JSON |
|
||||
| React to file change | FileChanged | Exit code or JSON |
|
||||
|
||||
## 1. Message Routing Matrix
|
||||
|
||||
@@ -48,18 +76,20 @@ Creates production-quality Claude Code hooks (bash and JS/mjs) with correct mess
|
||||
|
||||
| Event | Claude sees? | Delivery | Notes |
|
||||
|-------|:---:|----------|-------|
|
||||
| SessionStart | YES | `<system-reminder>` | Bug #16538: plugin hooks.json breaks delivery. Use settings.json |
|
||||
| UserPromptSubmit | YES | `<system-reminder>` appended | Works |
|
||||
| PreToolUse | YES | `<system-reminder>` | Regression #19432 in v2.1.12 |
|
||||
| PostToolUse | YES | `<system-reminder>` | Works (Issue #15345 confirms) |
|
||||
| SessionStart | YES | `<system-reminder>` | Stable (~~#16538~~ not reproducible since v2.1.37+) |
|
||||
| UserPromptSubmit | YES | `<system-reminder>` appended | Stable |
|
||||
| PreToolUse | YES | `<system-reminder>` | Stable (~~#19432~~ fixed in v2.1.15+) |
|
||||
| PostToolUse | YES | `<system-reminder>` | Stable (Issue #15345 confirms) |
|
||||
| PostToolUseFailure | YES | Needs verification | Presumed working, limited data |
|
||||
| SubagentStart | YES | Injected into **subagent** context | Not parent |
|
||||
| Notification | YES | `<system-reminder>` | Works |
|
||||
| Stop | N/A | Field not supported | -- |
|
||||
| SubagentStop | N/A | Field not supported | -- |
|
||||
| PreCompact | N/A | Field not supported | -- |
|
||||
| SessionEnd | N/A | Field not supported | -- |
|
||||
| TeammateIdle | N/A | Field not supported | Exit codes only |
|
||||
| TaskCompleted | N/A | Field not supported | Exit codes only |
|
||||
| Notification | YES | `<system-reminder>` | Stable |
|
||||
| Stop | N/A | Field not supported | Use `reason` |
|
||||
| SubagentStop | N/A | Field not supported | Use `reason` |
|
||||
| PreCompact | N/A | Field not supported | Use `systemMessage` |
|
||||
| SessionEnd | N/A | Field not supported | Informational event |
|
||||
| TeammateIdle | N/A | JSON `{continue, stopReason}` (v2.1.52+) | -- |
|
||||
| TaskCompleted | N/A | JSON `{continue, stopReason}` (v2.1.52+) | -- |
|
||||
| TaskCreated | N/A | JSON `{continue, stopReason}` (v2.1.52+) | -- |
|
||||
|
||||
### stdout (exit 0, JSON)
|
||||
|
||||
@@ -67,6 +97,7 @@ Creates production-quality Claude Code hooks (bash and JS/mjs) with correct mess
|
||||
|-------|:---:|-------|
|
||||
| SessionStart | YES | Parsed, context injected |
|
||||
| UserPromptSubmit | YES | Parsed, context injected |
|
||||
| PreToolUse | YES | Parsed, context injected |
|
||||
| All others | NO | Verbose mode only (Ctrl+O) |
|
||||
|
||||
### systemMessage
|
||||
@@ -77,18 +108,19 @@ Goes to **user UI only** -- Claude does NOT see it. Exception: async hooks deliv
|
||||
|
||||
| Event type | Claude sees? | Notes |
|
||||
|------------|:---:|-------|
|
||||
| Blocking (PreToolUse, Stop, SubagentStop, TeammateIdle, TaskCompleted) | YES | Delivered as error context |
|
||||
| Non-blocking (SessionStart, PreCompact, Notification, SessionEnd, SubagentStart) | NO | User UI only |
|
||||
| Blocking (PreToolUse, PermissionRequest, UserPromptSubmit, Stop, SubagentStop, TeammateIdle, TaskCompleted, TaskCreated, ConfigChange, WorktreeCreate, Elicitation, ElicitationResult) | YES | Delivered as error context |
|
||||
| Non-blocking (SessionStart, PostToolUse, PostToolUseFailure, PreCompact, PostCompact, Notification, SessionEnd, SubagentStart, InstructionsLoaded, StopFailure, CwdChanged, FileChanged, WorktreeRemove) | NO | User UI only |
|
||||
|
||||
### decision + reason
|
||||
|
||||
| Event | Target | Notes |
|
||||
|-------|--------|-------|
|
||||
| Stop | Claude | `decision:"block"` + `reason` -> Claude continues |
|
||||
| SubagentStop | Claude | `decision:"block"` + `reason` -> subagent continues |
|
||||
| PostToolUse | Claude | `reason` delivered as feedback |
|
||||
| UserPromptSubmit | User only | Claude does NOT see block reason |
|
||||
| PreToolUse | Claude | `permissionDecisionReason` delivered when deny |
|
||||
| Event | Claude sees reason? | Notes |
|
||||
|-------|:---:|-------|
|
||||
| Stop | YES | `decision:"block"` + `reason` -> Claude continues, sees reason |
|
||||
| SubagentStop | YES | `decision:"block"` + `reason` -> subagent continues, sees reason |
|
||||
| PostToolUse | YES (via additionalContext) | No decision field; reason delivered as feedback |
|
||||
| UserPromptSubmit | NO (UI only) | `decision:"block"` -> prompt rejected, Claude does NOT see reason |
|
||||
| PreToolUse | YES | `permissionDecisionReason` delivered when deny |
|
||||
| PermissionRequest | N/A | `decision.behavior`: allow/deny/ask. `decision.message` on deny |
|
||||
|
||||
### updatedInput (PreToolUse only)
|
||||
|
||||
@@ -98,36 +130,50 @@ Silently modifies tool parameters. Claude unaware of change. Most reliable injec
|
||||
|
||||
| Goal | Best channel | Event |
|
||||
|------|-------------|-------|
|
||||
| Inject context for Claude | `additionalContext` | SessionStart, PreToolUse, PostToolUse, SubagentStart |
|
||||
| Modify tool parameters | `updatedInput` | PreToolUse |
|
||||
| Inject context for Claude | `additionalContext` | SessionStart, PreToolUse, UserPromptSubmit |
|
||||
| Inject into subagent | `updatedInput.prompt` | PreToolUse (matcher: Task) |
|
||||
| Block tool execution | `permissionDecision:"deny"` | PreToolUse |
|
||||
| Block session stop | `decision:"block"` + `reason` | Stop |
|
||||
| Inject into subagent | `additionalContext` | SubagentStart |
|
||||
| Inject into subagent prompt | `updatedInput.prompt` | PreToolUse (matcher: Task) |
|
||||
| Post-tool feedback | `additionalContext` | PostToolUse |
|
||||
| Inject into subagent context | `additionalContext` | SubagentStart |
|
||||
| Post-tool feedback | `additionalContext` | PostToolUse (stable) |
|
||||
| Modify tool parameters | `updatedInput` | PreToolUse |
|
||||
| Show user warning | `systemMessage` | Any event |
|
||||
| Block user prompt | `decision:"block"` | UserPromptSubmit |
|
||||
| Auto-allow permission | `decision: "allow"` | PermissionRequest |
|
||||
| Control teammates | `{continue, stopReason}` JSON | TeammateIdle, TaskCompleted, TaskCreated |
|
||||
| Prompt gate | `decision:"block"` | UserPromptSubmit |
|
||||
|
||||
## 2. All 14 Hook Events
|
||||
## 2. All 25 Hook Events
|
||||
|
||||
### Event Reference
|
||||
|
||||
| # | Event | Blocking? | Matcher | Key stdin fields |
|
||||
|---|-------|-----------|---------|-----------------|
|
||||
| 1 | SessionStart | No | `startup`, `resume`, `clear`, `compact` | `source`, `model`, `agent_type` |
|
||||
| 2 | UserPromptSubmit | Yes (exit 2 / decision:block) | No | `prompt` |
|
||||
| 3 | PreToolUse | Yes (allow/deny/ask) | Tool name regex | `tool_name`, `tool_input`, `tool_use_id` |
|
||||
| 4 | PermissionRequest | Yes (allow/deny) | Tool name regex | `tool_name`, `tool_input`, `permission_suggestions` |
|
||||
| 5 | PostToolUse | No | Tool name regex | `tool_name`, `tool_input`, `tool_response`, `tool_use_id` |
|
||||
| 6 | PostToolUseFailure | No | Tool name regex | `tool_name`, `tool_input`, `error`, `is_interrupt` |
|
||||
| 7 | Notification | No | `notification_type` | `message`, `title`, `notification_type` |
|
||||
| 8 | SubagentStart | No | Agent type | `agent_id`, `agent_type` |
|
||||
| 9 | SubagentStop | Yes (decision:block) | Agent type | `agent_id`, `agent_type`, `agent_transcript_path`, `stop_hook_active` |
|
||||
| 10 | Stop | Yes (decision:block) | No | `stop_hook_active` |
|
||||
| 11 | TeammateIdle | Yes (exit 2 only) | No | `teammate_name`, `team_name` |
|
||||
| 12 | TaskCompleted | Yes (exit 2 only) | No | `task_id`, `task_subject`, `task_description` |
|
||||
| 13 | PreCompact | No | `manual`, `auto` | `trigger`, `custom_instructions` |
|
||||
| 14 | SessionEnd | No | `reason` | `reason` |
|
||||
| # | Event | Blocking? | Matcher | Key stdin fields | Version |
|
||||
|---|-------|-----------|---------|-----------------|---------|
|
||||
| 1 | SessionStart | No | source: `startup`, `resume`, `clear`, `compact` | `source`, `model`, `agent_type` | -- |
|
||||
| 2 | UserPromptSubmit | Yes (exit 2 / decision:block) | No | `user_prompt` | -- |
|
||||
| 3 | PreToolUse | Yes (allow/deny/ask) | Tool name regex | `tool_name`, `tool_input`, `tool_use_id` | -- |
|
||||
| 4 | PermissionRequest | Yes (allow/deny) | Tool name regex | `tool_name`, `tool_input`, `permission_suggestions` | -- |
|
||||
| 5 | PostToolUse | No | Tool name regex | `tool_name`, `tool_input`, `tool_response`, `tool_use_id` | -- |
|
||||
| 6 | PostToolUseFailure | No | Tool name regex | `tool_name`, `tool_input`, `tool_use_id`, `error`, `is_interrupt` | -- |
|
||||
| 7 | Notification | No | `notification_type` | `message`, `title`, `notification_type` | -- |
|
||||
| 8 | SubagentStart | No | Agent type | `agent_id`, `agent_type` | -- |
|
||||
| 9 | SubagentStop | Yes (decision:block) | Agent type | `stop_hook_active`, `agent_id`, `agent_type`, `agent_transcript_path`, `last_assistant_message` | -- |
|
||||
| 10 | Stop | Yes (decision:block) | No | `stop_hook_active`, `last_assistant_message` | -- |
|
||||
| 11 | PreCompact | No | trigger: `manual`, `auto` | `transcript_path` | -- |
|
||||
| 12 | PostCompact | No | trigger: `manual`, `auto` | `transcript_path` | 2.1.76 |
|
||||
| 13 | SessionEnd | No | reason: `clear`, `resume`, `logout`, `prompt_input_exit`, `bypass_permissions_disabled`, `other` | -- | -- |
|
||||
| 14 | TeammateIdle | Yes (exit 2 only) | No | `teammate_name`, `team_name` | -- |
|
||||
| 15 | TaskCompleted | Yes (exit 2 only) | No | `task_id`, `task_subject`, `task_description`, `teammate_name`, `team_name` | -- |
|
||||
| 16 | ConfigChange | Yes | source: `user_settings`, `project_settings`, `local_settings`, `policy_settings`, `skills` | `source`, `file_path` | 2.1.49 |
|
||||
| 17 | WorktreeCreate | Yes | No | -- | 2.1.50 |
|
||||
| 18 | WorktreeRemove | No | No | -- | 2.1.50 |
|
||||
| 19 | InstructionsLoaded | No | load_reason: `session_start`, `nested_traversal`, `path_glob_match`, `include`, `compact` | `file_path`, `memory_type`, `load_reason`, `globs`, `trigger_file_path`, `parent_file_path` | 2.1.69 |
|
||||
| 20 | Elicitation | Yes | MCP server name | MCP-specific fields | 2.1.76 |
|
||||
| 21 | ElicitationResult | Yes | MCP server name | MCP-specific fields | 2.1.76 |
|
||||
| 22 | StopFailure | No | error_type: `rate_limit`, `authentication_failed`, `billing_error`, `invalid_request`, `server_error`, `max_output_tokens`, `unknown` | `error`, `error_details`, `last_assistant_message` | 2.1.78 |
|
||||
| 23 | CwdChanged | No | No | -- | 2.1.83 |
|
||||
| 24 | FileChanged | No | filename (basename) | `file_path` | 2.1.83 |
|
||||
| 25 | TaskCreated | Yes | No | `task_id`, `task_subject`, `task_description`, `teammate_name`, `team_name` | 2.1.84 |
|
||||
|
||||
### Common stdin fields (ALL events)
|
||||
|
||||
@@ -137,7 +183,9 @@ Silently modifies tool parameters. Claude unaware of change. Most reliable injec
|
||||
"transcript_path": "/path/to/transcript",
|
||||
"cwd": "/project",
|
||||
"permission_mode": "default",
|
||||
"hook_event_name": "PreToolUse"
|
||||
"hook_event_name": "PreToolUse",
|
||||
"agent_id": "uuid (subagents only, v2.1.69+)",
|
||||
"agent_type": "Explore|Plan|custom (subagents + --agent, v2.1.69+)"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -145,30 +193,69 @@ Silently modifies tool parameters. Claude unaware of change. Most reliable injec
|
||||
|
||||
| Exit code | Meaning | stdout | stderr |
|
||||
|-----------|---------|--------|--------|
|
||||
| 0 | Success | Parsed as JSON | Verbose mode |
|
||||
| 2 | Blocking error | IGNORED | Delivered to Claude (blocking) or user (non-blocking) |
|
||||
| Other | Non-blocking error | Ignored | Verbose mode |
|
||||
| 0 | Success | Parsed as JSON. For TeammateIdle/TaskCompleted: teammate terminates | Verbose mode |
|
||||
| 1 | Error (non-fatal) | For TeammateIdle/TaskCompleted: teammate continues. Others: error | Verbose mode |
|
||||
| 2 | Critical error | IGNORED | Delivered to Claude (blocking) or user (non-blocking) |
|
||||
|
||||
### Exit code behavior by event
|
||||
|
||||
| Event | exit 0 | exit 1 | exit 2 |
|
||||
|-------|--------|--------|--------|
|
||||
| PreToolUse | JSON processed | Tool call cancelled | stderr -> Claude |
|
||||
| Stop | JSON processed | Ignored | stderr -> Claude |
|
||||
| SubagentStop | JSON processed | Ignored | stderr -> Claude |
|
||||
| SessionStart | JSON processed | Warning in UI | stderr -> UI |
|
||||
| PreCompact | JSON processed | Compact continues | stderr -> UI |
|
||||
| TeammateIdle | Teammate terminates | Teammate continues | stderr -> UI |
|
||||
| TaskCompleted | Task accepted | Task re-assigned | stderr -> UI |
|
||||
| PostToolUse | JSON processed | Warning | stderr -> UI |
|
||||
|
||||
## 3. Hook Types
|
||||
|
||||
| Type | Description | Timeout | Use case |
|
||||
|------|-------------|---------|----------|
|
||||
| `command` | Shell command, JSON stdin/stdout | 600s | Custom logic, file I/O, external tools |
|
||||
| `http` | POST JSON to URL, receives JSON response (v2.1.63+) | 600s | External API/webhook integration, remote delegation |
|
||||
| `prompt` | Single LLM call (Haiku) | 30s | Quick validation, content generation |
|
||||
| `agent` | Subagent with Read/Grep/Glob, up to 50 turns | 60s | Complex analysis, multi-step checks |
|
||||
|
||||
### Common fields for all types
|
||||
|
||||
| Field | Description | Applies to |
|
||||
|-------|-------------|------------|
|
||||
| `type` | Required: `"command"`, `"http"`, `"prompt"`, `"agent"` | All |
|
||||
| `if` | Conditional filter (permission rule syntax, v2.1.85+): `"Bash(git *)"`, `"Edit(*.ts)"` | Tool events |
|
||||
| `timeout` | Seconds before cancellation | All |
|
||||
| `statusMessage` | Spinner text while hook runs | All |
|
||||
| `once` | `true` = run once per session (skills only) | Skills |
|
||||
|
||||
### HTTP hook example (v2.1.63+)
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "http",
|
||||
"url": "http://localhost:8080/hooks/pre-tool-use",
|
||||
"timeout": 30,
|
||||
"headers": { "Authorization": "Bearer $MY_TOKEN" },
|
||||
"allowedEnvVars": ["MY_TOKEN"]
|
||||
}
|
||||
```
|
||||
|
||||
## 4. Configuration Locations
|
||||
|
||||
Priority (highest first):
|
||||
|
||||
| # | Location | Scope | Notes |
|
||||
|---|----------|-------|-------|
|
||||
| 1 | `~/.claude/settings.json` | All projects | User global |
|
||||
| 1 | `.claude/settings.local.json` | Project (gitignored) | Highest priority, personal project |
|
||||
| 2 | `.claude/settings.json` | Project (committable) | Team-shared |
|
||||
| 3 | `.claude/settings.local.json` | Project (gitignored) | Personal project |
|
||||
| 4 | Managed policy settings | Organization | MDM/admin |
|
||||
| 5 | Plugin `hooks/hooks.json` | Plugin-scoped | With plugin enabled |
|
||||
| 6 | Agent/Skill frontmatter YAML | Component-scoped | While component active |
|
||||
| 3 | `~/.claude/settings.local.json` | Global (gitignored) | Personal global |
|
||||
| 4 | `~/.claude/settings.json` | Global (committable) | User global |
|
||||
| 5 | Enterprise policy | Organization | MDM/admin |
|
||||
| 6 | Plugin `hooks/hooks.json` | Plugin-scoped | Additive (merged, not overridden) |
|
||||
| 7 | Agent/Skill frontmatter YAML | Component-scoped | While component active |
|
||||
|
||||
**Merge rule:** Hooks from different sources are merged (not overridden). For a single event, ALL registered hooks execute in parallel.
|
||||
|
||||
### settings.json format
|
||||
|
||||
@@ -231,14 +318,36 @@ hooks:
|
||||
command: "./scripts/validate.sh"
|
||||
```
|
||||
|
||||
### Conditional `if` field (v2.1.85+)
|
||||
|
||||
Reduces hook overhead -- hook only fires when `if` condition matches (permission rule syntax):
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"PreToolUse": [{
|
||||
"matcher": "Bash",
|
||||
"if": "Bash(git *)",
|
||||
"hooks": [{"type": "command", "command": "bash validate-git.sh"}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Format: `ToolName(pattern)` -- same syntax as permission rules.
|
||||
|
||||
## 5. Environment Variables
|
||||
|
||||
| Variable | Description | Available |
|
||||
|----------|-------------|-----------|
|
||||
| `$CLAUDE_PROJECT_DIR` | Project root | All hooks |
|
||||
| `$CLAUDE_PLUGIN_ROOT` | Plugin installation dir | Plugin hooks |
|
||||
| `$CLAUDE_PLUGIN_DATA` | Persistent plugin data dir (survives updates, v2.1.78+) | Plugin hooks |
|
||||
| `$CLAUDE_CODE_REMOTE` | `"true"` in remote env | All hooks |
|
||||
| `$CLAUDE_ENV_FILE` | Path for persistent env vars | SessionStart only |
|
||||
| `$CLAUDE_ENV_FILE` | Path for persistent env vars | SessionStart, CwdChanged, FileChanged |
|
||||
| `$CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS` | SessionEnd hooks timeout in ms (default 1500ms, v2.1.78+) | SessionEnd hooks |
|
||||
| `$CLAUDE_CODE_SUBPROCESS_ENV_SCRUB` | `1` = scrub Anthropic/cloud credentials from subprocess env (v2.1.83+) | All hooks |
|
||||
| `$CLAUDE_PLUGIN_OPTION_<KEY>` | Plugin `userConfig` values (v2.1.78+) | Plugin hooks |
|
||||
|
||||
## 6. Output Schemas
|
||||
|
||||
@@ -331,6 +440,109 @@ hooks:
|
||||
}
|
||||
```
|
||||
|
||||
### PermissionRequest -- Allow/Deny/Ask
|
||||
|
||||
```json
|
||||
{
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "PermissionRequest",
|
||||
"decision": {
|
||||
"behavior": "allow"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| `behavior` | Effect |
|
||||
|------------|--------|
|
||||
| `allow` | Auto-allow the operation |
|
||||
| `ask` | Show standard permission dialog |
|
||||
| `deny` | Reject without prompting user |
|
||||
|
||||
### PermissionRequest -- Allow with permission mutation
|
||||
|
||||
```json
|
||||
{
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "PermissionRequest",
|
||||
"decision": {
|
||||
"behavior": "allow",
|
||||
"updatedInput": { "command": "npm test" },
|
||||
"updatedPermissions": [{
|
||||
"type": "addRules",
|
||||
"rules": [{ "toolName": "Bash", "ruleContent": "npm *" }],
|
||||
"behavior": "allow",
|
||||
"destination": "session"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### PreToolUse -- Answer AskUserQuestion (v2.1.85+)
|
||||
|
||||
```json
|
||||
{
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "PreToolUse",
|
||||
"permissionDecision": "allow",
|
||||
"updatedInput": {
|
||||
"question": "Which database?",
|
||||
"answer": "PostgreSQL"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### PostToolUse -- Feedback
|
||||
|
||||
```json
|
||||
{
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "PostToolUse",
|
||||
"additionalContext": "Post-tool feedback for Claude"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### TeammateIdle/TaskCompleted/TaskCreated -- JSON control (v2.1.52+)
|
||||
|
||||
```json
|
||||
{
|
||||
"continue": false,
|
||||
"stopReason": "Task limit reached. Stopping teammate."
|
||||
}
|
||||
```
|
||||
|
||||
### Elicitation -- MCP form response (v2.1.76+)
|
||||
|
||||
```json
|
||||
{
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "Elicitation",
|
||||
"action": "accept",
|
||||
"content": { "field_name": "value" }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| `action` | Effect |
|
||||
|----------|--------|
|
||||
| `accept` | Auto-fill MCP form with `content` |
|
||||
| `decline` | Decline the elicitation |
|
||||
| `cancel` | Cancel the elicitation |
|
||||
|
||||
### WorktreeCreate -- Return path (v2.1.84+, http hooks)
|
||||
|
||||
```json
|
||||
{
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "WorktreeCreate",
|
||||
"worktreePath": "/path/to/created/worktree"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Empty pass-through
|
||||
|
||||
```json
|
||||
@@ -430,11 +642,18 @@ async function main() {
|
||||
// Event-specific fields:
|
||||
// PreToolUse: tool_name, tool_input, tool_use_id
|
||||
// PostToolUse: tool_name, tool_input, tool_response, tool_use_id
|
||||
// Stop: stop_hook_active
|
||||
// SubagentStart/Stop: agent_id, agent_type
|
||||
// UserPromptSubmit: prompt
|
||||
// PostToolUseFailure: tool_name, tool_input, tool_use_id, error, is_interrupt
|
||||
// Stop: stop_hook_active, last_assistant_message
|
||||
// SubagentStart: agent_id, agent_type (= subagent_type, subagent_id)
|
||||
// SubagentStop: stop_hook_active, agent_id, agent_type, agent_transcript_path, last_assistant_message
|
||||
// UserPromptSubmit: user_prompt
|
||||
// SessionStart: source, model, agent_type
|
||||
// PreCompact: trigger, custom_instructions
|
||||
// PreCompact: transcript_path
|
||||
// ConfigChange: source, file_path
|
||||
// StopFailure: error, error_details, last_assistant_message
|
||||
// FileChanged: file_path
|
||||
// InstructionsLoaded: file_path, memory_type, load_reason, globs
|
||||
// TaskCreated/TaskCompleted: task_id, task_subject, task_description, teammate_name, team_name
|
||||
|
||||
// --- Infinite loop protection (Stop/SubagentStop) ---
|
||||
// if (input.stop_hook_active) {
|
||||
@@ -502,12 +721,36 @@ import { readStdin, output } from './lib/utils.mjs';
|
||||
|
||||
## 8. Known Bugs
|
||||
|
||||
| Bug | Impact | Workaround |
|
||||
|-----|--------|------------|
|
||||
| #16538 | Plugin SessionStart `additionalContext` not delivered | Use settings.json instead of hooks.json |
|
||||
| #19432 | PreToolUse `additionalContext` regression in v2.1.12 | Use `updatedInput` as fallback injection method |
|
||||
| #14281 | Duplicate `<system-reminder>` injection | Claude Code side -- no workaround needed |
|
||||
| #10373 | SessionStart hooks not working for new sessions | Works for `resume`, `clear`, `compact` matchers |
|
||||
| Bug | Impact | Status | Workaround |
|
||||
|-----|--------|--------|------------|
|
||||
| #14281 | Duplicate `<system-reminder>` injection | Active | Make context idempotent |
|
||||
|
||||
### Fixed Bugs (reference only)
|
||||
|
||||
| Bug | Was | Fixed in |
|
||||
|-----|-----|----------|
|
||||
| ~~#16538~~ | Plugin SessionStart `additionalContext` not delivered | v2.1.37+ (not reproducible) |
|
||||
| ~~#19432~~ | PreToolUse `additionalContext` regression | v2.1.15+ |
|
||||
| ~~#10373~~ | SessionStart hooks not working for new sessions | v2.1.20+ |
|
||||
| ~~allow-bypass~~ | PreToolUse `allow` bypassed `deny` permission rules | v2.1.77 |
|
||||
| ~~skill-double~~ | Skill hooks fired twice per event | v2.1.72 |
|
||||
| ~~plugin-stop~~ | Plugin Stop/SessionEnd hooks skipped after `/plugin` | v2.1.70 |
|
||||
| ~~session-double~~ | SessionStart hooks called twice on `--resume`/`--continue` | v2.1.73 |
|
||||
| ~~sessionend~~ | SessionEnd hooks unreliable | v2.1.79 |
|
||||
| ~~plugin-perm~~ | Plugin scripts "Permission denied" on macOS/Linux | v2.1.86 |
|
||||
| ~~uninstall~~ | Uninstalled plugin hooks kept firing | v2.1.83 |
|
||||
|
||||
### Channel Reliability Matrix
|
||||
|
||||
| Channel | Reliability | Notes |
|
||||
|---------|-------------|-------|
|
||||
| `updatedInput` (PreToolUse) | High | Stable, most reliable injection method |
|
||||
| `additionalContext` (PreToolUse) | High | Regression v2.1.12 fixed in v2.1.15+ |
|
||||
| `additionalContext` (SessionStart) | High | Stable since v2.1.37+ |
|
||||
| `additionalContext` (PostToolUse) | High | Stable (Issue #15345 confirms) |
|
||||
| `decision`/`reason` (Stop) | High | Stable |
|
||||
| `systemMessage` | High | Stable (but Claude does NOT see it) |
|
||||
| `permissionDecision` (PreToolUse) | High | Stable |
|
||||
|
||||
## 9. Best Practices
|
||||
|
||||
@@ -570,24 +813,45 @@ if (input.stop_hook_active) {
|
||||
|----------|---------|
|
||||
| Execution | Background, non-blocking |
|
||||
| `decision` fields | IGNORED |
|
||||
| `systemMessage` | Delivered on NEXT turn |
|
||||
| `additionalContext` | Delivered on NEXT turn |
|
||||
| `systemMessage` | Delivered on NEXT turn (not instant) |
|
||||
| `additionalContext` | May not arrive before Claude processes |
|
||||
| Blocking events | Always synchronous (PreToolUse, Stop, SubagentStop, UserPromptSubmit, PermissionRequest) |
|
||||
| Use case | Logging, metrics, slow file operations |
|
||||
|
||||
### Sync/Async recommendation by event
|
||||
|
||||
| Event | Sync/Async | Reason |
|
||||
|-------|-----------|--------|
|
||||
| SessionStart | Sync (waits) | Context needed before first turn |
|
||||
| PreToolUse | Sync (blocks) | Must decide allow/deny before execution |
|
||||
| PostToolUse | Async OK | Result is informational |
|
||||
| PreCompact | Sync (waits) | Must write handoff before compaction |
|
||||
| Notification | Async OK | Informational |
|
||||
|
||||
## 11. Matcher Patterns
|
||||
|
||||
| Event | Matcher type | Examples |
|
||||
|-------|-------------|----------|
|
||||
| PreToolUse | Tool name (regex) | `Bash`, `Write\|Edit`, `Task`, `mcp__.*` |
|
||||
| PostToolUse | Tool name (regex) | `Bash`, `Read`, `Task` |
|
||||
| PostToolUseFailure | Tool name (regex) | `Bash` |
|
||||
| PermissionRequest | Tool name (regex) | `Bash`, `Write` |
|
||||
| SessionStart | Source string | `startup`, `resume`, `clear`, `compact` |
|
||||
| PreToolUse | Tool name regex | `Bash`, `Write\|Edit`, `Task`, `mcp__.*` |
|
||||
| PostToolUse | Tool name regex | `Bash`, `Read` |
|
||||
| SessionEnd | Reason string | `clear`, `resume`, `logout`, `prompt_input_exit`, `other` |
|
||||
| SubagentStart | Agent type | `developer`, `Explore`, `my-agent` |
|
||||
| SubagentStop | Agent type | `developer`, `reviewer` |
|
||||
| PreCompact | Trigger | `manual`, `auto` |
|
||||
| Notification | Type string | `notification_type` value |
|
||||
| SessionEnd | Reason | `reason` value |
|
||||
| PreCompact / PostCompact | Trigger | `manual`, `auto` |
|
||||
| Notification | Type string | `permission_prompt`, `idle_prompt`, `auth_success`, `elicitation_dialog` |
|
||||
| ConfigChange | Source string | `user_settings`, `project_settings`, `local_settings`, `policy_settings`, `skills` |
|
||||
| InstructionsLoaded | Load reason | `session_start`, `nested_traversal`, `path_glob_match`, `include`, `compact` |
|
||||
| FileChanged | Filename (basename) | `.envrc`, `.env` |
|
||||
| StopFailure | Error type | `rate_limit`, `authentication_failed`, `billing_error`, `invalid_request`, `server_error`, `max_output_tokens`, `unknown` |
|
||||
| Elicitation / ElicitationResult | MCP server name | Server name string |
|
||||
| Stop | No matcher | Always fires |
|
||||
| UserPromptSubmit | No matcher | Always fires |
|
||||
| TeammateIdle / TaskCompleted / TaskCreated | No matcher | Always fires |
|
||||
| WorktreeCreate / WorktreeRemove | No matcher | Always fires |
|
||||
| CwdChanged | No matcher | Always fires |
|
||||
|
||||
> Omit `matcher` -> hook fires for ALL instances of that event.
|
||||
|
||||
@@ -742,6 +1006,9 @@ SessionStart -> count tests | PostToolUse -> increment | Stop -> verify count >
|
||||
| File system tasks | `command` | Direct access |
|
||||
| External tool integration | `command` | System calls |
|
||||
| Performance-critical | `command` | Lower latency |
|
||||
| External API / webhook | `http` | No subprocess, direct HTTP POST |
|
||||
| Remote delegation | `http` | Offload to external service |
|
||||
| File-reading analysis | `agent` | Read/Grep/Glob access, multi-step |
|
||||
|
||||
> Default: prompt hooks for most cases; command hooks for deterministic/performance-critical.
|
||||
|
||||
@@ -877,6 +1144,8 @@ try {
|
||||
| 10 | Performance | <1s for blocking hooks |
|
||||
| 11 | Known bugs | Check routing matrix for broken channels |
|
||||
| 12 | Syntax check | `bash -n` for bash, `node --check` for mjs |
|
||||
| 13 | `if` conditional | Use `if` field (v2.1.85+) to reduce hook overhead when applicable |
|
||||
| 14 | Hook type | `command` for deterministic, `http` for API, `prompt` for NL, `agent` for file analysis |
|
||||
|
||||
## 19. Deliverable Format
|
||||
|
||||
@@ -896,8 +1165,39 @@ VERIFICATION:
|
||||
- Syntax valid
|
||||
```
|
||||
|
||||
## 20. Version History
|
||||
|
||||
| Version | Event/Feature | Type |
|
||||
|---------|--------------|------|
|
||||
| 2.1.49 | `ConfigChange` | New event |
|
||||
| 2.1.50 | `WorktreeCreate`, `WorktreeRemove` | New events |
|
||||
| 2.1.50 | `last_assistant_message` in Stop/SubagentStop stdin | New field |
|
||||
| 2.1.52 | JSON response for TeammateIdle/TaskCompleted (was exit-code only) | Enhancement |
|
||||
| 2.1.63 | `http` hook type | New type |
|
||||
| 2.1.69 | `InstructionsLoaded` | New event |
|
||||
| 2.1.69 | `agent_id`, `agent_type` in common stdin fields | New fields |
|
||||
| 2.1.70 | Fix: plugin Stop/SessionEnd hooks after `/plugin` operation | Bug fix |
|
||||
| 2.1.72 | Fix: skill hooks firing twice per event | Bug fix |
|
||||
| 2.1.73 | Fix: SessionStart hooks called twice on `--resume`/`--continue` | Bug fix |
|
||||
| 2.1.76 | `PostCompact` | New event |
|
||||
| 2.1.76 | `Elicitation`, `ElicitationResult` | New events |
|
||||
| 2.1.77 | Fix: PreToolUse `allow` no longer bypasses `deny` permission rules | Security fix |
|
||||
| 2.1.78 | `StopFailure` | New event |
|
||||
| 2.1.78 | `CLAUDE_PLUGIN_DATA`, `CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS` | New env vars |
|
||||
| 2.1.78 | `CLAUDE_PLUGIN_OPTION_<KEY>` for plugin userConfig | New env var |
|
||||
| 2.1.79 | Fix: SessionEnd hooks reliable execution | Bug fix |
|
||||
| 2.1.83 | `CwdChanged`, `FileChanged` | New events |
|
||||
| 2.1.83 | `CLAUDE_CODE_SUBPROCESS_ENV_SCRUB` | New env var |
|
||||
| 2.1.83 | Fix: uninstalled plugin hooks no longer phantom-fire | Bug fix |
|
||||
| 2.1.84 | `TaskCreated` | New event |
|
||||
| 2.1.84 | `WorktreeCreate` supports `type: "http"` | Enhancement |
|
||||
| 2.1.85 | Conditional `if` field for tool event hooks | New feature |
|
||||
| 2.1.85 | PreToolUse can answer `AskUserQuestion` via `updatedInput` | Enhancement |
|
||||
| 2.1.86 | Fix: plugin scripts "Permission denied" on macOS/Linux | Bug fix |
|
||||
|
||||
## Sources
|
||||
|
||||
- [Claude Code Hooks](https://code.claude.com/docs/en/hooks)
|
||||
- [Claude Code Changelog](https://code.claude.com/docs/en/changelog)
|
||||
- [Custom Subagents](https://code.claude.com/docs/en/sub-agents)
|
||||
- Bug references: #16538, #19432, #14281, #10373
|
||||
- Bug references: #14281
|
||||
|
||||
@@ -27,11 +27,16 @@ tools: Read, Write, Edit, Glob, Grep, Task, Skill, AskUserQuestion
|
||||
|
||||
Creates Claude Code skills following official Anthropic best practices.
|
||||
|
||||
## Communication Style
|
||||
|
||||
Adapt to user's technical level. Non-technical users: explain "frontmatter", "YAML", "assertion".
|
||||
Experienced developers: skip explanations, move faster. Watch for context cues.
|
||||
|
||||
> Skills replace Commands. `.claude/commands/review.md` and `.claude/skills/review/SKILL.md` both create `/review`. Commands are legacy — create Skills.
|
||||
|
||||
## ⚠️ Activation Reality
|
||||
|
||||
**Skills auto-activate only 20-50% of the time.** This is a known issue ([#10768](https://github.com/anthropics/claude-code/issues/10768), [#15136](https://github.com/anthropics/claude-code/issues/15136)).
|
||||
**Skills auto-activate only 20-50% of the time.** Known issue ([#10768](https://github.com/anthropics/claude-code/issues/10768), [#15136](https://github.com/anthropics/claude-code/issues/15136) — both closed NOT PLANNED).
|
||||
|
||||
| Method | Activation Rate |
|
||||
|--------|-----------------|
|
||||
@@ -145,7 +150,7 @@ Imperative form: "Do X" (not "You should do X").
|
||||
| Field | Limits | Description |
|
||||
|-------|--------|-------------|
|
||||
| `name` | 64 chars | lowercase/numbers/hyphens. Uses directory name if omitted |
|
||||
| `description` | 150-300 chars, ONE line, no colons | What + when. Claude uses for auto-invocation |
|
||||
| `description` | 150-250 chars optimal (truncated at 250 since v2.1.84), ALWAYS single line, no colons | What + when. Claude uses for auto-invocation. Front-load keywords |
|
||||
|
||||
> ⚠️ Avoid `:` in description — breaks YAML frontmatter parsing. Use ` - ` or rewrite.
|
||||
|
||||
@@ -180,10 +185,11 @@ Imperative form: "Do X" (not "You should do X").
|
||||
|-------|--------|-------------|
|
||||
| `allowed-tools` | Read, Grep, Glob, Bash(git:*), Skill | Restrict available tools |
|
||||
| `model` | opus, sonnet, haiku | Override model |
|
||||
| `effort` | low, medium, high, auto | Override effort level for this skill invocation (v2.1.80+) |
|
||||
| `effort` | low, medium, high, max, auto | Override effort level for this skill invocation (v2.1.80+) |
|
||||
| `context` | fork | Run in isolated subagent |
|
||||
| `agent` | Explore, Plan, general-purpose, custom | Subagent type (with `context: fork`) |
|
||||
| `hooks` | object | Hooks scoped to skill lifecycle |
|
||||
| `once` | true/false | Hook fires once per session (default: false) |
|
||||
|
||||
# Context Modes
|
||||
|
||||
@@ -323,17 +329,20 @@ Summarize this PR...
|
||||
| `$ARGUMENTS` | All arguments passed when invoking the skill | — |
|
||||
| `$0`, `$1`, `$2` | Specific argument by 0-based index | — |
|
||||
| `${CLAUDE_SESSION_ID}` | Current session ID | — |
|
||||
| `${CLAUDE_SKILL_DIR}` | Absolute path to directory containing the skill's SKILL.md | v2.1.69 |
|
||||
| `${CLAUDE_SKILL_DIR}` | Absolute path to directory containing the skill's SKILL.md | v2.1.71 |
|
||||
|
||||
> `${CLAUDE_SKILL_DIR}` — string substitution (NOT env var). Replaced in SKILL.md before sending to model. Plugin skills → skill subdirectory, not plugin root. NOT available in hooks/agents — use `$CLAUDE_PLUGIN_ROOT` there.
|
||||
|
||||
> `$ARGUMENTS` inside ` ```bash ``` ` blocks is a **shell variable** (empty/undefined), NOT Claude Code substitution. Claude Code replaces `$ARGUMENTS` only in markdown text. Fix: put `$ARGUMENTS` in text, use placeholder in bash block.
|
||||
|
||||
# Invocation Matrix
|
||||
|
||||
| Configuration | User | Claude | In Context |
|
||||
|---------------|------|--------|------------|
|
||||
| (default) | Yes | Yes | Description always, full on invoke |
|
||||
| `disable-model-invocation: true` | Yes | No | Not loaded |
|
||||
| `user-invocable: false` | No | Yes | Description always |
|
||||
| Configuration | User | Claude | In Context | Budget |
|
||||
|---------------|------|--------|------------|--------|
|
||||
| (default) | Yes | Yes | Description always, full on invoke | description in budget |
|
||||
| `disable-model-invocation: true` | Yes | No | Not loaded | 0 — not loaded |
|
||||
| `user-invocable: false` | No | Yes | Description always | description in budget |
|
||||
| Both `true` + `false` | No | No | Inaccessible (useless config) | 0 |
|
||||
|
||||
# Skill Tool
|
||||
|
||||
@@ -379,6 +388,17 @@ hooks:
|
||||
command: "./scripts/validate.sh"
|
||||
```
|
||||
|
||||
Supported events: `PreToolUse` (blockable), `PostToolUse` (non-blockable), `Stop` (blockable).
|
||||
|
||||
**`once: true`** — skill fires once per session. Use for initialization tasks:
|
||||
```yaml
|
||||
---
|
||||
name: session-init
|
||||
once: true
|
||||
description: Initializes project environment on first use
|
||||
---
|
||||
```
|
||||
|
||||
# Description Optimization
|
||||
|
||||
Claude uses description to decide when to invoke. **Description quality directly affects activation rate** (20% → 72%).
|
||||
@@ -434,7 +454,7 @@ description: |
|
||||
Trigger keywords: presentation, slides, deck, pptx.
|
||||
Triggers - "create presentation", "make slides".
|
||||
|
||||
# ✅ GOOD — single line, 150-300 chars, triggers only
|
||||
# ✅ GOOD — single line, 150-300 chars, what + triggers
|
||||
description: Creates conventional git commits with proper format. Use when - committing, saving work. Trigger keywords - commit, git commit, save changes.
|
||||
```
|
||||
|
||||
@@ -446,7 +466,7 @@ description: [One sentence - what it does]. Use when - [scenarios]. Trigger keyw
|
||||
|
||||
**Rules:**
|
||||
- ONE line, no `|` multiline
|
||||
- 150-300 chars total
|
||||
- 150-250 chars optimal (truncated at 250 since v2.1.84). ALWAYS single line — no multiline YAML `|`
|
||||
- Drop `Triggers -` phrases section (saves ~80 chars)
|
||||
- Use ` - ` separator instead of `:`
|
||||
|
||||
@@ -466,6 +486,22 @@ export SLASH_COMMAND_TOOL_CHAR_BUDGET=50000 # 50K chars
|
||||
|
||||
**Symptom:** Some skills never activate → they're beyond budget, Claude doesn't see them.
|
||||
|
||||
### Trigger Eval Queries (optional but recommended)
|
||||
|
||||
Generate 10 realistic eval queries to test description effectiveness:
|
||||
|
||||
| Type | Count | Description |
|
||||
|---|---|---|
|
||||
| Should trigger | 5 | Queries where skill SHOULD activate. Different phrasings, casual/formal mix |
|
||||
| Should NOT trigger | 5 | Near-misses — share keywords but need different tool. NOT obviously irrelevant |
|
||||
|
||||
Key: should-not-trigger queries must be TRICKY, not obvious. "Write fibonacci" as negative for PDF skill is useless.
|
||||
|
||||
Present to user via AskUserQuestion: "Here are 10 test queries for your skill's description. Look right?"
|
||||
|
||||
Then mentally evaluate: "Given this description, would Claude trigger for each query?"
|
||||
If too many misses → iterate description 2-3 times.
|
||||
|
||||
# Body Style
|
||||
|
||||
Use imperative form:
|
||||
@@ -475,6 +511,18 @@ Use imperative form:
|
||||
| Configure authentication before making requests. | You should configure authentication. |
|
||||
| Validate input data using the provided schema. | You need to validate input data. |
|
||||
|
||||
## Writing Approach
|
||||
|
||||
Explain WHY behind instructions, not just WHAT. LLMs respond better to reasoning than rigid rules.
|
||||
|
||||
| Rigid | Theory of mind |
|
||||
|---|---|
|
||||
| ALWAYS validate input before processing | Validate input first — unvalidated data causes silent corruption in downstream steps |
|
||||
| NEVER use print() for logging | Use the project logger instead of print() — print output disappears in production and pollutes test output |
|
||||
|
||||
If writing ALWAYS/NEVER in all caps — reframe as consequence explanation.
|
||||
Help the model understand context so it can generalize beyond specific examples.
|
||||
|
||||
# Content Organization
|
||||
|
||||
| Location | Content |
|
||||
@@ -545,7 +593,7 @@ Follow the loaded reference document.
|
||||
|
||||
# Resource Path Resolution
|
||||
|
||||
Use `${CLAUDE_SKILL_DIR}` (v2.1.69+) for bash commands, relative paths for Read instructions.
|
||||
Use `${CLAUDE_SKILL_DIR}` (v2.1.71+) for bash commands, relative paths for Read instructions.
|
||||
|
||||
```yaml
|
||||
# Bash — use ${CLAUDE_SKILL_DIR} (CWD is project root, not skill dir)
|
||||
@@ -601,6 +649,17 @@ Priority: Enterprise > Personal > Project. Plugin skills: `/plugin-name:skill-na
|
||||
|
||||
## Step 1: Understand
|
||||
|
||||
### Check Conversation History
|
||||
|
||||
If the current conversation already contains a workflow the user wants to capture
|
||||
(e.g., "turn this into a skill"), extract from history first:
|
||||
- Tools used and their sequence
|
||||
- Steps taken and corrections made
|
||||
- Input/output formats observed
|
||||
- Edge cases encountered
|
||||
|
||||
Confirm extracted workflow with user before proceeding.
|
||||
|
||||
Identify usage patterns: direct examples from user, validated scenarios, real-world use cases. If invoked directly from main conversation (foreground) — use AskUserQuestion for max 2-3 clarifying questions: functionality, usage examples, trigger phrases. If invocation type was provided in prompt — skip questions.
|
||||
|
||||
### Invocation Type (CRITICAL)
|
||||
@@ -655,13 +714,18 @@ Write SKILL.md: frontmatter → overview (1-2 sentences) → instructions (imper
|
||||
|
||||
## Step 5: Validate
|
||||
|
||||
**EXECUTE** validate-skill.sh:
|
||||
```bash
|
||||
bash "$BC_PLUGIN_ROOT/skills/skills/scripts/validate-skill.sh" path/to/skill && echo "✅" || echo "❌"
|
||||
```
|
||||
|
||||
### Structure Checklist
|
||||
|
||||
| Check | Details |
|
||||
|-------|---------|
|
||||
| Structure | SKILL.md with valid YAML frontmatter |
|
||||
| `name` | ≤64 chars, lowercase-hyphens |
|
||||
| `description` | 150-300 chars, ONE line, third-person, no colons |
|
||||
| `description` | 150-250 chars optimal (truncated at 250 since v2.1.84), single line, third-person, no colons |
|
||||
| Body | <500 lines, imperative form |
|
||||
| `context` | `fork` if standalone |
|
||||
| `agent` | Appropriate type |
|
||||
@@ -675,10 +739,10 @@ Write SKILL.md: frontmatter → overview (1-2 sentences) → instructions (imper
|
||||
|
||||
| Check | Details |
|
||||
|-------|---------|
|
||||
| Triggers only | Description has NO summary, only "Use when -", "Trigger keywords -" |
|
||||
| What + When + Keywords | Description includes what skill does + scenarios + trigger keywords |
|
||||
| Keywords present | `Trigger keywords - deploy, staging, prod, release` |
|
||||
| Scenarios present | `Use when - deploying, releasing, shipping` |
|
||||
| One line | No multiline `|`, single YAML line, 150-300 chars |
|
||||
| One line | No multiline `|`, single YAML line, 150-250 chars (truncated at 250 since v2.1.84) |
|
||||
| Third-person | "Deploys..." not "I deploy..." or "Use this to..." |
|
||||
| Critical → slash | `disable-model-invocation: true` for risky operations |
|
||||
| Test activation | Say trigger phrase → skill loads? |
|
||||
@@ -701,10 +765,49 @@ Expected: Always works (100%)
|
||||
|
||||
If Test 1 fails but Test 3 works → optimize description or use `disable-model-invocation: true`.
|
||||
|
||||
## Step 5.5: Quick Eval
|
||||
|
||||
After validation, test the skill with realistic prompts.
|
||||
|
||||
### Generate Test Prompts
|
||||
|
||||
Create 3-5 realistic test prompts — things a real user would actually say.
|
||||
Include detail: file paths, personal context, casual speech, abbreviations.
|
||||
|
||||
| Too abstract | Realistic |
|
||||
|---|---|
|
||||
| "Format this data" | "ok I have this csv in ~/Downloads/sales_q4.csv and need to add a profit margin column" |
|
||||
| "Create a chart" | "can you make a bar chart from the monthly revenue data in report.xlsx" |
|
||||
|
||||
### Run Test Prompts
|
||||
|
||||
For each prompt, spawn a subagent with the skill and evaluate output:
|
||||
- Did the skill trigger? (for LLM-invocable skills)
|
||||
- Did the output match expectations?
|
||||
- Were there unnecessary steps or wasted work?
|
||||
|
||||
### Evaluate Results Inline
|
||||
|
||||
After runs complete, analyze:
|
||||
1. Which prompts triggered the skill, which didn't
|
||||
2. Output quality — does it match what user would expect
|
||||
3. Common patterns — did all runs write similar scripts? → bundle in scripts/
|
||||
4. Wasted effort — did the skill cause unnecessary work? → trim instructions
|
||||
|
||||
If issues found → fix and re-run. If all good → proceed to Step 6.
|
||||
|
||||
## Step 6: Iterate
|
||||
|
||||
Refine based on real-world usage feedback. Check Claude's thinking to verify triggering.
|
||||
|
||||
### Detect Repeated Work
|
||||
|
||||
After running test cases, read transcripts. If all runs independently wrote similar helper scripts
|
||||
or took the same multi-step approach — that's a signal to bundle it:
|
||||
1. Write the common script once in `scripts/`
|
||||
2. Reference from SKILL.md
|
||||
3. Saves every future invocation from reinventing the wheel
|
||||
|
||||
# Common Patterns
|
||||
|
||||
## Reference (Inline)
|
||||
@@ -879,12 +982,15 @@ Source: [skills docs](https://code.claude.com/docs/en/skills)
|
||||
| Using `$BC_PLUGIN_ROOT` for own scripts in SKILL.md | Use `${CLAUDE_SKILL_DIR}` — it's the skill's own directory |
|
||||
| Treating `${CLAUDE_SKILL_DIR}` as env var | It's string substitution in SKILL.md only, not available in hooks/agents |
|
||||
| `skill.md` (lowercase) | Must be `SKILL.md` (uppercase) — lowercase silently ignored ([#17417](https://github.com/anthropics/claude-code/issues/17417)) |
|
||||
| `context: fork` with 5+ phases | Memory loss, forgets task — use inline + external state |
|
||||
| Reserved skill names ("code", "debug", "bug-fix") | Skill won't load — avoid reserved words |
|
||||
| Description >250 chars | Truncated since v2.1.84 — front-load keywords |
|
||||
|
||||
## Activation Mistakes (cause 20% rate)
|
||||
|
||||
| Mistake | Fix |
|
||||
|---------|-----|
|
||||
| Summary in description | **Only triggers!** No "Creates X with Y features" |
|
||||
| Summary WITHOUT triggers | Include BOTH what skill does AND trigger keywords |
|
||||
| No trigger keywords | Add `Trigger keywords: deploy, staging, prod` |
|
||||
| No "Use when:" | Add `Use when: deploying, releasing, shipping` |
|
||||
| Vague description | Specific: "Deploy to k8s" not "Helps with deployment" |
|
||||
@@ -892,6 +998,7 @@ Source: [skills docs](https://code.claude.com/docs/en/skills)
|
||||
| Second-person body | Imperative: "Do X" not "You should do X" |
|
||||
| Critical without slash | Add `disable-model-invocation: true` for critical ops |
|
||||
| Too many skills | Exceeds `SLASH_COMMAND_TOOL_CHAR_BUDGET` → some invisible |
|
||||
| Plugin skills: `disable-model-invocation` ignored | Plugin skills always in context ([#22345](https://github.com/anthropics/claude-code/issues/22345)) — copy to `.claude/skills/` if parity needed |
|
||||
|
||||
# LLM Text Rules
|
||||
|
||||
@@ -956,6 +1063,50 @@ Run optimization: `Skill(skill="text-optimize", args="path/to/SKILL.md")`
|
||||
```
|
||||
Explicit mention increases activation to ~70%.
|
||||
|
||||
# Known Bugs
|
||||
|
||||
| # | Bug | Impact | Status | Workaround |
|
||||
|---|-----|--------|--------|------------|
|
||||
| [#13919](https://github.com/anthropics/claude-code/issues/13919) | Skill context lost after compaction ~55K tokens | Instructions forgotten in long sessions | Open | Re-invoke `/name` or external state |
|
||||
| [#39686](https://github.com/anthropics/claude-code/issues/39686) | claude.ai skills silently injected (~6000 tokens) | 37% of skill budget consumed; no opt-out | Open | No workaround |
|
||||
| [#22345](https://github.com/anthropics/claude-code/issues/22345) | Plugin skills ignore `disable-model-invocation` | Plugin skills always in context (~4400 tokens) | Open | No workaround |
|
||||
| [#17688](https://github.com/anthropics/claude-code/issues/17688) | Skill-scoped hooks don't fire in plugins | Hooks from SKILL.md frontmatter not working for plugin skills | Open | Use plugin hooks.json |
|
||||
| [#35641](https://github.com/anthropics/claude-code/issues/35641) | `/reload-plugins` doesn't load skills from new plugins | Skills emitter not called on reload | Open | Restart session |
|
||||
| [#33080](https://github.com/anthropics/claude-code/issues/33080) | Built-in skills silently conflict with custom | Built-in takes priority; no notification | Open | Namespace prefix (e.g., `my-`) |
|
||||
| [#36031](https://github.com/anthropics/claude-code/issues/36031) | User-level skills visible in autocomplete but not invoked in Desktop | SKILL.md not loaded; CLI works | Open | Use CLI |
|
||||
| [#17417](https://github.com/anthropics/claude-code/issues/17417) | `skill.md` (lowercase) silently ignored | Skill not discovered | Open | Use `SKILL.md` (uppercase) |
|
||||
| [#10768](https://github.com/anthropics/claude-code/issues/10768) | Auto-activation unreliable (20-50%) | Skill not invoked on relevant request | Closed (NOT PLANNED) | Optimize description (50-72%) or `/name` (100%) |
|
||||
| [#15136](https://github.com/anthropics/claude-code/issues/15136) | Claude fails to invoke skill despite instructions | Skill skipped; 6+ duplicates | Closed (NOT PLANNED) | `/name` for 100% |
|
||||
|
||||
## Architectural Limitations
|
||||
|
||||
| Limitation | Details | Workaround |
|
||||
|------------|---------|------------|
|
||||
| Subagents cannot spawn subagents | `AgentTool` excluded from `SubAgentLoop` | Chain from main conversation |
|
||||
| `context: fork` degrades at 5+ phases | Task structure memory loss | Inline + hooks/external state |
|
||||
| Description budget | 2% of context or 16K chars | `SLASH_COMMAND_TOOL_CHAR_BUDGET` env var |
|
||||
| `${CLAUDE_SKILL_DIR}` only in SKILL.md | Not available in hooks/agents | `$CLAUDE_PLUGIN_ROOT` in hooks/agents |
|
||||
| Compaction erases skill context | CLAUDE.md re-read, skills are not | Re-invoke `/name`, external state |
|
||||
| Description <=250 chars | Truncated since v2.1.84 | Front-load keywords |
|
||||
| Plugin skills lack parity | `disable-model-invocation` and skill-scoped hooks don't work | Copy skill to `.claude/skills/` |
|
||||
| Reserved names | Skills named "code", "debug", "bug-fix" don't load | Avoid reserved words |
|
||||
|
||||
## Version History (Skill Features)
|
||||
|
||||
| Version | Date | Changes |
|
||||
|---------|------|---------|
|
||||
| v2.1.85 | 2026-03-26 | `if` field for hooks; fix: skill hooks fired twice |
|
||||
| v2.1.84 | 2026-03-26 | Descriptions <=250 chars; alphabetical `/skills` sort |
|
||||
| v2.1.80 | 2026-03-19 | `effort` frontmatter for skills (`low`/`medium`/`high`/`max`) |
|
||||
| v2.1.76 | 2026-03-14 | `/effort` slash command |
|
||||
| v2.1.74 | 2026-03-12 | Fix: `ask` rules bypassed via `allowed-tools` |
|
||||
| v2.1.73 | 2026-03-11 | Fix: deadlock on mass skill file changes |
|
||||
| v2.1.72 | 2026-03-10 | Fix: built-in slash commands hidden; skill hooks dropped |
|
||||
| v2.1.71 | 2026-03-07 | `${CLAUDE_SKILL_DIR}` variable; `/claude-api` skill |
|
||||
| v2.1.69 | 2026-03-05 | Security: nested discovery skips gitignored dirs; fix: `:` in description |
|
||||
| v2.1.47 | 2026-02-18 | Fix: crash on numeric `name`/`description`; fix: `argument-hint` YAML sequence |
|
||||
| v2.1.45 | 2026-02-17 | Plugin skills available immediately after install (no restart) |
|
||||
|
||||
# Sources
|
||||
|
||||
- [Claude Code Skills](https://code.claude.com/docs/en/skills) — official docs, string substitutions table
|
||||
@@ -963,9 +1114,5 @@ Run optimization: `Skill(skill="text-optimize", args="path/to/SKILL.md")`
|
||||
- [Skill Best Practices](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices)
|
||||
- [agentskills.io](https://agentskills.io)
|
||||
- [Skills Don't Auto-Activate](https://scottspence.com/posts/claude-code-skills-dont-auto-activate)
|
||||
- [GitHub #10768 - Intent Matching Broken](https://github.com/anthropics/claude-code/issues/10768) (OPEN)
|
||||
- [GitHub #12541 - Feature request for $SKILL_DIR](https://github.com/anthropics/claude-code/issues/12541) — led to `${CLAUDE_SKILL_DIR}`
|
||||
- [GitHub #13919 - Context loss](https://github.com/anthropics/claude-code/issues/13919) (OPEN)
|
||||
- [GitHub #15136 - Fails to invoke](https://github.com/anthropics/claude-code/issues/15136) (OPEN)
|
||||
- [GitHub #17417 - SKILL.md case-sensitivity](https://github.com/anthropics/claude-code/issues/17417) — lowercase silently ignored
|
||||
- [GitHub #9716 - Not aware of skills](https://github.com/anthropics/claude-code/issues/9716) (OPEN)
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
],
|
||||
"PermissionRequest": [
|
||||
{
|
||||
"matcher": "Edit|Write|MultiEdit",
|
||||
"matcher": "Edit|Write|MultiEdit|Bash",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
|
||||
@@ -2,10 +2,91 @@
|
||||
set -euo pipefail
|
||||
|
||||
INPUT=$(cat)
|
||||
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty')
|
||||
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
|
||||
|
||||
ALLOW='{"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"allow"}}}'
|
||||
|
||||
# --- Helper: check if a single path is within allowed directories ---
|
||||
is_allowed_path() {
|
||||
local p="$1"
|
||||
# Skip global ~/.claude/
|
||||
[[ "$p" == "$HOME/.claude/"* || "$p" == "$HOME/.claude" ]] && return 1
|
||||
# System temp dirs
|
||||
[[ "$p" == /tmp/* || "$p" == /tmp || "$p" == /private/tmp/* || "$p" == /private/tmp ]] && return 0
|
||||
# Allowed .claude/ subdirectories (both relative .claude/ and absolute */.claude/)
|
||||
case "$p" in
|
||||
.claude/tasks/*|.claude/tasks|*/.claude/tasks/*|*/.claude/tasks) return 0 ;;
|
||||
.claude/tmp/*|.claude/tmp|*/.claude/tmp/*|*/.claude/tmp) return 0 ;;
|
||||
.claude/reports/*|.claude/reports|*/.claude/reports/*|*/.claude/reports) return 0 ;;
|
||||
.claude/rules/*|.claude/rules|*/.claude/rules/*|*/.claude/rules) return 0 ;;
|
||||
.claude/skills/*|.claude/skills|*/.claude/skills/*|*/.claude/skills) return 0 ;;
|
||||
.claude/scripts/*|.claude/scripts|*/.claude/scripts/*|*/.claude/scripts) return 0 ;;
|
||||
.claude/agents/*|.claude/agents|*/.claude/agents/*|*/.claude/agents) return 0 ;;
|
||||
.claude/hooks/*|.claude/hooks|*/.claude/hooks/*|*/.claude/hooks) return 0 ;;
|
||||
.claude/private/*|.claude/private|*/.claude/private/*|*/.claude/private) return 0 ;;
|
||||
.claude/convention/*|.claude/convention|*/.claude/convention/*|*/.claude/convention) return 0 ;;
|
||||
.claude/plans/*|.claude/plans|*/.claude/plans/*|*/.claude/plans) return 0 ;;
|
||||
.claude/settings.json|.claude/settings.local.json|*/.claude/settings.json|*/.claude/settings.local.json) return 0 ;;
|
||||
.claude/TASK.md|.claude/CLAUDE.md|*/.claude/TASK.md|*/.claude/CLAUDE.md) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# --- Bash tool handling ---
|
||||
if [[ "$TOOL_NAME" == "Bash" ]]; then
|
||||
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
|
||||
[[ -z "$CMD" ]] && { echo '{}'; exit 0; }
|
||||
|
||||
# Block network commands unconditionally
|
||||
if echo "$CMD" | grep -qE '\b(curl|wget|ssh|scp|rsync|nc|ncat|socat|ftp|sftp)\b'; then
|
||||
echo '{}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Block dangerous redirections / evals
|
||||
if echo "$CMD" | grep -qE '(>\s*/dev/|>\s*/etc/|\beval\b|\bexec\b|\bsource\b|\b\.\s+/)'; then
|
||||
echo '{}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# For rm: only allow within .claude/tasks/ or .claude/tmp/ or /tmp/
|
||||
if echo "$CMD" | grep -qE '\brm\b'; then
|
||||
RM_PATHS=$(echo "$CMD" | grep -oE '(\.claude|/tmp|/private/tmp)[^ ]*' || true)
|
||||
[[ -z "$RM_PATHS" ]] && { echo '{}'; exit 0; }
|
||||
while IFS= read -r rp; do
|
||||
case "$rp" in
|
||||
.claude/tasks/*|*/.claude/tasks/*) ;;
|
||||
.claude/tmp/*|*/.claude/tmp/*) ;;
|
||||
/tmp/*|/private/tmp/*) ;;
|
||||
*) echo '{}'; exit 0 ;;
|
||||
esac
|
||||
done <<< "$RM_PATHS"
|
||||
echo "$ALLOW"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Extract all path-like tokens that reference .claude/ or temp dirs
|
||||
# Match: .claude/..., /abs/path/.claude/..., /tmp/..., /private/tmp/...
|
||||
ALL_PATHS=$(echo "$CMD" | grep -oE '(/[^ "'"'"'|;&>]*/?\.claude/[^ "'"'"'|;&>]*|\.claude/[^ "'"'"'|;&>]*|/tmp/[^ "'"'"'|;&>]*|/private/tmp/[^ "'"'"'|;&>]*)' || true)
|
||||
|
||||
# If no .claude/ or temp paths found, not our concern -- don't auto-allow
|
||||
[[ -z "$ALL_PATHS" ]] && { echo '{}'; exit 0; }
|
||||
|
||||
# Verify ALL extracted paths are within allowed directories
|
||||
while IFS= read -r path; do
|
||||
[[ -z "$path" ]] && continue
|
||||
if ! is_allowed_path "$path"; then
|
||||
echo '{}'
|
||||
exit 0
|
||||
fi
|
||||
done <<< "$ALL_PATHS"
|
||||
|
||||
echo "$ALLOW"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# --- Edit/Write/MultiEdit tool handling (existing logic) ---
|
||||
if [ -z "$FILE_PATH" ]; then
|
||||
echo '{}'
|
||||
exit 0
|
||||
@@ -20,6 +101,8 @@ fi
|
||||
case "$FILE_PATH" in
|
||||
*/.claude/tasks/*|*/.claude/tasks)
|
||||
echo "$ALLOW" ;;
|
||||
*/.claude/tmp/*|*/.claude/tmp)
|
||||
echo "$ALLOW" ;;
|
||||
*/.claude/reports/*|*/.claude/reports)
|
||||
echo "$ALLOW" ;;
|
||||
*/.claude/rules/*|*/.claude/rules)
|
||||
@@ -42,6 +125,8 @@ case "$FILE_PATH" in
|
||||
echo "$ALLOW" ;;
|
||||
*/.claude/TASK.md|*/.claude/CLAUDE.md)
|
||||
echo "$ALLOW" ;;
|
||||
/tmp/*|/private/tmp/*)
|
||||
echo "$ALLOW" ;;
|
||||
*)
|
||||
echo '{}' ;;
|
||||
esac
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "claude-plugin-brewcode",
|
||||
"version": "3.4.8",
|
||||
"version": "3.4.9",
|
||||
"description": "Infinite task execution with automatic handoff for Claude Code",
|
||||
"keywords": [
|
||||
"claude-code",
|
||||
@@ -36,6 +36,6 @@
|
||||
},
|
||||
"claude-plugin": {
|
||||
"name": "brewcode",
|
||||
"version": "3.4.8"
|
||||
"version": "3.4.9"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,6 +157,11 @@ Task tool:
|
||||
|
||||
Research topic, then create skill via skill-creator.
|
||||
|
||||
### Step 0: Check Conversation History
|
||||
|
||||
Before research — check if current conversation already contains workflow to capture.
|
||||
If yes: extract tools, steps, corrections, I/O formats. Skip research, go directly to Step 4 with extracted context.
|
||||
|
||||
### Step 1: Determine Input Type
|
||||
|
||||
| Input | Action |
|
||||
@@ -243,6 +248,19 @@ Task tool:
|
||||
model: opus
|
||||
```
|
||||
|
||||
### Step 5: Post-Create Eval (optional)
|
||||
|
||||
Ask user via AskUserQuestion:
|
||||
```
|
||||
header: "Quick Eval"
|
||||
question: "Run 3 test prompts to verify the skill works?"
|
||||
options:
|
||||
- label: "Yes — test it"
|
||||
- label: "No — I'll test manually"
|
||||
```
|
||||
|
||||
If yes: spawn skill-creator agent with eval prompt targeting the new skill.
|
||||
|
||||
</instructions>
|
||||
|
||||
---
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "brewdoc",
|
||||
"version": "3.4.8",
|
||||
"version": "3.4.9",
|
||||
"description": "Brewdoc - Claude Code documentation tools: auto-sync for skills/agents/rules, my-claude installation docs, memory optimization",
|
||||
"author": {
|
||||
"name": "Maksim Kochetkov",
|
||||
|
||||
Reference in New Issue
Block a user