Flows

Rethinking workflows

When building start.chat we realized something, something of a secret:

Apps’ slash commands are skills…
… what if you can just… chain them together?

We wanted some sort of flow system from the start — any intranet needs it, and every platform already implements flows, just usually in their backend.

We knew we wanted to find an 80/20 solution — let your dedicated infrastructure for flows handle the intense stuff, but give you something you can create, test, and edit 10x faster:

  • Text-first
  • LLM-first
  • Easy to read and understand
  • Low conceptual burden
  • Easy to fit in small space
  • Outputs deterministic code

So, we iterated quite a lot until we had Pipedown, a portable plain-text format for pipelines.

Like Markdown adds very very little syntax and then gets out of the way, Pipedown just gives you a few constructs to actions and AI into automated pipelines.

What is a flow?

Kind of like this:

/github fetch open issues from myorg/myrepo filter to high priority only /notify alert the team about critical issues

Steps starting with /app action call a specific installed app.

Steps without / are LLM steps — natural language instructions processed by AI to transform, filter, or summarize data.

There’s 12 special words or symbols on top of that, but that’s it. The rest is determined by the runtime.

Our runtime does some really fun things we’ve figured out that make flows both very powerful, but also very fast, and deterministic. In fact, you can even copy our flows out as plain JavaScript snippets to use anywhere you want.

Richer example

# Daily Issue Digest Fetches high-priority GitHub issues and alerts the team each morning every day 09:00 /github fetch open issues from myorg/myrepo filter to issues labeled "critical" or "urgent" = issues /notify alert @team about {{issues}}
  1. Runs every day at 9am
  2. Fetches issues from GitHub
  3. Uses AI to filter to critical/urgent ones, tagging the result as #issues
  4. Sends a notification referencing that tagged output

Note that you don’t need to label “issues” in this flow, as steps always return two things: summary and data, which are passed to the next step, and all steps in start.chat automatically figure out how to use their summary and data intelligently when they first run using LLMs, saving the “strategy” — a simple JS snippet they figure out iteratively — in a cache, in order to run instantly from then on out.

Step types

TypeSyntaxDescription
App action/app action argscalls an installed app’s action
LLM stepplain textAI processes the previous output
Conditionalif conditionskips subsequent steps if false
Cancelcancel if conditionstops the flow entirely if true
Wait/wait @person or /wait 2hpauses for approval or a duration
Error handler! retry 3, ! ignore, ! fallbackcontrols error behavior
Parallel* stepruns step in parallel with siblings

See Writing Flows for the complete syntax reference.

Triggers

Flows support three trigger types:

Manual — click the play button to run on demand. This is the default.

Schedule — run at set intervals:

every day 09:00 /stripe balance /notify alert @finance

Event — run when an app emits events:

on stripe /chat message in parent channel

Or target a specific event:

on stripe.payment check if amount > 1000 /notify alert @finance about large payment

See When Flows Run for all frequencies and event options.

Creating flows

Write a flow directly in any message. Start detects the flow syntax, creates a flow record, and shows a play button to run it. Multi-line flows work in code blocks too.

Where flows run

Each flow gets its own thread in the Flows channel. When a flow runs, each step executes sequentially and the output is posted to the thread.

StatusDescription
idlewaiting to start
runningcurrently executing steps
completeall steps finished successfully
faileda step encountered an error
cancelledmanually stopped or cancelled by a cancel if step
waitingpaused on a /wait step