Automations, workflows & loops
Three ways an agent does work you aren't sitting there for: something outside wakes it, a design runs several agents in order, or one agent repeats until the goal is actually met.
On this page(10 sections)
Automation, workflow or loop?
They get mistaken for each other, so the distinction first:
| Use | When |
|---|---|
| An automation | Something outside should start the work: a clock, a webhook, a message, a change in the workspace. |
| A workflow | The work is several agents in a particular order, each handing on to the next. You author it once and run it repeatedly. |
| A loop | One agent should keep going until a goal is met, rather than stopping after one turn. |
Automations
An automation is a trigger, a prompt, and the choices about who runs it. When it fires, the agent wakes with your prompt and whatever the trigger carried.
| Trigger | Fires on |
|---|---|
| Schedule | A cron expression. A nightly cleanup, a morning report, a weekly release note. |
| Webhook | An address anything can POST to, with a token minted when you save it. The caller has no sign-in, which is the point: a pipeline, a monitor, a cron box elsewhere. |
| Listener | A connected provider's own events: a Discord or Slack message, an email arriving, a pipeline failing, a Visitor chat visitor. Narrow it by channel, by event type, or to messages that mention the agent. |
| Workspace | Something happened in the sandbox itself: a turn settled, an agent landed, dependencies broke or were fixed. Optionally scoped to one repo. |
curl -X POST "$SANDBOX/automations/nightly-sweep/fire?token=…" \
-H "content-type: application/json" \
-d '{"release":"v2.4.0"}'
{ "ok": true }Deciding not to run
A guard is a shell one-liner run in the workspace before the wake. Exit 0 and the agent wakes; anything else is recorded as skipped. It is the cheap way to stop a schedule spending a turn to discover there was nothing to do: is the queue empty, did the branch move, does yesterday's report already exist.
Who serves the wake
An automation can pin its provider, model, harness and account. The account matters more here than anywhere else, because nobody is watching. A sandbox holds several side by side, and the first can run out of headroom or belong to an organisation that turned the plan off. Every fire then errors until somebody reads the row. Pinning is the difference between a quiet nightly sweep and a Visitor chat that turned visitors away all day.
Approving a fire
Two ways to keep a hand on the wheel, and they are different promises:
- Require approval holds every fire in a queue until you approve it. Nothing runs on its own.
- Hold for a while puts the fire in the same visible queue and runs it once the hold elapses and no turn is live: a window to cancel or start early, with silence as consent. That is what a "checks broke, a fix is about to start" notice wants.
An explicit "ask me" always wins over a hold. A held fire snapshots the payload that caused it, so approving it later replays exactly what fired, and it survives a restart. The snapshot keeps its conversation too, so a visitor's chat stays one thread.
Who may talk to it
Approval answers "should this run?" by asking you every time. On a source that knows who is writing (Discord, Slack, Telegram, WhatsApp, e-mail) an automation can answer it by who sent the message instead. Switch on Decide per person who it answers and name people by the id the service vouches for, never by a display name, which anyone can change to; on Discord a role id names everyone who holds it. Each rule says which persona those people get: a support desk for the customers, no persona at all for the boss, which is the full agent you talk to yourself. Everyone else is ignored, held for you, or answered as configured.
People it answers as different agents never share a conversation, so the boss's thread and the customers' thread in one channel are two threads with two memories. Everyone who reaches the automation, admitted or not, is listed under seen recently, so naming a stranger after the fact is one click rather than a copied id.
Chores
An automation can be marked a chore: maintenance of this codebase rather than a reaction to the outside world. It fires like any other automation; the flag only decides which shelf it sits on, because a nightly dependency audit and a nightly Stripe poll are both "schedule" and are not the same kind of thing.
Workflows
A workflow is a design: named steps, each declaring which must finish before it starts. That makes it a graph rather than a list, so independent steps run at once: two models on one task, or three reviewers on one diff. The design is checked when you save. A cycle, a dependency naming a missing step, or a step with no way to know it is finished is refused with the sentence the editor shows you while you type.
Every step is an ordinary isolated agent: it appears on the fleet board, you can read its transcript, and it lands like anything else. Nothing fires a workflow on its own; somebody runs it, or an automation's prompt does.
| Per step | What it decides |
|---|---|
| Goal | What "done" means, in your words: the sentence the step is measured against. Leave it out and the step is measured against whatever was asked of the run this time, which is usually what you meant. |
| Instruction | What the step is told to do, which is a different sentence: "the suite is green" is a goal, "run the tests, take the top failure, fix it" is an instruction. Leave it out and the request is handed over verbatim. |
| Handoff | Whether this step starts fresh or continues from the one before it. |
| Output | Nothing, a structured claim (done plus a reason), or JSON matching fields you declare. |
| Checks | What else has to be true: a shell command that must exit 0, or a judge given a rubric. ANDed with the output above. |
| Spend cap | A dollar ceiling. The one resource you cannot recover after an unattended fan-out. |
A step's own word for it is advisory, which is why a command check outranks everything else. "The suite passes" is a fact; "I believe I am done" is a self-assessment, and it exists because plenty of goals have no command to check them.
Gates
A gate turns a finished run into a release decision, for a pipeline that cannot sign in. It reads one declared field off one named step and compares it against the values that mean ship it: an allowlist, never a blocklist. A model answering "mostly-pass" must not ship, and nobody should have to enumerate the ways it can hedge. The gate's webhook carries its own token, minted on save.
Keeping the gate separate from the design is the point. What a run does stays the graph's business, so today's release check can be an acceptance sweep and next month's a security review, without the gate learning what either is.
On GitHub it's one step. Paste the gate's URL into a repository secret and add the Intentic Agent Gate action, from the GitHub Marketplace, to your workflow. The build then waits for the verdict: green when it passes, red when it fails, and left alone when the gate couldn't reach a decision because a check that breaks is not the same as a product that broke. The reason shows up right on the run.
- uses: intentic/gate-action@v1
with:
url: ${{ secrets.INTENTIC_GATE_URL }}Any other CI system calls the same URL with one command. The action is also the tidy way to fire a webhook automation from a workflow: point the step at an automation's address instead, and it hands over what just happened without you keeping any curl around.
Loops
A loop is started against a conversation: "keep going until this is true". It has no editor and no id, because it is not a thing you maintain: it converges or gives up, and then it is history. The conversation need not exist yet, which lets "run this until it's green" be the first thing you say to a new agent.
It uses the same fields as a workflow step: a goal, an output and checks. It also asks whether each iteration starts fresh or continues the last one. Long-running work wants fresh, so context doesn't rot; a keep-refining-this loop wants continue.
Stopping a loop does not stop the turn. Stop means "don't start another iteration" and leaves work in flight alone, so you can call the last one while watching iteration six do something good. Killing the running turn is the agent's own Stop; press both to abandon a loop outright.
Every loop that has run is kept, with its iteration history because "why did it stop at four?" is the question a loop gets read for.
Related pages
- Parallel agents: what each of these opens: an isolated conversation you review and land.
- Visitor chat: a listener automation with a chat widget on the front of it.
- Capabilities: connect the system whose events you want to wake on.
- Guide: keeping an agent running unattended: what actually survives a closed laptop, and the limits to set before it runs.