.toml file into version control and launch with a single command:
Minimal example
A run config needs at minimum a schema version and a goal:run.toml
Goal precedence: CLI
--goal > [run].goal > Graphviz graph attribute.
Full example
run.toml
Sections
[run.model]
Override the default model and provider for all nodes that don’t have an explicit model assigned via a stylesheet.
run.toml
Provider values are catalog provider ID strings. Built-in IDs like
anthropic and openai work, and settings-defined IDs like proxy work after they are added under [llm.providers.<id>].
At run creation, Fabro resolves the primary selector and every node selector against the ready-provider snapshot. It persists the selected canonical model slug and provider, so resuming the run does not choose a different provider just because credentials or priorities changed. The configured fallback chain remains available for failures that occur while the materialized run is executing.
Historical built-in provider API IDs are accepted for compatibility and normalize before this selection. For example, name = "openai/gpt-5.6-sol" is treated as the canonical gpt-5.6-sol selector; omit provider to use readiness and priority, or set provider separately to pin an offering.
[run.model.controls]
Set default model controls for all nodes that do not override them in the workflow stylesheet:
run.toml
Fallbacks with splice
Use the reserved"..." marker in fallbacks to splice in the inherited list from lower-precedence layers:
run.toml
[run.prepare]
Ordered list of steps to run before the workflow starts. Use this to clone repositories, install dependencies, or prepare the environment.
run.toml
Each step must exit with status 0. If any step fails, the run aborts before the workflow starts. Prepare steps replace across layers — the higher-precedence layer wins wholesale.
Fabro substitutes
{{ vars.* }} when the server creates the run, then resolves {{ env.* }} from the worker process and {{ secrets.* }} from token entries in the server vault immediately before the worker executes the steps. Worker-time environment and secret expressions remain in the persisted run definition; resolved secret values are not persisted. A missing environment variable, missing secret, or non-token secret aborts startup with the affected step and token named in the error.
[run.clone]
Configure whether clone-based sandboxes clone the run’s GitHub origin before execution.
run.toml
enabled = false to start Docker and Daytona runs with an empty provider workspace. Use prepare steps to clone or create any files the workflow needs.
[run.run_branch]
Configure Fabro’s managed fabro/run/<id> checkpoint branch.
run.toml
[run.meta_branch]
Configure Fabro’s managed fabro/meta/<id> metadata branch.
run.toml
[run.environment] and [environments.<slug>]
Runs select a reusable named environment by slug. Environment catalogs can be
defined in settings.toml, .fabro/project.toml, or workflow.toml.
run.toml
[run.environment.*] and apply to the
selected environment only:
When
provider = "local", Fabro runs directly in the resolved working
directory. If you want local isolation, create or enter a separate clone or Git
worktree yourself.
Environment variable values can combine literal text with server variables, worker environment variables, and token secrets:
run.toml
Missing or non-token secret references fail closed before sandbox startup. For backward compatibility, an environment value that references only a missing
{{ env.* }} value is passed through in source form; use preflight or prepare-step interpolation when an absent worker variable must be a hard error.
[run.integrations.github.permissions]
Request a scoped GitHub App token for workflow stages that need GITHUB_TOKEN inside the sandbox. Values map directly to GitHub App permission names and access levels.
run.toml
GITHUB_TOKEN if the app is not configured or is not installed on the repository.
This table follows the normal settings precedence order. A higher-precedence layer can set permissions = {} to clear inherited permissions and run without a GitHub token.
[run.notifications]
Define named notification routes for run events. Slack lifecycle notifications are configured here, not in server config.
run.toml
Each enabled Slack route posts once for each matching lifecycle event. Messages include the run ID, an Open in Fabro link when available, workflow label, terminal result, duration, and pull request details when those are already present in the run event stream.
run.failed is emitted only when the run terminally fails. A failed stage that routes onward to a normal completion path produces run.completed, not run.failed.
If a Slack route’s channel is missing, empty, or references an unresolved environment variable, Fabro logs a warning and skips that route. Delivery failures are logged and never fail or alter the run.
[run.checkpoint]
Configure how git checkpoint commits behave.
run.toml
exclude_globs replaces across layers — the higher-precedence layer wins wholesale. skip_git_hooks and commit_timeout use normal override semantics: the highest layer that sets the field wins.
[run.inputs]
Define inputs that are rendered into final workflow string attributes. See Variables for the full reference.
run.toml
goal and node prompt attributes with {{ inputs.name }} syntax:
c-i.fabro
import paths, @file paths, or child workflow paths, or any attribute besides prompt and goal — other attributes such as script and label are literal text.
If a workflow template references an undefined input like {{ inputs.langauge }}, fabro validate reports a warning. Run-style commands promote that diagnostic to an error before creating or starting a run.
TOML [run.inputs] tables replace wholesale across layers. Unlike labels, TOML input tables do not merge by key — the highest-precedence config layer that sets inputs wins its entire map.
CLI input flags are sparse overrides on top of the resolved config inputs:
-I / --input to override multiple keys. CLI input flags have the highest precedence, merge per key, and preserve unrelated inherited inputs. Duplicate CLI keys are accepted; the last value wins.
[run.artifacts]
Configure automatic collection of test artifacts (Playwright reports, JUnit XML, screenshots, etc.) from the execution environment after each stage.
run.toml
Artifact collection is opt-in — when no
[run.artifacts] section is present, no file scanning occurs.
Artifact globs use / as the separator and have the same semantics in every sandbox:
*and?match within one path segment.- Bracket expressions such as
[abc]and[!abc]match one character. **matches across directories when used as a complete segment.- Leading dots are matched normally.
- Patterns use
/, are relative to the sandbox working directory, and are case-sensitive. Backslashes are invalid. - Absolute patterns and patterns containing a
..segment are invalid.
.ai/reports/*.md matches direct Markdown children of .ai/reports, while .ai/reports/**/*.md also matches nested reports. *.trace.zip matches only the working-directory root; use **/*.trace.zip to match at any depth. To collect date-named implementation plans, use .ai/plans/????-??-??-*.md.
Each collection reflects the post-stage workspace state rather than filesystem modification timestamps. A path with unchanged content is recorded only once per run; if its content changes, Fabro captures the new version.
Fabro resolves the configured workspace root but does not recurse through symlinks below it while collecting artifacts. Dependency, cache, and build directories such as .git, node_modules, target, .venv, .cache, and dist are pruned. A collection is limited to 100 files, 10 MB per file, and 50 MB total.
[run.agent]
Configure workflow agent behavior that is not tied to a single stage.
run.toml
fabro_tools defaults to false. Set it to true only for runs whose agents should be able to use the same Fabro run-management MCP tool catalog exposed to human MCP clients: create, search, get, interact, gather, events, and pair.
One workflow-agent exception is intentional: fabro_run_create always creates child runs parented to the current run. If an agent supplies parent_id, it must match the current run ID.
This setting is separate from normal agent permissions and from MCP server configuration. permissions controls workspace tool access, while [run.agent.mcps] configures external MCP servers available to the agent.
[run.agent.mcps]
Configure MCP servers available to agent stages during the workflow run. Each server is a named TOML table under [run.agent.mcps]. All three transport types are supported: stdio, http, and sandbox.
run.toml
run.toml
Inline transport commands, URLs, env values, and headers support
{{ vars.* }}, {{ env.* }}, and {{ secrets.* }} interpolation. As with prepare steps, server variables resolve at run creation and worker env/token secrets resolve at launch; missing values fail closed. See MCP runtime interpolation for the standalone fabro exec difference.
The sandbox transport runs the MCP server inside the workflow’s sandbox. This is useful for tools that need access to the sandbox environment, such as browser automation with Playwright. See MCP for details.
[run.pull_request]
Automatically open a GitHub pull request when the workflow run completes successfully. Requires a GitHub App to be configured.
run.toml
[[run.hooks]]
Define hooks that run in response to lifecycle events. Each hook is a TOML array entry:
run.toml
Hook merge semantics: hooks with matching
id values replace in place. Hooks without an id from a higher-precedence layer append after the fully merged inherited hook list.
See Hooks for hook types beyond scripts (HTTP, prompt, agent).
Graph path resolution
The[workflow].graph path is resolved relative to the TOML file’s parent directory, not the current working directory. This means a run config and its workflow can live side by side:
Precedence
Settings can come from multiple sources. Fabro resolves them in this order (first match wins):Stylesheet rules on individual nodes always take priority over run config values.
Project defaults (.fabro/project.toml)
The .fabro/project.toml project config can set default values for any of the [run.*] sections described above. These defaults apply to all runs in the project unless the workflow config overrides them:
.fabro/project.toml
run.inputs tables replace wholesale, CLI input flags merge per key at highest precedence, environment env and labels merge by key, and run.prepare.steps replaces whole-list.
Machine defaults
When running locally, the machine defaults at~/.fabro/settings.toml can set run-scoped defaults too. Same merge rules apply.
Validation
Fabro validates the run config when it loads:_versioncheck — Only_version = 1(or missing, which defaults to1) is accepted. The legacy top-levelversionkey is rejected with a rename hint.- Unknown keys — Any top-level key not in
[project],[workflow],[run],[cli],[server], or_versionis rejected with a targeted rename hint pointing at the v2 replacement path. - Variable check — Undefined workflow or prompt template variables produce diagnostics.
fabro validatereports them as warnings; run-style commands treat them as errors before creating or starting a run.
fabro preflight to validate a run config without executing it: