By Sagar Shankaran, Founder of CallSphere
Step-by-step guide to building a production Claude Agent Skill — frontmatter, procedural body, scripts, reference files, and testing discovery and execution.
Key takeaways
Reading about Agent Skills is one thing; shipping one your whole team relies on is another. This is a hands-on walkthrough that takes you from an empty directory to a working, tested skill that Claude loads on its own when the task calls for it. We'll build a realistic example — a skill that turns messy support-ticket exports into a clean weekly summary — and you'll see every file, every command, and every decision along the way.
Every skill begins as a directory. Create the structure first so you have somewhere to put each piece as you build it. The minimum is a single SKILL.md; we'll add a script and a reference file because our example needs both.
mkdir -p ticket-summary/scripts ticket-summary/reference
touch ticket-summary/SKILL.md
touch ticket-summary/scripts/parse_tickets.py
touch ticket-summary/reference/summary-format.md
Naming matters more than it looks. The folder name becomes part of how you and your teammates refer to the skill, and it should read like a capability — ticket-summary, not helper or v2. Treat the whole directory as a unit of organizational knowledge you'll version-control and review like any other code.
The frontmatter is the first thing to get right because it controls discovery. Claude only sees the name and description when deciding whether to load the skill, so the description must read like a precise trigger condition, naming the input it expects and the output it produces.
---
name: ticket-summary
description: Converts raw support-ticket CSV or JSON exports into a structured weekly summary with volume, top issues, and SLA breaches. Use when the user shares a ticket export and asks for a digest or report.
---
Notice the description does two jobs: it states what the skill does and the exact situation that should trigger it. Avoid soft phrasing like "helps with support data." If you can't tell from the description alone when the skill should fire, neither can Claude.
The body is loaded only after the skill is selected, so it can be detailed — but it should read like a runbook, not prose. Give Claude an explicit ordered procedure, tell it which script to run, and tell it where to find the output format. Below the diagram is the flow this body encodes.
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
flowchart TD
A["User shares ticket export"] --> B{"Description matches?"}
B -->|Yes| C["Load SKILL.md body"]
C --> D["Run parse_tickets.py on the file"]
D --> E["Read structured JSON output"]
E --> F["Open reference/summary-format.md"]
F --> G["Compose weekly digest"]
G --> H["Return summary to user"]
Here is a body that matches that flow. Each step is unambiguous, the heavy lifting is delegated to the script, and the formatting rules live in a linked file so the body stays short.
# Ticket Summary
When the user provides a ticket export:
1. Run `scripts/parse_tickets.py <file>` to normalize the export.
It outputs JSON with: total, by_category, sla_breaches, top_issues.
2. If the script errors, report the exact error and ask for a clean export.
Do not attempt to parse the raw file yourself.
3. Read `reference/summary-format.md` for the required section order.
4. Produce the summary using that format. Round percentages to whole numbers.
5. Always include the SLA-breach count even if it is zero.
Parsing a CSV, counting categories, and computing SLA breaches are deterministic operations. Letting the model do them by hand wastes context and invites arithmetic mistakes. A script does them reliably, and only its compact JSON output enters context. This is the single biggest quality lever in skill design: keep the model reasoning about what to do, and let code do what is mechanical.
import sys, json, csv
from collections import Counter
path = sys.argv[1]
rows = list(csv.DictReader(open(path)))
by_cat = Counter(r["category"] for r in rows)
breaches = sum(1 for r in rows if r["sla"] == "breached")
print(json.dumps({
"total": len(rows),
"by_category": dict(by_cat),
"sla_breaches": breaches,
"top_issues": [c for c, _ in by_cat.most_common(5)],
}))
The body told Claude to surface script errors rather than fall back to manual parsing — that instruction is what keeps a malformed file from silently producing a wrong summary. Be explicit about failure handling in the body; the script's job is to fail loudly, the body's job is to react sanely.
The reference file holds detail the body shouldn't carry: the exact section order, tone, and any boilerplate. Because it loads only when the body opens it, you can be as thorough as you like without paying for it on every invocation. Keep one concern per reference file so future skills can reuse it.
For our example, summary-format.md specifies the digest layout — headline volume number first, then top issues with counts, then SLA section, then a one-line trend note. Putting this in its own file also means a non-engineer can adjust the report format without touching the procedure or the script.
Two failure modes, two tests. First, test discovery: paste a realistic prompt ("here's last week's ticket export, can I get the digest") and confirm Claude loads the skill at all. If it doesn't, the description is the problem — sharpen it. Second, test execution: give it a real file and confirm the script runs, the output is read, and the format matches. If a step is skipped, the body wasn't explicit enough.
The fastest debugging tool is the transcript. Read what Claude actually did turn by turn. Did it call the script or try to eyeball the CSV? Did it open the reference file? Each deviation maps directly to a line you can tighten in the body. Iterate there rather than rewriting from scratch.
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
A useful habit is to keep a short set of fixture inputs — one clean export, one malformed, one empty — and run all three after every change to the skill. Discovery and execution can both regress quietly when you edit the description or reorder the procedure, and a thirty-second fixture run catches it before your teammates do. Once the skill is stable, those same fixtures become the regression suite that protects it as the underlying systems evolve.
SKILL.md, a scripts/ dir, and a reference/ dir.| Concern | Put it in | Why |
|---|---|---|
| When to fire | Frontmatter description | It's the discovery index |
| What to do | SKILL.md body | Loaded on selection |
| Mechanical work | scripts/ | Deterministic, off-context |
| Formatting detail | reference/ | Loaded only when needed |
As short as it can be while remaining an unambiguous procedure — often well under a page. Anything detailed or reusable belongs in a linked reference file, and anything mechanical belongs in a script.
No. Skills that are purely about judgment or formatting can be all instructions. Add a script the moment a step is deterministic, repetitive, or numeric — that's where scripts pay off.
Read it cold and ask: could I tell exactly when this should fire and what it takes in and gives back? If not, rewrite it to name the trigger, input, and output explicitly.
Read the transcript. Every place Claude skipped a step or improvised maps to a line in the body you can make more explicit. Iterate there rather than starting over.
The same build-test-iterate loop powers CallSphere's voice and chat agents — skills that load mid-conversation, call tools while the caller waits, and complete real bookings without a human. Try it at callsphere.ai.
Source & attribution: This is an independent, original explainer inspired by Anthropic's coverage on the Claude blog. Claude, Claude Code, Claude Cowork, Claude Opus, and the Model Context Protocol are products and trademarks of Anthropic. CallSphere is not affiliated with or endorsed by Anthropic.

Written by
Sagar Shankaran· Founder, CallSphere
LinkedInSagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
Anthropic's Claude Fable 5 and Mythos 5 explained: pricing, availability, frontier benchmarks, the dual-model safeguard architecture, and what they mean for AI agents.
Where Claude Code, MCP, and multi-agent systems are taking GTM engineering next, and how to prepare your team now for standing and multi-agent workflows.
Where Claude Cowork and the Claude agent ecosystem are heading next — standing agents, MCP, skills as a moat — and the concrete moves to prepare your team now.
The metrics, leading signals, and anti-metrics that prove Claude Cowork is working — acceptance rate, time-to-outcome, and why usage counts mislead.
Shipping an agentic GTM workflow is easy; proving it works is hard. The metrics, signals, and eval loops that show a Claude Code rebuild is paying off.
A realistic end-to-end Claude Cowork use case: a quarterly vendor-spend review from vague ask to shipped deliverable, with every agentic step shown.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco
Watch how CallSphere handles real customer calls, schedules appointments, and processes payments — live.
Try Live DemoBook a DemoCalculate Your ROI