All posts
Claude CodeApril 28, 20255 min read

Claude Code Skills and Hooks: Automating Your Dev Workflow

Claude Code lets you build custom slash commands (skills) and automated hooks that run before or after every response. Here's how to build both — with practical examples.

claude codeskillshooksdeveloper toolsautomation
Arjun KayalMoni
Arjun KayalMoni

@fullstack-spiderman

Updated May 16, 2026

Claude Code Skills and Hooks: Automating Your Dev Workflow

Claude Code ships with a powerful extensibility layer that most developers haven't touched yet: skills (custom slash commands you define) and hooks (shell commands that run automatically around Claude's responses). Together they let you turn Claude Code into a fully customised engineering assistant tuned to your specific stack and workflow.

What Are Skills?

A skill is just a Markdown file that lives in ~/.claude/skills/ (user-level) or .claude/skills/ (project-level). When you type /skill-name in Claude Code, Claude reads that file and follows its instructions.

That's it. No plugins to install, no build step, no API registration.

~/.claude/skills/
  review.md          → /review
  deploy.md          → /deploy
  tdd.md             → /tdd
  changelog.md       → /changelog

Writing Your First Skill

Let's build a /review skill that performs a consistent code review:

# /review
 
Perform a comprehensive code review of the changes in the current branch.
 
## What to check
 
1. **Correctness** — Does the logic do what it claims? Check edge cases.
2. **Security** — Look for injection risks, exposed secrets, insecure defaults.
3. **Performance** — Identify N+1 queries, missing indexes, unnecessary allocations.
4. **Test coverage** — Are new code paths covered by tests?
5. **API contracts** — Are public interfaces backward-compatible?
 
## Output format
 
Return your review as:
 
- A one-paragraph overall summary (green/yellow/red status)
- A bulleted list of specific issues, each with: severity (🔴 critical / 🟡 warning / 🟢 suggestion), file:line reference, and a concrete fix
 
Focus on what matters. Skip style comments — the linter handles those.

Save this as ~/.claude/skills/review.md, then type /review in Claude Code. Claude will run git diff or check staged changes automatically and apply the framework from your skill file.

A TDD Skill

Here's a more opinionated skill that enforces test-driven development:

# /tdd
 
Implement the following feature using strict test-driven development.
 
## Process
 
1. Write a failing test first — do not write implementation code yet
2. Show me the test and ask for confirmation before continuing
3. Write the minimum implementation to make it pass
4. Refactor if needed (no new functionality)
5. Repeat for the next case
 
## Rules
 
- One failing test at a time
- Tests go in the appropriate __tests__/ directory, mirroring src/ structure
- Use the existing test framework (detect from package.json)
- Name tests as: `describe('FeatureName', () => { it('should ...', () => {}) })`
- Do NOT add tests retroactively — always test-first
 
When I give you a requirement, start with step 1 immediately.

Now /tdd add user authentication with JWT will walk through the whole TDD cycle with you, one red-green-refactor loop at a time.

What Are Hooks?

Hooks are shell commands configured in .claude/settings.json that Claude Code runs automatically at specific points in its lifecycle. They let you enforce rules without remembering to ask Claude about them.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Running: $CLAUDE_TOOL_INPUT'"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "bun run typecheck 2>&1 | head -20"
          }
        ]
      }
    ]
  }
}

Hook timing options

HookWhen it fires
PreToolUseBefore Claude calls any tool
PostToolUseAfter a tool completes
StopWhen Claude finishes responding
NotificationOn permission prompts

Practical Hook: Auto-lint on File Edit

Run ESLint automatically every time Claude edits a file:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "eslint --fix \"$CLAUDE_TOOL_INPUT_FILE_PATH\" 2>&1 | tail -5"
          }
        ]
      }
    ]
  }
}

If lint fails, Claude Code sees the output and automatically fixes the issues before moving on. You never have to say "also run the linter" — it just happens.

Practical Hook: Test Runner After Changes

Run relevant tests every time a source file changes:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "bun test --testPathPattern=$(basename $CLAUDE_TOOL_INPUT_FILE_PATH .ts) 2>&1 | tail -20"
          }
        ]
      }
    ]
  }
}

Claude won't declare a task done if tests are failing — the hook output feeds back into its context.

Combining Skills + Hooks

The real power is combining both. Example: a /ship skill that uses hooks for safety:

~/.claude/skills/ship.md:

# /ship
 
Prepare this feature for merge.
 
Steps:
1. Run the full test suite and fix any failures
2. Run the linter and fix issues
3. Check for console.logs or debug code and remove them
4. Update the CHANGELOG.md with the feature description
5. Create a conventional commit: feat(scope): description
6. Push the branch and open a draft PR
 
Do not proceed to the next step until the current one passes cleanly.

.claude/settings.json:

{
  "hooks": {
    "Stop": [
      {
        "type": "command",
        "command": "bun run typecheck && echo '✅ Types OK' || echo '❌ Type errors found'"
      }
    ]
  }
}

Now /ship triggers a full pre-flight check, and the Stop hook ensures types pass before Claude hands control back to you.

Where Settings Live

  • User-level (~/.claude/settings.json) — applies to every project
  • Project-level (.claude/settings.json) — applies to this repo only, committed to git
  • Local override (.claude/settings.local.json) — gitignored personal overrides

Skills follow the same pattern: ~/.claude/skills/ for global, .claude/skills/ for project-specific.

Getting Started

  1. Create ~/.claude/skills/ if it doesn't exist
  2. Write your first skill file (start with /review — it's immediately useful)
  3. Add a PostToolUse hook that runs your type checker
  4. Iterate — skills are just markdown, change them as your workflow evolves

The best skills are ones that encode the things you always have to remind Claude about. Write them down once, and you'll never have to repeat yourself again.

📚

Enjoyed this article?

If it saved you time or sparked an idea, consider buying me a book.

📚 Buy me a book