Building Skills and Agents — Reference Guide
This is the reference for building new skills and agents in this project. Read this before creating any SKILL.md or agent definition.
When to Use What
| Need | Use | Why |
|---|---|---|
| Always-true project rules | rules/ file | Auto-loaded every session |
| Reference material for specific areas | context/ file | Loaded on-demand, saves tokens |
| Repeatable workflow triggered by user | Skill (/name) | Loaded only when invoked |
| Repeatable workflow triggered by Claude | Skill (auto-triggered) | Description-matched |
| Isolated multi-step task | Agent (subagent) | Own context window, clean separation |
| Heavy research or file reading | Agent | Keeps main context clean |
| Parallel independent work | Multiple agents | Run simultaneously |
| Persistent knowledge across sessions | Agent with memory: project | Maintains MEMORY.md |
Rule of thumb: If it's a workflow Carson triggers → skill. If it's a task Claude delegates → agent. If it's always relevant → rule. If it's sometimes relevant reference material → context file.
Skill Format (SKILL.md)
Directory Structure
.claude/skills/{skill-name}/
├── SKILL.md ← Required. Frontmatter + instructions.
├── templates/ ← Optional. Template files the skill copies/fills.
├── schemas/ ← Optional. JSON schemas for structured output.
└── reference/ ← Optional. Reference docs the skill reads.
Frontmatter Fields
---
name: skill-name # Lowercase, hyphens only. Max 64 chars.
description: >- # What it does + when to trigger. Max 1024 chars.
One-line description Claude uses to decide whether to auto-invoke.
Write in third person. Be "pushy" — undertriggering is more common.
user_invocable: true # true = appears in /menu. false = Claude-only.
argument: "required arg" # Hint shown during autocomplete.
# argument-hint: "[optional args]" # Alternative field name (both work).
disable-model-invocation: true # true = ONLY manual /invoke, never auto-triggered.
allowed-tools: Read, Grep, Bash # Tool allowlist. Omit = all tools available.
model: opus # sonnet | opus | haiku. Omit = inherit.
effort: high # low | medium | high | max. Opus 4.6 only.
context: fork # fork = isolated subagent. Omit = inline (sees conversation).
agent: general-purpose # Subagent type when context: fork. Can be custom agent name.
paths: "src/api/**" # Glob patterns — auto-activate when working on matching files.
---
Variable Substitutions (available in skill body)
| Variable | Description |
|---|---|
$ARGUMENTS | All arguments passed when invoking |
$0, $1, $2 | Positional arguments (0-indexed) |
${CLAUDE_SKILL_DIR} | Absolute path to this skill's directory |
!`command` | Shell command output injected at load time (preprocessing) |
Skill Body Structure
The markdown body below the frontmatter IS the prompt. Structure it as clear instructions:
---
(frontmatter)
---
## Context
What this skill does and why.
## Inputs
What $ARGUMENTS contains and how to parse it.
## Steps
1. Step one...
2. Step two...
## Output
What to display/save when done.
Key Behaviors
- Progressive loading: Only name + description (~100 tokens) loaded at startup. Full content loaded when invoked.
- Description budget: All skill descriptions share 1% of context window. Keep descriptions under 250 chars.
- "ultrathink": Include this word anywhere in skill content to enable extended thinking.
- Chaining: Skills can instruct Claude to invoke other skills (e.g., "Next, run
/draft-email"). Claude decides whether to follow through. - No nesting: Subagents spawned by skills CANNOT spawn their own subagents.
Agent Format (.claude/agents/)
File Location
.claude/agents/{agent-name}.md
Single markdown file. No subdirectory needed (unlike skills).
Frontmatter Fields
---
name: agent-name # REQUIRED. Lowercase, hyphens.
description: >- # REQUIRED. When to delegate to this agent.
Describe what this agent does. Include "use proactively" for eager delegation.
tools: Read, Glob, Grep, Bash # Tool allowlist. Omit = all tools.
disallowedTools: Write, Edit # Tool denylist (applied before allowlist).
model: sonnet # sonnet | opus | haiku | inherit.
maxTurns: 20 # Max agentic turns before stop.
memory: project # user | project | local. Persistent MEMORY.md.
skills: # Skills injected at startup (by name).
- api-conventions
isolation: worktree # Run in temp git worktree (isolated repo copy).
background: false # true = always run as background task.
effort: high # low | medium | high | max.
permissionMode: default # default | acceptEdits | dontAsk | bypassPermissions.
hooks: # Lifecycle hooks scoped to this agent.
PreToolUse:
- matcher: "Bash"
hooks:
- type: command
command: "./scripts/validate.sh"
---
The markdown body IS the agent's system prompt.
The agent sees ONLY this + environment details.
It does NOT see the main conversation history.
Key Behaviors
- Auto-delegation: Claude reads
descriptionand delegates matching tasks automatically. - Explicit invocation: User says "use the {name} agent" or @-mentions it.
- Session-wide:
claude --agent {name}makes every interaction use this agent. - No nesting: Agents CANNOT spawn other subagents. Only the main thread can use the Agent tool.
- Memory:
memory: projectcreates.claude/agent-memory/{name}/MEMORY.mdthat persists across conversations. Useful for agents that build knowledge over time. - Isolation:
isolation: worktreegives the agent an isolated copy of the repo. Auto-cleaned if no changes made.
This Project's Patterns
When building skills/agents for Rut'n Buck, follow these established patterns:
Supabase Access (inline Node.js via Bash)
Every skill that touches the database uses this boilerplate:
node -e "
const fs = require('fs');
const env = fs.readFileSync('.env','utf8');
env.split('\\n').forEach(l => {
const [k,...v] = l.split('=');
if (k && v.length) process.env[k.trim()] = v.join('=').trim();
});
const { createClient } = require('@supabase/supabase-js');
const sb = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_SERVICE_ROLE_KEY);
// ... your query here
"
This runs server-side with the service role key (bypasses RLS). Used for reads and writes.
Helper Scripts (stdin + CLI flags)
Reusable Node.js scripts live in /scripts/:
save-research.js—--find "Name"or--update <uuid>, reads JSON from stdin via heredocgoogle-places.js— positional args:"Business Name" "Bozeman, MT"
When building new skills that save data, consider adding a helper script rather than inline Node.js if the save logic will be reused.
Parallel Agents
For research-heavy skills, spawn 2-3 agents simultaneously with different focuses:
Launch 3 Agent tool calls in parallel:
- Agent 1: Reviews & Location (WebSearch + WebFetch)
- Agent 2: Website & Menu (WebFetch the site)
- Agent 3: Social & Digital (WebSearch for social profiles)
Each agent gets specific instructions and the Google Places data as shared context.
Interactive Save Pattern
Skills that generate content (emails, analyses) should:
- Display the output formatted in the terminal
- Ask Carson which option to save (or whether to save at all)
- Only then write to Supabase
State Machine
Use a status column (e.g., research_status) to track progress:
not_started → running → done / failed
Skills should check status before proceeding and update it on completion.
Output Format
All skills display a formatted markdown summary in the terminal. Data is saved to Supabase, not local files. The terminal output is for Carson to review — the database is the source of truth.
Composability
Skills can reuse other skills' steps. Example: /refresh-research delegates to /research-lead Steps 2-4 rather than duplicating the logic.
After Creating a New Skill or Agent
- Update CLAUDE.md — Add the skill/agent to the appropriate list with a one-line description
- Update this file — If the new skill introduces a pattern worth replicating, add it to "This Project's Patterns"
- Update
context/site-map.md— Add the new files - Test it — Invoke the skill/agent with a real example before considering it done
Common Mistakes to Avoid
- Vague descriptions — Claude won't auto-trigger if the description is generic. Be specific about WHEN to use it.
- Too many tools — Restrict tools to what's needed. Read-only agents shouldn't have Write/Edit.
- Forked context without enough info —
context: forkagents don't see conversation history. Include everything they need in the skill body. - Giant SKILL.md — Keep under 500 lines. Move reference material to separate files in the skill directory and read them with
${CLAUDE_SKILL_DIR}. - Duplicating Supabase boilerplate — If you're writing the same inline Node.js pattern, consider a helper script.
- Forgetting to update context system — New skills/agents should be reflected in CLAUDE.md and relevant context files.