Rewrite Unit 2 around a Claude Code workflow#108
Conversation
Base: variant A (Claude Code — install, activation debugging, build Space, iterate) From variant B: 'Inside the Box' (load/select/compose) + 'The Real SDK' (native SDK path) From variant D: skill-creator install/tour, the loop, description optimization Minimal prose edits — files moved into place for review.
| ```bash | ||
| /plugin marketplace add huggingface/skills | ||
| /plugin install gradio@huggingface/skills | ||
| ``` |
There was a problem hiding this comment.
Ran this as written and got Plugin "gradio" not found. The @ suffix needs the registered marketplace name (huggingface-skills), and the plugin is huggingface-gradio per marketplace.json. Also adding /reload-plugins — after install the slash menu is cached, so /huggingface-gradio returns "Unknown skill" until you reload (line 76 mentions this but a student hits the error before getting there).
Same name/suffix issue is in unit0/setup.mdx:45 and unit1/hands-on-find-install.mdx:40,89,137,175 (hugging-face-model-trainer → huggingface-llm-trainer, etc.) — flagging here rather than spamming those files since it's the same fix pattern.
| ```bash | |
| /plugin marketplace add huggingface/skills | |
| /plugin install gradio@huggingface/skills | |
| ``` | |
| ```bash | |
| /plugin marketplace add huggingface/skills | |
| /plugin install huggingface-gradio@huggingface-skills | |
| /reload-plugins | |
| ``` |
| /plugin install gradio@huggingface/skills | ||
| ``` | ||
|
|
||
| Use this when someone else maintains the skill and ships it as part of a plugin. Plugin skills are namespaced as `/plugin-name:skill-name`. For this repository, the plugin name is `huggingface-skills`, so a plugin-installed skill gets a namespaced command instead of a bare `/skill-name`. |
There was a problem hiding this comment.
Two small corrections: huggingface-skills is the marketplace name; the plugin here is huggingface-gradio. And the namespaced form is optional — current Claude Code accepts both bare /huggingface-gradio and /huggingface-gradio:huggingface-gradio.
| Use this when someone else maintains the skill and ships it as part of a plugin. Plugin skills are namespaced as `/plugin-name:skill-name`. For this repository, the plugin name is `huggingface-skills`, so a plugin-installed skill gets a namespaced command instead of a bare `/skill-name`. | |
| Use this when someone else maintains the skill and ships it as part of a plugin. Plugin skills can be invoked with the bare name (`/huggingface-gradio`) or the namespaced form (`/plugin-name:skill-name`) if you need to disambiguate. |
| /plugin install gradio@huggingface/skills | ||
| ``` | ||
|
|
||
| Use this when someone else maintains the skill and ships it as part of a plugin. Plugin skills are namespaced as `/plugin-name:skill-name`. For this repository, the plugin name is `huggingface-skills`, so a plugin-installed skill gets a namespaced command instead of a bare `/skill-name`. |
There was a problem hiding this comment.
When you run /plugin install, Claude Code prompts for a scope (Personal / Project shared / Project local) and the page doesn't say which to pick. Suggest adding right after this paragraph:
When prompted for a scope, pick Personal —
huggingface-gradiois a general-purpose skill you'll want everywhere. The starter'shf-brand/brutalistskills, by contrast, live in the project's.claude/skills/because they only make sense for that one app.
(One sentence is enough — a full scope breakdown would pull focus from the activation lesson.)
| 1. Say what the skill does | ||
| 2. Say when to use it in the language a user would actually type | ||
|
|
||
| ## Slash Commands vs Auto-Activation |
There was a problem hiding this comment.
Reading-order nit: this section introduces the two ways a skill enters a turn (auto vs explicit /), but the "How Activation Works" section above it has already dived into the mechanics of auto activation. Swapping them — this section first, then "How Activation Works" — gives the reader the "two routes in" model before drilling into one of them.
|
|
||
| - `disable-model-invocation: true` stops automatic activation and keeps the skill manual-only | ||
| - `user-invocable: false` hides it from the slash-command menu | ||
| - `paths:` limits activation to matching files or folders |
There was a problem hiding this comment.
Worth linking the full reference here — there are several more keys (allowed-tools, allowed-directories, etc.) and the docs will stay current as the set grows.
| - `paths:` limits activation to matching files or folders | |
| - `paths:` limits activation to matching files or folders | |
| See the [Claude Code skills reference](https://code.claude.com/docs/en/skills) for the full set of frontmatter fields. |
|
|
||
| ## Skills vs MCP | ||
|
|
||
| Skills are instructions. MCP servers are tools. A skill teaches Claude how to do something with the tools it already has; an MCP server gives Claude a new capability, like talking to Slack or querying a database. You will often use them together, but they solve different problems. |
There was a problem hiding this comment.
| Skills are instructions. MCP servers are tools. A skill teaches Claude how to do something with the tools it already has; an MCP server gives Claude a new capability, like talking to Slack or querying a database. You will often use them together, but they solve different problems. | |
| Skills are instructions; MCP servers provide tools. A skill tells Claude *how* to use what it already has. An MCP server gives Claude something new to use — a Slack client, a database connection, a browser. You'll often use them together: the `huggingface-gradio` skill tells Claude how to structure a Gradio app, and it needs no MCP server because writing Python files is a tool Claude already has. A skill for "post my model card to Slack" would need both — the skill for the *how*, a Slack MCP server for the *ability*. |
| Copy your Unit 1 skill into your personal Claude Code skills directory: | ||
|
|
||
| ```bash | ||
| mkdir -p ~/.claude/skills/dataset-publisher | ||
| cp path/to/your/dataset-publisher/SKILL.md ~/.claude/skills/dataset-publisher/ | ||
| ``` |
There was a problem hiding this comment.
Unit 1's hands-on-write-skill.mdx already ends with cp -r dataset-publisher/ ~/.claude/skills/dataset-publisher/, so for most students this is a no-op and the path/to/your/ placeholder is confusing. Suggest:
| Copy your Unit 1 skill into your personal Claude Code skills directory: | |
| ```bash | |
| mkdir -p ~/.claude/skills/dataset-publisher | |
| cp path/to/your/dataset-publisher/SKILL.md ~/.claude/skills/dataset-publisher/ | |
| ``` | |
| If you completed Unit 1, `dataset-publisher` is already in `~/.claude/skills/dataset-publisher/`. If you skipped Unit 1, grab the skill from [Hands-on: Write Your First Skill](../unit1/hands-on-write-skill) before continuing. |
| in a structured way. What's a good approach? | ||
| ``` | ||
|
|
||
| This exact prompt comes from the Unit 2 draft logs. |
There was a problem hiding this comment.
"This exact prompt comes from the Unit 2 draft logs" reads like a leftover authoring note.
| This exact prompt comes from the Unit 2 draft logs. |
| Rewrite it so it includes natural trigger language: | ||
|
|
||
| ```yaml | ||
| description: Create and publish datasets to the Hugging Face Hub. Use when | ||
| the user wants to share structured data, publish a dataset, upload examples | ||
| for training, create a dataset card, or share Q&A pairs with a team. | ||
| ``` | ||
|
|
||
| Save the file. Then start a fresh Claude Code session and ask the same prompt again. | ||
|
|
||
| If you installed the skill through a plugin instead of a plain directory copy, use: | ||
|
|
||
| ```text | ||
| /reload-plugins | ||
| ``` | ||
|
|
||
| to make Claude Code pick up the plugin change without restarting. |
There was a problem hiding this comment.
| Rewrite it so it includes natural trigger language: | |
| ```yaml | |
| description: Create and publish datasets to the Hugging Face Hub. Use when | |
| the user wants to share structured data, publish a dataset, upload examples | |
| for training, create a dataset card, or share Q&A pairs with a team. | |
| ``` | |
| Save the file. Then start a fresh Claude Code session and ask the same prompt again. | |
| If you installed the skill through a plugin instead of a plain directory copy, use: | |
| ```text | |
| /reload-plugins | |
| ``` | |
| to make Claude Code pick up the plugin change without restarting. | |
| Open `~/.claude/skills/dataset-publisher/SKILL.md` and rewrite the `description` so it includes natural trigger language: | |
| ```yaml | |
| description: Create and publish datasets to the Hugging Face Hub. Use when | |
| the user wants to share structured data, publish a dataset, upload examples | |
| for training, create a dataset card, or share Q&A pairs with a team. | |
| ``` | |
| Save, then ask the same prompt again — Claude Code re-reads skill descriptions each turn, so no restart needed. |
| The starter also includes `skills/brutalist/`. Swap it in: | ||
|
|
||
| ```bash | ||
| rm -rf .claude/skills/hf-brand | ||
| cp -r skills/brutalist .claude/skills/ | ||
| ``` | ||
|
|
||
| Then ask Claude to restyle `app.py` again. Same app, different personality: |
There was a problem hiding this comment.
Suggest dropping the rm -rf and keeping both style skills mounted — then the prompt names the one you want. Shows that multiple skills can coexist and that explicit prompting (or /brutalist) picks between them.
| The starter also includes `skills/brutalist/`. Swap it in: | |
| ```bash | |
| rm -rf .claude/skills/hf-brand | |
| cp -r skills/brutalist .claude/skills/ | |
| ``` | |
| Then ask Claude to restyle `app.py` again. Same app, different personality: | |
| The starter also includes `skills/brutalist/`. Add it alongside `hf-brand`: | |
| ```bash | |
| cp -r skills/brutalist .claude/skills/ | |
| ``` | |
| Then ask Claude to restyle `app.py` using the brutalist skill specifically. Same app, different personality: |
| For this course, the least fragile path is to copy the skill directly: | ||
|
|
||
| ```bash | ||
| git clone https://github.com/anthropics/skills ~/anthropic-skills | ||
| mkdir -p ~/.claude/skills | ||
| cp -R ~/anthropic-skills/skills/skill-creator ~/.claude/skills/ | ||
| ``` |
There was a problem hiding this comment.
The clone-and-copy works, but it's the one place in the unit that doesn't use the /plugin flow we just taught. skill-creator ships in the example-skills plugin from anthropics/skills, so we can dogfood the lesson:
| For this course, the least fragile path is to copy the skill directly: | |
| ```bash | |
| git clone https://github.com/anthropics/skills ~/anthropic-skills | |
| mkdir -p ~/.claude/skills | |
| cp -R ~/anthropic-skills/skills/skill-creator ~/.claude/skills/ | |
| ``` | |
| Install it via the Anthropic skills marketplace: | |
| ```bash | |
| /plugin marketplace add anthropics/skills | |
| /plugin install example-skills@anthropic-agent-skills | |
| /reload-plugins | |
| ``` | |
| > **Note:** `example-skills` bundles ~12 example skills, not just `skill-creator`. You'll see them in your `/` menu — that's expected. |
| @@ -0,0 +1,83 @@ | |||
| # Quiz: Using Skills with Claude Code | |||
There was a problem hiding this comment.
Suggest shifting the weight from exercise-recall toward concepts that transfer. Q1/2/10 are great as-is; a few others test specific function/file names from one starter (Q4/5/7) or CLI flags (Q9), and Q8's "correct" answer will change if the skill-creator page is retargeted. Draft below keeps the strongest originals (incl. select_skills for the inside-the-box exercise), generalizes Q3, and adds skill-vs-MCP, explicit-vs-auto, and where-should-a-project-skill-live. Answer key is heavy on B's — worth shuffling letters before publish.
Proposed quiz.mdx
# Quiz: Using Skills with Claude Code
Test your understanding of the ideas and workflows from Unit 2. Passing this quiz is part of the **Claude Code Specialization** track described in Unit 0.
The same questions are stored in `course/quiz/data/unit_2.json`.
## Questions
1. Where should a project-local skill live if you want it versioned with the repository?
A. `~/.claude/skills/<name>/SKILL.md`
B. `.claude/skills/<name>/SKILL.md`
C. `skills/<name>/README.md`
D. `.mcp/<name>/SKILL.md`
2. What is the main signal Claude uses to decide whether to auto-activate a skill?
A. The skill directory name
B. The longest heading inside `SKILL.md`
C. The `description` field in frontmatter
D. The file modification time
3. A skill's body is correct, but it never auto-activates on natural prompts. What's the most likely fix?
A. Move it from `.claude/skills/` to `~/.claude/skills/`
B. Rewrite the `description` to include the language a user would actually type
C. Add more headings to `SKILL.md`
D. Convert it to an MCP server
4. Why does an agent read skill *descriptions* before loading full skill *bodies*?
A. Descriptions are cached and bodies are not
B. Selecting on short descriptions is cheap; injecting full bodies costs context, so you only want the relevant ones
C. Claude Code requires two passes for every skill
D. Skill bodies cannot be read at runtime
5. What's the difference between a skill and an MCP server?
A. Skills run in the browser; MCP servers run locally
B. A skill tells Claude *how* to use tools it has; an MCP server gives Claude a *new* tool
C. Skills are YAML; MCP servers are JSON
D. There is no difference — they're interchangeable
6. When would you type `/skill-name` instead of relying on auto-activation?
A. Auto-activation only works for plugin skills
B. When you want that specific skill's workflow now, regardless of whether your prompt wording matches its description
C. Slash invocation is required the first time you use any skill
D. Auto-activation is deprecated
7. In the `agent/` starter, what is `select_skills(...)` responsible for?
A. Building the Gradio UI
B. Choosing which skill names are relevant to the current user message
C. Writing new skill files
D. Packaging plugin metadata
8. You're writing a style skill for one specific app. Where should it live?
A. In the project's `.claude/skills/` — it's specific to this codebase and you'll edit it as the app changes
B. Installed via `/plugin install` from a marketplace
C. In `~/.claude/skills/` so every project gets it
D. Inside `SKILL.md` in the repo root
9. What is `skill-creator` primarily for?
A. Converting MCP servers into skills
B. Scaffolding a new skill from scratch — directory, `SKILL.md`, and an eval loop to tune activation
C. Publishing Spaces to the Hub
D. Translating skills between agent runtimes
10. Why are small focused skills often better than one giant catch-all skill?
A. Claude Code ignores large skills entirely
B. Small skills are easier to trigger, debug, and keep behavior-specific
C. The Agent Skills specification forbids multi-section skills
D. Only small skills can contain scripts
<details>
<summary>Answer key</summary>
1. B
2. C
3. B
4. B
5. B
6. B
7. B
8. A
9. B
10. B
</details>
Proposed unit_2.json
[
{
"question": "Where should a project-local skill live if you want it versioned with the repository?",
"answer_a": "~/.claude/skills/<name>/SKILL.md",
"answer_b": ".claude/skills/<name>/SKILL.md",
"answer_c": "skills/<name>/README.md",
"answer_d": ".mcp/<name>/SKILL.md",
"correct_answer": "B"
},
{
"question": "What is the main signal Claude uses to decide whether to auto-activate a skill?",
"answer_a": "The skill directory name",
"answer_b": "The longest heading inside SKILL.md",
"answer_c": "The description field in frontmatter",
"answer_d": "The file modification time",
"correct_answer": "C"
},
{
"question": "A skill's body is correct, but it never auto-activates on natural prompts. What's the most likely fix?",
"answer_a": "Move it from .claude/skills/ to ~/.claude/skills/",
"answer_b": "Rewrite the description to include the language a user would actually type",
"answer_c": "Add more headings to SKILL.md",
"answer_d": "Convert it to an MCP server",
"correct_answer": "B"
},
{
"question": "Why does an agent read skill descriptions before loading full skill bodies?",
"answer_a": "Descriptions are cached and bodies are not",
"answer_b": "Selecting on short descriptions is cheap; injecting full bodies costs context, so you only want the relevant ones",
"answer_c": "Claude Code requires two passes for every skill",
"answer_d": "Skill bodies cannot be read at runtime",
"correct_answer": "B"
},
{
"question": "What's the difference between a skill and an MCP server?",
"answer_a": "Skills run in the browser; MCP servers run locally",
"answer_b": "A skill tells Claude how to use tools it has; an MCP server gives Claude a new tool",
"answer_c": "Skills are YAML; MCP servers are JSON",
"answer_d": "There is no difference",
"correct_answer": "B"
},
{
"question": "When would you type /skill-name instead of relying on auto-activation?",
"answer_a": "Auto-activation only works for plugin skills",
"answer_b": "When you want that specific skill's workflow now, regardless of whether your prompt wording matches its description",
"answer_c": "Slash invocation is required the first time you use any skill",
"answer_d": "Auto-activation is deprecated",
"correct_answer": "B"
},
{
"question": "In the agent/ starter, what is select_skills(...) responsible for?",
"answer_a": "Building the Gradio UI",
"answer_b": "Choosing which skill names are relevant to the current user message",
"answer_c": "Writing new skill files",
"answer_d": "Packaging plugin metadata",
"correct_answer": "B"
},
{
"question": "You're writing a style skill for one specific app. Where should it live?",
"answer_a": "In the project's .claude/skills/ — it's specific to this codebase and you'll edit it as the app changes",
"answer_b": "Installed via /plugin install from a marketplace",
"answer_c": "In ~/.claude/skills/ so every project gets it",
"answer_d": "Inside SKILL.md in the repo root",
"correct_answer": "A"
},
{
"question": "What is skill-creator primarily for?",
"answer_a": "Converting MCP servers into skills",
"answer_b": "Scaffolding a new skill from scratch, including directory, SKILL.md, and an eval loop to tune activation",
"answer_c": "Publishing Spaces to the Hub",
"answer_d": "Translating skills between agent runtimes",
"correct_answer": "B"
},
{
"question": "Why are small focused skills often better than one giant catch-all skill?",
"answer_a": "Claude Code ignores large skills entirely",
"answer_b": "Small skills are easier to trigger, debug, and keep behavior-specific",
"answer_c": "The Agent Skills specification forbids multi-section skills",
"answer_d": "Only small skills can contain scripts",
"correct_answer": "B"
}
]
| @@ -0,0 +1,85 @@ | |||
| # The `skill-creator` Skill | |||
There was a problem hiding this comment.
Bigger thought on this page: it currently re-tunes the dataset-publisher description that the student already fixed by hand on the previous page, so the before/after they see won't match what's on screen — and it shows skill-creator doing description-tuning rather than its primary job (scaffolding from scratch).
Proposal: have skill-creator build a personal-brand Gradio style skill (my-brand) instead. Student picks 3 adjectives + 2 colors, skill-creator scaffolds it into .claude/skills/, then they re-run the "restyle app.py" prompt with their own skill. It threads build-space → skill-creator → publish into one arc, and the published Space becomes a personal artifact for the certification.
Draft below
Proposed skill-creator.mdx
# The `skill-creator` Skill
You've used two style skills someone else wrote. Now build your own — not by hand, but with `skill-creator`, Anthropic's skill for authoring skills.
## Install It
`skill-creator` ships in the `example-skills` plugin from the Anthropic skills marketplace:
```bash
/plugin marketplace add anthropics/skills
/plugin install example-skills@anthropic-agent-skills
/reload-plugins
```
Run `/skill-creator` to confirm it's available.
<Tip>
`example-skills` bundles about a dozen example skills, not just `skill-creator`. You'll see them in your `/` menu — that's expected.
</Tip>
## What It Gives You
`skill-creator` is not just one markdown file. It is a small toolkit:
```text
skill-creator/
├── SKILL.md
├── scripts/
├── eval-viewer/
├── agents/
└── references/
```
That is progressive disclosure again: `SKILL.md` defines the workflow, `scripts/` runs evaluation and packaging steps, `eval-viewer/` renders results, and `agents/`/`references/` hold material Claude only needs at specific moments.
## Build a Personal Brand Skill
You've seen `hf-brand` and `brutalist`. Now make one that's yours.
Pick three adjectives and two colors. For example: *playful, minimal, confident* with primary `#0ea5e9` and accent `#f97316`. Then, in Claude Code inside `~/unit2-starter`:
```text
Use skill-creator to scaffold a Gradio style skill called `my-brand`.
Aesthetic: playful, minimal, confident. Primary #0ea5e9, accent #f97316.
Include guidance on typography, spacing, and copy tone.
Put it in .claude/skills/my-brand/.
```
`skill-creator` will draft `SKILL.md`, propose a description, and ask whether to run an activation-eval pass. Say yes once — you're after a clean first draft, not a perfect one.
## Try It
`my-brand` is already in `.claude/skills/` — `skill-creator` put it there alongside `hf-brand` and `brutalist`. Now ask for it by name:
```text
Restyle app.py using the my-brand skill.
```
Same scaffold. Your skill. Your outcome.

## Why This Matters
`skill-creator` is built for this: scaffolding a skill from scratch — directory, frontmatter, body, eval loop. You used it on a tiny aesthetic skill, but the same workflow scales to skills with helper scripts, templates, and references.
By this point you have seen all three layers:
1. **Use** a skill someone else wrote (`hf-brand`, `brutalist`)
2. **Debug** why a skill doesn't activate (`dataset-publisher`)
3. **Author** a skill from scratch with tooling (`my-brand`)
Now publish the Space — styled with the skill you built.
There was a problem hiding this comment.
If you take this direction, two cross-refs elsewhere would need a matching tweak:
hands-on-iterate.mdx:79 (closing line):
| # The `skill-creator` Skill | |
| Next, use `skill-creator` to scaffold a style skill of your own. |
introduction.mdx:13 (learning objective):
| # The `skill-creator` Skill | |
| - Use `skill-creator` to scaffold a new skill from scratch and run one activation-eval pass |
(Both are fine as-is if you keep the current dataset-publisher flow.)
| # Pass theme to Blocks(), not launch(): | ||
| with gr.Blocks(theme=theme) as demo: | ||
| ... | ||
| demo.launch() |
There was a problem hiding this comment.
Gradio 6.0 moved theme/css from gr.Blocks() to .launch() — so this guidance now produces a deprecation warning (UserWarning: parameters have been moved from the Blocks constructor to launch() in Gradio 6.0). App still runs, but since the heading says "Gradio 6.x" it's worth flipping. Same change at brutalist/SKILL.md:43-45.
| # Pass theme to Blocks(), not launch(): | |
| with gr.Blocks(theme=theme) as demo: | |
| ... | |
| demo.launch() | |
| # Pass theme to launch() (Gradio 6.x moved it from Blocks): | |
| with gr.Blocks() as demo: | |
| ... | |
| demo.launch(theme=theme) |
|
Ran the whole unit end-to-end as a student (fresh Claude Code, fresh starter dir) — line comments cover everything I hit. Most are small mechanical fixes ( Two bigger proposals are in the threads on One thing I couldn't verify from my side: the |
Summary
app.pyflow and add a runnableagent/mini-project for the load/select/compose exerciseskill-creator, and currenthfCLI publishingTesting
python3 -m compileall course/units/en/unit2/starter/app.py course/units/en/unit2/starter/agentpython3 -m json.tool course/quiz/data/unit_2.json >/dev/nullgit diff --check