Durable Workflows Over Ephemeral Scripts: Inside Ramp's Laminar Architecture

Back to blog
Mehran Mozaffari·

Why Scripting Runtimes Collapse Under Production Workflows

When teams transition from conversational toy demos to enterprise back-office automation, they almost invariably start with in-process agent loops. The setup is familiar: an async Python while loop that calls an LLM, parses tool parameters, invokes a function, appends the message to an in-memory list, and repeats. For ad-hoc chat, this feels adequate. For mission-critical enterprise workflows like automated month-end accounting close or multi-day invoice reconciliation, treating an agent as an ephemeral script is architectural suicide.

Production workflows break the request-reply model across three core axes:

  1. Survival Across Operational Faults: A month-end close job routinely runs for hours, traversing ledger reconciliations, parsing banking feeds, and processing hundreds of invoices. If the underlying Kubernetes pod gets evicted, suffers an out-of-memory crash, or undergoes a rolling deployment, an in-process agent vanishes. Unless you have meticulously engineered distributed checkpointing at every step, the in-flight context and partial execution state evaporate.
  2. Asynchronous Human Interventions: High-stakes financial operations cannot run fully autonomous end-to-end. They inevitably pause for human approvals—such as an accountant signing off on an unusual journal entry adjustment. When an agent must sleep for eighteen hours awaiting an external approval, holding an active HTTP connection or an open Python execution thread is an anti-pattern. The workflow must suspend completely, release all compute resources, and rehydrate cleanly when the approval arrives.
  3. Mid-Flight Steering Without Deadlocks: If an operator notices an agent heading down a hallucinated rabbit hole, synchronous loops force an ugly dilemma: kill the entire process and start over, or let it complete its wasted run. Production agents demand the ability to queue steering instructions and user corrections into an active generation loop without race conditions or memory deadlocks.

This operational reality explains why Ramp abandoned standard scripting harnesses when building Laminar. Treating an agent loop as a transient script conflates orchestration with execution. As I explored when evaluating Why I Stopped Building Separate Stacks for Chat and Background Agents: The Durable Rails Architecture, reliable agents cannot be built as stateless wrappers around model APIs. They require durable execution engines where state transitions, suspension, and retries are first-class distributed systems primitives.

The Core Triad: State Durability via Temporal, Postgres, and S3

To solve state fragility, Ramp structured Laminar around three decoupled storage layers: Temporal, Postgres, and S3. Rather than forcing a single database to handle workflow orchestration, relational queries, and massive prompt transcripts, Laminar assigns distinct operational responsibilities to each primitive.

Screenshot of https://builders.ramp.com/post/building-laminar
Ramp's technical deep dive into Laminar's architecture and decoupled state primitives

sequenceDiagram
    autonumber
    actor User
    participant API as Laminar API
    participant PG as Postgres (Metadata)
    participant S3 as S3 (Context Store)
    participant WF as Temporal Workflow
    participant Worker as Worker Activity (LLM / Tool)

    User->>API: Submit task / prompt
    API->>PG: Record session state & metadata
    API->>S3: Persist full context & payload snapshot
    API->>WF: Start or trigger workflow execution
    activate WF
    WF->>Worker: Schedule LLM Activity (with context pointer)
    activate Worker
    Worker->>S3: Fetch context snapshot
    Worker->>Worker: Execute LLM inference
    Worker-->>WF: Return model response & tool call intent
    deactivate Worker
    WF->>PG: Update step status & token metrics
    WF->>Worker: Schedule Tool Execution Activity
    activate Worker
    Worker->>Worker: Execute tool action
    Worker->>S3: Append tool output to context payload
    Worker-->>WF: Return execution status
    deactivate Worker
    WF->>API: Stream intermediate output
    API-->>User: Render real-time update
    deactivate WF

Here is how the triad partitions responsibility:

  • Temporal (Execution History & Determinism): Temporal coordinates the resilient execution loop. The agent session is modeled as an indestructible workflow. Crucially, strict discipline must be maintained: never place LLM API calls or tool executions directly inside the Temporal workflow definition. Temporal workflows require pure determinism for event replay. Because LLM generation is inherently non-deterministic and external APIs can fail, all network I/O, model inference, and tool executions must execute inside isolated Temporal Activities. The workflow orchestrates activity scheduling, timer waits, and external approvals.
  • Postgres (Relational Session Tracking): Postgres maintains indexed relational state: user session mappings, organization scopes, run statuses, token usage metrics, and audit checkpoints. This allows frontend queries, dashboard reporting, and administrative overrides without burdening Temporal’s internal state store.
  • S3 (Context Payloads & Compaction): Temporal event histories have strict size constraints (typically recommended under 10,000 events or 50MB). Storing multi-turn conversation histories, massive JSON schemas, and large ledger data directly within Temporal workflow history triggers rapid performance degradation and replay timeouts. Laminar offloads raw transcripts, document snapshots, and compaction artifacts to S3, passing lightweight object pointers between Temporal activities.

This separation prevents workflow history bloat while preserving deterministic replay safety across multi-day lifecycles.

Taming Context Bloat: The 3-Tier MCP Tool Catalog

The naive pattern in modern agent development is to dump dozens of complete JSON schemas into the prompt's system context. While this works when an agent possesses three tools, it collapses in an enterprise setting like Ramp, where an agent might interface with hundreds of internal microservices, bank connectors, and ERP endpoints. Passing hundreds of tool definitions floods the context window, consumes thousands of input tokens on every turn, and severely degrades the model’s reasoning precision.

To overcome this, Laminar implements a deferred discovery pipeline structured around the Model Context Protocol (MCP), breaking tool binding into three distinct tiers: Catalog, Search, and Dispatch.

flowchart TD
    Start["Agent Execution Turn"] --> QueryGen["Agent Generates Semantic Tool Query"]
    QueryGen --> Search["MCP Catalog Search (Lexical & Vector Filter)"]
    Catalog[("MCP Catalog Registry")] --> Search
    Search --> Filter["Top-K Candidate Schemas Extracted"]
    Filter --> Inject["Dynamic Schema Injection into Turn Context"]
    Inject --> LLM["LLM Generates Tool Call Arguments"]
    LLM --> Dispatch["Safe Dispatch (Schema Validation & Sandbox Execution)"]
    Dispatch --> Result["Tool Result Appended to History"]
  1. Catalog: A centralized registry of all available internal tools exposed via standard MCP endpoints. Each tool includes strict parameter typing and comprehensive semantic descriptions.
  2. Search: The agent prompt does not contain all tool definitions. Instead, the model is equipped with a meta-tool: a tool search interface. When the model determines it needs external data or execution capabilities, it generates a semantic search query against the catalog. The platform retrieves only the top-K relevant tool schemas.
  3. Dispatch: The selected tool definitions are dynamically injected into the immediate prompt context for the next step. Once the model outputs structured arguments, Laminar executes the call through a validated dispatch pipeline enforcing authorization scopes and safety policies.

While this pattern keeps the prompt context lean, it introduces two non-trivial production trade-offs that I monitor closely in deferred systems:

First, semantic discovery brittleness. The discovery step is only as reliable as the alignment between the model's generated search query and the catalog's metadata. If an agent queries for "reconcile balance" but the catalog exposes fetch_ledger_journal_entries, lexical retrieval misses, and vector embeddings can fail to bridge the semantic gap. When this happens, the agent hallucinates a missing tool or fails silently.

Second, latency compounding. Every novel tool call transforms into a multi-hop execution: generating the query, searching the catalog, injecting the schema, running the model again to populate arguments, and finally executing the dispatch. For streaming, user-facing interactions, doubling the roundtrip overhead can turn a snappy interface sluggish. Deferred discovery is an indispensable architecture for scale, but it demands meticulous metadata governance and aggressive client-side caching to remain viable in production.

Sandbox-as-a-Tool: Decoupling Compute from Session State

A common trap in early agent architecture is conflating the agent's session lifecycle with the compute environment that runs its code. Teams spin up a stateful virtual machine or dedicated container for a user session, let the agent execute shell commands directly inside it, and keep that environment alive for the duration of the task.

In enterprise environments, this pattern creates three major headaches:

  1. State and VM Drift: Long-lived execution environments accumulate dirty file systems, orphan processes, and conflicting package installations across successive turns. When an execution fails, debugging whether the fault stemmed from model logic or residual container state becomes nearly impossible.
  2. Security Blast Radius: Housing an agent session inside a persistent VM with long-lived network access to internal services means any prompt injection or rogue script execution exposes surrounding VPC infrastructure.
  3. Idle Infrastructure Costs: If an agent session spans days while awaiting human input or background batch jobs, keeping dedicated microVMs or containers warm burns cloud budget on compute that sits idle 99% of the time.

Laminar sidesteps this by treating compute strictly as an on-demand utility: "Sandbox-as-a-Tool." The agent's session state lives durably in Postgres, S3, and Temporal, entirely decoupled from execution runtimes. When an agent needs to evaluate an accounting script, parse a spreadsheet, or run arbitrary Python code, the harness provisions a disposable, isolated cloud sandbox, executes the payload with strict egress controls, captures stdout and return values, and tears the environment down.

┌────────────────────────────────────────────────────────┐
│                   Laminar Control Plane                │
│             (Temporal + Postgres + S3 State)           │
└───────────────────────────┬────────────────────────────┘
                            │ On-demand tool dispatch
                            ▼
┌────────────────────────────────────────────────────────┐
│             Ephemeral Cloud Sandbox (MicroVM)          │
│  • Fresh execution context  • Strict egress isolation   │
│  • Syncs output back to S3  • Immediate teardown       │
└────────────────────────────────────────────────────────┘

The engineering challenge this introduces—and one I regularly encounter when analyzing patterns like Durable AI Coding in Ephemeral Sandboxes: Dissecting Vercel Labs' durable-harness—is transient file system evaporation. In multi-turn accounting reconciliation, an agent might output an intermediate reconciliation artifact or formatted ledger cache in turn one, expecting that file to persist for turn two. If the container vanishes after the tool invocation finishes, the next sandbox starts completely blank.

To make disposable sandboxes viable for multi-step reasoning, your platform must treat disk state as an explicit persistence layer. Every tool completion must serialize modified directory diffs or generated output artifacts back to S3 or an attached snapshot volume before the container terminates, allowing the subsequent sandbox instance to rehydrate working directory state deterministically.

Architectural Archetypes: Durable Control Planes vs. In-Process Orchestrators

Looking across the agent landscape, implementations generally fall into four distinct architectural archetypes: provider-managed platforms, in-process graph runtimes, event-driven task orchestrators, and durable control planes like Laminar.

Low Control / Ephemeral                                       High Control / Durable
◄──────────────────────────────────────────────────────────────────────────────────►
OpenAI Assistants          LangGraph                    Inngest / Hatchet          Laminar
(Provider Managed)         (In-Process Graph Runtime)   (Event-Driven Engine)      (Durable Control Plane)

Provider-hosted platforms like the OpenAI Assistants API deliver the fastest zero-to-one velocity, but they hide persistence inside a black box. You cannot inspect intermediate checkpoint memory, you are constrained to static function registries that crowd context, and code execution is restricted to proprietary environments. Most critically, steering an in-flight run requires aborting it entirely, throwing away partial progress.

Frameworks like LangGraph move orchestration back into your codebase, using state graphs that checkpoint after each step into Postgres or Redis. For linear tasks or short conversational loops, this scripting-first pattern works well. However, because execution remains fundamentally in-process, surviving Kubernetes pod evictions or worker crashes mid-inference requires heavy custom plumbing. Furthermore, pauses for external human reviews typically lock execution between graph nodes rather than supporting asynchronous, non-blocking suspension natively.

Event-driven engines like Inngest or Hatchet, alongside durable workflow engines like Temporal, represent the architecture I favor for production back-office automation. Here, the agent loop is decomposed into deterministic workflows and isolated worker activities. Mid-flight steering does not require killing active tasks; external inputs queue directly into the workflow, allowing human corrections to update execution state without race conditions.

Architectural Dimension Laminar (Ramp Internal) LangGraph OpenAI Assistants API Inngest
State Persistence Deterministic Event History: Temporal replay across worker crashes; context payloads offloaded to S3. External Checkpointing: Snapshots state dicts to Postgres/Redis between graph node executions. Managed Thread IDs: Opaque, provider-hosted storage; closed to direct state inspection or custom replay. Step Durability: Event-driven step memoization and automatic step retries via background queues.
Tool Context Management 3-Tier Deferred Discovery: MCP Catalog + dynamic semantic search + schema dispatch. Static Schemas: Injects full tool definitions into system prompts on every execution turn. Static Function Specs: Configured per assistant; scales linearly against context limits. User-Defined: Requires manual implementation of retrieval patterns over function definitions.
Sandboxing & Compute Decoupled Sandbox-as-a-Tool: Ephemeral, disposable cloud microVMs spun up via tool dispatch. In-Process / Fixed Container: Executes in application host process or attached local Docker instances. Hosted Code Interpreter: Proprietary, provider-managed sandboxes with restricted network access. API Integrations: Dispatches execution steps out to third-party container runtimes (e.g., E2B, Modal).
Mid-Flight Steering Queued Workflow Inputs: Asynchronously steers running loops without tearing down execution state. Node-Level Interrupts: Execution pauses between discrete graph steps; rigid mid-generation control. Run Cancellation: Active runs must be explicitly cancelled and recreated, dropping in-flight context. Event Routing: Workflows listen for incoming events to update execution state asynchronously.
Enterprise Auth & Integrations Central Connectors Service: Unified token refresh, delegated scopes, and centralized audit trails. Per-Invocation Config: Credentials managed via environment variables or custom request context. Console OAuth: Third-party actions configured via provider dashboards with static access tokens. Step-Level Secrets: Secrets injected into individual step execution functions.

The trade-off is the operational tax. Running a platform like Laminar means maintaining Temporal infrastructure, managing event history limits, and strictly separating non-deterministic LLM activities from deterministic workflow definitions. For a team building a basic customer-support chatbot, that distributed systems footprint is overkill. But for mission-critical enterprise tasks that touch banking rails, reconcile ledgers, and require multi-day human approval gates, a durable control plane is the only architecture that genuinely holds up.

The Operational Tax: Replay Poisoning, Token Expiry, and Race Conditions

Adopting a durable control plane is not a free lunch. Replacing in-memory loops with Temporal eliminates state fragility, but it introduces distributed systems failure modes that can blindside an unprepared team.

Temporal workflow history hits hard operational ceilings at 50,000 events
Temporal workflow history hits hard operational ceilings at 50,000 events

The most insidious trap is workflow replay non-determinism. Temporal reconstructs workflow state by replaying execution histories against your application code. In standard backend services, business logic rarely changes mid-execution. Agent code, however, is volatile: prompt templates evolve, system instructions undergo prompt engineering, and parsing branches shift. If an engineer modifies workflow-level orchestration logic without wrapping changes in strict versioning checks (workflow.GetVersion), active long-running sessions poison their replay histories. The replayed events diverge from the new code path, throwing non-deterministic assertion panics and bricking in-flight agent sessions.

stateDiagram-v2
    [*] --> ActiveExecution
    ActiveExecution --> SuspendedWaiting: Requires Human Approval
    ActiveExecution --> CompactingState: Event Count Exceeds Threshold
    
    CompactingState --> ActiveExecution: ContinueAsNew Replay Safe
    
    SuspendedWaiting --> TokenRefresh: Human Approval Received
    SuspendedWaiting --> InterruptHandling: Interrupt Event Received
    SuspendedWaiting --> TimedOut: Approval Timeout
    
    TokenRefresh --> ActiveExecution: Token Validated & Activity Resumed
    InterruptHandling --> ActiveExecution: Context Updated & Plan Adjusted
    TimedOut --> [*]

Compounding this is history bloat. Recursive reasoning and iterative tool loops generate enormous event counts. Temporal recommends keeping workflow histories under 10,000 events (with hard ceilings at 50,000 events or 50MB). An agent caught in an unconstrained retry loop will exceed these thresholds, causing worker memory saturation and degraded replay performance. Durable agent workflows must implement defensive compaction routines using ContinueAsNew, rolling compressed context snapshots and S3 pointers into a fresh execution thread before event limits hit.

Equally perilous are mid-flight race conditions against mutating actions. When an operator injects an interrupt event while an agent is executing, the workflow cannot magically undo side effects. If an LLM Activity has already dispatched an irreversible tool—such as an automated payment execution or ledger adjustment—an incoming user interrupt cannot recall the worker request. Unless mutating tools are guarded behind strict confirmation gates and idempotent transactional boundaries, mid-flight interrupts introduce inconsistent state.

Finally, long-duration human pauses expose connector token decay. When an agent sleeps for days awaiting financial sign-off, downstream OAuth credentials stored in the connector layer silently expire. Resuming execution without an automated credential validation and refresh phase guarantees that the very next downstream API call fails abruptly.

Blueprint for Applied Operators: Implementing Durable Harnesses Without Ramp's Scale

You do not need Ramp’s headcount to operationalize durable agent execution. Ramp proved that the winning architectural pattern relies on standard distributed systems primitives rather than proprietary agent runtimes. By combining managed orchestrators, dynamic tool indexing, and on-demand microVMs, a lean team can assemble an enterprise-grade harness in days.

For complex financial workflows, consider building a Durable Invoice Reconciliation Agent with Human Approval Gates. This architecture automates multi-day accounts payable pipelines: parsing batches of invoice PDFs, reconciling line items against ERP records, and suspending execution whenever discrepancies exceed a configurable dollar threshold. You can anchor orchestration on Temporal Cloud or Inngest, track ledger entities in Postgres, offload PDF documents and context snapshots to S3, and expose ERP endpoints via a dedicated MCP connector service. The critical engineering discipline here lies in managing authorization life cycles: enforce proactive token refresh routines to prevent silent OAuth expiration during extended human reviews, and enforce two-phase confirmation barriers so mutating ledger writes cannot fire twice if an external event races with an active worker.

For data-heavy workflows where context budgets are scarce, implement a Deferred-Discovery Code Interpreter with Ephemeral MicroVMs. This pattern enables an analytics agent to interrogate hundreds of internal SQL models and evaluate exploratory Python scripts without cramming entire database schemas into the prompt. The harness pairs an MCP server hosting vector-indexed table definitions with disposable microVM sandboxes like E2B or Modal mounted directly as tools. The failure mode to design against is transient file system evaporation. Because ephemeral containers vanish after tool dispatch, intermediate CSVs or chart artifacts generated in turn one will disappear before turn two unless your dispatch layer explicitly serializes modified directory outputs back to S3 after every execution.

Similarly, an engineering organization can deploy a Resilient Incident Triage and Remediation Dispatcher. This operational agent correlates observability telemetry across monitoring APIs and executes remediation runbooks under active user steering. By pairing a lightweight distributed task queue like Hatchet or Temporal with dynamic tool discovery and client-side streaming event hooks, on-call engineers can inject steering commands mid-investigation. To prevent operational bottlenecks, guard against workflow history bloat: massive raw log dumps must be aggressively summarized and persisted to object storage, triggering ContinueAsNew rollovers before event counts breach orchestrator thresholds.

Resources

Updated 2026-10-19 by Mehran Mozaffari.

Related posts