Triggers → conditions → LLM → actions.
The Flow Engine is the beating heart of ChannelDesk. It is where your cron schedules, webhooks, device events and Claude sessions meet — composable, resumable, observable.
Trigger anything
/api/flows/webhook/{token}),
and event (FlowEventBus matches on system activity).
Claude-step in-line
Device actions
Durable
Observable
Flow-tools MCP
Thirteen node types. One canvas.
Trigger, agent, condition — and ten more building blocks. Drop them on the canvas, wire them up, run.
Outputs flow forward through a results map — every step can reference any earlier step's output.
Don't write flows. Ask for them.
Every flow has a chat tab wired to a flow-tools MCP server.
Describe what you want, Claude adds the nodes, and the canvas reloads with the result.
morning-routine. Trigger: cron 0 7 * * 1-5. Steps:
hue scene kitchen.ceiling.on → hue scene bedroom:sunrise
→ Claude step (flow-tools, github, calendar MCPs)
→ telegram.reply with the summary.
Reload canvas → condition node after the trigger that calls the nl-holidays MCP and short-circuits when today is a public holiday.
Flows can call other flows.
Drop a sub-flow node onto the canvas and it runs another flow as a step —
synchronously, with its outputs piped into the next node's results map.
Build a primitive once, call it from anywhere.
- •
vacuum-journaldbuilt once — called fromdisk-pressure,weekly-cleanup, andpost-deploy - • Sub-flow runs land in
FlowRunEntity.triggeredBy = sub-flowso you can audit who called whom - • Edit the child once; every parent picks up the change next run
- • Wraps as cleanly inside a
for-eachas any other node — fan out a sub-flow per worker
cron · 0 */15 * * * →
ssh-command (df -h) →
condition (any > 85%) →
for-each (host) →
sub-flow: vacuum-journald →
notification.
A flow that fixes its own pull requests.
Webhook fires when a PR is opened. Tests run. SonarQube runs. If anything fails, the flow routes to a Claude agent that reads the report, edits the code, pushes a fix, and loops back to the top — until everything is green or it gives up and asks for help.
pull_request.opened)
ssh-command · npm test on the build host
integration-command · run SonarQube scan, fetch issues
condition · all green?
notification · “ready for human review” in chat
agent · spawns Claude with the failure report attached. Claude reads the diff, edits the code, runs the affected tests locally, and pushes a fix commit. Sub-flow loops back to npm test.
notification · “giving up, here's what I tried” with the full transcript.
Every primitive earns its place
- • Webhook trigger — GitHub fires on PR opened
- • ssh-command — runs the test suite on a real machine
- • integration-command — calls the Sonar scanner
- • condition — green / not green branch
- • agent — Claude session with the failure report + repo
- • sub-flow — re-runs the test+sonar block after the fix
- • approval gate — agent asks before
git push
Where it ends up
You wake up. Either the PR is green and tagged for human review, or there's a chat message with three diffs the agent tried, why each failed, and the question that stumped it.
One page, every automation.
The flow list shows trigger type, enabled state and the last successful run. Toggle a flow off without losing its definition; clone it to draft a variant.
- • Cron, webhook, manual, device — colour-coded by trigger type
- • Disabled flows stay searchable and editable
- • Per-flow chat dock so Claude can rewrite the flow itself
Don't write the automation. Describe it.
ChannelDesk's flow editor has a chat tab. Tell Claude what you want, watch the canvas update.