Skip to content

footprintjs

TypeScript workflow engine that records each run's stages, state changes and decision evidence, so AI agents and people can explain and debug what happened.
import { flowChart, decide, narrative } from 'footprintjs';
// 1. Define your input and your state
interface OrderInput {
orderId: string;
total: number;
}
interface OrderState {
tier?: string;
status?: string;
}
// 2. Build your flowchart
const chart = flowChart<OrderState>('Validate', async (scope) => {
const { total } = scope.$getArgs<OrderInput>(); // run input arrives as args
scope.tier = total > 100 ? 'premium' : 'standard';
}, 'validate')
.addDeciderFunction('Route', (scope) => {
return decide(scope, [
{ when: { tier: { eq: 'premium' } }, then: 'express', label: 'Premium order' },
], 'standard');
}, 'route')
.addFunctionBranch('express', 'ExpressShip', async (scope) => {
scope.status = 'express-shipping';
})
.addFunctionBranch('standard', 'StandardShip', async (scope) => {
scope.status = 'standard-shipping';
})
.setDefault('standard')
.end()
.build();
// 3. Run and observe
const rec = narrative();
await chart.recorder(rec).run({ input: { orderId: 'ORD-001', total: 149 } });
console.log(rec.getEntries().map((e) => e.text).join('\n'));
// Stage 1: The process began with Validate.
// Step 1: Write tier = "premium"
// Stage 2: Next, it moved on to Route.
// Step 1: Read tier = "premium"
// [Condition]: It evaluated Rule 0 "Premium order": tier "premium" eq "premium" ✓, and chose ExpressShip.
// Stage 3: Next, it moved on to ExpressShip.
// Step 1: Write status = "express-shipping"