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/Deployment guide
NEW TO RUNIFOLD?Build the complete mental model in 45 minutes
Deployment guide

Deploy Runifold in a Rust web service

Build a complete Axum API, place credentials and policy at the server boundary, and choose streaming or durable background work.

Practical guide·10 min

Put Runifold behind an application boundary

A web service should own provider credentials, user authentication, admission, Run construction, error mapping, and observability. The browser sends product inputs to your service; it does not call model providers with a long-lived key.

client → authentication → admission → RunContext → Agent → Provider
                                ↘ journal / metrics / traces

Create provider clients and runtimes once during startup. Create a fresh Agent or RunContext for request-specific policy.

Build a complete Axum service

cargo new runifold-api
cd runifold-api
cargo add runifold@0.9.0
cargo add runifold-providers@0.9.0 --features openai
cargo add axum@0.8
cargo add serde@1 --features derive
cargo add tokio@1 --features macros,rt-multi-thread,net

Replace src/main.rs:

use axum::{Json, Router, extract::State, http::StatusCode, routing::post};
use runifold::{ProviderModelExt, ProviderRuntime};
use runifold_providers::openai::OpenAiClient;
use serde::{Deserialize, Serialize};
 
#[derive(Clone)]
struct AppState { runtime: ProviderRuntime }
 
#[derive(Deserialize)]
struct PromptRequest { prompt: String }
 
#[derive(Serialize)]
struct PromptResponse { answer: String }
 
async fn prompt(
    State(state): State<AppState>,
    Json(request): Json<PromptRequest>,
) -> Result<Json<PromptResponse>, (StatusCode, String)> {
    let answer = state.runtime
        .agent("http-assistant")
        .system("Answer precisely and expose uncertainty.")
        .prompt_text(request.prompt)
        .await
        .map_err(|error| (
            StatusCode::BAD_GATEWAY,
            format!("model request failed: {error}"),
        ))?;
 
    Ok(Json(PromptResponse { answer }))
}
 
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let runtime = OpenAiClient::from_api_key(
        std::env::var("OPENAI_API_KEY")?
    )?.runtime("gpt-5")?;
 
    let app = Router::new()
        .route("/prompt", post(prompt))
        .with_state(AppState { runtime });
    let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?;
 
    axum::serve(listener, app).await?;
    Ok(())
}

Set OPENAI_API_KEY, run cargo run, then send a JSON request to POST /prompt. This complete service is compiled in documentation CI.

Add request policy before exposure

The minimal service proves integration, not production safety. Add:

  • authenticated tenant and actor identity;
  • input and body-size limits;
  • per-tenant admission and concurrency limits;
  • an explicit RunContext with token, turn, Tool, and wall-time budgets;
  • capability grants derived from authorization, never request JSON;
  • cancellation when the client disconnects;
  • stable public error codes without leaking provider bodies.

Use RunContext, budgets, and capability security for the request envelope.

Choose streaming or background work

Use SSE or WebSocket when the user is waiting for incremental output. Preserve terminal success, refusal, usage, and failure semantics instead of flattening the stream to text chunks.

Use a durable Workflow when work must survive process loss, wait for a signal, or continue after the HTTP request ends. Return a task identifier and let a Worker own execution; do not keep an HTTP connection open for hours.

Pass the deployment checklist

Before routing production traffic, verify:

  1. secrets enter only through the deployment environment;
  2. health checks do not call a paid model;
  3. graceful shutdown cancels or hands off active Runs;
  4. retries happen only for errors marked safe;
  5. logs correlate tenant, Run, provider, and model without sensitive content;
  6. latency, error, refusal, budget, and saturation metrics have alerts;
  7. one live smoke request validates the deployed network path.