# `fledge.toml` Reference
`fledge.toml` lives in your project root and defines tasks, lanes, and release behavior. It's read by `fledge run`, `fledge lanes`, `fledge release`, and `fledge watch`. Plugins with the `metadata` capability can read it through the `fledge_config` metadata key.
If no `fledge.toml` exists, `fledge run` falls back to language-aware auto-detection. As soon as the file exists, it takes full precedence. There is no merging with auto-detection.
For plugin manifests (`plugin.toml`), see [Extend: Plugins](./plugins.md). For global user config (`~/.config/fledge/config.toml`), see [Configuration](./configuration.md).
## Creating it
```bash
fledge run --init # starter file with detected tasks
fledge lanes init # adds default lanes for your stack
fledge templates init my-app # included in scaffolded projects
```
## File layout at a glance
```toml
schema_version = 1 # optional, currently unused
[tasks] # individual commands you can run
build = "cargo build"
[tasks.test] # full form
cmd = "cargo test"
description = "Run the test suite"
deps = ["build"]
env = { RUST_LOG = "debug" }
dir = "."
[lanes.ci] # named pipelines that chain tasks
description = "Full CI pipeline"
steps = [
{ parallel = ["fmt", "lint"] },
"test",
"build",
]
fail_fast = true
[release] # extra files to bump on `fledge release`
files = ["flake.nix"]
```
That's the entire schema. Everything else on this page expands one of these sections.
## `[tasks]`
Tasks are the building blocks. Lanes reference them by name, and you run them directly with `fledge run <name>`.
### Short form
A bare command string:
```toml
[tasks]
build = "cargo build"
test = "cargo test"
lint = "cargo clippy --all-targets -- -D warnings"
```
Short-form tasks have no description, no deps, no env, no working directory.
### Full form
A table when you need more than a command:
```toml
[tasks.deploy]
cmd = "cargo install --path ."
description = "Build and install locally"
deps = ["test"]
env = { RUST_LOG = "info" }
dir = "crates/cli"
```
| `cmd` | string | yes | n/a | Shell command. Run via `sh -c` (Unix) or `cmd /C` (Windows). |
| `description` | string | no | (uses `cmd`) | Shown by `fledge run --list`. |
| `deps` | array of strings | no | `[]` | Tasks to run first. Resolved recursively. Cycles are detected and rejected. |
| `env` | table | no | `{}` | Environment variables set for the task's process. |
| `dir` | string | no | project root | Working directory, relative to the project root. |
### Mixing forms
You can mix short and full in the same file:
```toml
[tasks]
build = "cargo build"
fmt = "cargo fmt"
[tasks.ci]
cmd = "cargo test --workspace"
description = "Full workspace test"
deps = ["fmt", "build"]
```
## `[lanes]`
Lanes chain tasks (and inline commands) into named pipelines. Run with `fledge lanes run <name>`.
```toml
[lanes.ci]
description = "Full CI pipeline"
steps = [
{ parallel = ["fmt", "lint"] },
"test",
"build",
]
fail_fast = true
```
| `description` | string | no | `"(no description)"` | Shown by `fledge lanes list`. |
| `steps` | array | yes | n/a | Ordered steps. At least one is required. |
| `fail_fast` | bool | no | `true` | If `false`, every step runs even after failures and a summary is reported at the end. |
### Step types
A step can be one of three shapes. Mix them freely.
#### Task reference
Just a string naming a task in `[tasks]`:
```toml
steps = ["lint", "test", "build"]
```
Task `deps` resolve automatically before the step runs.
#### Inline command
A one-off shell command without cluttering `[tasks]`:
```toml
steps = [
"test",
{ run = "cargo build --release" },
{ run = "tar -czf release.tar.gz -C target/release my-app" },
]
```
#### Parallel group
Items inside a `parallel` array run concurrently. The lane waits for all of them before the next step:
```toml
steps = [
{ parallel = ["fmt", "lint"] },
"test",
]
```
Items in a parallel group can be task references or inline commands:
```toml
steps = [
{ parallel = [
"lint",
{ run = "cargo audit" },
"fmt",
] },
"test",
]
```
Parallel groups cannot be nested.
### `fail_fast`
```toml
[lanes.audit]
description = "Run everything, report all failures"
fail_fast = false
steps = ["lint", "test", "audit"]
```
| `true` (default) | Stop at the first failed step. |
| `false` | Run every step; print a final report listing every failure. |
Use `fail_fast = false` for "give me the full picture" lanes (audit, broad checks). Keep `true` for CI gates where there's no point continuing after a break.
## `[release]`
Controls additional files that `fledge release` bumps alongside the language's standard manifest (`Cargo.toml`, `package.json`, `pyproject.toml`, `pom.xml`, `build.gradle`, `setup.cfg`, or `plugin.toml`).
```toml
[release]
files = ["flake.nix", "docs/install.md"]
```
| `files` | array of strings | `[]` | Extra files whose `version "X.Y.Z"` line should be rewritten on release. Paths are relative to the project root and may not escape it. |
The bumper looks for the regex `version\s*[=:]\s*["']?(\d+\.\d+\.\d+)` and rewrites the matched version. Files without a matching line are silently skipped.
`fledge release --dry-run` reports the same set of files the real run would bump, including these extras.
> **Heads-up for plugin authors:** Don't list `Formula/*.rb` (Homebrew formulae) here. Formulae need a fresh `sha256` per release that doesn't exist until release artifacts are uploaded; bump them in a follow-up workflow instead.
## `schema_version`
```toml
schema_version = 1
```
Currently parsed but unused. Reserved for future breaking-change migrations. Safe to omit.
## Imported lanes (`.fledge/lanes/*.toml`)
`fledge lanes import <source>` writes imported lane definitions to a generated file under `.fledge/lanes/`. The filename is derived from the source ref as `<owner>-<repo>[-<subpath>].toml` (lowercased, with `/` in subpaths replaced by `-`). For example, `fledge lanes import CorvidLabs/fledge-lanes/rust` writes to `.fledge/lanes/corvidlabs-fledge-lanes-rust.toml`. These files are auto-loaded by `fledge lanes run` after your top-level `fledge.toml`. Your local definitions win on name collisions.
Each imported file has the same shape as `fledge.toml` but typically contains only `[tasks]` and `[lanes]` from the upstream source:
```toml
# Imported from CorvidLabs/fledge-lanes/rust@v1.0.0
[tasks]
fmt-check = "cargo fmt --check"
[lanes.rust-ci]
description = "Rust CI from CorvidLabs/fledge-lanes"
steps = ["fmt-check", "lint", "test", "build"]
```
The leading `# Imported from <source>` comment is parsed and used to display the lane's trust tier in `fledge lanes list`.
## Full worked example
A real-world Rust project mixing every section:
```toml
# fledge.toml. example project
schema_version = 1
[tasks]
build = "cargo build"
test = "cargo test"
lint = "cargo clippy --all-targets -- -D warnings"
fmt = "cargo fmt --check"
fmt-fix = "cargo fmt"
audit = "cargo audit"
[tasks.docs-serve]
cmd = "mdbook serve docs --open"
description = "Serve docs locally with live reload"
[tasks.deploy]
cmd = "scripts/deploy.sh"
description = "Deploy the API"
deps = ["test", "build"]
env = { DEPLOY_TARGET = "staging" }
dir = "."
[lanes.check]
description = "Quick pre-commit check"
steps = [
{ parallel = ["fmt", "lint"] },
"test",
]
[lanes.ci]
description = "Full CI pipeline"
steps = [
{ parallel = ["fmt", "lint"] },
"test",
"build",
]
[lanes.audit]
description = "Every quality check, report all failures"
fail_fast = false
steps = ["fmt", "lint", "test", "audit"]
[lanes.release]
description = "Pre-release validation"
steps = ["fmt", "lint", "test", "build", "audit"]
[release]
files = ["flake.nix"]
```
## Validating
| `fledge lanes validate` | Lane references resolve, no dependency cycles, lane structure is well-formed. |
| `fledge lanes validate --strict` | Treats warnings as errors. Useful in CI. |
| `fledge lanes validate --json` | Machine-readable report. |
| `fledge run --list` | Parses `[tasks]` and shows everything fledge can see. |
| `fledge lanes list` | Parses `[lanes]` and shows every lane plus its source (local vs. imported). |
A parse failure on any section bails with a context-rich error pointing at the offending TOML.
## Behavior reference
A few subtle but documented behaviors worth knowing:
- **Project precedence.** If `fledge.toml` exists, auto-detection is fully disabled. Fledge uses only what's in the file.
- **Empty `[tasks]` is an error.** `fledge run` bails with a "no tasks defined" message rather than silently running nothing.
- **Empty `[lanes]` is an error for `fledge lanes run`.** The error tells you to add lanes, import them, or run `fledge lanes init`.
- **Unknown fields are ignored.** TOML keys not in the schema are silently accepted (forward-compatible) but have no effect.
- **`description` is optional everywhere.** Tasks fall back to showing `cmd`, lanes fall back to `(no description)`.
- **Path handling differs by field.** Task `dir` is joined to the project root as configured and is *not* currently canonicalized. Values like `"../sibling"` are accepted and will resolve outside the project. `[release].files` paths *are* canonicalized and rejected if they escape the project root.
## Related
- [Run: Tasks and Lanes](./lanes.md). Workflow walkthrough, auto-detection, watch mode
- [Configuration](./configuration.md). Global `~/.config/fledge/config.toml`
- [Extend: Plugins](./plugins.md). `plugin.toml` reference and ecosystem
- [Plugin Protocol Spec](https://github.com/CorvidLabs/fledge/blob/main/specs/plugin/plugin-protocol.spec.md). `fledge-v1` JSON wire protocol
- [CLI Reference](./cli-reference.md). Every subcommand and flag