Claude Code Skills vs Hooks: When to Use Each Approach?
Problem
I was using Claude Code daily, but my code quality was inconsistent. Sometimes tests ran, sometimes they didn’t. Sometimes formatting was applied, sometimes I forgot. I’d tell Claude “run typecheck before committing” but it would forget half the time.
Then I discovered two mechanisms for improving workflow: Skills and Hooks. But I didn’t understand the difference. When should I use which?
Here’s what happened when I tried to use Skills for everything:
# I put everything in CLAUDE.md- Always run typecheck after editing TypeScript files- Always run tests before committing- Always format code after saves- Always check for console.log before commits- Follow TDD workflow for new features- Run security review before commitsThe result? Claude followed these rules maybe 60% of the time. In long sessions, it would forget. When context grew, compliance dropped. I was frustrated.
What Happened?
I found a Reddit thread by DevMoses titled “From Zero to Fleet: The Claude Code Progression Ladder” that explained the problem perfectly.
The key insight was: Skills are probabilistic, Hooks are deterministic.
From the thread:
"the hooks insight is the one most people skip over imo. theres a massive difference between telling the agent 'always run typechecks' vs making the environment enforce it on every save. the first one degrades, the second one just works."I was using Skills (telling Claude what to do) when I should have been using Hooks (making the environment enforce it).
The Solution
I learned to separate my needs into two categories:
Use Skills for Judgment-Based Workflows
Skills are markdown protocol files that load on demand. They work best for complex workflows requiring Claude’s judgment.
I created a skill for TDD workflow:
---name: tdd-workflowdescription: Use this skill when writing new features, fixing bugs, or refactoring code.---
# Test-Driven Development Workflow
## When to Activate- Writing new features or functionality- Fixing bugs or issues- Refactoring existing code
## Core Principles1. Tests BEFORE Code2. Minimum 80% coverage3. Unit + Integration + E2E tests
## TDD Workflow Steps1. Write user journeys2. Generate test cases3. Run tests (they should FAIL)4. Implement code5. Run tests (they should PASS)6. Refactor7. Verify coverageThis works because TDD requires judgment:
- How should I structure the tests?
- What edge cases matter?
- When is refactoring done?
Claude needs context and expertise to make these decisions.
Use Hooks for Quality Gates
Hooks are scripts that run on lifecycle events. They work best for quality gates that should never be skipped.
I added a PostToolUse hook for typechecking:
{ "hooks": { "PostToolUse": [{ "matcher": "Edit|Write|MultiEdit", "hooks": [{ "type": "command", "command": "npx tsc --noEmit --pretty", "timeout": 30000 }] }] }}Now every time I edit a TypeScript file, typecheck runs automatically. No judgment needed. No “remembering” required.
I also added a security reminder hook:
#!/usr/bin/env python3"""PreToolUse hook for security reminders."""
import jsonimport sys
def main(): input_data = json.load(sys.stdin) tool_name = input_data.get('tool_name', '')
# Check for security-sensitive operations if tool_name == 'Edit': file_path = input_data.get('tool_input', {}).get('file_path', '') if 'auth' in file_path or 'secret' in file_path.lower(): print(json.dumps({ "systemMessage": "Security-sensitive file. Review for hardcoded credentials." }))
sys.exit(0)
if __name__ == '__main__': main()This hook fires before every edit to auth-related files. Claude gets a reminder, but I don’t have to explicitly ask for it.
Why This Matters
The difference is in reliability:
Skills: "Run typecheck" -> ~50-80% compliance (Claude decides)Hooks: On Edit -> typecheck runs -> 100% compliance (automatic)I tested this empirically. Over 100 TypeScript edits:
- Skills approach: 67 typechecks ran (67%)
- Hooks approach: 100 typechecks ran (100%)
The continuous-learning-v2 skill documentation explains why:
"v1 relied on skills to observe. Skills are probabilistic - they fire ~50-80% of the time based on Claude's judgment. Hooks fire 100% of the time, deterministically."This reliability gap compounds over time. In a session with 50 edits, Skills might miss 15-25 typechecks. Hooks miss zero.
Common Mistakes
I made several mistakes before understanding the difference.
Mistake 1: Using Skills for Quality Gates
# In CLAUDE.md- Always run typecheck after editing TypeScript- Always run linter before commits- Always check for console.logThis relies on Claude’s judgment and context. In long sessions, it gets forgotten.
Correct: Use Hooks
{ "hooks": { "PostToolUse": [{ "matcher": "Edit", "hooks": [{ "type": "command", "command": "npx tsc --noEmit --pretty" }] }] }}This runs automatically, every time, with zero token cost.
Mistake 2: Using Hooks for Complex Workflows
Hooks are scripts, not intelligence. They can:
- Check if files match patterns
- Run commands
- Block operations
But they cannot:
- Provide nuanced guidance
- Adapt to context
- Make judgments
I tried to put TDD workflow in a hook and it failed because the hook couldn’t decide what tests to write.
Correct: Use Skills for Complex Workflows
# In skill file## TDD Workflow Steps1. Write user journeys2. Generate test cases3. Run tests (they should FAIL)4. Implement codeSkills provide structured expertise. Claude can adapt this to the specific context.
Mistake 3: Ignoring Both
Without Skills or Hooks, I was:
- Repeating the same instructions every session
- Getting inconsistent quality across sessions
- Not learning from patterns
The combination is powerful. I now use both:
Skills: Domain expertise (TDD, security review, architecture decisions)Hooks: Quality gates (typecheck, lint, format, security scan)The Combined Approach
The most effective setup uses both Skills and Hooks together. Here’s how they complement each other:
+--------------------------------+--------+----------------------------------+| Need | Use | Why |+--------------------------------+--------+----------------------------------+| "Always format on save" | Hook | 100% enforcement, zero tokens || "Guide me through TDD" | Skill | Complex workflow, needs judgment || "Block console.log commits" | Hook | Preventive, deterministic || "Security best practices" | Skill | Expertise, checklists, context || "Log all tool usage" | Hook | Background, no AI needed || "Code review checklist" | Skill | 10+ items, nuanced feedback |+--------------------------------+--------+----------------------------------+The continuous-learning system demonstrates this combination:
Skill: Provides the intelligence (how to detect patterns, evolve instincts) Hook: Provides the reliability (captures every action deterministically)
Together, they create a system that:
- Thinks when needed (Skills)
- Enforces always (Hooks)
- Learns continuously (both working together)
How I Applied This
I restructured my Claude Code setup:
Global Hooks (in settings.json):
- PostToolUse typecheck for TypeScript files
- PreToolUse security reminder for auth files
- Stop hook for console.log audit
Global Skills (in ~/.claude/skills/):
- TDD workflow for feature development
- Security review checklist
- Code review checklist
Project-Specific (in .claude/):
- Skills for domain expertise (e.g., React patterns for a React project)
- Hooks for project-specific quality gates
The result? My code quality became consistent. Typecheck runs on every edit. Tests run before commits. Security reviews happen at the right time. But I also get nuanced guidance for complex decisions.
Summary
In this post, I showed when to use Skills versus Hooks in Claude Code. The key point is that Skills are probabilistic expertise protocols while Hooks are deterministic lifecycle scripts.
Start here:
- Add a PostToolUse hook for typechecking TypeScript edits
- Create a skill for your team’s code review checklist
- Watch quality improve automatically while expertise scales
The difference between telling Claude “always run typecheck” and having a hook that enforces it is the difference between 67% compliance and 100% compliance. For quality gates, that gap matters.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments