What We Are Building
This post explains what a Claude agent is, how it works, and how skills let you write agents that are tiny, flexible, and easy to change - using a real, runnable example from start to finish.
The example is a grading agent. By the end, you will have a working agent that:
- Reads a CSV of student marks
- Calculates a letter grade (A, B+, C−, etc.) and a GPA (4.0 scale) for each subject
- Computes each student’s overall grade
- Writes a graded CSV and a formatted markdown report
The entire agent is thirty lines of JavaScript. The grading rules, the output format, and the report layout all live in plain markdown files - not in the code. That separation is the core idea this post is built around.
Key Concepts (Before We Dive In)
What is a Claude agent? A Claude agent is a program that takes a plain-English instruction and carries it out - reading files, writing output, running calculations. Unlike a chatbot that just responds to messages, an agent actually does things. You give it a task; it figures out the steps.
What is the Claude Agent SDK? The Claude Agent SDK is a JavaScript/TypeScript library from Anthropic that makes it straightforward to build agents powered by Claude. It handles sending your prompt to Claude, letting Claude call tools (like reading or writing files), and streaming the result back to you. Install it with:
| |
What is a skill?
A skill is a folder you drop into .claude/skills/. Inside is a SKILL.md file written in plain markdown that tells the agent what the skill does and how to do it. The SDK finds skills automatically at startup and loads the right one based on the user’s prompt. You will see exactly how this works in the example below.
The Problem Skills Solve
Imagine writing a grading agent the naive way:
This works on day one. On day two the teacher says: “Can we move the A boundary to 95%?” Now you - a developer - have to edit a string buried in a source file, redeploy the service, and hope nothing else broke.
Skills fix this by moving the grading rules out of the code and into a plain markdown file. The teacher can edit the rules themselves. The agent code never changes.
Project Structure
Here is the full layout of grade-agent:
| |
That’s it. Five meaningful files. Let’s walk through each one.
Step 1 - The Input (sample-marks.csv)
The agent reads a simple CSV. Each row is a student. Each column (after name) is a subject mark out of the configured maximum (default 100).
Nothing special here - this is a plain CSV a teacher could export from any spreadsheet.
Step 2 - The Skill (SKILL.md)
This is where all the actual grading knowledge lives. The file has two parts.
Part A: The Front Matter
The front matter sits at the very top between --- lines. The SDK reads only this part during startup to know what the skill does:
The description is how the SDK matches your prompt to the right skill. When you ask Claude to “grade the marks”, it reads this description and says: “Yes, grade-csv matches.”
Beginner tip: Write your description to cover the different ways a user might phrase the same request. The line “even if they don’t say ‘GPA’ explicitly” is important - it catches natural language like “grade my class” that doesn’t use technical terms.
Part B: The Body
Below the front matter is the body - plain markdown. Claude reads this when the skill is active and follows it like a recipe:
| |
This is the entire grading policy. No Python, no JSON. A teacher can open this file in any text editor and understand it immediately. If the school changes its grading scale next year, someone edits one row in the table. The agent code stays the same.
Step 3 - The Templates
Templates define the shape of the output - separate from the rules that compute it.
graded.template.md - describes the columns the output CSV must have:
| |
So for a CSV with math, science, and english subjects, the output gets columns:
name, math_letter, math_gpa, science_letter, science_gpa, english_letter, english_gpa, average, overall_letter, overall_gpa
report.template.md - the markdown report skeleton with placeholders:
Claude reads both templates before writing any output, then fills in every placeholder with the computed values.
Why separate templates? Keeping layout in templates means you can change the report design without touching the grading rules - and vice versa. They are independent concerns in separate files.
Step 4 - The Agent (index.js)
Here is the complete agent, with every line explained:
| |
What is missing from this file? Every single grading rule. The agent does not know what an A− is. It does not know that GPAs exist. It does not know what columns the output CSV should have. All of that lives in SKILL.md and the templates.
This is intentional. The agent is just plumbing. The skill is the product.
Step 5 - How It All Fits Together
Here is exactly what happens from the moment you run npm run grade:
| |
Nothing in this chain requires you to have written any grading logic in JavaScript.
Step 6 - The Output
After running the agent against the sample CSV, you get:
data/output/graded.csv:
data/output/report.md (rendered):
All of this was produced by thirty lines of JavaScript and a markdown file.
Running It Yourself
You need Node 18+, Git, and an Anthropic API key.
You will see Claude’s summary appear in the terminal, and find graded.csv and report.md in data/output/.
Use your own CSV:
Try These Experiments
These hands-on experiments are the best way to feel how skills work.
Experiment 1 - Change a grading rule without touching code:
Open .claude/skills/grade-csv/SKILL.md. Find the row for 93–100 → A and change it to 95–100 → A. Add a row for 93–94 → A-. Run the agent again. Carol’s overall grade will change - same JavaScript, different behaviour, because only the skill changed.
Experiment 2 - Add a column to the report without touching code:
Open templates/report.template.md and add a {{highest_score}} placeholder. Then add a sentence to the workflow in SKILL.md saying “find the student with the highest average and insert their name at {{highest_score}}”. Run the agent. The new column appears automatically.
Experiment 3 - Add a brand-new skill:
Create this file: .claude/skills/summarize-feedback/SKILL.md
| |
Now run: node src/index.js --input ./feedback.csv
The agent routes to the new skill automatically. You did not change index.js at all.
Conclusion
Claude agents are not complicated once you see a full example. The agent itself is just plumbing - a prompt and a query() call. The skill is where all the domain knowledge lives: the rules, the workflow, the output format.
The one thing to get right is your skill description. Write it to cover the natural ways a user might phrase the task, not just the technical term. Everything else follows from that.
Once you have the pattern down, adding a new capability is just dropping a folder. That is what makes Claude agents worth learning.
