Flows are YAML-defined chains of agent steps and GitLab API actions that execute sequentially, passing state between steps via Redis.
A flow is a sequence of steps. Each step is either:
- Agent step — runs an AI agent (code-reviewer, chat, pipeline-debugger, etc.)
- Action step — performs a GitLab API call (create branch, open MR, post comment)
Steps produce output stored in the flow state. Subsequent steps can reference
previous outputs via template placeholders like {review.summary}.
Triggered on an issue with @codeward /implement. Steps:
- Analyze the issue (chat agent)
- Post implementation plan as comment
- Create a branch
- Generate code (chat agent)
- Self-review the implementation (code-reviewer)
- Open a merge request (if review is not critical)
- Notify on the issue
Triggered on an MR with @codeward /full-review. Steps:
- Code review (code-reviewer agent)
- Security scan (security-triage agent, skipped on failure)
- Post summary comment with combined results
Triggered on an MR with @codeward /fix-pipeline. Steps:
- Diagnose pipeline failure (pipeline-debugger agent)
- Post diagnosis report as comment
Flow definitions live in agents/flows/*.yml:
name: my-flow # Unique flow name
version: "1.0"
description: What this flow does
trigger:
command: "@codeward /my-flow" # Slash command to trigger
target: merge_request # "merge_request" or "issue"
timeout: 1800 # Total flow timeout in seconds
steps:
# Agent step
- name: step_name
agent: code-reviewer # Agent from registry
action: optional_action # Optional action override
input_from: previous_step # Step name to get input from
output_key: result # Key to store output in state
condition: "review.severity != 'critical'" # Skip if false
on_failure: abort # "abort" or "skip"
timeout: 300 # Step timeout in seconds
# Action step
- name: action_name
type: action
action: post_comment # Action type (see below)
output_key: result
condition: "always"
params:
body: "Result: {result.summary}"| Action | Description | Required Params |
|---|---|---|
create_branch |
Create a git branch | branch_name, ref |
open_merge_request |
Open a new MR | source_branch, target_branch, title |
post_comment |
Post a note/comment | body, optional target ("issue" or "merge_request") |
add_label |
Add labels to an MR | labels (list) |
Conditions are safe expressions evaluated against the flow state:
review.severity != 'critical' # String comparison
security.confirmed_count == 0 # Numeric comparison
pipeline.status == 'success' # Dotted path access
condition1 and condition2 # Boolean AND
condition1 or condition2 # Boolean OR
always # Always true
never # Always false
Supported operators: ==, !=, <, >, <=, >=, in, not in, and, or, not.
Invalid expressions evaluate to false (safe default).
Action params support {dotted.path} placeholders resolved against flow state:
body: "Review: {review.summary} (severity: {review.severity})"Missing keys are left as-is (not replaced).
GET /flows/{flow_id}
Returns:
{
"id": "abc123...",
"name": "full-review",
"status": "running",
"current_step": 2,
"total_steps": 3,
"started_at": "2026-03-28T12:00:00Z",
"state": { "review": { "severity": "info" } },
"error": null
}- Create a new YAML file in
agents/flows/ - Define the trigger command and target
- List steps (agent or action)
- Restart the app to load the new flow
The flow will be available as a slash command automatically.