Counting visitors…
Browse all docs
Start · 9Find your path through RunifoldLearn Runifold in 45 minutesUnderstand the complete Runifold platformYour first trustworthy runChoose the right execution APIChoose crates and Cargo featuresBuild common Runifold applicationsRunifold frequently asked questionsTroubleshoot Runifold applications
Execution kernel · 7Understand RunContextCoordinate external effects safelyBound work with budgets and cancellationHandle errors and retries safelyEvents, journals, and execution evidenceDesign capability-safe executionRecover safely from checkpoints
Models & providers · 7Route across models without duplicate outputChoose and configure a providerUse the provider-neutral model protocolBuild on the Provider Runtime contractUse OpenAI control-plane and Realtime APIsTest and benchmark provider adaptersSet up OpenAI, Anthropic, Gemini, and Ollama
Agents · 7Build and configure an AgentGive an Agent typed toolsAdd conversations and semantic memoryDelegate to child Agents safelyReturn structured Rust valuesStream without losing semanticsGround an Agent with retrieval
Durable workflows · 7Compose deterministic workflowsMake workflows durableOperate durable workflow workersCoordinate timers, signals, and durable waitsRun multi-tenant workflow infrastructureRun parallel branches and safe racesVersion and evolve durable workflows
Integrations · 7Connect through MCPChoose stores and persistence boundariesExpose durable work through MCP TasksBuild and evaluate retrieval pipelinesUse MCP Resources, Prompts, and SamplingCache MCP responses without crossing authorityDeploy Runifold in a Rust web service
Quality & operations · 10Test without the networkEvaluate quality and prevent regressionsObserve the complete run treeRun safely in browsers and at the edgeRead reliability claims preciselyRun reproducible evaluations in CIOperate Runifold with SLOsGovern Task retention and deletionArchive audit evidence to S3-compatible WORM storageManage compatibility and trusted releases
Docs/Trusted execution
NEW TO RUNIFOLD?Build the complete mental model in 45 minutes
Trusted execution

Coordinate external effects safely

Record intent before execution, replay completed work, and fail closed when a write may already have happened.

Practical guide·10 min

Why effects need a boundary

A model call, tool, or worker can fail after an external system accepted a write but before the caller received success. At that point, “retry” may mean “charge twice,” “send twice,” or “delete the next resource.”

Runifold calls this an ambiguous effect. The runtime does not erase that uncertainty behind a generic transient error.

Use the effect boundary for externally visible writes whose outcome must be recovered: payments, notifications, provisioning, approvals, and destructive operations. Ordinary pure calculation does not need it.

The write-ahead lifecycle

EffectExecutor coordinates one logical operation through durable states:

StateMeaningSafe next action
Preparedintent is durable; handler has not startedexecute
Startedhandler may have reached the destinationapply recovery policy
Completedcanonical output is durablereplay output, no I/O
Faileda definitive handler error is durablereturn the same failure
use std::sync::Arc;
use runifold::{
    EffectExecutor, EffectRecoveryPolicy, InMemoryEffectStore,
};
 
let executor = EffectExecutor::new(Arc::new(InMemoryEffectStore::new()));
let outcome = executor
    .execute(
        effect_request,
        &run,
        &handler,
        EffectRecoveryPolicy::RejectAmbiguous,
    )
    .await?;

Use a durable EffectStore when recovery must survive process restart. The in-memory store is appropriate only for tests and process-local behavior.

Recovery policy

RejectAmbiguous is the default. It refuses to repeat a Started operation whose result is unknown.

RetrySafe still retries only when the request contract proves it safe:

  • Pure and ReadOnly operations;
  • IdempotentWrite with a stable idempotency key.

It never turns a non-idempotent write into a safe operation. An idempotency key must identify the same logical request at the destination, not merely a fresh retry attempt.

Agent tools and effects

Tool descriptors declare effect and risk. The Agent uses those semantics when coordinating callable execution. Completed calls can be replayed from a shared effect store; a different request at the same execution position is rejected instead of receiving the wrong cached result.

Inject a durable shared executor when an Agent checkpoint may resume in another process. Keep ToolError safe for model visibility and retain detailed operator diagnostics outside the transcript.

Cancellation is not rollback. If cancellation wins while the handler is in flight, the effect remains ambiguous until reconciled.

Production checklist

  • classify every write by actual destination behavior;
  • derive stable idempotency keys from business identity;
  • persist intent before sending the external request;
  • use bounded deadlines but preserve ambiguous state after timeout;
  • keep full effect outputs out of journal events unless explicitly approved;
  • expose a reconciliation queue for ambiguous high-risk effects;
  • fault-test “destination committed, response was lost.”

If you cannot explain how an operation recovers after that last failure, it is not ready for automatic retry.