Course Content
Files & Resources
Ship executable code and reference docs alongside SKILL.md, and design scripts that agents can run non-interactively
Beyond a Single Markdown File
The dice-roller from the hands-on lesson needed nothing but instructions, and the anatomy lesson introduced scripts/, references/, and assets/ conceptually. This lesson is where you actually use them. Most real skills need more: a script that does something a shell one-liner can’t, a reference doc too long to keep in the main body, a template the agent fills in. That’s what scripts/, references/, and assets/ are for — and all three are loaded on demand, not up front, which is what keeps a large skill from costing more than a small one until it’s actually used.
One-Off Commands vs. Bundled Scripts
When an existing package already does what you need, reference it directly in SKILL.md without a scripts/ directory at all. Several ecosystems provide tools that resolve dependencies automatically at runtime:
| Tool | Ecosystem | Notes |
|---|---|---|
uvx | Python | Isolated environments, aggressive caching, ships with uv |
pipx | Python | Not bundled — needs separate install |
npx / bunx | JavaScript | Runs a package without a local install |
deno run | JavaScript/TS | Sandboxed by default |
go run | Go | Compiles and runs in one step |
uvx ruff@0.8.0 check .
uvx black@24.10.0 .Two habits make one-off commands reliable inside a skill:
- Pin versions (
npx eslint@9.0.0, not barenpx eslint) so the command behaves the same a year from now as it does today. - State prerequisites in the instructions (“Requires Node.js 18+”) rather than assuming the agent’s environment has them — or use the
compatibilityfrontmatter field for runtime-level requirements.
Move to a bundled script once a command grows complex enough that it’s hard to get right on the first try — several chained flags, conditional logic, or anything you’d want tested once rather than re-derived by the agent every time.
Referencing Bundled Files
Paths in SKILL.md are relative to the skill directory root — the agent resolves them automatically, no absolute paths needed. List available scripts explicitly so the agent knows they exist before it needs them:
## Available scripts
- **`scripts/validate.sh`** — Validates configuration files
- **`scripts/process.py`** — Processes input dataThen instruct the agent to run them as part of a workflow:
## Workflow
1. Run the validation script:
\`\`\`bash
bash scripts/validate.sh "$INPUT_FILE"
\`\`\`
2. Process the results:
\`\`\`bash
python3 scripts/process.py --input results.json
\`\`\`The same relative-path convention applies inside references/*.md files, because the agent executes commands from the skill directory root regardless of which file the instruction came from.
Self-Contained Scripts
When you need reusable logic beyond a one-off command, bundle a script in scripts/ that declares its own dependencies inline — the agent runs it with a single command, no separate manifest or install step. Python, Deno, Bun, and Ruby all support some form of inline dependency declaration; Python’s is PEP 723, a TOML block inside # /// markers:
# /// script
# dependencies = [
# "beautifulsoup4",
# ]
# ///
from bs4 import BeautifulSoup
html = '<html><body><h1>Welcome</h1><p class="info">This is a test.</p></body></html>'
print(BeautifulSoup(html, "html.parser").select_one("p.info").get_text())Run it with uv:
uv run scripts/extract.pyuv run builds an isolated environment, installs the declared dependencies, and runs the script — pipx run scripts/extract.py also supports PEP 723 if you prefer that route. Pin dependency versions with PEP 508 specifiers ("beautifulsoup4>=4.12,<5"), constrain the Python version with requires-python, and use uv lock --script if you need a full lockfile for reproducibility.
Designing Scripts for Agentic Use
An agent reads a script’s stdout and stderr to decide what to do next — it isn’t a human watching a terminal. Three design choices make the difference between a script an agent can use reliably and one it gets stuck on.
Never prompt interactively. This is a hard constraint of the execution environment, not a style preference: agents run scripts in non-interactive shells and cannot respond to a TTY prompt, a password dialog, or a confirmation menu. A script that blocks waiting for input hangs indefinitely, and the agent has no way to unblock it.
# Bad — hangs waiting for input
$ python scripts/deploy.py
Target environment: _
# Good — fails clearly and tells the agent what to provide
$ python scripts/deploy.py
Error: --env is required. Options: development, staging, production.
Usage: python scripts/deploy.py --env staging --tag v1.2.3Accept all input through command-line flags, environment variables, or stdin — never through an interactive prompt.
Document usage with --help. This output is the primary way an agent learns your script’s interface, so treat it as documentation, not an afterthought:
Usage: scripts/process.py [OPTIONS] INPUT_FILE
Process input data and produce a summary report.
Options:
--format FORMAT Output format: json, csv, table (default: json)
--output FILE Write output to FILE instead of stdout
--verbose Print progress to stderr
Examples:
scripts/process.py data.csv
scripts/process.py --format csv --output report.csv data.csvKeep it concise — this text enters the agent’s context window alongside everything else it’s tracking, so a --help output the length of a manual defeats its own purpose.
Write error messages the agent can act on. An error directly shapes what the agent tries next, so “invalid input” tells it nothing useful, while an error naming the exact problem and the expected format lets it self-correct without another round trip to you.
Choosing What Goes in references/
references/ holds documentation the agent reads only when a specific condition is met — not on every run. Good candidates: a detailed technical reference too long for the main body, a form or data-format template, domain-specific notes split by topic (finance.md, legal.md).
Keep individual files focused. A single 2,000-line REFERENCE.md defeats progressive disclosure just as surely as cramming everything into SKILL.md — the agent still has to load the whole thing once any part of it is relevant. Several smaller, topic-scoped files let the agent load only the slice it actually needs.
Choosing What Goes in assets/
assets/ holds static resources the agent uses as-is rather than reads for instructions: document or config templates, diagrams, lookup tables, schemas. The distinction from references/ is usage — references inform what the agent does; assets are material the agent’s output is built from or validated against.
Putting It Together: A Slightly Larger Skill
pdf-processing/
├── SKILL.md
├── scripts/
│ ├── extract_tables.py # self-contained, PEP 723 deps
│ └── merge.sh # one-off wrapper around a pinned CLI
├── references/
│ ├── form-fields.md # loaded only when the task involves form filling
│ └── ocr-fallback.md # loaded only when a PDF has no text layer
└── assets/
└── invoice-template.jsonIn SKILL.md, each reference gets an explicit load condition, per the progressive loading model from two lessons back:
If the PDF has no extractable text layer, read `references/ocr-fallback.md`
before proceeding — do not attempt OCR without it.That one sentence is what makes the whole structure work: without a stated trigger condition, the agent has no way to know a reference file is relevant, and either loads it needlessly or never finds it at all.
Summary
- Use a one-off, version-pinned command when an existing tool already does the job; move to a bundled script once the command gets complex
- Self-contained scripts with inline dependency declarations (PEP 723 for Python) run with a single command and need no separate install step
- Scripts for agentic use must never prompt interactively, should document their interface via
--help, and should fail with specific, actionable error messages references/holds documentation loaded on demand — keep files small and topic-scoped, and always state the condition under which the agent should read oneassets/holds static resources the agent’s output is built from, distinct from instructional reference material
You now know how to build a skill of any size. Next, you’ll learn to check that a skill actually works the way you intend — testing it by hand, and then with a small, repeatable set of prompts.
