Skip to main content
Every SkillSpec contract contains a decision model — a deterministic fold over an ordered rule set that maps an input to a selected route, a forbidden set, a list of clarifying questions, and a set of post-task closures. The fold is evaluated without invoking a model: given rule order and a user input, the decision is reproducible and testable. This is intentionally boring. The goal is inspectable steering, not a hidden policy language.

Routes

Routes are the candidate ways to satisfy work. Each route has a stable machine id, a human label, and an optional rank. Lower rank means earlier default preference when no rule has explicitly selected a route.
Routes may also declare:
  • checks — a list of command ids that must pass before the route is used
  • tool_boundary — a phase-scoped permission contract (see Tool boundaries)
  • execution_plan — an ordered sequence of named phases, each with its own requires, forbid, and optional sub-tool_boundary
The route id is a stable API identifier. Human label and description can change without breaking tests and cross-references; the id must not churn.

Rules

Rules are the conditional steering layer. Each rule has an optional when predicate and a set of typed effects. Rules are evaluated in file order against the current input. When a rule matches, its effects are applied additively to the running decision state.
A rule without a when clause is unconditional — it matches every input. The reason field carries a human-readable rationale that is recorded in the trace and shown in alignment reports.

Predicate fields

The when predicate can combine any of these fields. Multiple fields compose with logical AND. Values inside user_says_any compose with logical OR. Phrase matching is case-insensitive and word-boundary–aware — "browse" matches "browse the page" but not "unobserved".

Rule effect algebra

Rules apply in file order. The algebra is additive for most fields, with two exceptions:
The key properties:
  • prefer sets the currently selected route — last matching prefer wins in file order.
  • route_order replaces the current ordering — a later rule can completely reorder.
  • forbid is a union — every matched rule adds its forbidden set; nothing removes from it.
  • elicit appends — all matched rules contribute their elicitation requests.
  • after_success appends — all closures from matched rules accumulate.
Two individually valid rule sets can compose to different decisions under different concatenation order. This order-sensitivity is a property to test, not to hide — scenario tests pin the composed outcome for a given input.
After all rules are evaluated, if no rule has set a route via prefer, the first route in the current route_order is selected. This is the default_route_order basis, which appears in the decision trace.

Elicitations

Elicitations are bounded questions. They are used when the skill should ask for a specific missing decision instead of guessing or asking open-ended questions. A rule requests an elicitation by adding its id to elicit. The elicitation itself lives in the elicitations mapping and defines the choices, an optional default, and an optional cap on how many choices may be selected.
Each choice may:
  • sets — write named facts into the decision context
  • route — steer to a specific route if selected
  • next — advance to a named state in the state machine
  • safety — classify the consequence of this choice (read_only, local_write, destructive, etc.)
Choices do not execute commands. They surface a decision. required_when describes when the elicitation is mandatory — for example, when the selected route matches a given id, or when a named fact is absent from the context.
When authoring YAML by hand, quote question strings that contain : . An unquoted question: What are we reviewing: a dependency list? parses as a broken mapping before SkillSpec validation runs.

Tool boundaries

Tool boundaries are phase-scoped permission contracts. They can appear at three levels, inherited from outer to inner:
A boundary does not enforce by itself — it gives the harness a concrete pre-tool-call checklist. Any action outside the rendered boundary requires explicit user permission before use.

Complete example

The following contract is drawn from the before-after example. It shows routes, a steering rule, an elicitation, and scenario tests that prove the composed decision:
Run the decision engine against these tests with:
And run it against a specific input to see the decision trace: