Capabilities

Workflows that wait for people.

Health work is long, interrupted and full of systems that fail. A Health Loop is TypeScript, but every step is checkpointed, a retry never repeats work that succeeded, and a run can wait days for a scan or a call without holding compute.

Nothing is done twice.

Each step saves its return value. A crash, deploy or network blip replays the saved value instead of the work.

Waiting is free.

A run parks at a scan or a call and resumes from the same line when the person finishes.

Every run is inspectable.

The input, each step, its timing, its return value and every log line sit on one timeline.

Deploys do not break live work.

Each deploy is a version. Runs already in progress finish on the version they started with.
How it works

The mechanism, in order.

  1. Something starts a run. Your system posts to the loop, a person clicks Run, a store event fires, or another loop triggers it.
  2. The run starts a step. step.do names a unit of work, runs it, and stores its JSON return value against the run.
  3. A failed step retries. The platform tries a failed step once more after a second. A step that already succeeded is replayed, not rerun.
  4. The run waits when it must. step.waitForScan and step.waitForVoiceComplete suspend the run until the person finishes or the timeout fires.
  5. The run returns an outcome. The value from run() is the run output. An uncaught error fails the run and keeps the message and stack.
health-scan.tsTypeScript
import { workflow } from "@loops/sdk";

type ScanRequest = { patientId: string; phoneNumber: string };

export const healthScanWorkflow = workflow<ScanRequest>({
  id: "health-scan",
  execute: async ({ step, event, env }) => {
    const { patientId, phoneNumber } = event.body;

    await step.do("Generate a health scan", async ({ ctx }) => {
      await ctx.FACIAL_SCAN.create({ metadata: { patientId, phoneNumber } });
    });

    // The run parks here. No compute is held while it waits.
    const scan = await step.waitForScan({ timeout: "30 minutes" });

    return step.do("Send the report", async ({ ctx }) => {
      await ctx.SMS.send({ to: phoneNumber, content: `Your report: ${await scan.pdfUrl()}` });
      return { patientId, scanId: scan.id };
    });
  },
});
The specifics

What you get, and where it stops.

The step is the boundary. step.do and the two wait methods are the durable surfaces. Code between steps runs again on replay, so side effects belong inside a step.
Returns must be JSON. Objects, arrays, strings, numbers, booleans and null survive a replay. Functions and class instances do not.
Retries are fixed. A failed step gets one more try after a second. Retry counts and backoff are not tunable per step today; catch an error if you want to handle it yourself.
State is per run. Runs do not share state. To carry something between runs, write it to the organisation-wide user record.
Test before you deploy. The playground runs sample turns and inputs. Each deploy adds a version, rollback picks an older one, and the Runs tab can restart a run with the same input.
Where it stops. The workflow is code. Quality checks are the runs, steps and logs you review.
FAQ

Questions

How long can a run wait?

As long as the timeout you set on the wait. While a run is suspended it holds no compute, and it stays visible as running until the wait resolves or times out.

What happens to a run when we deploy?

It finishes on the version it started with. A new deploy only changes the version that new runs pick up.

Can we retry a failed run?

Yes. The run detail page has a Restart action that triggers the loop again with the same input. The steps that already succeeded replay from their saved values.

Do we have to write TypeScript?

For full control, yes. You can also start from a ready-made agent, or describe the job in the health CLI and edit the code it produces.

Is there a scheduler?

Not in the product today. Your own scheduler, CRM or store calls the loop API at the times you choose, and every call becomes a run.

Ollie’s agents give wellness guidance. They don’t diagnose or prescribe, and they hand off to a human expert when it matters.