Skip to content

How Do I Create Custom Skills in Claude Code for Repeated Workflows?

Problem

I kept repeating the same workflows in Claude Code. Every time I finished implementing a feature, I had to manually ask Claude to write tests, check for console.log statements, review the code, commit, and push. It was the same sequence every single time.

Here’s what my typical workflow looked like:

Me: "I'm done with the login feature. Please write tests for it."
Claude: [writes tests]
Me: "Now check for any console.log statements I might have left."
Claude: [finds and removes console.log]
Me: "Review the code for any issues."
Claude: [reviews code]
Me: "Now commit and push."
Claude: [commits and pushes]

This was tedious. I was spending more time orchestrating Claude than actually coding. And sometimes I would forget a step - like the time I pushed code with three console.log statements still in it.

I needed a way to package this workflow so Claude could run it automatically.

What I Tried First

I tried using CLAUDE.md to define the workflow. I added this to my project’s CLAUDE.md file:

CLAUDE.md (WRONG APPROACH)
# After Implementation
When I finish implementing something, you should:
1. Write tests
2. Check for console.log
3. Review code
4. Commit and push

This didn’t work. Claude would sometimes remember, sometimes not. The instructions were too vague about when to trigger. And I couldn’t manually invoke them when I needed them.

Then I found out about Claude Code skills through a Reddit discussion.

The Solution

Claude Code has a feature called “skills” that lets you create reusable workflows. A skill is just a folder with a SKILL.md file.

The basic structure is simple:

Skill Directory Structure
.claude/skills/
└── my-skill/
└── SKILL.md

The SKILL.md file has two parts: frontmatter with metadata, and the actual instructions.

Here’s my finalize skill that solved my problem:

.claude/skills/finalize/SKILL.md
---
name: finalize
description: Run after implementation is complete. Performs finalization workflow - write missing tests, simplify code, review code, commit, and push. Use when user says "finalize", "done implementing", or after completing a feature.
disable-model-invocation: true
---
# Finalization Workflow
After an implementation is complete, execute this sequence:
1. **Write Missing Tests**
- Check for untested functions
- Add unit tests for new code
- Ensure 80%+ coverage
2. **Simplify Code**
- Remove dead code
- Extract repeated patterns
3. **Review Code**
- Check for console.log statements
- Verify error handling
- Validate input types
4. **Commit and Push**
- Create descriptive commit message
- Push to remote branch
Report summary of all changes made.

Now when I type /finalize in Claude Code, it runs the entire sequence automatically. No more manual step-by-step requests.

Two Ways Skills Get Triggered

Skills can be triggered in two ways:

1. Manual invocation with slash commands

When you type /finalize, Claude runs that skill. This is controlled by the disable-model-invocation: true setting, which prevents automatic triggering.

2. Automatic invocation based on description

If you set disable-model-invocation: false or omit it entirely, Claude will automatically trigger your skill when the description matches the context.

For example, this skill auto-triggers when relevant:

.claude/skills/project-conventions/SKILL.md
---
name: project-conventions
description: Code style and patterns for this project. Apply automatically when writing or reviewing code.
user-invocable: false
---
# Project Conventions
## Naming Conventions
- React components: PascalCase
- Utilities: camelCase
- Constants: UPPER_SNAKE_CASE
## Forbidden
- No `any` types
- No `console.log` in production code

This skill runs in the background whenever I’m coding. I don’t need to invoke it manually.

The Critical Detail I Missed

My first skill didn’t work. Here’s what I wrote:

SKILL.md (WRONG)
---
name: finalize
description: Finalize workflow
---

Claude never triggered it. I didn’t understand why until I read the documentation more carefully.

The description field is the trigger mechanism. Claude matches your task context against this description. If the description doesn’t contain the right keywords, Claude won’t know when to use the skill.

I rewrote it:

SKILL.md (CORRECT)
---
name: finalize
description: Run after implementation is complete. Performs finalization workflow - write missing tests, simplify code, review code, commit, and push. Use when user says "finalize", "done implementing", or after completing a feature.
disable-model-invocation: true
---

Now the description includes:

  • When to use it (“after implementation is complete”)
  • What it does (“write missing tests, simplify code, review code, commit”)
  • Trigger phrases (“finalize”, “done implementing”)

After this change, /finalize worked perfectly.

Skills with Bundled Resources

Skills can also include scripts, templates, and reference documentation. This is useful for more complex workflows.

Enhanced Skill Structure
.claude/skills/
└── new-component/
├── SKILL.md
├── templates/
│ ├── component.tsx.template
│ ├── component.test.tsx.template
│ └── component.stories.tsx.template
└── scripts/
└── validate.sh

The SKILL.md can reference these resources:

.claude/skills/new-component/SKILL.md
---
name: new-component
description: Scaffold a new React component with tests and stories. Use when user says "create component", "new component", or mentions React component creation.
disable-model-invocation: true
---
# Create React Component: $ARGUMENTS
Use templates in [templates/](templates/) directory:
1. Generate component from `component.tsx.template`
2. Generate tests from `component.test.tsx.template`
3. Generate Storybook story from `component.stories.tsx.template`
Replace placeholders:
- `{{ComponentName}}` with PascalCase name
- `{{component-name}}` with kebab-case name

This way, you’re not rewriting the same templates every time. The skill packages everything together.

Where to Put Skills

Skills can live in two places:

Global skills at ~/.claude/skills/ - available in all projects

Project skills at <project>/.claude/skills/ - only available in that project

I keep general skills globally (like /finalize) and project-specific skills locally (like a skill for a specific API convention used only in one project).

To verify your skills are loaded correctly, run:

Terminal window
/skills

Claude will list all available skills.

Common Mistakes

I made several mistakes while learning skills:

Mistake 1: Vague descriptions

# WRONG - Claude won't know when to use this
description: Helper for coding
# RIGHT - Clear trigger conditions
description: Run after implementation is complete. Use when user says "finalize" or "done implementing".

Mistake 2: Over-explaining in the body

Claude is already smart. The SKILL.md body should contain instructions, not explanations of what Claude already knows.

# WRONG - Too much explanation
This skill helps you write better code. Tests are important because they catch bugs. You should always test your code before shipping...
# RIGHT - Just the instructions
1. Check for untested functions
2. Add unit tests for new code
3. Ensure 80%+ coverage

Mistake 3: Wrong scope

A skill should do one thing well. My first attempt at a skill tried to handle testing, linting, security review, and deployment. It was too complex and often failed.

I split it into four separate skills:

  • /finalize - post-implementation workflow
  • /security-check - security-specific review
  • /deploy - deployment workflow
  • /test-coverage - coverage analysis

Each skill is focused and reliable.

Why Skills Matter

Before skills, I repeated myself constantly. I explained the same coding conventions in every session. I manually requested the same review steps.

With skills, I package expertise once and reuse it forever:

Before SkillsWith Skills
Re-explain conventions every sessionLoad once, reuse
Manually request review stepsAutomated sequences
Inconsistent enforcementConsistent patterns
Knowledge lives in my headKnowledge lives in SKILL.md

Skills transform Claude Code from a chatbot into a programmable development environment. You define the workflows, Claude executes them consistently.

Summary

In this post, I showed how to create custom skills in Claude Code. The key points:

  1. Create a folder at .claude/skills/<skill-name>/ with a SKILL.md file
  2. The description field in frontmatter is the trigger mechanism - include relevant keywords
  3. Use disable-model-invocation: true for manual-only skills with slash commands
  4. Bundle templates and scripts for complex workflows
  5. Keep skills focused on single domains

Next step: Identify one workflow you repeat daily and create a skill for it. Run /skills to verify it loads correctly, then invoke it with /skill-name.

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