Packages
@loop-engine/core
@loop-engine/core defines the type contract used by every other @loop-engine/* package and ships no runtime implementations.
Install
1npm install @loop-engine/coreOverview
Core provides branded identifiers, actor and guard primitives, and canonical loop lifecycle interfaces. Runtime, DSL, adapters, and SDK layers all import these contracts.
Branded IDs
1export type LoopId = string & { readonly __brand: "LoopId" }2export type StateId = string & { readonly __brand: "StateId" }3export type TransitionId = string & { readonly __brand: "TransitionId" }4export type AggregateId = string & { readonly __brand: "AggregateId" }5export type ActorId = string & { readonly __brand: "ActorId" }6export type GuardId = string & { readonly __brand: "GuardId" }7export type SignalId = string & { readonly __brand: "SignalId" }8export type OutcomeId = string & { readonly __brand: "OutcomeId" }9export type CorrelationId = string & { readonly __brand: "CorrelationId" }Helper constructors cast incoming strings to branded IDs:
1import { aggregateId, transitionId } from "@loop-engine/core"2 3const aggregate = aggregateId("EXP-2026-001")4const transition = transitionId("approve")Loop definition types
1export type ActorType = "human" | "automation" | "ai-agent" | "system"2export type LoopStatus =3 | "pending"4 | "active"5 | "completed"6 | "failed"7 | "cancelled"8 | "suspended"9 10export interface GuardSpec {11 id: GuardId12 description: string13 failureMessage: string14 severity: "hard" | "soft"15 evaluatedBy: "runtime" | "module" | "external"16}17 18export interface StateSpec {19 id: StateId20 description?: string21 isTerminal?: boolean22 isError?: boolean23}24 25export interface TransitionSpec {26 id: TransitionId27 from: StateId28 to: StateId29 allowedActors: ActorType[]30 guards?: GuardSpec[]31 sideEffects?: SideEffectSpec[]32 description?: string33}34 35export interface LoopDefinition {36 id: LoopId37 version: string38 description: string39 domain: string40 states: StateSpec[]41 initialState: StateId42 transitions: TransitionSpec[]43 outcome: OutcomeSpec44 participants?: string[]45 spawnableLoops?: LoopId[]46 metadata?: Record<string, unknown>47}Runtime state types
1export interface ActorRef {2 id: ActorId3 type: ActorType4 displayName?: string5 metadata?: Record<string, unknown>6}7 8export interface LoopInstance {9 loopId: LoopId10 aggregateId: AggregateId11 currentState: StateId12 status: LoopStatus13 startedAt: string14 updatedAt: string15 correlationId?: string16 completedAt?: string17 metadata?: Record<string, unknown>18}19 20export interface TransitionRecord {21 aggregateId: AggregateId22 loopId: LoopId23 transitionId: TransitionId24 signal: SignalId25 fromState: StateId26 toState: StateId27 actor: ActorRef28 occurredAt: string29 evidence?: Record<string, unknown>30}Signal and outcome types
1export interface OutcomeSpec {2 id: OutcomeId3 description: string4 valueUnit: string5 measurable: boolean6 businessMetrics?: BusinessMetric[]7}8 9export interface Signal {10 id: SignalId11 type: string12 subject: string13 confidence?: number14 observedAt: string15 payload: Record<string, unknown>16 triggeredLoopId?: LoopId17}Design principles
- Type-first boundaries keep packages interoperable without runtime coupling.
- Zero runtime dependencies keep
coresafe for shared libraries and edge bundles. - Branded IDs reduce accidental string mixing across loop, actor, transition, and signal contexts.