Getting Started
Quick Start
Install the OSS governance runtime locally, define a decision loop, and run a governed transition in minutes. For vocabulary (Providers, Channels, Integrations, guards, evidence), read Runtime Taxonomy first — or continue here and return to Architecture for the full runtime model. For self-host direction vs hosted Cloud (and roadmap-only services), see Runtime Platform Direction.
Prerequisites
Node.js 18+ and npm or pnpm.
Install
1npm install @loop-engine/sdkDefine a loop and run it
1"cmt">// @no-typecheck2import { aggregateId, transitionId } from '@loop-engine/core'3import { LoopBuilder, createLoopSystem } from '@loop-engine/sdk'4 5const approval = LoopBuilder6 .create('expense.approval', 'finance')7 .description('Expense report approval')8 .state('SUBMITTED')9 .state('UNDER_REVIEW')10 .state('APPROVED', { isTerminal: true })11 .state('REJECTED', { isTerminal: true })12 .initialState('SUBMITTED')13 .transition({14 id: 'start_review',15 from: 'SUBMITTED',16 to: 'UNDER_REVIEW',17 actors: ['automation']18 })19 .transition({20 id: 'approve',21 from: 'UNDER_REVIEW',22 to: 'APPROVED',23 actors: ['human']24 })25 .transition({26 id: 'reject',27 from: 'UNDER_REVIEW',28 to: 'REJECTED',29 actors: ['human']30 })31 .outcome({32 id: 'expense_approved',33 description: 'Expense report approved',34 valueUnit: 'expense_approved',35 businessMetrics: [36 { id: 'm_expense_approved', label: 'Expense report approved', unit: 'count' }37 ]38 })39 .build()40 41const { engine, eventBus } = await createLoopSystem({ loops: [approval] })42eventBus.subscribe(async (event) => console.log(event.type))43 44await engine.start({45 loopId: 'expense.approval',46 aggregateId: aggregateId('EXP-2026-001'),47 actor: { type: 'automation', id: 'system:intake', serviceId: 'intake' }48})49 50await engine.transition({51 aggregateId: aggregateId('EXP-2026-001'),52 transitionId: transitionId('start_review'),53 actor: { type: 'automation', id: 'system:router', serviceId: 'router' }54})55 56await engine.transition({57 aggregateId: aggregateId('EXP-2026-001'),58 transitionId: transitionId('approve'),59 actor: { type: 'human', id: 'manager@acme.com', userId: 'manager-1', displayName: 'Manager' },60 evidence: { comment: 'Approved for Q1 budget' }61})62 63const state = await engine.getState(aggregateId('EXP-2026-001'))64console.log(state?.currentState) "cmt">// APPROVED65console.log(state?.status) "cmt">// completed