Nomae Caseflow · Hosted durable execution

The runtime for work thattakes weeks to finish.

Bookings that wait on a vendor. Approvals that wait on a human. Onboarding that spans a month. Caseflow makes long-lived business processes as reliable as a database transaction — written as plain code.

Event-sourced state
Deterministic replay
Human-in-the-loop waits
Serverless underneath
The model

Your whole workflow is two functions.

Decide looks at the case state and new events and returns what happens next. Execute runs one side effect. Everything else — persistence, retries, replay, timers, pauses — is the runtime's job.

Because Decide is deterministic, Caseflow can re-run it after any crash and land in exactly the same place. There is no workflow DSL to learn and no framework to structure your app around: it is Go code you can unit-test with a plain in-memory store.

type Handler interface {
    // Decide is pure: case state + new events in,
    // one decision out. The runtime replays it
    // safely after any crash or redeploy.
    Decide(ctx context.Context, view *CaseView) (*Decision, error)

    // Execute runs one side effect. Errors become
    // events your logic handles — never lost work.
    Execute(ctx context.Context, c *Case, cmd *Command) (json.RawMessage, error)
}
func (b *Booking) Decide(ctx context.Context,
    view *caseflow.CaseView) (*caseflow.Decision, error) {

    state := b.replay(view) // fold new events into state

    switch {
    case state.NeedsVendorRequest():
        return execute("SEND_VENDOR_REQUEST", state)

    case state.AwaitingCustomerReply():
        return waitForEvent("CUSTOMER_REPLIED",
            72*time.Hour, state)

    case state.Confirmed():
        return complete(state)
    }

    return waitUntil(state.NextFollowUp(), state)
}
// Start a case — idempotent by ID.
err := engine.StartCase(ctx, "booking-8451",
    "assisted_booking", input)

// Deliver what it is waiting for — from a webhook,
// an operator action, or a chat bot. The workflow
// resumes the moment the event lands.
err = engine.ResolveCurrentWait(ctx, "booking-8451",
    &caseflow.Event{
        Type:    "CUSTOMER_REPLIED",
        Source:  "email",
        Payload: payload,
    })
The loop

One durable loop, from first event to done.

A case can live for minutes or for months. The loop is the same either way, and every step of it is persisted before it runs.

  1. 01

    An event arrives

    A command result, a customer reply, an operator decision, or a timeout — everything reaches the case as an ordered, immutable event.

  2. 02

    Your decision function runs

    The runtime hands it the case state and every event since the last run. It is pure and deterministic, so replaying it is always safe.

  3. 03

    The decision becomes durable work

    Execute a command, wait for an event with a deadline, sleep until a timestamp, or complete the case. Each outcome is persisted before it runs.

  4. 04

    Crash anywhere, resume exactly there

    Lost responses are re-emitted, interrupted commands surface as failure events, and the loop picks up where the log ends.

In practice

Agent-assisted request processing.

A customer sends a request. An AI agent drafts the vendor email, a human supervisor approves it from a messenger, the vendor answers by email days later — and if they do not, the case nudges them. This is Caseflow's founding workload: it is the exact shape of the assisted-booking cases it runs in production today.

  • The AI agent is just a command — bounded, retried, and auditable like any other side effect.
  • The supervisor's tap and the vendor's email are just events — one delivery call each.
  • Silence is just a timeout — the reminder path is one more branch in Decide.
case booking-8451 · event logcompleted
  1. 01
    CASE_STARTEDweb form

    A customer request lands, with the original payload attached to the case.

  2. 02
    COMMAND_COMPLETEDagent

    An LLM agent reads the request and drafts an email to the vendor.

  3. 03
    WAIT_FOR_EVENTengine

    The draft goes to a supervisor on Telegram. The case pauses — for free.

  4. 04
    SUPERVISOR_APPROVEDmessenger

    One tap in the chat resolves the wait. The workflow resumes instantly.

  5. 05
    COMMAND_COMPLETEDemail

    The approved email goes out. Sending is a durable, retried command.

  6. 06
    WAIT_TIMED_OUTengine

    No vendor reply within 72 hours. The silence is just another event.

  7. 07
    COMMAND_COMPLETEDemail

    The reducer decides to send a polite reminder, then waits again.

  8. 08
    VENDOR_REPLIEDemail

    The inbound reply arrives via webhook. The agent extracts the outcome.

  9. 09
    CASE_COMPLETEDengine

    The customer is notified and the case closes with its full history intact.

Guarantees

The failure modes are the product.

Long-lived workflows fail in ways request/response code never sees: processes die mid-side-effect, replies arrive after timeouts, retries collide with themselves. Caseflow's runtime is built around those cases, not around the happy path.

Crash-safe replay

A pending decision that never made it back is re-emitted on the next run. Killing a process mid-case is a non-event, not an incident.

Exactly-once claiming

Commands are claimed with conditional writes. A duplicate execution attempt becomes an idempotent no-op instead of a double charge.

Interrupted work is surfaced

A command that dies mid-flight may or may not have had its effect. Caseflow reports it as a failure event and lets your logic decide — it never guesses.

Bounded retries

Transient infrastructure failures retry automatically within a strict budget. Business failures become events immediately — no retry storms.

No stuck workflows

Every wait carries a deadline. Timeouts become events your logic handles, and a late reply still reaches the case afterwards.

Unbounded lifetime

Executions roll over automatically before platform history limits, and spin bugs — logic that loops without consuming events — are detected and failed fast.

Under the hood

Serverless where it counts.

Caseflow runs on managed AWS primitives with nothing for you to operate. A sleeping case consumes no compute — a workflow that waits three weeks for a reply costs what three weeks of nothing costs.

AWS Step Functions Standard

A domain-blind state machine drives the loop: run the decision, execute commands, pause on task tokens, sleep on timers. Waits cost nothing while they sleep.

DynamoDB event log

Case state, commands, waits, and the strictly ordered event log live in DynamoDB with conditional writes guarding every contended transition.

Task-token waits

Human input resumes the workflow the moment it arrives — a resolved wait releases its token immediately instead of polling on a schedule.

Where it fits

What Caseflow replaces.

Instead of cron, queues, and status columns

The state machine hiding in your glue code becomes one deterministic function with a complete audit log. No more reconciling a status column against reality.

Instead of operating a workflow cluster

Durable-execution platforms are powerful — and a real operational commitment. Caseflow gives you the same guarantees on serverless primitives, with no workers, shards, or upgrades to manage.

Instead of hand-rolled sagas

Compensation logic, retry budgets, and timeout handling are the runtime's job. Your code only answers one question: given what just happened, what happens next?

Early access

Put your first case on it.

Caseflow runs production booking workflows today. Join the waitlist and we will reach out as hosted early access opens — bring one long-lived process and we will help you model it.

No spam — one email when early access opens, nothing else.