Skip to main content
A run config is a TOML file that bundles a workflow graph with all the settings needed to execute it — the goal, model, sandbox, prepare steps, inputs, and hooks. Instead of passing a dozen CLI flags, you check a .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
Set 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
Sparse run-level overrides live under [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
Only requested permissions are included. The upper bound is the permission set granted to the installed GitHub App, and Fabro logs a warning and continues without 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
Inputs can be used in graph goal and node prompt attributes with {{ inputs.name }} syntax:
c-i.fabro
Inputs cannot parameterize workflow structure, file references such as node IDs, edges, 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:
Repeat -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.
For example, .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
To reuse a definition from the server-managed MCP catalog, reference its ID instead of defining an inline transport:
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:
Absolute paths are used as-is.

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
Project defaults and workflow config values merge per the normative merge matrix: most fields merge by field (higher-precedence wins per key), 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:
  • _version check — Only _version = 1 (or missing, which defaults to 1) is accepted. The legacy top-level version key is rejected with a rename hint.
  • Unknown keys — Any top-level key not in [project], [workflow], [run], [cli], [server], or _version is rejected with a targeted rename hint pointing at the v2 replacement path.
  • Variable check — Undefined workflow or prompt template variables produce diagnostics. fabro validate reports them as warnings; run-style commands treat them as errors before creating or starting a run.
Use fabro preflight to validate a run config without executing it: