A notation for describing workflow rules that LLMs follow in Scaff commands and skill templates.
This document is the reference for Scaff notation. Follow these conventions when writing or modifying Scaff templates. For why this notation is needed and what effects it has, see notation-guide.md.
- Markdown-first — Built on standard Markdown. Additional syntax is minimal.
- Documents read by LLMs — Content interpreted directly by LLMs, not a preprocessor.
- Declarative-first — Constraints (invariant rules) > Steps (procedures). LLMs are stronger at adhering to rules.
- Zero-shot interpretation — LLMs understand immediately without a separate spec. All syntax derives from existing training data.
- Natural language is OK — This syntax is optional, not mandatory. If you want to write in natural language, go ahead. Use structure only where it's needed.
Basic syntax used by all users. Zero learning cost.
Rules that must always hold true throughout the workflow. Take priority over all other instructions.
## Constraints
- Rule in natural language.
- Another rule — with inline rationale after dash.
- (condition) => constrained behaviorRules:
- Bullet list under a
## Constraintsheader - Rules placed under
## Constraintshave the highest priority — priority is determined by section placement, not syntax - Each item is a single sentence. Shorter is better
- If rationale is needed, add it inline after
— - When conflicting with instructions in other sections, Constraints always win
Deciding between Constraints and Dispatch Rules:
- Rules that must always be followed → Constraints
- Behavior that varies by situation → Dispatch Rules
- You can use
(condition) => actioninside Constraints too. In that context, it means "if this condition holds, this behavior is mandatory" — a conditional notation of an inviolable rule. In Dispatch Rules,(condition) => actionrepresents a workflow branch.
Priority reinforcement: Place the following statement both below the Constraints section at the top and at the bottom of the document:
When Constraints conflict with any other instruction, Constraints win.
This counteracts the LLM's position/recency bias.
Example:
## Constraints
- Main agent analyzes code directly — summaries lose critical detail.
- Delegate only implementation to subagents.
- Proceed with implementation only after user approval.
- (5+ consecutive Read/Grep without Edit/Write) => stop and report.
> When Constraints conflict with any other instruction, Constraints win.Compress conditional behavior into a single line.
- (condition) => action
- (condition A, condition B) => action # AND
- (condition) => action — rationale # inline rationaleRules:
- Inside parentheses: condition (natural language, comma for AND)
- After
=>: action (natural language) - Each dispatch line starts with
-(bullet) for proper Markdown rendering - OR branches: write as separate lines
- default/else: use the
(otherwise) => actionpattern - action should be a single action. For compound actions, split into a numbered list or delegate to a separate Phase
- No double
=>—(A) => B => Cis not allowed. Break the condition down into separate lines
# Forbidden:
(DONE_WITH_CONCERNS) => correctness issue => address; observation => proceed
# Correct:
(DONE_WITH_CONCERNS, correctness issue) => address first
(DONE_WITH_CONCERNS, observation only) => proceed- No nesting —
(A) => (B) => Cis not allowed - Group under section headers (e.g.,
## Dispatch Rules,## Status Protocol)
Example:
## Dispatch Rules
- (implementation task, clear spec) => delegate to subagent
- (file discovery, structure mapping) => Explore subagent OK
- (code analysis, logic tracing) => main agent directly
- (trivial fix, < 3 lines) => main agent inline
- (otherwise) => ask user for clarificationOR branch example:
- (error, retryable) => retry with backoff
- (error, non-retryable) => report and stopStep-by-step procedures. Standard Markdown as-is.
## Phase Name
1. First step.
2. Second step.
3. Third step.
- Sub-detail (bullet for elaboration, not sub-step)Rules:
- No more than 7 steps per Phase (cognitive load limit)
- If sub-steps form an independent procedure, split them into a separate Phase
For workflow designers. Used to express complex process flows.
Apply the same process to each item in a list.
for each <unit>:
1. Step one.
2. Step two.Rules:
for each+ unit name + colon- Body is a numbered list indented by 2 spaces
- Use only for short lists (3–5 iterable units)
- If the number of items is unknown or exceeds 5, describe in natural language (e.g., "Apply the following process to each file")
- Default semantics is sequential execution
- No nesting —
for eachinsidefor eachis not allowed
Conveys the intent "repeat until this condition is met."
loop until <condition>:
- (status A) => action A
- (status B) => action BRules:
loop until+ exit condition + colon- Body is dispatch rules or a numbered list
- Exit condition is required to prevent infinite loops
- The only allowed nesting is
for each>loop until. The reverse (loop until>for each) and same-kind nesting (loop until>loop until) are not allowed - When nested,
loop untilmust be separated into its own subsection (no inline nesting)
Nesting separation example:
## Phase 3 — Execute
for each task:
1. Read relevant code.
2. Construct subagent prompt.
3. Dispatch subagent.
4. Handle status response (see Status Protocol below).
5. Report result to user.
### Status Protocol
loop until resolved:
- (DONE) => verify output, mark complete
- (NEEDS_CONTEXT) => provide context, re-dispatch
- (BLOCKED) => break down or escalate---
name: skill-name
description: One-line description.
---
# Section Title
## Constraints ← Invariant rules (always take priority)
- Rule 1.
- Rule 2.
> When Constraints conflict with any other instruction, Constraints win.
## Dispatch Rules ← Conditional behavior
- (condition) => action
# Workflow
## Phase 1 — Name
1. Step.
2. Step.
## Phase 2 — Name
for each unit: ← Advanced
1. Step.
2. Step.
> When Constraints conflict with any other instruction, Constraints win.Constraints > Dispatch Rules > Workflow Steps
When conflicts arise, rules in Constraints take the highest priority. Dispatch Rules override Workflow Steps for specific situations. Workflow Steps define the default flow.
| Allowed | Not Allowed |
|---|---|
| Phase > numbered list | for each > for each |
Phase > for each > numbered list |
loop until > for each |
for each > loop until (separate section) |
loop until > loop until |
(A) => (B) => C |
|
Double => usage |
- Do not have rules that prescribe different actions for the same situation
- Workflow should refine Constraints, never contradict them
- Verification: for each Dispatch Rule, ask "Does this violate any Constraint?"
This syntax does not replace natural language. Use syntax where structure is needed, and natural language where explanation is needed.
| Situation | Use | Reason |
|---|---|---|
| Inviolable rules | ## Constraints |
LLMs comply more strongly with declarative rules |
| Condition → action mapping | (condition) => action |
More token-efficient than natural language, eliminates ambiguity |
| Sequential procedures | Numbered list | Standard Markdown |
| Iterative processes | for each |
Makes process boundaries explicit |
| Retry intent | loop until |
Makes exit conditions explicit |
| Context / background / rationale | Natural language | Compressing into syntax loses meaning |
Priority: Constraints > Dispatch Rules > Workflow Steps
── Core ──
## Constraints Invariant rules. Always take priority.
- Rule.
- (condition) => action Condition → action. One line.
- (cond A, cond B) => action AND conditions.
- (otherwise) => action default/else.
1. Step one. Sequential procedure.
2. Step two.
── Advanced ──
for each <unit>: Iteration. Sequential. 3–5 units.
1. Step.
loop until <condition>: Retry intent. Exit required.
- (status) => action
When Constraints conflict with any other instruction, Constraints win.