M
MeshWorld.
AI Claude Claude Code Agent Skills Tutorial 5 min read

How to Write Your First Claude Code Skill (SKILL.md Guide)

By Vishnu Damwala

Agent Skills turn Claude Code from a smart assistant into a programmable automation layer. Instead of typing out the same multi-step workflow every session, you define it once in a SKILL.md and invoke it with a single slash command.

This tutorial builds a /smart-commit skill — it runs lint, formats the diff, writes a commit message following conventional commits, and commits. A workflow most developers do manually, every day.

Prerequisites

  • Claude Code installed (npm install -g @anthropic-ai/claude-code)
  • A git repository to test in
  • Basic familiarity with Markdown

Skill directory structure

A skill lives in a directory inside your project (or globally in ~/.claude/skills/):

.claude/
└── skills/
    └── smart-commit/
        ├── SKILL.md       ← required
        └── README.md      ← optional docs

Create the directory:

mkdir -p .claude/skills/smart-commit

Write the SKILL.md

Create .claude/skills/smart-commit/SKILL.md:

# Skill: Smart Commit

## Trigger
/smart-commit

## Description
Runs lint, reviews staged changes, writes a conventional commit message, and commits.

## Tools
- shell: true
- read_file: true

## Instructions

You are helping the developer commit their staged changes cleanly.

Follow these steps in order:

### Step 1: Check for staged changes
Run `git diff --cached --stat` to see what is staged.
If nothing is staged, stop and tell the user to stage files first with `git add`.

### Step 2: Run lint
Run `git diff --cached --name-only` to get the list of changed files.
For JS/TS files, run `npx eslint --no-eslintrc --rule 'no-console: warn' <files>` (skip if no JS/TS files).
If lint fails with errors (not warnings), stop and show the errors. Do not commit broken code.

### Step 3: Review the diff
Run `git diff --cached` to read the full diff.
Understand what changed: what was added, removed, or modified.

### Step 4: Write a commit message
Based on the diff, write a commit message following Conventional Commits format:
- `feat:` for new features
- `fix:` for bug fixes
- `refactor:` for code changes that do not fix a bug or add a feature
- `docs:` for documentation changes
- `chore:` for build process, tooling, config
- `style:` for formatting changes only

Rules:
- Subject line: max 72 characters, imperative mood, no period at end
- If the change is complex, add a blank line and a short body (2-4 sentences max)
- Do not mention file names in the subject — describe the intent

Show the message to the user BEFORE committing and ask for confirmation.

### Step 5: Commit
After user confirms, run:
`git commit -m "<the message>"`

Report the commit hash and subject line when done.

## On Failure
If any step fails, explain what went wrong and what the user needs to fix before trying again.

Test it

Stage some changes and run:

git add src/some-file.ts
claude /smart-commit

Claude will:

  1. Check what is staged
  2. Lint the changed files
  3. Read the diff
  4. Propose a commit message like feat: add user authentication middleware
  5. Wait for your confirmation
  6. Commit

If you want to change the message, just say so and Claude will revise it.

Add a lifecycle hook

Hooks run shell commands at key points. Add this to your SKILL.md to log every skill invocation:

## Hooks
before_start: echo "[smart-commit] Starting at $(date)" >> ~/.claude/skill-log.txt
after_success: echo "[smart-commit] Committed: $(git log -1 --oneline)" >> ~/.claude/skill-log.txt

Now every commit is logged with a timestamp.

Make it team-shareable

Add a skills.json to your project root so teammates get the skill automatically:

{
  "skills": [
    {
      "name": "smart-commit",
      "path": ".claude/skills/smart-commit"
    }
  ]
}

When a teammate runs claude skills sync, Claude Code installs all project skills automatically.

Publish it as a community skill

To share your skill publicly:

  1. Create a GitHub repo named skill-smart-commit
  2. Put SKILL.md at the root
  3. Add a skill.json manifest:
{
  "name": "smart-commit",
  "version": "1.0.0",
  "description": "Lint, review, and commit with conventional commit messages",
  "trigger": "/smart-commit",
  "author": "your-github-username"
}

Others can install it with:

claude skills install github:your-username/skill-smart-commit

Extending the skill

Once the pattern is clear, extending is easy. Some ideas:

Add test running: After lint, run pnpm test --passWithNoTests and stop if tests fail.

Add a co-author line: Append Co-Authored-By: Claude <claude@anthropic.com> to every commit body.

Support monorepos: Detect which package was changed and scope the commit type accordingly (feat(auth):, fix(api):).

Add a dry-run mode: Pass --dry-run as an argument to preview without committing.

Each addition is just more steps in the ## Instructions block. No code required.

Key things to remember

  • Instructions are plain English — Claude interprets them, you do not write code
  • Keep steps numbered and explicit — Claude follows them literally
  • Use stop and tell the user language to create checkpoints
  • Test incrementally — run the skill after each addition to verify behavior

Next steps