Summary
What this post covers: A complete examination of Claude Code Skills (markdown-based, frontmatter-typed instruction sets invoked by slash commands) including how they operate internally, the built-in skills, six production-ready custom skills, advanced patterns, and the means of sharing them with a team.
Key insights:
- Skills, custom commands, and CLAUDE.md play distinct roles: CLAUDE.md is the always-on “constitution,” custom commands are quick project macros, and Skills are structured, composable, typed-argument modules with frontmatter. The appropriate tool should be selected for each task.
- Skills resolve in priority order: built-in first, then user (
~/.claude/skills/), then project (.claude/skills/). A project skill can override or extend a built-in by reusing the same name. - The invocation flow (parse, load, inject arguments, inject context, execute) is what gives Skills their power. Claude is not improvising but following a carefully written playbook injected at runtime.
- The six worked examples (
/deploy,/write-tests,/refactor,/db-migrate,/api-doc,/security-audit) follow the same pattern: typed arguments, ordered steps, explicit constraints, and failure-handling instructions written in plain English. - The most direct path to value is to select one manual workflow that took more than five minutes this week, encode it as a user-level skill, refine it through a few real invocations, then promote it to a project skill so that the entire team benefits.
Main topics: What Are Skills in Claude Code?, How Skills Work Internally, Built-in Skills Available Immediately, Anatomy of a Skill File, Building Custom Skills Step by Step, Advanced Skill Techniques, Sharing Skills With a Team and the Community, Skills in the Broader Claude Code Ecosystem, Common Mistakes and How to Fix Them, Conclusion, References.
Consider the experience of typing six characters into a terminal and watching Claude Code automatically run a test suite, build the application, deploy it to staging, verify the health checks, and report back with a summary, all without further intervention. No copy-pasting of scripts. No recall of command-line flags. No switching among documentation tabs. A single /deploy staging completes the task.
This is precisely what Skills in Claude Code make possible. Users of Claude Code may have encountered slash commands such as /commit and /review-pr, which accomplish a substantial amount with a single invocation. These are Skills, and they represent one of the most capable yet least understood extension points in the Claude Code ecosystem.
A point that most developers overlook is that Skills are not simply shortcuts. They are markdown-based instruction sets that fundamentally alter how Claude Code behaves when invoked. They inject specialized context, define structured workflows, and can accept arguments, transforming Claude Code from a general-purpose AI assistant into a purpose-built tool for a specific workflow. A custom Skill can be created in approximately five minutes.
The following guide examines Skills in detail. It addresses what they are conceptually, how they operate internally, which built-in Skills ship with Claude Code, and how to construct custom Skills. Six complete, practical skill examples are provided that can be copied directly into a project. By the conclusion, readers will have the material required to create a library of custom Skills that materially improves team productivity.
What Are Skills in Claude Code?
At their core, Skills are specialized capabilities that extend Claude Code’s functionality through markdown-based instruction sets. When a Skill is invoked via a slash command (for example, /commit), Claude Code loads the corresponding markdown file into its context window. That markdown file contains detailed instructions that Claude follows to complete the task. Skills function as expert playbooks: each one trains Claude Code to act as a specialist for a particular task.
This differs fundamentally from a freeform request such as “make a commit.” Given a freeform request, Claude Code uses general knowledge to determine the appropriate action. When a Skill is invoked, Claude Code receives a carefully constructed set of instructions written by someone who has considered the optimal approach to that specific task. The Skill may specify which git commands to run, how to format the commit message, what checks to perform before committing, and how to handle edge cases.
Skills and Custom Commands: The Distinction
Readers familiar with Claude Code’s custom commands (the markdown files in .claude/commands/) may wonder how Skills differ. The distinction matters, and understanding it informs the selection of the appropriate mechanism for a given purpose.
Custom commands are project-specific markdown files that reside in a repository’s .claude/commands/ directory. They are straightforward: a markdown file is written, and when the corresponding slash command is typed, Claude Code loads those instructions. They are suitable for project-specific workflows.
Skills are a more structured and capable system. They have frontmatter metadata (name, description, argument schemas), support typed arguments, can be composed with other Skills, and exist at multiple levels: built-in, user-level, and project-level. Skills are invoked internally through the Skill tool, which provides a standardized interface for loading and executing them.
| Feature | Skills | Custom Commands | CLAUDE.md Instructions |
|---|---|---|---|
| Location | ~/.claude/skills/ or .claude/skills/ |
.claude/commands/ |
CLAUDE.md in project root |
| Invocation | Slash command (/skill-name) |
Slash command (/command-name) |
Always loaded automatically |
| Arguments | Typed arguments with schema | Free-text $ARGUMENTS |
Not applicable |
| Metadata | Frontmatter (name, description, args) | Filename only | None |
| Composability | Can call other Skills | Limited | Not applicable |
| Scope | Built-in, user, or project | Project only | Project only |
| Best For | Reusable, structured workflows | Simple project-specific tasks | Persistent context and rules |
How Skills Work Internally
An understanding of the internals is not merely academic; it informs the construction of better Skills. The following sections trace the precise sequence of events from the moment a slash command is typed to the moment Claude Code begins executing instructions.
The Invocation Flow
When /deploy staging is typed in Claude Code, the following sequence of events occurs:
Step 1: Command Parsing. Claude Code recognizes the slash prefix and parses the input into a skill name (deploy) and arguments (staging). It searches for a matching skill across all registered locations: built-in skills first, then user skills in ~/.claude/skills/, then project skills in .claude/skills/.
Step 2: Skill Loading. The matching markdown file is read from disk. The frontmatter is parsed to extract metadata, including the skill’s name, description, and argument schema. The body of the markdown file contains the actual instructions.
Step 3: Argument Injection. If the skill defines arguments, the user’s input is matched against the schema. The $ARGUMENTS placeholder in the skill body is replaced with the actual argument value (in this case, staging).
Step 4: Context Injection. The processed markdown content is injected into Claude’s context as instructions. This is the critical step: Claude Code now has a detailed playbook for the task. The Skill tool handles this injection internally.
Step 5: Execution. Claude Code follows the injected instructions, using its available tools (Bash, Read, Write, Edit, Grep, and others) to carry out each step. The instructions may direct it to read files, run commands, make edits, or invoke other Skills.
Skill Resolution Order
When multiple skills share the same name, Claude Code uses a priority order to determine which one to load:
- Built-in skills: shipped with Claude Code itself. These take highest priority.
- User skills: located in
~/.claude/skills/. These are personal to the user and apply across all projects. - Project skills: located in
.claude/skills/within the repository. These are specific to the project and shared with all team members who clone the repository.
commit) will be superseded by the built-in version. Unique names should be chosen for custom skills in order to avoid conflicts.
The Skill Tool
Internally, Skills are invoked through a dedicated Skill tool. This is part of Claude Code’s tool system, which also includes the Bash tool, Read tool, Edit tool, and others. When the system detects a slash command that matches a skill, it invokes the Skill tool with the skill name and any arguments. The Skill tool then handles loading, parsing, and context injection.
This architecture is significant because it positions Skills as first-class citizens within Claude Code’s tool ecosystem. They are not an ad hoc workaround but a core extension mechanism designed to be reliable, composable, and consistent.
Built-in Skills Available Immediately
Claude Code ships with several built-in Skills that handle common development workflows. Users may already have used some of these without recognizing them as Skills. The most important are described below.
The /commit Skill
This is arguably the most heavily used built-in skill. The /commit command does not simply run git commit; it follows a detailed workflow:
- Runs
git statusto see what has changed - Runs
git diffto understand the actual changes - Reads recent commit messages to match the repository’s style
- Analyzes the changes and drafts a meaningful commit message
- Stages relevant files (avoiding sensitive files like
.env) - Creates the commit with a properly formatted message
- Verifies success with a final
git status
The skill also handles pre-commit hook failures gracefully. If a hook fails, it addresses the issue and creates a new commit rather than amending the previous one, which could destroy prior work.
The /review-pr Skill
The /review-pr 123 command directs Claude Code to retrieve the pull request, read through every changed file, analyse the code quality, check for bugs and security issues, and provide a detailed review. It uses the gh CLI to interact with GitHub, reading diffs, comments, and PR metadata to produce a comprehensive review.
The /pr Skill
The /pr skill automates pull-request creation. It examines all commits on the branch since it diverged from the base branch, analyses the full set of changes (not only the latest commit), drafts a PR title and description, pushes to the remote if needed, and creates the PR using gh pr create. The resulting PR description includes a summary, a test plan, and proper formatting.
Discovering Available Skills
To view every skill available in the current context, the user may type / in Claude Code and pause. The autocomplete will display all registered skills, including built-in, user-level, and project-level skills. This is the most direct method of discovery.
/ followed by a partial name filters the list. For example, /re displays skills beginning with “re,” such as /review-pr, /refactor, or any custom skills with that prefix.
Anatomy of a Skill File
Before constructing custom Skills, an understanding of the structure of a skill file is necessary. Every skill is a markdown file with two parts: frontmatter (metadata) and body (instructions).
The Frontmatter
The frontmatter is a YAML block at the top of the file, enclosed by triple dashes. It informs Claude Code of the skill’s name, its purpose, and the arguments it accepts.
---
name: deploy
description: Deploy application to staging or production environment
arguments:
- name: environment
description: Target environment (staging or production)
required: true
---
The frontmatter fields are as follows:
- name: The skill’s identifier, used for the slash command. A skill named
deployis invoked with/deploy. - description: A human-readable description shown in the skill listing and autocomplete.
- arguments: An array of argument definitions, each with a name, description, and required flag.
The Body
Below the frontmatter is the markdown body, which contains the actual instructions that Claude Code will follow. The body defines the workflow, specifies commands to run, sets expectations for output, and handles edge cases.
The body can use the $ARGUMENTS placeholder, which is replaced with whatever the user types after the slash command. For a skill invoked as /deploy staging, every instance of $ARGUMENTS in the body becomes staging.
A Complete Skill File
The following minimal but complete skill file illustrates the structure:
---
name: greet
description: Generate a greeting message for a team member
arguments:
- name: person
description: Name of the person to greet
required: true
---
Generate a warm, professional greeting message for $ARGUMENTS.
## Instructions
1. Use the person's name in the greeting
2. Reference the current project if possible
3. Keep it under 3 sentences
4. Output the greeting directly — do not save to a file
File Naming and Directory Structure
Skill files follow a simple naming convention: the filename (without the extension) becomes the command name. A file named deploy.md produces the /deploy command.
# Project skills (shared with team via git)
.claude/
skills/
deploy.md # /deploy
write-tests.md # /write-tests
db-migrate.md # /db-migrate
# User skills (personal, not shared)
~/.claude/
skills/
my-snippet.md # /my-snippet
quick-review.md # /quick-review
write-tests.md becomes the command /write-tests. Underscores and spaces should be avoided; hyphens are the convention.
Building Custom Skills Step by Step
The following sections describe the construction of six practical, production-ready skills that can be placed in any project. Each addresses a real problem that developers face daily, and each demonstrates a different skill-building technique.
Skill 1: /deploy: Deploy to Staging or Production
This skill automates the full deployment pipeline. It accepts an environment argument, runs pre-deployment checks, executes the deployment, and verifies system health afterward.
---
name: deploy
description: Deploy application to staging or production with safety checks
arguments:
- name: environment
description: Target environment — staging or production
required: true
---
You are deploying the application to the **$ARGUMENTS** environment.
Follow every step carefully. Do NOT skip safety checks.
## Step 1: Validate Environment
Confirm that "$ARGUMENTS" is either "staging" or "production".
If it is neither, stop immediately and tell the user:
"Invalid environment. Use: /deploy staging or /deploy production"
## Step 2: Pre-Deployment Checks
Run the following checks in parallel where possible:
1. **Git status check**: Run `git status` to ensure the working
directory is clean. If there are uncommitted changes, warn the
user and ask if they want to continue.
2. **Branch check**: Run `git branch --show-current`. If deploying
to production, verify we are on the `main` branch. If not, warn
the user.
3. **Test suite**: Run `npm test` (or the project's test command).
If any tests fail, STOP and report the failures. Do NOT deploy
with failing tests.
4. **Build check**: Run `npm run build` (or the project's build
command). If the build fails, STOP and report the error.
## Step 3: Deploy
For **staging**:
```bash
git push origin HEAD:staging
# or: npm run deploy:staging
# or: kubectl apply -f k8s/staging/
```
For **production**:
```bash
git push origin main:production
# or: npm run deploy:production
# or: kubectl apply -f k8s/production/
```
Adapt the deploy command to whatever deployment mechanism the
project uses. Check for deploy scripts in package.json, Makefile,
or deploy/ directory.
## Step 4: Post-Deployment Verification
1. Wait 30 seconds for the deployment to propagate
2. Run a health check against the deployed environment:
- Staging: `curl -s https://staging.example.com/health`
- Production: `curl -s https://example.com/health`
3. Check that the response includes a 200 status code
## Step 5: Report
Provide a summary:
- Environment deployed to
- Git commit SHA that was deployed
- Test results (pass/fail counts)
- Health check status
- Timestamp of deployment
Usage:
/deploy staging
/deploy production
The skill validates the argument, runs safety checks before deploying, and verifies health afterward. This is substantially more robust than a bare git push, and the workflow is identical every time, whether executed by the original author or by a colleague.
Skill 2: /write-tests: Generate Comprehensive Tests
This skill analyses a source file and generates a complete test suite for it. It automatically detects the project’s testing framework and follows existing test patterns.
---
name: write-tests
description: Generate comprehensive tests for a given source file
arguments:
- name: file_path
description: Path to the source file to test
required: true
---
Generate a comprehensive test suite for the file at: $ARGUMENTS
## Step 1: Analyze the Source File
Read the file at `$ARGUMENTS` completely. Identify:
- All exported functions, classes, and methods
- Input parameters and their types
- Return values and their types
- Side effects (API calls, file I/O, database queries)
- Edge cases (null inputs, empty arrays, boundary values)
- Error conditions and exception handling
## Step 2: Detect Testing Framework
Check the project for testing configuration:
- Look at `package.json` for jest, vitest, mocha
- Look at `pyproject.toml` or `setup.cfg` for pytest
- Look at `go.mod` for Go testing
- Look at existing test files to match patterns and conventions
Use whatever framework the project already uses. If none is
configured, recommend and use the most common one for the language.
## Step 3: Study Existing Test Patterns
Find existing test files in the project:
- Search for files matching `*.test.*`, `*.spec.*`, `test_*.*`
- Read 2-3 existing test files to understand:
- Import patterns
- Describe/it block structure
- Mocking patterns
- Assertion style
- Setup/teardown patterns
Match the existing style exactly.
## Step 4: Write the Tests
Create a test file following the project's naming convention
(e.g., `foo.test.ts` for `foo.ts`, `test_foo.py` for `foo.py`).
Include tests for:
- **Happy path**: Normal inputs producing expected outputs
- **Edge cases**: Empty inputs, null/undefined, boundary values
- **Error cases**: Invalid inputs, missing required parameters
- **Integration points**: Mock external dependencies
- **Regression targets**: Any complex logic that could break
Each test should:
- Have a clear, descriptive name
- Test exactly one behavior
- Follow the Arrange-Act-Assert pattern
- Include inline comments explaining WHY the test exists
## Step 5: Verify
Run the test suite to ensure all tests pass:
```bash
npm test -- --testPathPattern="" # JS/TS
pytest -v # Python
go test -v -run ./... # Go
```
If any test fails, fix it. All tests MUST pass before finishing.
## Step 6: Report
Tell the user:
- How many tests were written
- What categories they cover (happy path, edge cases, etc.)
- Any areas that could use additional testing
- The command to run just these tests
Usage:
/write-tests src/utils/parser.ts
/write-tests lib/models/user.py
A notable property of this skill is that it adapts to whatever project it is invoked in. It detects the testing framework, matches existing patterns, and produces tests that resemble those written by a team member because the instructions explicitly direct Claude Code to study and mirror the project’s conventions.
Skill 3: /refactor: Guided Code Refactoring
Refactoring carries risk. This skill adds safety rails by requiring tests to pass before and after changes, producing a detailed plan before any code is modified, and making changes incrementally.
---
name: refactor
description: Guided code refactoring with safety checks
arguments:
- name: description
description: What to refactor and why
required: true
---
You are performing a guided code refactoring based on this request:
"$ARGUMENTS"
Follow this process carefully to ensure the refactoring is safe.
## Step 1: Understand the Request
Parse the user's refactoring request. Identify:
- Which files or modules are involved
- What the current code does
- What the desired outcome is
- Why the refactoring is needed
Read all relevant source files completely before proceeding.
## Step 2: Run Existing Tests
Run the project's full test suite BEFORE making any changes.
Record the results. If tests are already failing, note which
ones and tell the user — those failures are pre-existing.
```bash
npm test 2>&1 | tail -20 # JS/TS
pytest -v 2>&1 | tail -20 # Python
go test ./... 2>&1 | tail -20 # Go
```
## Step 3: Create a Refactoring Plan
BEFORE making any code changes, present a detailed plan:
- List every file that will be modified
- For each file, describe what will change and why
- Identify potential risks (breaking changes, API changes)
- Note any files that import/depend on modified code
- Estimate the scope: small (1-2 files), medium (3-5), large (6+)
Wait for implicit approval — present the plan, then proceed.
## Step 4: Implement Changes
Make changes incrementally:
1. Modify one logical unit at a time
2. After each modification, check that the file is syntactically
valid (no broken imports, no undefined references)
3. Keep a mental changelog of every change made
Important rules:
- Do NOT change public API signatures without updating all callers
- Do NOT delete code that might be used elsewhere — search first
- Preserve all existing comments unless they are now incorrect
- Update comments and docstrings that reference changed behavior
## Step 5: Run Tests Again
Run the full test suite after all changes:
```bash
npm test
pytest -v
go test ./...
```
If any test that was previously passing now fails:
1. Analyze the failure
2. Fix the issue (either in the refactored code or the test)
3. Run tests again until all previously-passing tests still pass
## Step 6: Summary Report
Provide:
- List of all files modified with a one-line description of each
- Before/after comparison for key changes
- Test results: all passing, or note any changes
- Any follow-up refactoring that would be beneficial
Usage:
/refactor Extract the validation logic from UserController into a separate ValidationService class
/refactor Convert all callback-based functions in src/api/ to async/await
Skill 4: /db-migrate: Create Database Migrations
Database migrations are tasks in which incorrect details can be catastrophic. This skill generates migration files that match the project’s ORM and conventions.
---
name: db-migrate
description: Create a database migration for a schema change
arguments:
- name: description
description: Description of the schema change needed
required: true
---
Create a database migration for the following schema change:
"$ARGUMENTS"
## Step 1: Detect ORM and Migration Framework
Search the project for:
- `prisma/schema.prisma` → Prisma
- `alembic/` or `alembic.ini` → SQLAlchemy + Alembic
- `migrations/` + Django patterns → Django ORM
- `db/migrate/` → Rails ActiveRecord
- `drizzle.config.*` → Drizzle ORM
- `knexfile.*` → Knex.js
- `sequelize` in package.json → Sequelize
- `typeorm` in package.json → TypeORM
Read the existing migration files to understand patterns and
naming conventions.
## Step 2: Analyze Existing Schema
Read the current schema definition:
- Prisma: Read `prisma/schema.prisma`
- Alembic: Read the latest migration and models
- Django: Read `models.py` files
- TypeORM: Read entity files
Identify what tables, columns, and relationships already exist
that are relevant to the requested change.
## Step 3: Generate the Migration
Create the migration file using the framework's conventions:
**For Prisma:**
1. Update `prisma/schema.prisma` with the schema changes
2. Run `npx prisma migrate dev --name `
**For Alembic:**
1. Generate: `alembic revision --autogenerate -m "$ARGUMENTS"`
2. Review and edit the generated migration file
3. Ensure both upgrade() and downgrade() are correct
**For Django:**
1. Update the model in `models.py`
2. Run `python manage.py makemigrations`
3. Review the generated migration
**For Knex/TypeORM/Drizzle:**
Generate the appropriate migration file with both up and down
methods.
## Step 4: Safety Checks
Every migration MUST have:
- A **rollback/down migration** — never create an irreversible
migration without explicit user approval
- **Null safety** — new NOT NULL columns need defaults or a
data migration step
- **Index considerations** — add indexes for new foreign keys
and frequently-queried columns
- **No data loss** — column renames and type changes should
preserve existing data
## Step 5: Verify
Run the migration against the development database:
```bash
npx prisma migrate dev # Prisma
alembic upgrade head # Alembic
python manage.py migrate # Django
npx knex migrate:latest # Knex
```
Then verify by checking the schema matches expectations.
## Step 6: Report
Provide:
- Migration file path and name
- Summary of schema changes
- Whether a rollback migration exists
- Any manual steps needed (data backfill, etc.)
- The command to apply the migration
Usage:
/db-migrate Add a "last_login_at" timestamp column to the users table
/db-migrate Create a many-to-many relationship between posts and tags
Skill 5: /api-doc: Generate API Documentation
Keeping API documentation synchronized with code is a perennial challenge. This skill scans the codebase for route definitions and generates comprehensive, OpenAPI-compatible documentation.
---
name: api-doc
description: Generate API documentation by scanning route definitions
arguments:
- name: scope
description: Optional — specific file or directory to document (defaults to all routes)
required: false
---
Generate comprehensive API documentation for this project.
Scope: $ARGUMENTS (if empty, document all routes).
## Step 1: Discover Route Definitions
Search the codebase for route/endpoint definitions:
- **Express.js**: `app.get(`, `app.post(`, `router.get(`, etc.
- **FastAPI**: `@app.get(`, `@app.post(`, `@router.get(`
- **Django**: `urlpatterns`, `path(`, `@api_view`
- **Flask**: `@app.route(`, `@blueprint.route(`
- **Rails**: `routes.rb`, `resources :`, `get '/'`
- **Go**: `http.HandleFunc(`, `r.GET(`, `e.GET(`
- **Spring**: `@GetMapping`, `@PostMapping`, `@RequestMapping`
List all discovered endpoints.
## Step 2: Analyze Each Endpoint
For every endpoint, determine:
- HTTP method (GET, POST, PUT, DELETE, PATCH)
- URL path and path parameters
- Query parameters
- Request body schema (read the handler to see what fields
it expects)
- Response schema (read the handler to see what it returns)
- Authentication requirements (middleware, decorators)
- Error responses (what status codes and error formats)
## Step 3: Generate Documentation
Create a markdown file at `docs/api-reference.md` with the
following structure:
```markdown
# API Reference
## Authentication
[Describe auth mechanism]
## Endpoints
### [Resource Name]
#### GET /api/resource
Description of what this endpoint does.
**Parameters:**
| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| id | path | string | Yes | Resource ID |
**Response 200:**
```json
{ "id": "...", "name": "..." }
```
**Response 404:**
```json
{ "error": "Resource not found" }
```
```
Also generate an OpenAPI 3.0 YAML file at `docs/openapi.yaml`
if the project does not already have one.
## Step 4: Cross-Reference
- Verify every route in code has documentation
- Verify every documented route exists in code
- Flag any discrepancies
## Step 5: Report
Provide:
- Total number of endpoints documented
- Breakdown by HTTP method
- Any endpoints that could not be fully documented (and why)
- File paths for generated documentation
Usage:
/api-doc
/api-doc src/routes/users.ts
Skill 6: /security-audit: Check for Security Vulnerabilities
This skill can help prevent security incidents. It systematically checks for OWASP Top 10 vulnerabilities, dependency issues, and accidental exposure of secrets.
---
name: security-audit
description: Scan codebase for security vulnerabilities and secrets
arguments:
- name: scope
description: Optional — specific file or directory to audit (defaults to full project)
required: false
---
Perform a comprehensive security audit of this codebase.
Scope: $ARGUMENTS (if empty, audit the entire project).
## Step 1: Secrets Detection
Search the entire codebase for accidentally committed secrets:
1. Search for patterns matching:
- API keys: strings matching `[A-Za-z0-9_-]{20,}` near
keywords like "key", "token", "secret", "password"
- AWS credentials: `AKIA[0-9A-Z]{16}`
- Private keys: `-----BEGIN.*PRIVATE KEY-----`
- Connection strings with passwords
- Hardcoded passwords in configuration files
- JWT secrets
2. Check that `.gitignore` includes:
- `.env` and `.env.*`
- `*.pem`, `*.key`
- `credentials.json`, `secrets.yaml`
3. Check for `.env.example` that accidentally contains real values
## Step 2: OWASP Top 10 Check
Scan for common vulnerabilities:
**Injection (SQL, NoSQL, Command):**
- Search for string concatenation in database queries
- Search for unsanitized input in shell commands
- Search for `eval()`, `exec()`, or equivalent
**Broken Authentication:**
- Check password hashing (bcrypt/argon2 vs MD5/SHA1)
- Check session management
- Check for hardcoded credentials
**Sensitive Data Exposure:**
- Check for sensitive data in logs
- Check HTTPS enforcement
- Check for sensitive data in error messages
**XML External Entities (XXE):**
- Check XML parser configurations
**Broken Access Control:**
- Check for missing authorization middleware
- Check for IDOR vulnerabilities (direct object references)
**Security Misconfiguration:**
- Check CORS configuration
- Check for debug mode in production configs
- Check default credentials
**Cross-Site Scripting (XSS):**
- Check for unsanitized user input in HTML output
- Check for dangerouslySetInnerHTML (React)
**Insecure Deserialization:**
- Check for unsafe deserialization of user input
**Using Components with Known Vulnerabilities:**
- Run `npm audit` or `pip audit` or equivalent
- Check for outdated dependencies
**Insufficient Logging:**
- Check that authentication events are logged
- Check that authorization failures are logged
## Step 3: Dependency Audit
Run the appropriate dependency audit:
```bash
npm audit # Node.js
pip audit # Python
go vuln check ./... # Go
bundle audit # Ruby
```
## Step 4: Generate Report
Create a security report with severity ratings:
| Finding | Severity | Location | Recommendation |
|---------|----------|----------|----------------|
| ... | CRITICAL/HIGH/MEDIUM/LOW | file:line | Fix description |
Sort by severity (CRITICAL first).
For each finding:
- Describe the vulnerability
- Show the specific code involved
- Explain the potential impact
- Provide a concrete fix (code snippet)
## Step 5: Summary
Provide:
- Total findings by severity
- Top 3 most critical issues to fix immediately
- Overall security posture assessment
- Recommended next steps
Usage:
/security-audit
/security-audit src/auth/
This skill is particularly valuable because it codifies security knowledge that many developers do not retain in working memory. Every team member can now run a thorough security audit simply by typing twelve characters.
Advanced Skill Techniques
Once the basics are understood, several advanced patterns can make Skills considerably more capable.
Skills That Call Other Skills
One of the most useful features of Skills is that they can invoke other Skills. This permits the construction of complex workflows from simpler building blocks. For example, a /release skill might internally call /write-tests, then /security-audit, then /deploy:
---
name: release
description: Full release workflow — test, audit, deploy
arguments:
- name: version
description: Version number for this release
required: true
---
Execute the full release workflow for version $ARGUMENTS.
## Step 1: Run Tests
Invoke the /write-tests skill for any files changed since the
last release. Ensure full coverage on modified code.
## Step 2: Security Audit
Invoke the /security-audit skill on the entire project.
If any CRITICAL findings exist, STOP and report them.
## Step 3: Deploy
If all checks pass, invoke /deploy production.
## Step 4: Tag Release
```bash
git tag -a v$ARGUMENTS -m "Release $ARGUMENTS"
git push origin v$ARGUMENTS
```
Composition removes the need to duplicate logic across skills. Each capability is written once and then combined into higher-level workflows.
Skills That Read Project Configuration
Effective Skills adapt to the project in which they are run. Rather than hardcoding tool names or paths, Skills should read the project’s configuration files:
## Step 1: Detect Project Type
Read the project root to determine the technology stack:
- If `package.json` exists → Node.js project
- Read it to find the test command, build command, and linter
- If `pyproject.toml` exists → Python project
- Read it to find the test runner and build system
- If `go.mod` exists → Go project
- If `Cargo.toml` exists → Rust project
Use the detected commands throughout this skill instead of
hardcoded values.
This pattern makes Skills portable across different project types. The same /deploy skill can operate in a Node.js project, a Python project, or a Go project because it detects the stack first.
Skills with Complex Argument Handling
Although the $ARGUMENTS placeholder provides the raw user input, instructions that parse complex arguments can be written:
---
name: scaffold
description: Scaffold a new component with options
arguments:
- name: spec
description: "Format: component-name --type=page|component --with-tests --with-styles"
required: true
---
Parse the following specification: $ARGUMENTS
Extract:
- **Component name**: The first word
- **Type**: Value after --type= (default: component)
- **Include tests**: Whether --with-tests is present
- **Include styles**: Whether --with-styles is present
Example valid invocations:
- /scaffold UserProfile --type=page --with-tests --with-styles
- /scaffold Button --type=component --with-tests
- /scaffold Header
Because Claude Code parses the instructions rather than a shell, any argument format can be defined. Even natural-language arguments are acceptable.
Skills That Use Environment Variables
Skills can reference environment variables for configuration that should not be hardcoded:
## Deployment Configuration
Read the deployment target from environment variables:
```bash
echo $DEPLOY_HOST
echo $DEPLOY_USER
echo $DEPLOY_PATH
```
If any of these are not set, ask the user to configure them
in their .env file before proceeding.
Skills That Interact with MCP Servers
Model Context Protocol (MCP) servers extend Claude Code with additional capabilities such as database access, API integrations, and custom tools. Skills can use MCP servers by referencing their tools in instructions:
## Step 3: Query the Database
Use the database MCP server to check the current schema:
- List all tables
- Show the columns for the affected table
- Check for existing indexes
This information will guide the migration generation.
If MCP servers are configured for Slack, Jira, or internal APIs, Skills can orchestrate interactions across all of these systems, sending deployment notifications to Slack, creating Jira tickets for follow-up work, or querying internal services.
Error Handling in Skills
Robust Skills anticipate failure and provide clear guidance for recovery:
## Error Handling
If any step fails:
1. **Command not found**: The required tool may not be installed.
Tell the user what to install and how.
2. **Permission denied**: Suggest running with appropriate
permissions or checking file ownership.
3. **Network error**: Check if the target host is reachable.
Suggest checking VPN connection if applicable.
4. **Test failure**: Do NOT proceed with deployment. Show the
failing tests and ask the user how to proceed.
5. **Build failure**: Show the full error output and suggest
common fixes based on the error type.
In ALL error cases: provide the exact error message, the command
that failed, and a suggested fix. Never silently skip a failed step.
Testing Skills Before Sharing
Before a skill is committed to a project’s repository, it should be tested thoroughly:
- Begin at user level: Place the skill in
~/.claude/skills/first, so that only the author can see it. - Test with dry runs: Add a
--dry-runmode to the skill that prints the actions that would be taken without performing them. - Test edge cases: Invoke the skill with no arguments, incorrect arguments, and unusual inputs.
- Test in a clean environment: Clone a fresh copy of the repository and test the skill there to ensure it does not depend on local state.
- Solicit colleague review: A second reader catches unclear instructions and missing steps.
Sharing Skills With a Team and the Community
Skills are only as valuable as their reach. A capable deployment skill that resides on a single developer’s machine helps one person. The same skill committed to the project repository helps the entire team. The following sections describe the different sharing mechanisms.
Project Skills: Team-Wide via Git
Skills should be placed in .claude/skills/ within the repository and committed to git. Every team member who clones the repository obtains access to the same skills. This is the recommended approach for project-specific workflows.
# Add skills to your project
mkdir -p .claude/skills
cp deploy.md .claude/skills/
cp write-tests.md .claude/skills/
# Commit and push
git add .claude/skills/
git commit -m "Add team skills: deploy, write-tests"
git push
Benefits of project skills:
- Version controlled: changes to skills are visible together with their justifications.
- Code review: skill changes pass through the same PR process as code.
- Consistency: everyone uses the same workflows.
- Onboarding: new team members obtain immediate access to all workflows.
User Skills: Personal Productivity
Skills in ~/.claude/skills/ are personal. They apply to every project the user works on but are not shared. These are appropriate for:
- Personal coding-style preferences
- Workflows specific to an individual role (not every developer needs a
/deploy-to-my-dev-serverskill) - Experimental skills still under refinement
- Skills that reference personal configuration (SSH keys, personal servers)
Community Skill Repositories
As the Claude Code ecosystem grows, community repositories of skills are emerging. These are collections of production-proven skills that can be browsed, copied, and adapted for individual projects. When community skills are used, the following practices should be observed:
- The skill file should be read in full before installation, since it provides instructions that Claude Code will follow.
- Paths, commands, and conventions should be adapted to the target project.
- Skills should be tested in a safe environment first.
- Attribution should be retained if the skill carries a licence.
Best Practices for Team Skill Libraries
| Practice | Why It Matters |
|---|---|
| Prefix skill names with your team or project name | Avoids conflicts with built-in skills and other teams’ skills |
| Include a comment header in each skill with author and date | Makes it easy to find the right person to ask about a skill |
Write a README in .claude/skills/ listing all available skills |
New team members can discover skills without guessing names |
| Review skill changes in PRs just like code | A bad skill instruction can cause Claude Code to make mistakes |
| Keep skills focused—one skill, one job | Composable skills are more reusable than monolithic ones |
| Use composition for complex workflows | Avoids duplicating logic across multiple skills |
Skills in the Broader Claude Code Ecosystem
Skills do not exist in isolation. They are one element of a larger extension architecture that includes CLAUDE.md files, hooks, and MCP servers. Understanding how these elements fit together informs better design decisions about where to place logic.
Skills and CLAUDE.md
CLAUDE.md files provide persistent, always-on context. Every time Claude Code starts a session in a project, it reads the CLAUDE.md file and follows its instructions throughout the conversation. This is the appropriate location for:
- Project-wide coding standards (“always use single quotes”)
- Architectural decisions (“we use the repository pattern for data access”)
- File organization rules (“tests go in
__tests__/directories”) - Forbidden patterns (“never use
anytype in TypeScript”)
Skills, by contrast, are loaded on demand. They are appropriate for workflows that have a clear beginning and end: “deploy this,” “write tests for that,” “audit this code.” The distinction is that CLAUDE.md expresses “always remember this,” whereas Skills express “when this specific task is requested, perform it this way.”
Skills and Hooks
Hooks are automated behaviours that trigger on specific events: before a commit, after a file save, when a new file is created. They are configured in settings.json and run without user invocation. The key difference is that Skills are user-initiated (the user types the slash command), whereas hooks are event-initiated (they trigger automatically when an event occurs).
A common pattern uses Skills for manual workflows and hooks for automated enforcement. For example, the /security-audit skill permits developers to run manual audits, while a pre-commit hook automatically runs a lightweight secret scan on every commit.
Skills and MCP Servers
MCP servers provide tools: discrete capabilities such as “query a database” or “send a Slack message.” Skills provide workflows: sequences of steps that may use multiple tools. The relationship is complementary: Skills orchestrate, and MCP servers provide the building blocks.
Consider an example: an MCP server for a database provides Claude Code with the ability to run queries. A Skill instructs Claude Code when to run queries, what to query for, and what to do with the results, all within the context of a specific workflow such as generating a migration or auditing data integrity.
The Complete Extension Architecture
| Extension | When It Runs | What It Does | Best For |
|---|---|---|---|
| CLAUDE.md | Always (every session) | Provides persistent context and rules | Coding standards, project knowledge |
| Skills | On-demand (slash command) | Injects workflow instructions | Complex, multi-step workflows |
| Custom Commands | On-demand (slash command) | Injects simpler instructions | Project-specific quick tasks |
| Hooks | Automatically (on events) | Runs scripts on triggers | Enforcement, automation |
| MCP Servers | When tools are called | Provides external capabilities | Database, APIs, integrations |
Common Mistakes and How to Fix Them
After examination of numerous custom Skills, the following patterns appear most frequently as sources of difficulty.
| Mistake | What Happens | Fix |
|---|---|---|
| Instructions are too vague | Claude Code interprets the task differently each time, producing inconsistent results | Be specific: name exact commands, file paths, and expected outputs |
| No error handling | Skill silently fails or continues after an error, causing cascading problems | Add explicit “if this fails, do X” instructions for each critical step |
| Hardcoded paths and tools | Skill only works on the original author’s machine or project | Detect the project stack and adapt commands dynamically |
| Missing output format specification | Claude Code produces output in a random format each time | Specify exactly how output should be formatted (file, console, table) |
| No safety checks before destructive actions | Skill deploys broken code, drops a database table, or overwrites files | Always run tests, verify state, and confirm before destructive operations |
| Trying to do too much in one skill | Skill is fragile, hard to maintain, and confusing to use | Break it into smaller skills and use composition |
| Not testing with different argument values | Skill works with one input but breaks with others | Test with empty, minimal, and unusual arguments before sharing |
| Naming conflicts with built-in skills | Your custom skill is never invoked because the built-in takes precedence | Use unique, descriptive names—prefix with project or team name |
| Forgetting the frontmatter | Skill may not be recognized or arguments may not be parsed correctly | Always include the YAML frontmatter block with name, description, and arguments |
| No final report or summary | User has no idea what the skill did or whether it succeeded | End every skill with a “Report” step summarizing what was done |
npm test and check that the exit code is 0. If any test fails, show the first 30 lines of output and stop.”
Conclusion
Skills are among the features that distinguish casual Claude Code users from advanced users. They transform Claude Code from a chatbot with terminal access into a purpose-built automation platform that understands a team’s exact workflows. Unlike traditional automation tools, Skills are written in plain English: there is no DSL to learn, no YAML schemas to memorize, and no build system to configure.
The key points may be summarized as follows. Skills are markdown-based instruction sets loaded into Claude Code’s context on demand via slash commands. They have frontmatter for metadata and arguments, and a body of detailed instructions. They exist at three levels: built-in, user, and project, with built-in taking precedence. Built-in skills such as /commit, /review-pr, and /pr handle common git workflows, while custom skills can automate any workflow that can be described in English.
The six skill examples discussed (/deploy, /write-tests, /refactor, /db-migrate, /api-doc, and /security-audit) represent the kinds of high-value automations that save teams substantial time each week. They are, however, only starting points. The principal benefit emerges when an organization identifies the repetitive, error-prone workflows in its own development process and encodes them as Skills.
A recommended next step is the following: select one task that was performed manually this week, that took more than five minutes, and that involved multiple steps. Write a Skill for it. Place it in ~/.claude/skills/ and test it. Refine the instructions until the output matches the intended result. Then move it to .claude/skills/ and share it with the team. Within a month, the resulting library of Skills will produce measurable improvements in team velocity.