Skip to main content
A skill.spec.yml is a structured behavioral contract that lives next to your SKILL.md. It doesn’t replace prose — it structures the load-bearing decisions that prose alone can’t make inspectable. Where SKILL.md carries tone, context, and domain judgment, skill.spec.yml captures the parts that can be tested, checked, compiled, and traced: which route to take, what to forbid, which dependencies must exist, when to ask a clarifying question, and what a successful run must prove. The tagline is intentionally narrow: keep the prose, structure the decisions.

Anatomy of a contract

Every skill.spec.yml starts with a header block (schema, id, title, description) and then declares optional sections. Here is a representative contract based on the browser-research example:

Key sections

Routes are the candidate execution paths your skill knows about. Each route has a stable id, a human label, and an optional rank — lower rank means earlier default preference when no rule has made a selection.Routes can also carry a tool_boundary that restricts which tools the agent may call while executing that path, and checks — a list of command ids that must pass before the route is considered live.
Rules are the conditional steering layer. Each rule has an optional when predicate and a set of additive effects: prefer sets the selected route, route_order replaces the current ordering, forbid unions forbidden substitutions, elicit appends clarifying questions, and after_success schedules post-task closures.Rules are evaluated in file order. The effects compose additively — every matched rule contributes to the same running decision state.
Elicitations are bounded questions. Instead of guessing or asking open-ended questions, the skill declares a specific choice point with typed options. Each choice can set named facts, steer to a specific route, or advance to a named state.Elicitations do not execute commands by themselves — they surface a decision for the human or agent to make.
Dependencies declare every tool, file, environment variable, service, adapter, or browser capability that commands and routes need. They don’t grant permission to install or run anything — they give the harness a concrete preflight checklist.The CLI can check cli, file, and env dependencies directly. package, service, adapter, and browser dependencies are harness-specific and appear in reports as requiring harness checks.
The trace section declares which decision events the evaluator should persist. Setting required: true means a conforming harness must either write the trace or state that tracing is unavailable before relying on the decision.When record is empty or absent, an evaluator may record every v0 event kind.
Tests are scenario-based expectations — the primary proof mechanism for route decisions. Each test pairs a plain-text input with expectations over the decision: route selected, matched rules, forbidden substitutions, requested elicitations, and scheduled closures.Expectations use three forms: plain list (assert inclusion), *_exact (assert the exact set), and not_* (assert absence).
The proof section names the metrics the contract is trying to improve — steering accuracy, forbidden-substitution coverage, captured-artifact completeness, and similar measures. These become the targets for alignment reports.

What the CLI validates

Running skillspec validate skill.spec.yml performs a set of structural and cross-reference checks without invoking a model:
  • Every Rule.prefer references an existing Route.id
  • Every Rule.elicit item references an existing elicitation
  • Every Test.expect.route references an existing route
  • Every Trace.record item is one of the v0 trace event kinds
  • Every Command.requires.dependencies item references an existing dependency
  • The import dependency graph is acyclic (checked with skillspec imports check)
  • No declared resource is orphaned — every resource without incoming references must declare used_by
  • Unknown fields are rejected (the schema is strict and fail-closed)
The full adoption gate before relying on a contract looks like this:
Typed v0 objects are strict: unknown fields are invalid, so a misspelled behavior field silently disappearing is a validation error, not a silent no-op.

Relation to SKILL.md

The contract doesn’t replace the prose in SKILL.md. It structures the load-bearing decisions that prose alone hides inside paragraphs. A skill with a valid contract still loads its SKILL.md prose at activation. The contract makes the critical decisions inspectable alongside that prose — not instead of it.
A good contract captures the behavioral load-bearing parts: the choices that could go wrong silently if a model improvises. Straightforward prose explanations can stay in prose.