mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-07 08:27:12 +00:00
Invert the docs convention so the Mintlify-published site lives under docs/public/ and internal artifacts (strategy docs, brainstorms, plans, etc.) sit at docs/ root or docs/internal/. Tools that default to writing into docs/ now land in the catch-all instead of leaking into the published tree. - Move Mintlify content (administration/, agents/, api-reference/, changelog/, core-concepts/, examples/, execution/, getting-started/, human-tools/, integrations/, languages/, reference/, tutorials/, workflows/, images/, logo/, docs.json, favicon.svg, dot-highlight.js) into docs/public/. - Collapse docs-internal/ into docs/internal/. - Update Rust path references (fabro-api/build.rs, fabro-server, fabro-dev), TypeScript generator arg, CI path filters, clippy.toml reasons, AGENTS.md/CLAUDE.md, and README.md image refs. Mintlify dashboard project root must be updated to docs/public/ in a follow-up. .mintignore move/trim and .claude/skills/ updates land in a separate commit.
103 lines
3.1 KiB
Text
103 lines
3.1 KiB
Text
---
|
|
title: "Variables"
|
|
description: "Using templates in workflows"
|
|
---
|
|
|
|
Fabro uses `{{ ... }}` templates for workflow strings and prompts.
|
|
|
|
## Template context
|
|
|
|
Workflow and prompt templates can reference:
|
|
|
|
| Expression | Resolves to |
|
|
|---|---|
|
|
| `{{ goal }}` | The workflow goal |
|
|
| `{{ inputs.name }}` | A value from `[run.inputs]` |
|
|
|
|
Environment variables are **not** available in workflow or prompt templates. Use `{{ env.NAME }}` only in config strings and HTTP hook headers.
|
|
|
|
## Run config inputs
|
|
|
|
Define typed inputs in `[run.inputs]`:
|
|
|
|
```toml title="run.toml"
|
|
_version = 1
|
|
|
|
[workflow]
|
|
graph = "check.fabro"
|
|
|
|
[run]
|
|
goal = "Run repository checks"
|
|
|
|
[run.inputs]
|
|
repo_name = "fabro"
|
|
repo_url = "https://github.com/fabro-sh/fabro"
|
|
language = "rust"
|
|
```
|
|
|
|
These values are available throughout the workflow as `{{ inputs.* }}`:
|
|
|
|
```dot title="check.fabro"
|
|
digraph Check {
|
|
graph [goal="Run tests for {{ inputs.repo_name }}"]
|
|
|
|
start [shape=Mdiamond, label="Start"]
|
|
exit [shape=Msquare, label="Exit"]
|
|
|
|
clone [label="Clone", shape=parallelogram, script="git clone {{ inputs.repo_url }} repo"]
|
|
test [label="Test", prompt="Run the {{ inputs.language }} test suite in the repo/ directory."]
|
|
|
|
start -> clone -> test -> exit
|
|
}
|
|
```
|
|
|
|
## `goal`
|
|
|
|
Agent and prompt nodes also receive the workflow goal at runtime:
|
|
|
|
```dot title="example.fabro"
|
|
digraph Example {
|
|
graph [goal="Implement the login feature"]
|
|
|
|
plan [label="Plan", prompt="Create a plan for: {{ goal }}"]
|
|
}
|
|
```
|
|
|
|
That prompt becomes `Create a plan for: Implement the login feature`.
|
|
|
|
## Expansion timing
|
|
|
|
Fabro expands templates in multiple passes:
|
|
|
|
1. Before DOT parsing, `{{ inputs.* }}` can parameterize structural parts of the graph, including imported `.fabro` files.
|
|
2. After parsing, all string graph, node, and edge attributes are rendered again with the real `{ goal, inputs }` context.
|
|
3. Agent and prompt handlers do a final runtime render pass as a safety net.
|
|
|
|
`{{ goal }}` is preserved through the pre-parse step so it can be resolved later. That means goal-dependent MiniJinja control flow such as `{% if goal %}` is not useful in structural pre-parse templates.
|
|
|
|
## Undefined variables
|
|
|
|
Fabro uses strict undefined-variable handling. If a workflow template references an unknown value such as `{{ inputs.langauge }}`, validation fails instead of passing the literal text through to the model.
|
|
|
|
## Escaping
|
|
|
|
To emit literal template syntax, use MiniJinja escaping:
|
|
|
|
```dot
|
|
test [prompt="{% raw %}{{ goal }}{% endraw %}"]
|
|
```
|
|
|
|
You can also emit literal braces with expressions such as `{{ '{{' }}` when needed.
|
|
|
|
## Input merging
|
|
|
|
`[run.inputs]` intentionally replaces the inherited map wholesale rather than merging by key. Whichever layer has the highest precedence and sets `[run.inputs]` wins its entire map.
|
|
|
|
| Source | Priority |
|
|
|---|---|
|
|
| CLI flags (`-V key=value`, repeated) | Highest |
|
|
| `workflow.toml` `[run.inputs]` | |
|
|
| `.fabro/project.toml` `[run.inputs]` | |
|
|
| `~/.fabro/settings.toml` `[run.inputs]` | Lowest |
|
|
|
|
If you need per-key overrides on top of inherited defaults, set each input explicitly in the winning layer.
|