Debugging
Trill has three tools for understanding what your workflow does before (or while) it runs: dry-run, debug mode, and JSON debug mode.
Dry Run
See the execution plan without running anything:
trill run workflow.yaml --dry-run
This shows:
- Execution order based on the dependency graph
- Each step’s command (truncated if long)
- Template expressions that will be resolved at runtime
- Approval steps with their fields
- Conditional expressions on jobs and steps
Useful for verifying that dependencies are correct and steps are ordered how you expect.
Debug Mode
Step through each step interactively:
trill run workflow.yaml --debug
Before each step, trill pauses and shows:
- The step name and parent job
- The rendered command (after template substitution)
- The resolved environment variables
- The expression context (available variables)
- Any condition expression
You choose what to do:
| Command | Effect |
|---|---|
r or Enter | Run this step |
s | Skip this step |
c | Continue — run all remaining steps without pausing |
i | Inspect — show detailed debug information |
q | Quit — abort the entire workflow |
After each step completes, trill shows the result: status, duration, exit code, and any outputs produced.
Debug mode works with approval steps too. The debug hook fires first (you can skip or quit), then if you choose to run, the approval prompt appears.
JSON Debug Mode
For LLM agents and automation:
trill run workflow.yaml --debug --json
Every interaction becomes a JSON object on stdout, and responses are JSON objects on stdin. No terminal colors, no interactive prompts — just structured data.
Step Events
Before each step, trill emits:
{
"event": "step_pending",
"job": "build",
"step": "compile",
"template": "cargo build --release",
"command": "cargo build --release",
"env": {"CARGO_INCREMENTAL": "0"},
"context": {
"local": true,
"env": {},
"jobs": {},
"steps": {}
},
"condition": null,
"depends_on": []
}
Respond with an action:
{"action": "run"}
Available actions: run, skip, continue, quit.
After the step completes:
{
"event": "step_done",
"step": "compile",
"status": "succeeded",
"duration_ms": 1234,
"exit_code": 0,
"outputs": {},
"extensions": null,
"output": " Compiling trill v0.1.0\n Finished release [optimized] target(s)",
"output_truncated": false
}
The output and output_truncated fields are only present when captured
output is available. extensions is null when no extension jobs were
added, or a list of job names when extension jobs were injected.
Respond with a post-step action (or send an empty line / {"action": "continue"} to proceed):
{"action": "continue"}
Available post-step actions: continue, abort, extend.
The extend action injects new jobs into the DAG (same format as
$STEP_EXTEND_FILE, but in JSON):
{
"action": "extend",
"jobs": {
"hotfix": {
"depends_on": ["build"],
"steps": [{"name": "patch", "run": "echo patching"}]
}
}
}
The abort action cancels the remaining steps immediately:
{"action": "abort"}
On invalid input or parse errors, trill defaults to continue.
Approval Events
Approval steps emit:
{
"event": "approval_required",
"job": "deploy",
"step": "approve",
"prompt": "Deploy to production?",
"fields": [
{"name": "environment", "type": "select", "options": ["staging", "production"]}
]
}
Respond:
{"action": "approve", "outputs": {"environment": "production"}}
Or:
{"action": "reject"}
Workflow Summary
When the workflow finishes:
{
"event": "workflow_done",
"success": true,
"duration_ms": 5432
}
Combining Debug and Approval
Debug hooks fire before approval handlers. The flow for an approval step in debug mode:
- Debug hook shows step info, you choose Run/Skip/Quit
- If Run: approval handler prompts for input
- Debug hook shows the result (approved/rejected, outputs)
This means you can skip approval steps during debugging without needing to go through the approval flow.
Next Steps
- Advanced Concepts — Using JSON mode with LLM agents, dynamic extension, data flow