Home AI/ML Understanding Skills in Claude Code: What They Are, How They Work, and How to Build Your Own

Understanding Skills in Claude Code: What They Are, How They Work, and How to Build Your Own

Last updated: May 27, 2026
k
Published April 6, 2026 · Updated May 27, 2026 · 36 min read

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

 

Key Takeaway: CLAUDE.md functions as the “constitution” (always-on rules), custom commands as “quick macros” (simple project tasks), and Skills as “expert modules” (structured, reusable, composable capabilities). Each should be used where it fits best; the three mechanisms are complementary.

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 Lifecycle: From Slash Command to Output User Invokes /deploy staging Skill Loaded deploy.md parsed Context Injected $ARGUMENTS → staging Agent Executes Bash, Read, Edit… Output Result reported Step 1 Step 2 Steps 3–4 Step 5 Done

Skill Resolution Order

When multiple skills share the same name, Claude Code uses a priority order to determine which one to load:

  1. Built-in skills: shipped with Claude Code itself. These take highest priority.
  2. User skills: located in ~/.claude/skills/. These are personal to the user and apply across all projects.
  3. 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.
Caution: A project skill that shares its name with a built-in skill (for example, commit) will be superseded by the built-in version. Unique names should be chosen for custom skills in order to avoid conflicts.

Skill Types Hierarchy Built-in Skills Highest priority · Ships with Claude Code User Skills ~/.claude/skills/ Personal · Cross-project Project Skills .claude/skills/ Shared via git Custom Commands .claude/commands/ Simple project macros

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:

  1. Runs git status to see what has changed
  2. Runs git diff to understand the actual changes
  3. Reads recent commit messages to match the repository’s style
  4. Analyzes the changes and drafts a meaningful commit message
  5. Stages relevant files (avoiding sensitive files like .env)
  6. Creates the commit with a properly formatted message
  7. 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.

Tip: Typing / 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 deploy is 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

Anatomy of a Skill File Trigger /skill-name $ARGUMENTS Skill File (.md) Frontmatter name · description arguments schema Instructions Markdown body Step-by-step workflow rules Claude Executes Uses tools: Bash · Read Edit · Grep… Output Result to user slash command .md on disk injected into context tool calls terminal

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
Key Takeaway: Hyphens should be used in filenames for multi-word skill names. The file 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.
Tip: Explicit error handling should always be included in Skills. Without it, Claude Code will attempt to handle errors on its own, which is acceptable for simple cases. For critical workflows such as deployments, however, behaviour under failure should be specified explicitly.

Testing Skills Before Sharing

Before a skill is committed to a project’s repository, it should be tested thoroughly:

  1. Begin at user level: Place the skill in ~/.claude/skills/ first, so that only the author can see it.
  2. Test with dry runs: Add a --dry-run mode to the skill that prints the actions that would be taken without performing them.
  3. Test edge cases: Invoke the skill with no arguments, incorrect arguments, and unusual inputs.
  4. 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.
  5. 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-server skill)
  • 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:

  1. The skill file should be read in full before installation, since it provides instructions that Claude Code will follow.
  2. Paths, commands, and conventions should be adapted to the target project.
  3. Skills should be tested in a safe environment first.
  4. 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 any type 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

 

Caution: The single most common mistake is writing instructions that are too vague. A Skill is a playbook; the more precise the instructions, the more consistent and reliable the results. Rather than “run the tests,” the instruction should read “run 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.

References

You Might Also Like

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *