Loop Engine

Packages

@loop-engine/sdk

@loop-engine/sdk is the fastest way to define loops, create a runtime, and wire guards, events, and optional signals.

Install

1npm install @loop-engine/sdk

Re-export surface

Source-verified exports include:

  • LoopBuilder
  • createLoopSystem and createLoopEngine
  • guardRegistry and createSignalEngine
  • InMemoryEventBus
  • computeMetrics and buildTimeline
  • localRegistry and httpRegistry
  • core types: LoopDefinition, LoopInstance, TransitionRecord, Signal

createLoopSystem

1createLoopSystem(options: {
2 loops: LoopDefinition[]
3 store?: LoopStore
4 guards?: GuardRegistry
5 signals?: boolean
6 registry?: LoopRegistry
7}): Promise<{
8 engine: LoopEngine
9 signals?: SignalEngine
10 eventBus: InMemoryEventBus
11}>

Behavior from source:

  • store defaults to memoryStore()
  • guards defaults to guardRegistry
  • signals: true adds a SignalEngine
  • registry is additive; local loops[] win on ID conflicts
  • registry load failures log a warning and fall back to local loops
1import { aggregateId, transitionId } from "@loop-engine/core"
2import { LoopBuilder, createLoopSystem } from "@loop-engine/sdk"
3 
4const loop = LoopBuilder
5 .create("expense.approval", "finance")
6 .state("SUBMITTED")
7 .state("APPROVED", { isTerminal: true })
8 .state("REJECTED", { isTerminal: true })
9 .initialState("SUBMITTED")
10 .transition({ id: "approve", from: "SUBMITTED", to: "APPROVED", actors: ["human"] })
11 .transition({ id: "reject", from: "SUBMITTED", to: "REJECTED", actors: ["human"] })
12 .outcome({ id: "expense_approved", description: "Expense approved", valueUnit: "expense_approved" })
13 .build()
14 
15const { engine, eventBus } = await createLoopSystem({ loops: [loop] })
16 
17eventBus.subscribe(async (event) => {
18 if (event.type === "loop.transition.executed") {
19 console.log(event.transitionId)
20 }
21})
22 
23await engine.start({
24 loopId: "expense.approval",
25 aggregateId: aggregateId("EXP-1"),
26 orgId: "acme",
27 actor: { type: "system", id: "system:intake" }
28})
29 
30await engine.transition({
31 aggregateId: aggregateId("EXP-1"),
32 transitionId: transitionId("approve"),
33 actor: { type: "human", id: "manager@acme.com" },
34 evidence: { approved: true }
35})

Direct imports

1import {
2 LoopBuilder,
3 createLoopSystem,
4 createLoopEngine,
5 InMemoryEventBus,
6 type LoopDefinition
7} from "@loop-engine/sdk"

Package selection

  • Use @loop-engine/sdk for apps, scripts, and most services.
  • Use individual packages for tight bundle control or specialized integrations.