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/sdkRe-export surface
Source-verified exports include:
LoopBuildercreateLoopSystem(auto-wired aggregate; the runtime factorycreateLoopEnginelives in@loop-engine/runtime)guardRegistryandcreateSignalEngineInMemoryEventBuscomputeMetricsandbuildTimelinelocalRegistryandhttpRegistry- core types:
LoopDefinition,LoopInstance,TransitionRecord,Signal createAIActorfor provider-switched AI actor creation
createAIActor
createAIActor() gives a single SDK entrypoint for anthropic, openai, gemini, and grok.
Switching providers is a config change only:
1import { createAIActor } from "@loop-engine/sdk"2 3const actor = createAIActor({4 provider: "gemini",5 model: "gemini-1.5-pro",6 apiKey: process.env.GOOGLE_AI_API_KEY ?? ""7})If the underlying provider SDK is missing, it throws a targeted install command. Power users can still import individual adapter packages for custom client wiring.
createLoopSystem
1createLoopSystem(options: {2 loops: LoopDefinition[]3 store?: LoopStore4 guards?: GuardRegistry5 signals?: boolean6 registry?: LoopRegistry7}): Promise<{8 engine: LoopEngine9 signals?: SignalEngine10 eventBus: InMemoryEventBus11}>Behavior from source:
storedefaults tomemoryStore()guardsdefaults toguardRegistrysignals: trueadds aSignalEngineregistry(loop catalog client, typeLoopRegistry) is additive; localloops[]win on ID conflicts- catalog 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 = LoopBuilder5 .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})