🎯What you get here
Leave knowing how to write a skill that triggers on its own, a sub-agent that the main Claude delegates to at the right time, and how to understand Claude Code-exclusive features (dynamic injection, allowed-tools) that do NOT exist in Codex.
Detailed content
📦 Anatomy of a skill
A skill in Claude Code is a folder in .claude/skills/<nome>/ with a conventional structure. The heart is SKILL.md, but there are more pieces, each with a clear purpose.
Complete structure
.claude/skills/minha-skill/ ├── SKILL.md ← obrigatório (frontmatter + body) ├── scripts/ ← scripts auxiliares chamáveis │ ├── check.sh │ └── format.py ├── references/ ← docs profundas (lazy-load) │ ├── api-spec.md │ └── examples.md └── assets/ ← imagens, binários, templates └── template.html
Complete SKILL.md (real example)
--- name: revisar-pr description: Use quando o usuário pedir pra revisar uma PR ou diff. Triggers: "revisa PR", "review pull request", "olha o diff". allowed-tools: Bash(git diff:*), Bash(gh pr:*), Read, Grep, Glob disable-model-invocation: false --- # Revisar PR ## Passo a passo 1. Identifica a PR (número via $ARGUMENTS ou \`gh pr list\`) 2. Lê diff completo com \`gh pr diff <numero>\` 3. Para cada arquivo mudado, verifica: - Bugs de correção (não estilo) - Edge cases não tratados - Vulnerabilidades comuns 4. Consulta \`references/security-checklist.md\` se tocar em auth 5. Retorna findings categorizados por severity (high/med/low) ## Referências - Checklist completo: \`references/security-checklist.md\` - Padrões do repo: \`references/repo-conventions.md\`
✓ Well-made skill
- • Short, direct body (step-by-step)
- • Details in
references/(lazy) - •
allowed-toolsrestricted to what’s necessary - • description with real-world triggers
- • Scripts for deterministic actions
✗ Anti-pattern
- • 200KB body with EVERYTHING inline
- • description that just repeats the name
- • No allowed-tools (anything goes)
- • Scripts in the body instead of
scripts/ - • Mix multiple responsibilities
Key concepts
name + description min
Step-by-step, < 5KB
Loaded on demand
Actions without an LLM
🎯 Description — the art of the trigger
The biggest cause of a “skill not working” is bad description. It’s not a bug—it’s a semantic match failing. Claude reads the descriptions of all skills and chooses the best one for the current context. Your description is competing for attention.
✗ Poor description
description: Skill de revisão
→ Vague. Doesn't say when to use it. No trigger. The skill stays invisibly dormant.
✓ Good description
description: Use quando o usuário pedir pra revisar PR/diff. Triggers: "revisa PR #123", "review da branch", "olha o diff", "code review".
→ Says when. Lists real triggers. Match gets it right.
Recipe for a quality description
💡Empirical test
After writing it, open Claude Code and simulates 5 real prompts that should activate the skill. If it activates in 4/5, that's fine. If it activates in 2/5, the description is weak. Iterate.
Key concepts
Claude reads and decides
Trigger standard
User phrases
5 real prompts
👤 Auto-invocable sub-agents
A sub-agent is a specialized persona with its own system prompt, restricted tool surface, and isolated context. The main Claude reads the description and DELEGATES — on its own, without you asking by name. It’s the feature that most distinguishes Claude from Codex.
Example — .claude/agents/code-reviewer.md
--- name: code-reviewer description: Use proactively when the user finishes implementing a feature or before merging a PR. Specializes in catching correctness bugs. tools: Read, Grep, Glob, Bash(git diff:*) model: claude-opus-4-6 --- You are a senior code reviewer focused on correctness. ## Your role - Read the diff carefully - Flag correctness bugs (NOT style — linter handles that) - Check edge cases (null, empty, off-by-one, race conditions) - Note security risks (SQLi, XSS, path traversal, auth bypass) ## Output format A numbered list of findings: 1. **[severity]** file:line — what's wrong, why, suggested fix Be terse. No fluff.
Context isolation
A sub-agent opens its own window — it doesn’t clutter the main agent’s context. It returns only the result.
Parallelism
Claude can launch multiple sub-agents in parallel (Task tool). Useful for research from multiple angles.
Dedicated model
Each sub-agent can use a different model. Haiku for searches, Opus for analysis. Savings + quality.
Description with “proactively” — the secret
The word “proactively” in the description is a strong signal to the main Claude: “use this WITHOUT the user asking, when the context matches.” Without it, the subagent almost never fires on its own.
description: Use proactively when... // dispara sozinho description: Use when the user explicitly asks... // só sob pedido
Key concepts
By description
Delegation mechanism
tools: [a, b, c]
Keyword
🔌 MCP servers — declaration and use
MCP server exposes external tools to Claude. Declared in .mcp.json (project, goes into git) or ~/.claude.json (global). Each exposed tool becomes mcp__servidor__nome-tool.
.mcp.json (project)
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_TOKEN": "${GITHUB_TOKEN}" }
},
"postgres": {
"command": "uvx",
"args": ["mcp-server-postgres", "--db-url", "${DATABASE_URL}"]
},
"linear": {
"type": "http",
"url": "https://mcp.linear.app/sse",
"headers": { "Authorization": "Bearer ${LINEAR_TOKEN}" }
}
}
}
Allowlist in settings.json
{
"enabledMcpjsonServers": ["github", "postgres"], // só estes ativam
"permissions": {
"allow": [
"mcp__github", // libera tudo do server
"mcp__postgres__query" // libera tool específica
]
}
}
📦 stdio transport
Server runs as a child process via stdin/stdout. More common for local MCP.
Example: npm/uvx starts a process, Claude communicates through a pipe.
🌐 HTTP/SSE transport
Server runs as a remote service. Claude connects via HTTP with Server-Sent Events.
Example: Linear, Slack, SaaS services with an official MCP endpoint.
Key concepts
Project-level, goes in git
Global
Two transports
mcp__server__tool
🎨 Dynamic injection (backtick-bang) — Claude-only
Claude Code-specific syntax: inside SKILL.md or commands, code between crase-bang (`!comando`) is executed by the shell BEFORE the skill reaches the LLM. The result goes directly into the prompt — no additional tool call.
Practical example
--- name: branch-status description: Mostra contexto da branch atual antes de propor próxima ação --- # Status da branch Branch atual: `!git branch --show-current` Último commit: `!git log -1 --oneline` Diff vs main: `!git diff main...HEAD --stat` Com base no acima, sugira o próximo passo.
When you invoke /branch-status, Claude already receives an SKILL.md populated with the actual outputs. No need to ask "run git status" — it's already there.
✓ Good use cases
- • State snapshot (git, version, ENV)
- • List relevant files/branches
- • Get the latest log/error
- • Inject timestamp/date
- • Idempotent command result
✗ Caution
- • Destructive commands (rm, drop)
- • User input interpolated directly (injection)
- • Slow commands (hold up the skill for seconds)
- • Huge output (overflows context)
- • Side effects that change state
⚠️Watch out for portability
Backtick-bang does NOT exist in Codex. A skill that depends on it will fail there. Polyskill rewrites it as fallback prose ("run git status and analyze the result") when compiling for Codex—but loses actual injection.
Key concepts
Runs before the prompt
Already included in the context
Claude only
Fallback prose
🚦 disable-model-invocation and allowed-tools
Two frontmatter fields that give you fine-grained control about when and how the skill runs. Essential for dangerous or focused skills.
🔒 disable-model-invocation
disable-model-invocation: true
Prevents auto-triggering. Runs only when you explicitly invoke it (/nome-skill).
When to use: destructive skills (drop, deploy, push), skills that cost money (call a paid API), skills that ONLY you invoke intentionally.
🛡️ allowed-tools
allowed-tools: Read, Grep, Bash(git:*)
Restricts which tools the skill can use. Principle of least privilege.
When to use: a read skill should never write, an analysis skill should never open a terminal. Restrict it.
💡Security combo
For a dangerous skill: disable-model-invocation: true + allowed-tools ultra-restricted + description with an explicit warning. Triple guarantee.
Key concepts
disable-model-invoke
allowed-tools
Minimum required
model: haiku
🛍️ Plugins and marketplace
A plugin is a distributable package: bundles skills + agents + commands + hooks into a single versioned bundle. It's how you consume other people's work (claude-mem, context-mode, superpowers, etc.) and publish your own.
plugin.json — manifest
{
"name": "meu-plugin",
"version": "1.2.0",
"description": "Conjunto de skills pra refatorar TypeScript",
"author": "@meu-handle",
"skills": ["./skills/ts-refactor", "./skills/ts-test-gen"],
"agents": ["./agents/ts-reviewer.md"],
"commands": ["./commands/refactor.md"],
"hooks": [{ "event": "PostToolUse", "matcher": "Edit", "command": "./scripts/format.sh" }]
}
Namespace
Plugin skills become plugin:skill-name to avoid collisions.
Marketplace
Plugin index (marketplace.json). Install via /plugins.
Versioning
npm-style semver. Update via marketplace.
🦜Polyskill as a plugin
Polyskill is distributed as a plugin. You install it once and get the CLI + the meta-skill that drives the CLI in natural language. A plugin is the modern way to distribute software.
Key concepts
Bundle manifest
Public index
Namespace
Versioning
🎯Module summary
Next track:
T3 — Anatomy of Codex (AGENTS.md, .codex/, .agents/, openai.yaml)