Defining Workflows
A workflow is a YAML file that defines jobs and their steps.
Workflow Name
Workflows can have an optional name field for display purposes.
The name appears in the TUI title bar, the dashboard run list, and
the web UI:
name: Deploy Pipeline
jobs:
build:
steps:
- name: compile
run: cargo build --release
When name is omitted, the filename is used as the display name
(e.g. deploy.yaml). For workflows submitted without a filename,
a truncated run ID is shown instead.
Jobs
Jobs are the unit of parallel execution. They’re defined as a map where the key is the job name:
jobs:
build:
steps:
- name: compile
run: cargo build --release
test:
steps:
- name: run_tests
run: cargo test
Jobs with no dependencies run in parallel. Trill schedules as many concurrent jobs as the dependency graph allows.
Dependencies
Use depends_on to declare that a job needs another job to finish
first:
jobs:
setup:
steps:
- name: install
run: npm install
build:
depends_on: [setup]
steps:
- name: compile
run: npm run build
test:
depends_on: [setup]
steps:
- name: run
run: npm test
deploy:
depends_on: [build, test]
steps:
- name: ship
run: ./deploy.sh
Trill validates the dependency graph at startup. It rejects:
- References to jobs that don’t exist
- Circular dependencies (A depends on B, B depends on A)
- Self-references
Environment Variables
Set environment variables at the job level (available to all steps) or the step level:
jobs:
build:
env:
NODE_ENV: production
steps:
- name: compile
run: npm run build
env:
MINIFY: "true"
Step-level variables override job-level ones with the same name.
Timeouts
Jobs and steps can have a timeout that cancels execution if it
takes too long:
jobs:
build:
timeout: 30m
steps:
- name: checkout
run: git clone $REPO_URL .
timeout: 5m
- name: compile
run: cargo build --release
Timeout values use human-readable duration format: 5s, 30m,
1h30m, 2h. When a timeout expires, the job or step is marked
as timed out and subsequent steps are skipped.
Job Outputs
Jobs can expose outputs that other jobs consume. Outputs reference
step outputs using step_name.key format:
jobs:
build:
outputs:
tag: "docker_build.tag"
sha: "docker_build.sha"
steps:
- name: docker_build
run: |
TAG="v$(date +%s)"
SHA="abc123"
echo "{\"tag\": \"$TAG\", \"sha\": \"$SHA\"}" > "$STEP_OUTPUT_FILE"
deploy:
depends_on: [build]
steps:
- name: push
run: echo "Deploying {{ jobs.build.outputs.tag }}"
The $STEP_OUTPUT_FILE environment variable points to a temporary
file where steps write JSON key-value pairs. Trill reads this file
after each step and makes the values available to subsequent steps
and jobs.
See Defining Steps for more on step outputs and Advanced Concepts for the expression engine.
Conditionals
Jobs and steps support if conditions that control whether they
execute:
jobs:
deploy:
depends_on: [test]
if: "not local"
steps:
- name: push
run: ./deploy.sh
local_verify:
depends_on: [build]
if: "local"
steps:
- name: check
run: echo "Local verification passed"
The local variable is true when running on a local machine (as
opposed to a CI server). You can use not to negate conditions.
Conditions can also reference job statuses and outputs:
jobs:
deploy:
depends_on: [test]
if: "jobs.test.status == 'success'"
steps:
- name: push
run: ./deploy.sh
See Advanced Concepts for the full list of available context variables.
Failure Handling
When a step fails, subsequent steps in the same job are skipped and the job is marked as failed. Jobs that depend on a failed job are also skipped.
Steps can be marked allow_failure: true to continue even if they
exit with a non-zero code:
steps:
- name: lint
run: cargo clippy
allow_failure: true
- name: build
run: cargo build
To run a job even when a dependency fails, use status functions
in the if condition:
jobs:
build:
steps:
- name: compile
run: cargo build
cleanup:
depends_on: [build]
if: "always()"
steps:
- name: teardown
run: docker-compose down
notify:
depends_on: [build]
if: "failure()"
steps:
- name: alert
run: curl -X POST https://slack.example.com/webhook
Available status functions: always(), failure(), success(),
cancelled(). See Advanced Concepts
for details.
Cancelling siblings on failure
By default, when a job fails, its running siblings continue executing.
This can waste compute — if build-linux fails, build-mac keeps
running even though the downstream deploy (which needs both) will
never execute.
Set cancel_on_failure: true on a job to cancel all non-dependent
running and pending siblings when it fails:
jobs:
build-linux:
cancel_on_failure: true
steps:
- name: build
run: ./build.sh linux
build-mac:
cancel_on_failure: true
steps:
- name: build
run: ./build.sh mac
deploy:
depends_on: [build-linux, build-mac]
steps:
- name: ship
run: ./deploy.sh
If build-linux fails, build-mac is cancelled. deploy is
skipped (normal dependency failure propagation). Siblings whose if:
condition uses one of the status functions — always(), failure(),
success(), cancelled() — are exempt from cancellation and continue
running. That’s what keeps cleanup and notify jobs alive when the main
work fails.
CLI Flags
These flags apply to trill run:
| Flag | Env var | Effect |
|---|---|---|
--quiet | — | Suppress output except summary and exit code |
--dry-run | — | Show execution plan without running |
--debug | — | Step through each step interactively |
--debug --json | — | Debug mode with JSON protocol |
--local | — | Force local mode (overrides CI env auto-detection) |
--server <URL> | TRILL_SERVER | Submit workflow to trill.build instead of running locally |
--project <slug> | TRILL_PROJECT | Project slug or ID when submitting remotely (requires --server) |
--token <token> | TRILL_TOKEN | User token for remote submission (requires --server) |
--follow | — | Stream remote run events to console until completion (requires --server) |
--dashboard | — | Open the dashboard TUI for the submitted run (requires --server and --token) |
Exit codes: 0 = success (or submission success for remote
fire-and-forget), 1 = workflow failed, 2 = validation error.
Other Commands
Beyond trill run, a few subcommands help you work with runs on the
hosted service. All of them read TRILL_SERVER and TRILL_TOKEN from
the environment, so you only need to set them once per shell.
trill dashboard
A terminal UI for browsing and inspecting runs on a server. Shows live progress, lets you drill into job and step output, and submits approvals interactively.
trill dashboard --server https://app.trill.build --token trl_<token>
Filter to a single project with --project <slug>.
trill projects
List the projects your token has access to. Useful when you don’t
remember the slug to pass to --project:
trill projects --server https://app.trill.build --token trl_<token>
trill signal / trill approve
See Signals and
Approval Steps. Both commands work
against local files (no --server) or against a hosted service
(with --server and a user token).
Next Steps
- Defining Steps — Step types, approval gates, outputs
- Debugging — Interactive step-through debugging