
This article is for the operator who has Claude Code installed, has run a few one-off requests through it, and now wants to take one of those workflows and make it persistent. Maybe you've been pasting the same instructions into chat three times a week and you're tired of it. Maybe you ran a great report once and now you can't remember exactly how you asked for it. That's the moment a skill earns its place.
I'm going to walk you through building your first one end-to-end. Directory layout, what goes in SKILL.md, when to add a helper script, how to trigger it, and the gotchas that trip up everyone the first time. No frameworks, no SDK, no boilerplate. By the end of this article you'll have a working skill on your machine.
The mental model in 60 seconds
A Claude Code skill is a directory. That directory lives at ~/.claude/skills/<skill-name>/ and contains one required file called SKILL.md plus any helper scripts you want.
When you start Claude Code, it scans every skill directory and reads the description from each SKILL.md. When you type a message that matches one of those descriptions, Claude reads the full SKILL.md for that skill and follows the instructions inside it. If those instructions tell Claude to run a script, it runs the script.
That's the whole thing. No registration, no manifest, no plugin system. A skill is a folder Claude knows how to read.
Step 1: Pick a workflow worth turning into a skill
Before you write a line of YAML, make sure the workflow deserves to be a skill. I wrote a full checklist on this in When to Build a Claude Code Skill (And When Not To). The short version — a skill is worth building if the workflow is repeated weekly, touches files on disk, depends on context you don't want to retype, and chains multiple steps. Three out of four is the threshold.
For this walkthrough I'll use a workflow I run constantly — generating a quick weekly summary from a list of completed tasks I keep in a text file. It's repeated, file-based, context-dependent (I have a specific tone I want for these summaries), and multi-step (read file, parse, summarize, format). All four criteria, easy build.
Pick something on your own machine that fits the same shape. The work below applies to whatever workflow you choose.
Step 2: Create the directory
Open a terminal and make the directory. Skill names should be kebab-case and descriptive enough that you'll remember what they do six months from now.
mkdir -p ~/.claude/skills/weekly-summary
cd ~/.claude/skills/weekly-summary
That's it. The directory exists. Claude Code will find it the next time it boots, but there's nothing in it yet so it won't do anything.
If you want subdirectories for scripts or templates, create them now. I usually use scripts/ for any code the skill calls.
mkdir scripts
Step 3: Write the SKILL.md
This is the only required file. It has YAML frontmatter at the top (Claude reads this for routing) and markdown instructions below (Claude reads this when the skill is invoked).
Here is a working minimal version. Save this as ~/.claude/skills/weekly-summary/SKILL.md:
---
name: weekly-summary
description: Generate a concise weekly summary from a tasks log file. Trigger on "weekly summary", "summarize my week", "summarize tasks at [path]".
---
# weekly-summary
You generate a short weekly recap from a tasks log file.
## Inputs
The user gives you a path to a plain-text tasks file. Each line is one
completed task in the form `YYYY-MM-DD | description`. If no path is given,
default to `~/tasks.log`.
## What to do
1. Read the file at the given path.
2. Group entries by week (Monday to Sunday).
3. For the most recent week, write a 3-bullet summary — what shipped,
what got blocked, what carries into next week.
4. Keep the tone matter-of-fact. No exclamation points, no filler.
Return the summary as markdown. Don't add headers above it.
That's a real working skill. Read it once before continuing — every line is doing something.
The name and description keys are what Claude uses to decide whether to invoke the skill. The trigger phrases in the description are the most important text in the whole file. If your description is vague, Claude won't auto-invoke when you want it to. If it's specific and includes the actual phrases you'll type, it will fire reliably.
The body below the frontmatter is what Claude reads after it decides to run the skill. Think of it as a brief to a junior employee — name the inputs, name the steps, name the output format. Don't over-explain. Claude is competent.
Step 4: When to add a helper script
For a skill this simple, you don't need a script. Claude can read a file and write a summary in its own context. You'd add a helper script when:
- The work is deterministic and you want the same output every time (calculations, parsing, formatting).
- The work involves a third-party API call, a database query, or anything Claude can't do natively.
- The work runs on large data where it's faster to script than to read into context.
For the weekly summary, I'll add a tiny Python script that does the parsing and grouping deterministically, so Claude only has to write the prose. This gives more reliable output than asking Claude to count weeks itself.
Save this as ~/.claude/skills/weekly-summary/scripts/group_tasks.py:
#!/usr/bin/env python3
"""Group tasks by week. Print the most recent week's entries."""
import sys
from datetime import datetime, timedelta
from collections import defaultdict
def main(path):
weeks = defaultdict(list)
for line in open(path):
line = line.strip()
if not line or "|" not in line:
continue
date_str, desc = [p.strip() for p in line.split("|", 1)]
d = datetime.strptime(date_str, "%Y-%m-%d").date()
monday = d - timedelta(days=d.weekday())
weeks[monday].append(desc)
latest = max(weeks.keys())
print(f"Week of {latest}:")
for task in weeks[latest]:
print(f"- {task}")
if __name__ == "__main__":
main(sys.argv[1])
Then update the ## What to do section of SKILL.md to call the script:
## What to do
1. Run `python3 scripts/group_tasks.py <path>` to get the current week's tasks.
2. Read the output.
3. Write a 3-bullet summary — shipped, blocked, carryover.
Now Claude doesn't have to handle the parsing. The script does the boring part. Claude does the part that needs judgment.
Step 5: First invocation
Start Claude Code in any directory. Then type:
summarize my week from ~/tasks.log
Claude scans its skill descriptions, matches summarize my week against your skill's trigger phrases, and reads the full SKILL.md. It sees the instruction to run the script, runs it, gets the grouped output, and writes the 3-bullet summary based on it.
You should see something like this in the terminal:
Running skill: weekly-summary
Week of 2026-05-04:
- Shipped the Meta CLI dry-run gate
- Fixed the reporting skill's Amazon timezone bug
- Started the Skylar onboarding folder
Summary:
- Shipped — Meta CLI dry-run gate now blocks accidental pushes.
- Blocked — Amazon report still throws on Pacific timezone; needs a
one-line fix in the date parser.
- Carryover — Skylar onboarding folder is scaffolded but the research
baseline isn't started yet.
That's a working skill. It read your file, did its work, and gave you a clean output. The next time you want a weekly summary you type the same trigger and it just runs.
Common gotchas
These are the five things that trip people up the first time. None of them are obvious, all of them are easy to fix.
The description is too vague to auto-invoke. If your description reads like "a skill that helps with weekly stuff", Claude won't fire it when you type "summarize my week". The description has to include the phrases you actually type. Look at the trigger phrases in the example above — they include "weekly summary", "summarize my week", and "summarize tasks at [path]". Three real phrasings, not one. Write down how you'd actually ask, and put those exact phrases in the description.
Naming collisions with installed skills. If you name your skill report or audit or email, you'll collide with an installed skill of the same name. Run ls ~/.claude/skills/ first and pick a name that doesn't clash. I prefix workflow-specific skills with their domain — meta-ads-audit, weekly-summary, clare-monday-report.
Hardcoded paths instead of arguments. Don't bake /Users/yourname/tasks.log into the skill. Take a path as an argument, default to a sensible location, and ask if it's missing. Skills should travel — between machines, between projects, between people.
Script not executable, or wrong interpreter. If you wrote a script with #!/usr/bin/env python3 at the top and chmod +x it, fine. If not, always call it explicitly with python3 scripts/script.py in the SKILL.md instructions. The skill runs in whatever shell Claude Code spawns — don't assume a PATH that may not exist there.
Scope creep on day one. Your first skill should do one thing. The weekly summary skill above is one input, one output. Resist the urge to make it also handle monthly summaries, export to PDF, and email the result. Ship the one-thing version, use it for a month, and let real usage tell you what to add. Most skills I've abandoned were over-built before I knew what I actually needed.
Where to go next
Once your first skill clicks, the pattern repeats. Pick the next recurring workflow, run the checklist from the when-to-build article, make a directory, write a SKILL.md, add a script if the work is deterministic, test it once, ship it.
If you want the full set that runs a marketing operation, not just one skill, The Operator on operatorstack.app is the pre-built bundle: reporting, ad creative, audits, onboarding, comparisons, and client comms, plus The Lab where new skills land every month. One-time $397 launch price, going up as the Lab grows. Or hire Clare Digital and we'll build them into your accounts directly.
Either way, the first skill is the hard one. Once it works, the rest are a copy of the same pattern.