Battle-skills create-skill
Guide for creating a new Battle Skill from scratch. Use when adding a new skill, capturing a workflow, or turning a technique into a reusable skill. Triggers on "create a skill", "new skill", "add a skill".
git clone https://github.com/QuocTang/battle-skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/QuocTang/battle-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/create-skill" ~/.claude/skills/quoctang-battle-skills-create-skill && rm -rf "$T"
skills/create-skill/SKILL.mdCreate Skill
A guide for creating high-quality Battle Skills that AI agents can reliably use.
Claude Code skills follow the Agent Skills open standard, which works across multiple AI tools (Claude Code, Cursor, Gemini CLI, Codex CLI, Kiro, Antigravity). Claude Code extends the standard with invocation control, subagent execution, and dynamic context injection.
TL;DR — Quick Checklist
skills/ └── your-skill-name/ ├── SKILL.md ← required ├── references/ ← optional: large docs, cheat sheets ├── scripts/ ← optional: executable helpers └── assets/ ← optional: templates, icons, files
Run before committing:
python3 scripts/validate_skills.py skills/your-skill-name python3 scripts/gen_catalog.py
Where Skills Live
Where you store a skill determines who can use it. Higher-priority locations win when names conflict:
| Location | Path | Applies to |
|---|---|---|
| Enterprise | Managed settings (org-wide) | All users in organization |
| Personal | | All your projects |
| Project | | This project only |
| Plugin | | Where plugin is enabled (namespaced as ) |
Note: Claude also auto-discovers skills from nested
directories (e.g.,.claude/skills/), supporting monorepo setups.packages/frontend/.claude/skills/
Step 1 — Pick a Name
- Use lowercase kebab-case:
,react-patterns
,api-designdeploy-vercel - Name describes what the skill does, not what domain it's in
- No generic names:
,frontend,mischelpers
Step 2 — Create the Folder & SKILL.md
mkdir skills/your-skill-name touch skills/your-skill-name/SKILL.md
SKILL.md Frontmatter
All fields are optional, but
description is strongly recommended.
--- name: your-skill-name # max 64 chars, lowercase letters/numbers/hyphens only description: >- # Claude uses this to decide when to trigger the skill. What the skill does and when # Truncated after 250 chars — front-load key info. to use it. Be specific. argument-hint: [environment] # hint shown during autocomplete allowed-tools: Read Grep Bash # tools Claude can use without asking permission model: claude-sonnet-4-6 # override session model effort: high # low | medium | high | max context: fork # run in isolated subagent context agent: general-purpose # subagent type when context: fork disable-model-invocation: false # true = manual-only via /name user-invocable: true # false = hidden from / menu paths: "src/**/*.ts" # glob patterns limiting when skill activates hooks: # hooks scoped to skill lifecycle PreToolUse: - matcher: Bash hooks: - command: echo "tool use detected" shell: bash # bash (default) | powershell ---
Field Reference
| Field | Type | Description |
|---|---|---|
| string | Lowercase kebab-case, max 64 chars. Becomes the . If omitted, uses directory name. |
| string | What the skill does & when to use it. Truncated after 250 chars — front-load key use cases. |
| string | Hint for expected arguments, e.g. |
| string/list | Tools Claude can use without permission when skill is active, e.g. |
| string | Override session model, e.g. |
| string | | | | |
| string | to run in an isolated subagent context |
| string | Subagent type when — , , , or custom agent name |
| boolean | = Claude won't auto-trigger, invoke manually with |
| boolean | = hidden from menu, used for background knowledge |
| string/list | Glob patterns limiting when skill auto-activates |
| object | Hooks scoped to skill lifecycle |
| string | (default) or |
Invocation Control
How
disable-model-invocation and user-invocable affect who can trigger a skill and when it loads into context:
| Frontmatter | You can invoke | Claude can invoke | When loaded into context |
|---|---|---|---|
| (default) | Yes | Yes | Description always in context; full skill loads on invocation |
| Yes | No | Description not in context; full skill loads when you invoke |
| No | Yes | Description always in context; full skill loads on invocation |
String Substitutions
Use these variables in skill content for dynamic behavior:
| Variable | Description |
|---|---|
| All arguments passed when invoking the skill |
or | Access argument by 0-based index |
| Current session ID |
| Directory containing this |
Dynamic Context Injection
The
!`<command>` syntax runs shell commands before skill content is sent to Claude. The output replaces the placeholder — Claude only sees the final result.
--- name: pr-summary description: Summarize changes in a pull request context: fork agent: Explore --- ## Pull request context - PR diff: !`gh pr diff` - PR comments: !`gh pr view --comments` - Changed files: !`gh pr diff --name-only` ## Your task Summarize this pull request...
How it works:
- Each
executes immediately (preprocessing)!`<command>` - Command output replaces the placeholder in skill content
- Claude receives the fully-rendered prompt with actual data
Use
${CLAUDE_SKILL_DIR} to reference bundled scripts: !`python ${CLAUDE_SKILL_DIR}/scripts/gather.py`
Description Writing Guide
The
description field is the primary trigger mechanism — Claude reads it to decide if a skill is relevant. Write it to match how users naturally phrase requests. Minimum 10 words (the validator will warn if fewer).
Bad description:
How to write React components.
Good description:
Best practices for building React components, hooks, and state management. Use this skill when writing any React code, creating components, managing state, or when the user mentions React, JSX, hooks, or component architecture.
The good version: explains what it does, says when to use it, and lists trigger phrases.
Tip: Skill descriptions share a context budget (default: 1% of context window, min 8,000 chars). Set
env var to increase. Each description is capped at 250 chars regardless — front-load the key use case.SLASH_COMMAND_TOOL_CHAR_BUDGET
Step 3 — Write the Body
Anatomy of a Good Skill Body
# Skill Name One sentence explaining what this skill enables. --- ## When to Use This Skill - Situation A - Situation B ## When NOT to Use This Skill - Situation C (use X instead) ## Core Rules 1. Rule one — with brief explanation 2. Rule two — with brief explanation 3. ... ## Examples ### Good Example \`\`\`language // correct pattern \`\`\` ### Bad Example \`\`\`language // anti-pattern — explain why \`\`\` ## Anti-Patterns (Avoid) - What not to do and why
Principles
Keep SKILL.md under 500 lines. If you're going over, move large sections to
references/ and add a pointer in SKILL.md:
> For full API reference, see [references/api.md](references/api.md)
Be concrete, not abstract. Show code examples. Show the diff between right and wrong.
Enable extended thinking. Include the word
ultrathink anywhere in skill content to activate Claude's extended thinking mode for deeper reasoning.
Principle of No Surprise. The skill should do exactly what its name and description say — nothing more, nothing less.
Progressive disclosure: keep SKILL.md under 500 lines and link to supporting files (
references/, scripts/, assets/) that Claude reads only when needed.
| Layer | What lives here | When it's loaded |
|---|---|---|
| Metadata (name + description) | Frontmatter in SKILL.md | Always in context — used for skill matching |
| SKILL.md body | Core rules, examples, anti-patterns | When the skill triggers |
| Large docs, API refs, cheat sheets | On demand — Claude reads only when the task needs them |
| Executable helpers, scaffolders | On demand — Claude runs when the workflow requires it |
| Templates, config files, icons | On demand — Claude copies/uses when generating output |
Why this matters: AI agents have limited context windows. If you inline a 2000-line API reference into SKILL.md, it wastes tokens every time the skill triggers — even when only 10% of that content is relevant. Instead, keep SKILL.md focused on decision-making (rules, when/when-not, key examples) and offload reference material:
## Cloud Deploy Follow the rules below for all cloud deployments. > For provider-specific configuration, see: > - [references/aws.md](references/aws.md) > - [references/gcp.md](references/gcp.md) > - [references/azure.md](references/azure.md)
Claude will read the relevant
references/ file only when the user's task requires that specific provider.
Step 4 — Add Bundled Resources (Optional)
references/
— Large Docs
references/For cheat sheets, API references, framework docs that would bloat the main SKILL.md:
references/ ├── aws.md ├── gcp.md └── azure.md
Reference them from SKILL.md:
See [references/aws.md](references/aws.md) for AWS-specific config.
scripts/
— Executable Helpers
scripts/For deterministic, repetitive tasks the AI should run rather than reason about:
# scripts/scaffold.py # Scaffolds boilerplate for this skill's workflow
assets/
— Files & Templates
assets/For starter files, config templates, icons used in skill output.
Step 5 — Validate & Publish
# Validate your skill python3 scripts/validate_skills.py skills/your-skill-name # If all good, regenerate catalog python3 scripts/gen_catalog.py # Commit git add skills/your-skill-name CATALOG.md skills_index.json git commit -m "feat(skill): add your-skill-name"
Commit Convention
feat(skill): add <name> # new skill fix(skill): fix <name> # bug fix in skill improve(skill): update <name> # improvement deprecate(skill): remove <name> # removal
Step 6 — Update CHANGELOG.md
Add an entry under
[Unreleased]:
### Added - `your-skill-name` — One-line description of what it does
Restrict Skill Access
Control which skills Claude can invoke using permission rules:
# Allow specific skills Skill(commit) Skill(review-pr *) # Deny specific skills Skill(deploy *)
— exact matchSkill(name)
— prefix match (matchesSkill(name *)
)name-anything- Deny
entirely to block all skill invocations by ClaudeSkill
Note:
removes the skill from Claude's context entirely.disable-model-invocation: trueonly hides from theuser-invocable: falsemenu./
Quality Bar
Before submitting, ask yourself:
- Does the description clearly say when to use this skill?
- Are there concrete examples (not just abstract rules)?
- Does it cover anti-patterns (what NOT to do)?
- Is SKILL.md under 500 lines?
- Did
pass with no errors?validate_skills.py - Is the skill battle-tested — from real usage, not theory?
A skill that hasn't been used in a real project yet is a hypothesis, not a battle skill.
Example: Minimal Valid Skill
skills/ └── git-commit-message/ └── SKILL.md
--- name: git-commit-message description: Write clear, conventional git commit messages following Conventional Commits. Use when the user asks to write a commit message, summarize changes for git, or says "commit this". --- # Git Commit Message Write structured commit messages that make history readable. ## Format \`\`\` <type>(<scope>): <subject> [optional body] [optional footer] \`\`\` ## Types - `feat` — new feature - `fix` — bug fix - `docs` — documentation only - `refactor` — no feature/fix change - `test` — adding tests - `chore` — tooling, deps ## Rules 1. Subject line max 72 chars, imperative mood ("add" not "added") 2. Scope is optional but helpful: `feat(auth): add OAuth` 3. Body explains *why*, not *what* (the diff shows what) ## Example Good: `feat(auth): add Google OAuth login` Bad: `updated auth stuff`