fabro/docs/workflows/stylesheets.mdx
Bryan Helmkamp 21aff5431c Update docs, frontend, marketing, and skills for .fabro extension
Update 47 MDX doc pages, OpenAPI spec, SVG diagram, language
grammar, frontend demo data, marketing page, skills, and README
to use .fabro extension. Add "fabro" to fileTypes in language
grammars. Document stack.child_workflow alongside stack.child_dotfile.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 22:38:25 -04:00

135 lines
4.5 KiB
Text

---
title: "Model Stylesheets"
description: "Assign LLM models to workflow nodes using CSS-like rules"
---
Model stylesheets let you assign LLM models, providers, and settings to workflow nodes using a CSS-like syntax. Instead of hardcoding a model on every node, you write a set of rules that target nodes by ID, class, shape, or a universal wildcard — and Fabro applies them by specificity.
## Defining a stylesheet
Stylesheets are set in the `model_stylesheet` graph attribute:
```dot title="example.fabro"
digraph Example {
graph [
goal="Build and review a utility function",
model_stylesheet="
* { model: claude-haiku-4-5;}
.coding { model: claude-sonnet-4-5; reasoning_effort: high; }
#review { model: gemini-3.1-pro-preview;}
"
]
start [shape=Mdiamond, label="Start"]
exit [shape=Msquare, label="Exit"]
spec [label="Write Spec"]
implement [label="Implement", class="coding"]
test [label="Write Tests", class="coding"]
review [label="Code Review"]
start -> spec -> implement -> test -> review -> exit
}
```
In this example:
- **spec** gets Haiku (matches `*`)
- **implement** and **test** get Sonnet with high reasoning (match `.coding`)
- **review** gets Gemini Pro (matches `#review`)
## Selectors
Each rule starts with a selector that determines which nodes it applies to:
| Selector | Syntax | Matches | Specificity |
|---|---|---|---|
| Universal | `*` | All nodes | 0 |
| Shape | `box`, `tab`, `hexagon`, etc. | Nodes with that Graphviz shape | 1 |
| Class | `.classname` | Nodes with `class="classname"` | 2 |
| ID | `#nodeid` | The node with that specific ID | 3 |
### Assigning classes
Set the `class` attribute on a node to target it with class selectors. Multiple classes are space-separated:
```dot
implement [label="Implement", class="coding critical"]
```
This node matches both `.coding` and `.critical` rules.
## Properties
Stylesheets support four properties:
| Property | Description | Example |
|---|---|---|
| `model` | Model ID or alias | `claude-sonnet-4-5`, `opus`, `gemini-pro` |
| `provider` | Provider name (optional — auto-inferred from the model catalog when omitted) | `anthropic`, `openai`, `gemini` |
| `reasoning_effort` | Reasoning effort level | `low`, `medium`, `high` |
| `backend` | Agent execution backend — `api` (default) runs Fabro's own tool loop, `cli` delegates to an external CLI tool. See [Backends](/core-concepts/agents#backends). | `cli`, `api` |
See [Models](/core-concepts/models) for the full list of model IDs and aliases.
## Specificity and cascading
When multiple rules match the same node, the rule with the **highest specificity** wins. This follows the same principle as CSS:
```
* (0) < shape (1) < .class (2) < #id (3)
```
For example:
```
* { model: claude-haiku-4-5; }
.coding { model: claude-sonnet-4-5; }
#review { model: gpt-5.2; }
```
A node with `id="review"` and `class="coding"` gets `gpt-5.2` because `#id` (specificity 3) beats `.class` (specificity 2).
If two rules have the same specificity, the **last one** in the stylesheet wins.
## Explicit attributes override stylesheets
A model set directly on a node attribute always takes precedence over stylesheets, regardless of specificity:
```dot
implement [label="Implement", class="coding", model="claude-opus-4-6"]
```
Even if `.coding` sets `model: claude-sonnet-4-5`, this node uses Opus because the explicit attribute wins.
## Syntax reference
The stylesheet syntax is a simplified subset of CSS:
```
selector { property: value; property: value; }
```
- Selectors: `*`, `shape`, `.class`, `#id`
- Properties and values are separated by `:`
- Declarations are separated by `;`
- Whitespace is flexible — newlines and indentation are ignored
- CSS comments (`/* ... */`) are not supported
### Full example
```
* { model: claude-haiku-4-5;reasoning_effort: low; }
box { reasoning_effort: high; }
tab { reasoning_effort: low; }
.coding { model: claude-sonnet-4-5;reasoning_effort: high; }
.review { model: gemini-3.1-pro-preview;}
#final_check { model: claude-opus-4-6;reasoning_effort: high; }
```
This stylesheet:
- Defaults everything to Haiku with low reasoning
- Overrides all agent nodes (`box` shape) to high reasoning
- Keeps prompt nodes (`tab` shape) at low reasoning
- Routes `.coding` nodes to Sonnet
- Routes `.review` nodes to Gemini for independent critique
- Routes the `final_check` node to Opus for maximum quality