Loom

Type to search across the guides, specification and decision records.

↑↓ navigate ↵ open esc close Pagefind

Execution kernel for agentic applications

Agents that survive
contact with production.

Loom treats an agentic workflow as a process that unfolds over time, not a request that returns once. Every decision is recorded as an immutable fact — so any execution can be paused for a human, resumed on another machine, replayed bit-for-bit for debugging, forked to explore alternatives, and evaluated against its own history.

Plain TypeScript. No DSL, no YAML, no state machines. Open source on GitHub; not on npm yet, so you build it from source.

A human-in-the-loop flow, in full

No orchestration boilerplate. The gate is one await; its payload contract is declared once and enforced before anything is written to the log.

import { flow$, step$, handler$ } from "@loom/core";
import { z } from "zod";

const assess = step$({
  id: "assess",
  inputSchema: z.object({ table: z.string() }),
  outputSchema: z.object({ risk: z.enum(["low", "high"]) }),
  handler: handler$(async (input) => rateMigration(input.table)),
});

const ApprovalDecision = z.object({ approved: z.boolean(), approvedBy: z.string() });
type ApprovalDecision = z.infer<typeof ApprovalDecision>;

const runner = async (ctx, input) => {
  const { risk } = await ctx.run(assess, { table: input.table });
  if (risk === "low") return apply(input.table);

  // Durable checkpoint. The process can restart, redeploy, move machines —
  // when the approval arrives, execution resumes from exactly here.
  const decision = await ctx.suspend<ApprovalDecision>({
    on: "ApprovalGranted",
    correlationKey: input.table,
  });

  return decision.approved ? apply(input.table) : { applied: false };
};

export const migrationGuard = flow$({
  id: "migration-guard",
  version: "1.0.0",
  steps: [assess],
  // Parsed BEFORE the event is appended, so a malformed approval is refused
  // rather than becoming a permanent part of the log.
  resumeSchemas: { ApprovalGranted: ApprovalDecision },
});

Durable by default

Every step and decision is an immutable fact in an append-only log. State is fold(events) — never a mutable blob you hope stayed in sync.

Suspend for a human

One line parks an execution durably. It survives restarts, redeploys and machine moves, then resumes at exactly the same point — no state machine, no queue.

Replay, bit-for-bit

Re-fold any log and get identical state. Completed steps are served from the log, so effects never run twice. Debugging is time travel, not guesswork.

Fork and explore

Branch an execution at a checkpoint, simulate several strategies in parallel, promote the winner. Git-style branching for running processes.

Plain TypeScript

Flows read like async functions because they are. The intelligence is yours to write; Loom supplies the durable spine underneath it.

Pluggable everything

Storage, compute, LLM providers, protocols and renderers sit behind versioned SPIs with conformance kits. First- and third-party plugins wire identically.

~1.1M
transient calls/sec
per process, measured
~5.7K
durable exec/sec
1-step flow, measured
147
decision records
every trade-off written down
0
kernel hooks for plugins
existing seams only

Numbers are measured on committed benchmarks, not estimated — see the methodology and what they do not mean.

Start with a running flow in five minutes

Scaffold an app, run it headless, suspend it for approval, resume it, then replay the log and watch it reproduce exactly.