mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-05 08:10:39 +00:00
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>
135 lines
4.5 KiB
Text
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
|