docs(kyberforge): add component-selection research closing the when-to-use gap

## Why

The existing kyberforge research covered skills vs agents (ADR-0010),
Copilot track selection, and agent scope hierarchy — but had no documented
basis for three practical decisions: when to use MCP servers vs skills vs
agents, when hooks are the right tool vs skills, and when bin/ is
appropriate vs scripts/ inside a skill directory. Without this, the
plugin-author and agent-author skills have no research backing for those
choices.

## Implementation Notes

Sourced from official Claude Code plugin docs (code.claude.com), official
GitHub Copilot CLI docs (docs.github.com), and the Copilot
customization-cheat-sheet and comparing-cli-features pages — the latter
containing the only official "putting it together" decision table across
components. Context7 MCP was the primary retrieval mechanism; web reads
deepened the hooks and bin/ content.

Three files produced:
- overview.md — mental model, component roles, cross-provider portability
- decision-guide.md — explicit decision tables for all three gaps,
  including anti-patterns and Copilot surface support matrix
- hooks.md — full lifecycle event reference, stdin/stdout schema,
  hookSpecificOutput per event, plugin scope restriction

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0147vXtL5sP6vorDdqXGJJU9
This commit is contained in:
2026-06-28 20:49:05 +00:00
parent e1e85284d1
commit e3e43502db
4 changed files with 475 additions and 0 deletions

View File

@@ -0,0 +1,131 @@
---
topic: decision-guide
source_keys:
- context7-websites-code-claude
- context7-websites-github-en-copilot
- copilot-comparing-cli-features
- copilot-customization-cheat-sheet
- claude-code-plugins-reference
- claude-code-whats-new-2026-w14
---
## Master Decision Table
From the official Copilot CLI comparing-features guide:
| Requirement | Component |
|---|---|
| Copilot should always follow repository conventions | Custom instructions / `CLAUDE.md` |
| Repeatable on-demand workflow | Skill |
| Consistent prompting / broad standards | Custom instructions (not hooks) |
| Guardrails, policy, or automation around tool / session events | Hook |
| External service tool access | MCP server |
| Specialist operation with constrained toolset | Custom agent |
| Complex multi-step task delegation | Subagent (spawned automatically) |
| Package functionality for distribution | Plugin |
---
## Gap 1: MCP Servers vs Skills vs Agents
These three are often confused because all involve extending what Claude can do. The distinction is runtime model:
| | Skill | Agent | MCP Server |
|---|---|---|---|
| Runtime | No process — Claude reads instructions | Claude Code spawns a subagent session | Long-running external process |
| What it adds | Workflow instructions / prompt guidance | A scoped collaborator with its own model and tools | Callable tool functions |
| Who invokes | Claude (by reasoning) or user (`/name`) | Claude (by delegation) or user (`@agent-name`) | Claude (by reasoning, like any tool) |
| Isolation | None — runs in the main conversation | Full — own context window, system prompt, tool list | Full — separate process |
| Best for | Multi-step workflows Claude follows | Domain-focused tasks requiring extended reasoning or parallelism | External APIs, databases, real-time data, persistent services |
**Decision questions:**
1. Does this require a new callable function (e.g. "query database", "fetch issues", "run browser test")? → **MCP server.** MCP adds new tool verbs Claude can call, like built-ins.
2. Does this require a specialist persona with a restricted tool set and its own context? → **Agent.** Use when a task needs domain focus, turn budgeting, or tool isolation that would pollute the main conversation.
3. Does this require prompt guidance and workflow instructions Claude reasons about and follows? → **Skill.** Skills are the lightest option — no process, no isolation overhead, no daemon. Prefer skills when the capability is instructional rather than procedural-external.
**Anti-patterns:**
- Do not put an API call inside a skill body and expect it to work reliably — skills are instruction sets, not execution environments. Wrap the API in an MCP server tool instead.
- Do not use an agent when a skill suffices. Agents have overhead (isolated context, spawn cost). Use them only when isolation or domain specialization is the point.
- Do not use MCP for self-contained multi-step workflows that don't touch external systems — a skill handles that more cheaply.
---
## Gap 2: Hooks vs Skills
The official Copilot guide states it directly: "Avoid hooks when you primarily need consistent prompting (use skills), persistent preferences (use custom instructions), new external capabilities (use MCP servers)."
| | Skill | Hook |
|---|---|---|
| Trigger | Claude's reasoning or user slash command | Automatic — fires on matching lifecycle event |
| Format | Markdown prompt/instructions | JSON event matcher + shell/HTTP command |
| Can block tool calls | No | Yes (`PreToolUse`, `UserPromptExpansion`) |
| Can modify tool input/output | No | Yes (`updatedInput`, `updatedToolOutput`) |
| Runs deterministically | No — Claude decides | Yes — fires every time the event matches |
| Reasoning involved | Yes | None |
| Best for | Repeatable workflows Claude follows, reusable output formatting, optional task guidance | Security enforcement, context injection, post-processing, auditing, session automation |
**Decision questions:**
1. Must this execute at a specific lifecycle point regardless of what Claude plans to do? → **Hook.** Hooks fire unconditionally on event match — Claude cannot suppress them.
2. Must this block a tool call before it executes? → **Hook (`PreToolUse`).** Skills cannot block tool calls.
3. Is this a reusable workflow with multiple steps Claude should reason about? → **Skill.** Skills let Claude adapt to context; hooks execute blindly.
4. Does this inject dynamic per-session context (current branch, open tickets, environment state)? → **Hook (`SessionStart`).** Hooks get this information from the environment without any model inference cost.
5. Must this run after every file edit, every session end, or every prompt submission? → **Hook.** Skills run when Claude judges them relevant; hooks run every time.
**Examples by category:**
| Use case | Component | Reason |
|---|---|---|
| Auto-lint after every Write/Edit | Hook (PostToolUse) | Guaranteed execution, no reasoning |
| Block `rm -rf` commands | Hook (PreToolUse) | Synchronous enforcement before execution |
| Inject current git branch at session start | Hook (SessionStart) | Dynamic env context, zero model cost |
| Guide Claude through a release note workflow | Skill | Multi-step reasoning, optional invocation |
| Scan for secrets after file write | Hook (PostToolUse) | Must always run, cannot be skipped |
| Repeatable output formatting template | Skill | Claude reads and applies; no auto-trigger needed |
| Archive transcript when session ends | Hook (SessionEnd) | Session lifecycle, not reasoning-driven |
| Validate subagent output before returning | Hook (SubagentStop) | Lifecycle control point |
| Enforce ticket ID in commit messages | Hook (PreToolUse, matcher: Bash) | Policy enforcement before tool runs |
---
## Gap 3: `bin/` vs `scripts/` in a Skill
Both are ways to ship executable code alongside a plugin, but they differ in scope and invocation:
| | `bin/` (plugin root) | `scripts/` (inside `skills/<name>/`) |
|---|---|---|
| Scope | All Bash tool calls session-wide while plugin is enabled | That skill's content only |
| Invocation | Bare command name (`my-tool`) | Full path via `${CLAUDE_PLUGIN_ROOT}/skills/<name>/scripts/my-script.sh` |
| Shared? | Yes — any skill, agent, or hook can call it | No — local to the skill |
| PATH injection | Yes — added to Bash tool's PATH | No |
| Purpose | Shared CLI helpers used by multiple components | Skill-specific support scripts |
**Decision rule:**
- Use `bin/` when a utility is called by more than one component (two skills, a skill and a hook, etc.), or when you want Claude to be able to invoke it as a bare command in Bash without knowing the plugin's install path.
- Use `scripts/` when a helper is only needed by one skill and should be kept self-contained. This also supports the cache-isolation guarantee — the skill directory is fully portable.
**Anti-pattern:** Do not reference `scripts/` files from a hook or a different skill using a relative path — those paths break in plugin cache mode. Either put the shared file in `bin/`, or duplicate it into each skill's `scripts/` directory.
---
## Surface Support (Copilot)
Some components are not available on all surfaces. Verify availability before building:
| Component | VS Code | JetBrains | GitHub.com | Copilot CLI |
|---|:---:|:---:|:---:|:---:|
| Skills | yes | yes | yes | yes |
| Custom agents | yes | preview | yes | yes |
| Hooks | preview | no | yes | yes |
| MCP servers | yes | yes | yes | yes |
| Subagents | yes | preview | no | yes |
Hooks have the most limited surface support. If a behavior must work in JetBrains or non-CLI contexts, prefer a skill or MCP approach.

View File

@@ -0,0 +1,191 @@
---
topic: hooks
source_keys:
- claude-code-hooks
- claude-code-plugins-reference
- copilot-hooks
- copilot-customization-cheat-sheet
- context7-websites-code-claude
- context7-websites-github-en-copilot
---
## What Hooks Are
Hooks are user-defined shell commands or HTTP endpoints that execute deterministically at specific points in an agent's lifecycle. No model reasoning is involved — the hook fires unconditionally whenever its configured event matches, regardless of what Claude intended to do.
This is the defining property: hooks enforce invariants outside Claude's reasoning path. They are not invoked by Claude; they are triggered by the runtime on event occurrence.
---
## Lifecycle Events
### Claude Code
**Session-level** (once per session):
| Event | When | Can block? |
|---|---|---|
| `SessionStart` | Session begins or resumes | No |
| `Setup` | `--init-only` / `--init` / `--maintenance` mode | No |
| `SessionEnd` | Session terminates | No |
**Per-turn** (once per user prompt):
| Event | When | Can block? |
|---|---|---|
| `UserPromptSubmit` | User submits a prompt, before Claude processes it | Yes (exit 2) |
| `UserPromptExpansion` | A slash command expands into a prompt | Yes |
| `Stop` | Claude finishes responding | Yes |
| `StopFailure` | Turn ends due to API error | No |
**Agentic loop** (per tool call):
| Event | When | Can block? |
|---|---|---|
| `PreToolUse` | Before a tool call executes | Yes |
| `PermissionRequest` | Permission dialog appears | Yes |
| `PermissionDenied` | Tool denied by auto-mode classifier | No (can retry) |
| `PostToolUse` | After a tool call succeeds | Yes (further turns) |
| `PostToolUseFailure` | After a tool call fails | No |
| `PostToolBatch` | After a batch of parallel tool calls resolves | Yes |
**Subagent / team events**:
| Event | When | Can block? |
|---|---|---|
| `SubagentStart` | Subagent spawns | No |
| `SubagentStop` | Subagent finishes | Yes |
| `TeammateIdle` | Agent team teammate about to go idle | Yes |
**Task management**:
| Event | When | Can block? |
|---|---|---|
| `TaskCreated` | Task being created via `TaskCreate` | Yes |
| `TaskCompleted` | Task being marked complete | Yes |
**File / config (async)**:
| Event | When | Can block? |
|---|---|---|
| `FileChanged` | Watched file changes on disk | No |
| `ConfigChange` | Config file changes during session | Yes |
| `CwdChanged` | Working directory changes | No |
| `InstructionsLoaded` | `CLAUDE.md` or `.claude/rules/*.md` loaded | No |
**Context compaction**:
| Event | When | Can block? |
|---|---|---|
| `PreCompact` | Before context compaction | Yes |
| `PostCompact` | After compaction completes | No |
**MCP elicitation**:
| Event | When | Can block? |
|---|---|---|
| `Elicitation` | MCP server requests user input during a tool call | Yes |
| `ElicitationResult` | After user responds to MCP elicitation | Yes |
**Worktree**:
| Event | When | Can block? |
|---|---|---|
| `WorktreeCreate` | Worktree being created | Yes |
| `WorktreeRemove` | Worktree being removed | No |
### Copilot CLI
Copilot CLI uses a subset: `sessionStart`, `sessionEnd`, `userPromptSubmitted`, `preToolUse`, `postToolUse`, `errorOccurred`, `agentStop`.
---
## Inputs
Every hook receives a JSON object on stdin with these common fields:
```json
{
"session_id": "abc123",
"transcript_path": "/path/to/transcript.jsonl",
"cwd": "/current/working/directory",
"permission_mode": "default",
"hook_event_name": "PreToolUse",
"agent_id": "optional-subagent-id",
"agent_type": "optional-agent-name"
}
```
Tool events additionally include `tool_name` and `tool_input`. `UserPromptSubmit` adds `prompt` and `messages_in_context`. `SessionStart` adds `source` (`startup`, `resume`, `clear`, `compact`), and optionally `model` and `session_title`. `FileChanged` adds `file_path` and `change_type`.
---
## Outputs
**Exit codes:**
- `0` — success; Claude Code parses stdout as JSON for structured control
- `2` — blocking error; stderr sent to Claude; blocks the tool call on PreToolUse
- Other — non-blocking error; first line of stderr shown in transcript; execution continues
**Universal JSON output fields (exit 0 only):**
| Field | Effect |
|---|---|
| `continue: false` | Stops the current turn with `stopReason` message |
| `suppressOutput: true` | Hides hook output from the UI |
| `systemMessage` | Warning shown to the user in the UI |
**Event-specific output via `hookSpecificOutput`:**
`PreToolUse` — can allow, deny, or modify:
- `permissionDecision: "allow"` / `"deny"` with `permissionDecisionReason`
- `updatedInput` — replace the tool's input before it executes
- `additionalContext` — inject text into Claude's context
`PostToolUse` — can block further turns or replace what Claude sees:
- `decision: "block"` with `reason`
- `updatedToolOutput` — replace the tool result text Claude receives
- `additionalContext`
`Stop` / `SubagentStop` — can block turn completion:
- `decision: "block"` with `reason` (causes Claude to continue the agentic loop)
`SessionStart` — richest output; can inject context, set title, watch paths, reload skills:
- `additionalContext` — dynamic context added to Claude's context at session start
- `watchPaths` — file paths to monitor for `FileChanged` events
- `reloadSkills: true` — force skill reload
- `sessionTitle` — set or auto-generate the session title
Plain stdout behavior by event: for `SessionStart`, `Setup`, `SubagentStart`, `UserPromptSubmit`, and `UserPromptExpansion`, plain text stdout is added as context visible to the model. For all other events, plain text goes to the debug log only — use `hookSpecificOutput.additionalContext` instead.
---
## Common Patterns
**Block a dangerous command (PreToolUse):**
```json
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "rm -rf is blocked by policy"
}
}
```
**Inject git state at session start (SessionStart):**
```bash
echo "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"Branch: $(git branch --show-current)\nOpen issues: $(gh issue list --limit 5 --json number,title)\"}}"
```
**Auto-lint after edit (PostToolUse, matcher: `Edit|Write`):**
Exit 0 to continue, or exit 2 with lint errors in stderr to block the turn.
**Validate subagent output before returning (SubagentStop):**
Exit 2 if validation fails; Claude will retry the subagent call.
---
## Plugin Scope Restriction
Plugin-shipped hooks (in `hooks/hooks.json` inside a plugin directory) are silently ignored when the agent definition is loaded from a plugin's `agents/` directory. Per-agent hooks only work when the agent file is at `.claude/agents/` or `~/.claude/agents/`. This is a known limitation — copy the agent file to project or user scope to use per-agent hooks.

View File

@@ -0,0 +1,89 @@
---
topic: overview
source_keys:
- context7-websites-code-claude
- context7-websites-github-en-copilot
- claude-code-plugins-reference
- copilot-comparing-cli-features
---
## What Plugin Components Are
A plugin bundles multiple component types. Each has a distinct runtime role. Understanding which role a problem requires is the first decision.
The two primary axes are:
**Axis 1 — Who decides to invoke it?**
| Claude reasons about invoking | Fires automatically / deterministically |
|---|---|
| Skills | Hooks |
| Agents | Monitors (background watchers) |
| MCP server tools (Claude picks when to call) | MCP server process (always running when plugin enabled) |
**Axis 2 — What does it add?**
| Adds instructions / workflow guidance | Adds callable capabilities | Delegates work |
|---|---|---|
| Skills | MCP servers (new tool verbs) | Agents (subagent sessions) |
| Custom instructions | Hooks (side-effects, enforcement) | Subagents (parallel subtasks) |
---
## Component Roles
### Skills (`skills/`)
Markdown instruction files. Claude reads them and reasons about whether and how to follow them. No background process. No automatic trigger. Claude loads a skill when it judges the task matches — or the user invokes via slash command.
Skills are prompt guidance, not programs. They extend what Claude knows how to do.
### Agents (`agents/`)
Specialized subagent sessions with their own system prompt, tool restrictions, model choice, and turn budget. Claude spawns them when it needs to delegate a task requiring extended reasoning or domain focus. They run in isolated context windows — they do not inherit the parent conversation.
Agents extend what Claude can delegate to, not what it knows itself.
### MCP Servers (`.mcp.json`)
External processes that expose callable tool functions via the Model Context Protocol. They start automatically when the plugin is enabled and run as background services. Claude calls their tools the same way it calls built-ins (Read, Bash, etc.) — but decides when to call them based on context.
MCP servers extend the tool set Claude can call.
### Hooks (`hooks/hooks.json`)
Shell commands or HTTP endpoints that fire deterministically at specific lifecycle events. No model reasoning involved — the hook runs every time its event fires, regardless of what Claude intends. Hooks can block tool calls, modify inputs/outputs, inject context, and enforce policies.
Hooks enforce what happens automatically, outside of Claude's reasoning.
### `bin/` (plugin root)
Executables placed here are added to the Bash tool's `PATH` for the duration of the session while the plugin is enabled. Claude — or any hook, skill script, or agent — can invoke them as bare commands without absolute paths. Scoped to all Bash calls session-wide.
`bin/` is shared infrastructure for the plugin's other components.
### `scripts/` (inside a skill directory)
Local support files for one skill. Not on PATH. Referenced by absolute path via `${CLAUDE_PLUGIN_ROOT}` in hook commands or skill content. Scoped to the single skill, not available to other components.
### Monitors (`monitors/monitors.json`)
Background shell processes that run continuously and stream their stdout to Claude as notifications. Use for watching logs, polling external status, or reacting to filesystem changes in real time.
### `settings.json` (plugin root)
Default settings applied when the plugin is enabled. Currently supports `agent` (activate a named agent as the main session thread) and `subagentStatusLine`. Project and user settings override plugin settings on collision.
---
## Cross-Provider Portability
`SKILL.md` is portable — the same file works in Claude Code and Copilot CLI. All other component formats are provider-specific:
| Component | Claude Code format | Copilot CLI format |
|---|---|---|
| Skills | `skills/<name>/SKILL.md` | `skills/<name>/SKILL.md` (identical) |
| Agents | `.md` with YAML frontmatter | `.agent.md` with YAML frontmatter |
| Hooks | `hooks/hooks.json` | `hooks.json` (same schema) |
| MCP servers | `.mcp.json` | `.mcp.json` (same schema) |
| Manifest | `.claude-plugin/plugin.json` | `plugin.json` at root |

View File

@@ -0,0 +1,64 @@
# Sources
## context7-websites-code-claude
- **URL:** context7:/websites/code_claude
- **Description:** Official Claude Code documentation via Context7 — plugin architecture, component types, bin/ directory, hooks, MCP, agent SDK
- **Contributing files:** overview.md, decision-guide.md, hooks.md
- **Status:** `extracted`
## context7-websites-github-en-copilot
- **URL:** context7:/websites/github_en_copilot
- **Description:** Official GitHub Copilot documentation via Context7 — CLI plugin system, component comparison, hooks, MCP, custom agents
- **Contributing files:** overview.md, decision-guide.md, hooks.md
- **Status:** `extracted`
## copilot-comparing-cli-features
- **URL:** https://docs.github.com/en/copilot/concepts/agents/copilot-cli/comparing-cli-features
- **Description:** Copilot CLI component comparison guide — when to use custom instructions, skills, tools, MCP servers, hooks, subagents, custom agents, and plugins; includes the "Putting it together" decision table and "When shouldn't you use hooks?" section
- **Contributing files:** overview.md, decision-guide.md
- **Status:** `extracted`
## copilot-customization-cheat-sheet
- **URL:** https://docs.github.com/en/copilot/reference/customization-cheat-sheet
- **Description:** Copilot customization cheat sheet — full comparison table covering trigger mechanism, best-for scenarios, and IDE surface support matrix for all component types
- **Contributing files:** decision-guide.md
- **Status:** `extracted`
## copilot-hooks
- **URL:** https://docs.github.com/en/copilot/concepts/agents/hooks
- **Description:** Copilot hooks documentation — lifecycle events, hook configuration, example hook JSON for sessionStart, userPromptSubmitted, preToolUse, postToolUse, sessionEnd
- **Contributing files:** hooks.md
- **Status:** `extracted`
## claude-code-plugins-reference
- **URL:** https://code.claude.com/docs/en/plugins-reference
- **Description:** Claude Code plugins reference — full component directory layout, skills vs commands, agents frontmatter, hooks event list, MCP server config, bin/ directory, monitors, settings.json; includes per-component when-to-use guidance
- **Contributing files:** overview.md, decision-guide.md, hooks.md
- **Status:** `extracted`
## claude-code-whats-new-2026-w14
- **URL:** https://code.claude.com/docs/en/whats-new/2026-w14
- **Description:** Claude Code v2.1.91 changelog — bin/ directory PATH injection feature introduction and structure example
- **Contributing files:** decision-guide.md
- **Status:** `extracted`
## claude-code-hooks
- **URL:** https://code.claude.com/docs/en/hooks
- **Description:** Claude Code hooks deep reference — full lifecycle event table, stdin JSON schema, exit code semantics, hookSpecificOutput per event, hooks vs skills comparison table, hooks vs MCP servers vs agents
- **Contributing files:** hooks.md, decision-guide.md
- **Status:** `extracted`
## claude-code-agent-sdk-plugins
- **URL:** https://code.claude.com/docs/en/agent-sdk/plugins
- **Description:** Claude Code Agent SDK plugin documentation — plugin directory structure, skills vs commands distinction, component auto-discovery
- **Contributing files:** overview.md
- **Status:** `extracted`