State · Decision · Action

Workflows that wake, decide, and stop.

Describe the goal, the rules, the actions you allow, and what “done” means. One runtime does the rest—no new listener for every new idea.

Wake from

JiraSlackSchedulesAny webhookYour own tools

One loop. Three nouns.

Every workflow is the same cycle. Something changes the state, a single gate makes a decision, and only allow-listed actions run. Then the gate asks one question: are we done?

01

State

What we know right now

A JSON document per run, patched by wakes and by action results. It is the only memory the rules read.

02

Decision

What should happen next

Rules written as JSON conditions are evaluated in plain PHP. Same input, same decision. No model in the critical path.

03

Action

What we are allowed to do

Jobs from a registry of capability keys. Each action carries an idempotency key, so a repeated wake never doubles the work.

  1. 1Wake arrives
  2. 2Evaluate loads state
  3. 3Rules emit actions
  4. 4Done check — or stop

Hard limits on evaluations and actions mean a runaway workflow halts instead of looping. Failures are written into the run, not swallowed.

A workflow is a document.

Goals, rules, the capabilities it may use, and a definition of done. Edit it in the dashboard, ship it as data, and the same runtime picks it up. The agent is just one capability among several—called only when judgment is worth the cost.

  • ● Allow-listed capabilities per workflow
  • ● Append-only event log for every run
  • ● Works with a database queue or inline
{
  "goals": ["Triage every incident"],
  "capabilities": ["run_agent", "notify"],
  "rules": [{
    "id": "triage",
    "when": { "path": "state.incident.key", "op": "exists" },
    "do": [{
      "capability": "run_agent",
      "params": { "format": "json", "output_key": "triage" }
    }]
  }],
  "done_when": { "path": "state.closed", "op": "truthy" },
  "limits": { "max_evaluations": 30 }
}

Two workflows. Zero new listeners.

Both ship seeded in this demo and run through the exact same evaluate path.

Incident PM

A Jira webhook wakes a run. The agent triages, the channel is told, and when the issue is resolved a postmortem is drafted and the run closes itself.

jira.issue_created → triage → announce → resolved → postmortem → done

Homepage brief

Give it a client. It researches positioning, outlines the homepage sections, asks a human to review, and stops.

start → research → outline → review requested → done

Wake it with a single request.

Adapters only translate the outside world into a wake. Everything else happens in the runtime.

curl -X POST https://swift.truefrontier.app/webhooks/jira \
  -H 'Content-Type: application/json' \
  -d '{"webhookEvent":"jira:issue_created",
       "issue":{"key":"INC-1","fields":{"summary":"Checkout is slow",
       "priority":{"name":"High"},"status":{"name":"Open"}}}}'
Sign in to the dashboard