Write Claude Code Agent Skills That Actually Work

Write Claude Code Agent Skills That Actually Work

My agent Koda has 18 Claude Code agent skills. Each one is a markdown file in ~/.koda/skills/. No framework, no plugin system, no YAML config. A skill is a numbered list of steps the agent reads and follows using its normal tools.

This is the part of running a Claude Code agent in production that most tutorials skip. They cover tools, MCP servers, and API calls. Nobody talks about how you write Claude Code agent skills that encode decision-making into files the agent can actually follow.

What a skill looks like

Here is a real skill file from my production agent. This one handles self-healing — when a scheduled task crashes, the agent reads this file and follows it step by step:

---
name: self-heal
description: Diagnose and recover from errors, crashes, or degraded state
when: Something is broken, tasks are failing repeatedly, or you detect an error pattern
---

## Steps

### Phase 1: Diagnose

1. Run health check — returns pm2 status, restart count, uptime, recent errors.
2. Tail the last 50 lines of the error log.
3. Identify the failure type:
   - MODULE_NOT_FOUND or SyntaxError → config issue, don't restart yet
   - ECONNREFUSED or API timeout → transient, restart may help
   - High restart count (>5) → crash loop
   - Missing env var → check .env

### Phase 2: Fix

- Config issue: read config.json and .env, fix it, then restart.
- Crash loop: read error log, fix underlying issue first, then restart.
- Transient error: restart with reason.
- Code bug: propose the fix — don't modify source without user approval.

### Phase 3: Verify

1. Wait 30 seconds, run health check again.
2. Report to Discord: what broke, what you did, current status.

That is the entire file. The agent reads it, classifies the error, applies the matching fix, and reports back. When I need to change the recovery logic, I edit the markdown. No redeploy, no code change.

Why skills beat code for agent behaviour

Scripts handle deterministic work: API calls, file I/O, authentication flows. A Python script that posts a tweet will always post a tweet the same way.

Skills handle decision-making. “Should I retry or escalate?” “Which platform should I adapt this content for?” “Is this error transient or structural?” These are judgement calls that change as you learn what works.

The split is simple: if the task has no branching logic, write a script. If the task requires reading context and making choices, write a skill.

Three reasons skills work better than hardcoded logic for agent behaviour:

  1. The agent already knows how to execute. Claude Code can run bash commands, read files, call APIs, and edit code. A skill just tells it what to do and in what order. You don’t need to implement the execution layer — it already exists.
  2. Markdown is the agent’s native language. Claude processes markdown better than any other format. Headers create structure. Numbered lists create sequence. Code blocks create precision. The model was trained on millions of markdown files — this is the format where it makes the fewest mistakes.
  3. You can iterate in seconds. When a skill produces a bad result, you open the file, edit one line, and the next execution uses the updated version. No build step, no deployment, no version mismatch. The filesystem is the runtime.

The anatomy of a good skill

Every skill in my agent follows this structure:

---
name: skill-name-in-kebab-case
description: One sentence — what this skill does
when: Trigger condition — when should the agent use this skill?
---

## Steps

1. First step with specific tool call or command
2. Second step...
3. Decision point with if/then branches

## Notes

- Gotchas, credential locations, constraints

The frontmatter matters. The when field is how the agent decides which skill to load for a given task. “When: Playwright script fails with auth error” tells the agent exactly when to reach for the refresh-cookies skill instead of trying to debug the auth problem from scratch.

What makes a skill reliable

After writing 18 skills and watching them execute hundreds of times, these are the patterns that work:

Use exact file paths, not descriptions. Bad: “Check the config file.” Good: “Read ~/.koda/config.json.” The agent will find creative wrong paths if you leave it ambiguous.

Include the actual commands. Bad: “Post to Bluesky.” Good: mcp__bluesky-mcp__create-post(text="..."). The agent has dozens of tools available. Tell it which one to use.

Put decision trees in the steps, not the notes. The agent reads linearly. If a branching decision is buried in a “Notes” section at the bottom, it will miss it during execution.

Cap skills at 60 lines. If a skill is longer, it is two skills. Long skills cause the agent to lose track of where it is in the sequence, especially when context gets tight.

Write negation rules. “Never restart without diagnosing first” is more effective than “Always diagnose before restarting.” The agent finds creative ways to violate positive instructions. Negation rules are harder to work around.

Real examples from production

Skill that chains other skills

My post-to-x skill includes a decision gate:

## When to use this skill vs write-x-article

Use this skill (normal X post) when:
- The content is prose-only: insights, takes, short stories
- No code blocks, no rich formatting
- Under ~500 words

Use write-x-article instead when:
- The content has code blocks — X posts render them as ugly plain text
- The content is 600+ words and benefits from structure
- It's a tutorial or technical walkthrough

This routing logic lives in the skill file, not in code. The agent reads it, evaluates the draft, and picks the right publishing path. When I discovered that code blocks render badly in regular X posts, I added two lines to this skill. The agent immediately started routing technical content to the Article format.

Skill that learns from failure

My read-x-tweet skill exists because I made a mistake. On April 6th, I was asked to read a tweet by URL. I wrote a throwaway Node script instead of checking ~/.koda/scripts/ for the existing scan_viral_tweets.py which already had all the Playwright and cookie auth plumbing.

The skill file now includes this section:

## Why this skill exists

On 2026-04-06 I was asked to read a tweet by URL. I wrote a throwaway
script instead of checking ~/.koda/scripts/ for the existing
scan_viral_tweets.py — which already had the Playwright + cookie auth.
This skill exists so I don't repeat that mistake.

The agent reads that note every time it handles a tweet URL. It has not repeated the mistake.

Skill with approval gates

My publish-youtube-video skill enforces a hard approval requirement:

3. Publish via publish.py — ALWAYS use this script, never upload directly:
   python3 ~/.koda/scripts/publish.py /path/to/video.mp4 \
     --title "Video Title" --platforms youtube

4. Wait for reaction — publish.py sends a preview to Discord
   and waits for approval. Do NOT call YouTube upload tools directly.

The word “ALWAYS” and “NEVER” in the skill file acts as a constraint. The agent treats these as hard rules, not suggestions. Every video upload goes through Discord approval because the skill says it must.

How to start writing skills for your agent

You don’t need 18 skills on day one. Start with one:

  1. Pick a task you’ve done manually more than twice. Posting to social media, running a deployment check, pulling analytics — anything with 3+ steps.
  2. Write the steps as a numbered list. Include the exact commands and file paths. Be specific enough that a colleague who has never seen your codebase could follow the instructions.
  3. Save it to your agent’s skill directory. For Koda that is ~/.koda/skills/skill-name.md. For a Claude Code agent using the standard CLAUDE.md approach, put it in your project’s .claude/skills/ directory or reference it from your system prompt.
  4. Run the task and watch. The first execution will reveal what you forgot — a missing credential path, an ambiguous step, a decision branch you didn’t account for.
  5. Fix the skill file, not the agent. When something goes wrong, edit the markdown. After 3-4 iterations, the skill will be solid. After 10 executions, it will be reliable.

The compounding effect is real. Each skill you write makes the agent more capable without adding code. After two weeks of writing skills, my agent handles 21 scheduled tasks across 6 platforms, self-heals from failures, and operates for hours without my input. All of this runs on persistent memory — the agent reloads its skills, learnings, and state from disk every session.

FAQ

Are these the same as CLAUDE.md instructions?

Related but different. CLAUDE.md is a global system prompt — it sets tone, constraints, and general behaviour. Skills are task-specific recipes the agent loads when it needs to do a particular job. Think of CLAUDE.md as the employee handbook and skills as the standard operating procedures.

Can I use this with the Claude Agent SDK or just Claude Code CLI?

Both. The Agent SDK loads skills the same way — you reference them in the system prompt or put them in a directory the agent reads on boot. Koda uses the Agent SDK with skills loaded from ~/.koda/skills/. A Claude Code CLI project would use .claude/skills/ or reference them from .claude/CLAUDE.md.

How do I know when to write a skill vs a script?

If the task is deterministic (same input → same output every time), write a script. If the task requires reading context, making judgement calls, or handling variable conditions, write a skill. Most real workflows need both — the skill orchestrates, the scripts execute.

What happens when two skills conflict?

The when field in the frontmatter prevents this. Each skill has a specific trigger condition. If two skills could apply, make the when conditions mutually exclusive. In practice, I have never had a conflict across 18 skills because each one owns a distinct task.


I’m building the full skill library — every skill file, the runtime that loads them, the self-healing loop — inside my Build & Automate community. Real production code, not demo projects.


This post was published using Notipo — my Notion-to-WordPress sync tool. Write in Notion, publish to WordPress automatically.

Similar Posts