footprintjs 0.10.2 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/README.md +80 -503
  2. package/dist/esm/lib/builder/FlowChartBuilder.js +18 -11
  3. package/dist/esm/lib/builder/index.js +1 -1
  4. package/dist/esm/lib/builder/types.js +7 -4
  5. package/dist/esm/lib/engine/graph/StageNode.js +1 -1
  6. package/dist/esm/lib/engine/handlers/ChildrenExecutor.js +6 -2
  7. package/dist/esm/lib/engine/handlers/ExtractorRunner.js +3 -4
  8. package/dist/esm/lib/engine/handlers/RuntimeStructureManager.js +3 -3
  9. package/dist/esm/lib/engine/handlers/SelectorHandler.js +6 -2
  10. package/dist/esm/lib/engine/handlers/SubflowExecutor.js +9 -6
  11. package/dist/esm/lib/engine/traversal/FlowchartTraverser.js +46 -23
  12. package/dist/esm/types/lib/builder/FlowChartBuilder.d.ts +1 -0
  13. package/dist/esm/types/lib/builder/index.d.ts +1 -1
  14. package/dist/esm/types/lib/builder/types.d.ts +15 -69
  15. package/dist/esm/types/lib/engine/graph/StageNode.d.ts +4 -2
  16. package/dist/esm/types/lib/engine/handlers/ExtractorRunner.d.ts +1 -1
  17. package/dist/lib/builder/FlowChartBuilder.js +18 -11
  18. package/dist/lib/builder/index.js +1 -1
  19. package/dist/lib/builder/types.js +7 -4
  20. package/dist/lib/engine/graph/StageNode.js +1 -1
  21. package/dist/lib/engine/handlers/ChildrenExecutor.js +6 -2
  22. package/dist/lib/engine/handlers/ExtractorRunner.js +3 -4
  23. package/dist/lib/engine/handlers/RuntimeStructureManager.js +3 -3
  24. package/dist/lib/engine/handlers/SelectorHandler.js +6 -2
  25. package/dist/lib/engine/handlers/SubflowExecutor.js +9 -6
  26. package/dist/lib/engine/traversal/FlowchartTraverser.js +46 -23
  27. package/dist/types/lib/builder/FlowChartBuilder.d.ts +1 -0
  28. package/dist/types/lib/builder/index.d.ts +1 -1
  29. package/dist/types/lib/builder/types.d.ts +15 -69
  30. package/dist/types/lib/engine/graph/StageNode.d.ts +4 -2
  31. package/dist/types/lib/engine/handlers/ExtractorRunner.d.ts +1 -1
  32. package/package.json +1 -1
package/README.md CHANGED
@@ -10,581 +10,158 @@
10
10
  <a href="https://www.npmjs.com/package/footprintjs"><img src="https://img.shields.io/npm/v/footprintjs.svg?style=flat" alt="npm version"></a>
11
11
  <a href="https://github.com/footprintjs/footPrint/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License"></a>
12
12
  <a href="https://www.npmjs.com/package/footprintjs"><img src="https://img.shields.io/npm/dm/footprintjs.svg" alt="Downloads"></a>
13
- <a href="https://footprintjs.github.io/footprint-playground/"><img src="https://img.shields.io/badge/Try_it-Interactive_Playground-6366f1?style=flat&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJ3aGl0ZSI+PHBhdGggZD0iTTggNXYxNGwxMS03eiIvPjwvc3ZnPg==" alt="Interactive Playground"></a>
13
+ <a href="https://footprintjs.github.io/footprint-demo/"><img src="https://img.shields.io/badge/Live_Demo-View_App-10b981?style=flat&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJ3aGl0ZSI+PHBhdGggZD0iTTggNXYxNGwxMS03eiIvPjwvc3ZnPg==" alt="Live Demo"></a>
14
+ <a href="https://footprintjs.github.io/footprint-playground/"><img src="https://img.shields.io/badge/Playground-Try_it-6366f1?style=flat&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJ3aGl0ZSI+PHBhdGggZD0iTTggNXYxNGwxMS03eiIvPjwvc3ZnPg==" alt="Interactive Playground"></a>
14
15
  </p>
15
16
 
16
17
  <br>
17
18
 
18
- **MVC is a pattern for structuring backends. FootPrint is a different pattern &mdash; the flowchart pattern &mdash; where your business logic is organized as a graph of functions with transactional state.** The code becomes self-explainable: AI can read the structure, trace every decision, and explain what happened without reconstructing from logs.
19
+ <p align="center">
20
+ <img src="assets/hero.gif" alt="FootPrint demo — loan application with animated flowchart, memory inspector, and causal trace" width="800">
21
+ </p>
19
22
 
20
- > FootPrint is **not** a workflow engine, pipeline builder, or orchestrator. It's a code pattern &mdash; like how React changed how we build UIs, FootPrint changes how we structure backend logic to be AI-native.
23
+ **MVC is a pattern for backends. FootPrint is a different pattern** &mdash; the flowchart pattern &mdash; where your business logic is a graph of functions with transactional state. The code becomes self-explainable: AI reads the structure, traces every decision, and explains what happened &mdash; no hallucination.
21
24
 
22
25
  ```bash
23
26
  npm install footprintjs
24
27
  ```
25
28
 
26
- ## Quick Start
27
-
28
- ```typescript
29
- import { flowChart, FlowChartExecutor } from 'footprintjs';
30
-
31
- const chart = flowChart('Greet', (scope) => {
32
- scope.setValue('name', 'Alice');
33
- })
34
- .addFunction('Personalize', (scope) => {
35
- const name = scope.getValue('name');
36
- scope.setValue('message', `Hello, ${name}!`);
37
- })
38
- .setEnableNarrative()
39
- .build();
40
-
41
- const executor = new FlowChartExecutor(chart);
42
- const result = await executor.run();
43
-
44
- console.log(executor.getNarrative());
45
- // Stage 1: The process began with Greet.
46
- // Step 1: Write name = "Alice"
47
- // Stage 2: Next, it moved on to Personalize.
48
- // Step 1: Read name = "Alice"
49
- // Step 2: Write message = "Hello, Alice!"
50
- ```
51
-
52
- > **[Try it in the browser](https://footprintjs.github.io/footprint-playground/)** &mdash; no install needed
53
- >
54
- > **[Browse 25+ examples](https://github.com/footprintjs/footPrint-samples)** &mdash; features, flowchart patterns, flow recorder strategies, and a full loan underwriting demo
55
-
56
29
  ---
57
30
 
58
- ## Why a new pattern?
59
-
60
- **MVC** separates concerns into Model, View, Controller. It works, but the code is opaque to AI &mdash; an LLM can't trace why a request produced a specific result without parsing scattered logs.
31
+ ## The Problem
61
32
 
62
- **The flowchart pattern** structures the same logic as a graph of named functions with managed state. This gives you two things MVC can't:
63
-
64
- 1. **Self-describing code** &mdash; The structure auto-generates tool descriptions for LLM agents. No hand-written descriptions that drift from reality.
65
- 2. **Self-explaining execution** &mdash; Every run produces a causal trace showing what happened and why. An LLM reads the trace and explains decisions accurately &mdash; no hallucination.
33
+ Your LLM needs to explain why your code made a decision. Without structure, it reconstructs reasoning from scattered logs &mdash; expensive, slow, and hallucinates.
66
34
 
67
35
  | | MVC / Traditional | Flowchart Pattern (FootPrint) |
68
36
  |---|---|---|
69
- | **Code structure** | Controllers with implicit flow | Explicit graph of named functions |
70
37
  | **LLM explains a decision** | Reconstruct from scattered logs | Read the causal trace directly |
71
38
  | **Tool descriptions for agents** | Write and maintain by hand | Auto-generated from the graph |
72
39
  | **State management** | Global/manual, race-prone | Transactional scope with atomic commits |
73
40
  | **Debugging** | `console.log` + guesswork | Time-travel replay to any stage |
74
41
 
75
- ### Example: Loan rejection
42
+ ---
43
+
44
+ ## How It Works
76
45
 
77
- A loan application pipeline rejects Bob. The user asks: **"Why was I rejected?"**
46
+ A loan pipeline rejects Bob. The user asks: **"Why was I rejected?"**
78
47
 
79
- Without FootPrint, the LLM must reconstruct the reasoning from disconnected logs &mdash; expensive, slow, and unreliable. With FootPrint, the runtime produces this trace automatically from what the code actually did:
48
+ The runtime auto-generates this trace from what the code actually did:
80
49
 
81
50
  ```
82
51
  Stage 1: The process began with ReceiveApplication.
83
- Step 1: Write app = {applicantName, annualIncome, monthlyDebts, creditScore, }
52
+ Step 1: Write app = {applicantName, annualIncome, monthlyDebts, creditScore, ...}
84
53
  Stage 2: Next, it moved on to PullCreditReport.
85
- Step 1: Read app = {applicantName, annualIncome, monthlyDebts, creditScore, }
54
+ Step 1: Read app = {applicantName, annualIncome, monthlyDebts, creditScore, ...}
86
55
  Step 2: Write creditTier = "fair"
87
- Step 3: Write creditFlags = (1 item)
88
56
  Stage 3: Next, it moved on to CalculateDTI.
89
- Step 1: Read app = {applicantName, annualIncome, monthlyDebts, creditScore, }
57
+ Step 1: Read app = {applicantName, annualIncome, monthlyDebts, creditScore, ...}
90
58
  Step 2: Write dtiRatio = 0.6
91
- Step 3: Write dtiPercent = 60
92
- Step 4: Write dtiStatus = "excessive"
93
- Step 5: Write dtiFlags = (1 item)
94
- Stage 4: Next, it moved on to VerifyEmployment.
95
- Step 1: Read app = {applicantName, annualIncome, monthlyDebts, creditScore, …}
96
- Step 2: Write employmentVerified = true
97
- Step 3: Write employmentFlags = (1 item)
98
- Stage 5: Next, it moved on to AssessRisk.
59
+ Step 3: Write dtiStatus = "excessive"
60
+ Stage 4: Next, it moved on to AssessRisk.
99
61
  Step 1: Read creditTier = "fair"
100
62
  Step 2: Read dtiStatus = "excessive"
101
- Step 3: Read employmentVerified = true
102
- Step 4: Write riskTier = "high"
103
- Step 5: Write riskFactors = (1 item)
63
+ Step 3: Write riskTier = "high"
104
64
  [Condition]: A decision was made, and the path taken was RejectApplication.
105
65
  ```
106
66
 
107
- The LLM backtracks through the trace: `riskTier="high"` &larr; `dtiStatus="excessive"` &larr; `dtiPercent=60` &larr; `app.monthlyDebts=2100`. Every variable links to its cause. Cheaper model, fewer tokens, no hallucination:
67
+ The LLM backtracks: `riskTier="high"` &larr; `dtiStatus="excessive"` &larr; `dtiRatio=0.6` &larr; `app.monthlyDebts=2100`. Every variable links to its cause:
108
68
 
109
- > **LLM:** "Your application was rejected because your credit score of 580 falls in the 'fair' tier, your debt-to-income ratio of 60% exceeds the 43% maximum, and your self-employment tenure of 1 year is below the 2-year minimum. These factors combined placed you in the 'high' risk tier."
69
+ > **LLM:** "Your application was rejected because your debt-to-income ratio of 60% exceeds the 43% maximum, your credit score of 580 falls in the 'fair' tier, and your self-employment tenure of 1 year is below the 2-year minimum."
110
70
 
111
71
  That answer came from the trace &mdash; not from the LLM's imagination.
112
72
 
113
73
  ---
114
74
 
115
- ## The code that produced it
116
-
117
- This is regular backend code &mdash; just structured as a flowchart instead of a controller. No one wrote those trace sentences. The functions just read and write scope; the pattern produces the narrative automatically:
75
+ ## Quick Start
118
76
 
119
77
  ```typescript
120
- import {
121
- flowChart, FlowChartExecutor, ScopeFacade, toScopeFactory,
122
- } from 'footprintjs';
123
-
124
- // ── Stage functions: just read and write scope ─────────────────────────
125
-
126
- const receiveApplication = (scope: ScopeFacade) => {
127
- scope.setValue('app', {
128
- applicantName: 'Bob',
129
- annualIncome: 42_000,
130
- monthlyDebts: 2_100,
131
- creditScore: 580,
132
- employmentType: 'self-employed',
133
- employmentYears: 1,
134
- });
135
- };
136
-
137
- const pullCreditReport = (scope: ScopeFacade) => {
138
- const { creditScore } = scope.getValue('app') as any;
139
- const tier = creditScore >= 740 ? 'excellent'
140
- : creditScore >= 670 ? 'good'
141
- : creditScore >= 580 ? 'fair' : 'poor';
142
-
143
- scope.setValue('creditTier', tier);
144
- scope.setValue('creditFlags', tier === 'fair' ? ['below-average credit'] : []);
145
- };
146
-
147
- const calculateDTI = (scope: ScopeFacade) => {
148
- const { annualIncome, monthlyDebts } = scope.getValue('app') as any;
149
- const ratio = Math.round((monthlyDebts / (annualIncome / 12)) * 100) / 100;
150
-
151
- scope.setValue('dtiRatio', ratio);
152
- scope.setValue('dtiFlags', ratio > 0.43 ? [`DTI at ${Math.round(ratio * 100)}% exceeds 43%`] : []);
153
- };
154
-
155
- const verifyEmployment = (scope: ScopeFacade) => {
156
- const { employmentType, employmentYears } = scope.getValue('app') as any;
157
- const verified = employmentType !== 'self-employed' || employmentYears >= 2;
158
-
159
- scope.setValue('employmentVerified', verified);
160
- scope.setValue('employmentFlags', !verified
161
- ? [`${employmentType}, ${employmentYears}yr < 2yr minimum`] : []);
162
- };
163
-
164
- const assessRisk = (scope: ScopeFacade) => {
165
- const tier = scope.getValue('creditTier') as string;
166
- const ratio = scope.getValue('dtiRatio') as number;
167
- const verified = scope.getValue('employmentVerified') as boolean;
168
-
169
- scope.setValue('riskTier', (!verified || ratio > 0.43 || tier === 'poor') ? 'high' : 'low');
170
- };
171
-
172
- // Deciders return a branch ID — the only stage that needs a return value
173
- const loanDecider = (scope: ScopeFacade): string => {
174
- const tier = scope.getValue('riskTier') as string;
175
- if (tier === 'low') return 'approved';
176
- if (tier === 'high') return 'rejected';
177
- return 'manual-review';
178
- };
179
-
180
- // ── Build → Run → Narrative (D3-style chaining) ──────────────────────
181
-
182
- const chart = flowChart('ReceiveApplication', receiveApplication)
183
- .setEnableNarrative()
184
- .addFunction('PullCreditReport', pullCreditReport)
185
- .addFunction('CalculateDTI', calculateDTI)
186
- .addFunction('VerifyEmployment', verifyEmployment)
187
- .addFunction('AssessRisk', assessRisk)
188
- .addDeciderFunction('LoanDecision', loanDecider as any)
189
- .addFunctionBranch('approved', 'Approve', () => {})
190
- .addFunctionBranch('rejected', 'Reject', () => {})
191
- .addFunctionBranch('manual-review', 'ManualReview', () => {})
192
- .setDefault('manual-review')
78
+ import { flowChart, FlowChartExecutor, ScopeFacade } from 'footprintjs';
79
+
80
+ const chart = flowChart('FetchUser', (scope: ScopeFacade) => {
81
+ scope.setValue('user', { name: 'Alice', tier: 'premium' });
82
+ }, 'fetch-user')
83
+ .addFunction('ApplyDiscount', (scope: ScopeFacade) => {
84
+ const user = scope.getValue('user') as any;
85
+ const discount = user.tier === 'premium' ? 0.2 : 0.05;
86
+ scope.setValue('discount', discount);
87
+ }, 'apply-discount')
88
+ .addDeciderFunction('Route', (scope: ScopeFacade): string => {
89
+ return (scope.getValue('discount') as number) > 0.1 ? 'vip' : 'standard';
90
+ }, 'route')
91
+ .addFunctionBranch('vip', 'VIPCheckout', (scope: ScopeFacade) => {
92
+ scope.setValue('lane', 'VIP express');
93
+ })
94
+ .addFunctionBranch('standard', 'StandardCheckout', (scope: ScopeFacade) => {
95
+ scope.setValue('lane', 'Standard');
96
+ })
97
+ .setDefault('standard')
193
98
  .end()
99
+ .setEnableNarrative()
194
100
  .build();
195
101
 
196
- const executor = new FlowChartExecutor(chart, toScopeFactory(ScopeFacade));
102
+ const executor = new FlowChartExecutor(chart);
197
103
  await executor.run();
198
104
 
199
- const narrative = executor.getNarrative(); // ← the trace above
200
- ```
201
-
202
- The functions are ordinary TypeScript &mdash; no decorators, no special annotations. The flowchart pattern captures stage transitions, decisions, reads, and writes automatically. That's the difference from MVC: in MVC, this trace doesn't exist. In the flowchart pattern, it's a byproduct of the structure.
203
-
204
- ---
205
-
206
- ## What makes it self-explainable
207
-
208
- The flowchart pattern produces two AI-readable outputs automatically &mdash; no extra code needed:
209
-
210
- ### Build-time: tool description for LLM agents
211
-
212
- When you call `.build()`, the structure auto-generates `chart.description` &mdash; a complete description of what the code does:
213
-
214
- ```
215
- FlowChart: ReceiveApplication
216
- Steps:
217
- 1. ReceiveApplication
218
- 2. PullCreditReport
219
- 3. CalculateDTI
220
- 4. VerifyEmployment
221
- 5. AssessRisk
222
- 6. LoanDecision — Decides between: approved, rejected, manual-review
223
- ```
224
-
225
- Register this as a **tool description**. When an LLM agent has multiple tools to choose from, it can read each tool's description and pick the right one &mdash; without you writing tool descriptions by hand:
226
-
227
- ```typescript
228
- // Each flowchart's auto-generated description becomes the tool description
229
- const tools = [
230
- {
231
- name: 'process-loan',
232
- description: loanChart.description,
233
- // FlowChart: ReceiveApplication
234
- // Steps:
235
- // 1. ReceiveApplication
236
- // 2. PullCreditReport ...
237
- // 6. LoanDecision — Decides between: approved, rejected, manual-review
238
- handler: (input) => runWithChart(loanChart, input),
239
- },
240
- {
241
- name: 'check-fraud',
242
- description: fraudChart.description,
243
- // FlowChart: AnalyzeTransaction
244
- // Steps:
245
- // 1. AnalyzeTransaction
246
- // 2. CheckVelocity
247
- // 3. CheckGeolocation
248
- // 4. FraudDecision — Decides between: allow, block, review
249
- handler: (input) => runWithChart(fraudChart, input),
250
- },
251
- ];
252
-
253
- // The LLM sees exactly what each tool does — enough to pick the right one.
254
- // No manual description writing. The structure IS the description.
255
- ```
256
-
257
- ### Runtime: causal trace for LLM explanation
258
-
259
- After `.run()`, the trace shows what the code *actually did* &mdash; every value read, every value written, every decision made. Ship it alongside the result so any LLM can explain what happened and why.
260
-
261
- **Build-time tells the LLM what the code does. Runtime tells the LLM what the code did.** That's what makes it self-explainable &mdash; the pattern produces both automatically.
262
-
263
- ---
264
-
265
- ## How the pattern works
266
-
267
- The flowchart pattern has three parts &mdash; the same way MVC has Model, View, Controller:
268
-
269
- 1. **Builder** &mdash; Define your business logic as a graph of named functions. Like how a controller defines routes, but the structure is an explicit flowchart.
270
- 2. **Scope** &mdash; Transactional state shared across stages. Writes are buffered and committed atomically. This replaces scattered state management.
271
- 3. **Engine** &mdash; Executes the graph and auto-generates the causal trace. You write functions; the pattern produces the explanation.
272
-
273
- ```
274
- ┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐
275
- │ FlowChartBuilder │─────>│ FlowChart │─────>│ FlowChartExecutor │
276
- │ (Build-time DSL) │ │ (Compiled Tree) │ │ (Runtime Engine) │
277
- └─────────────────────┘ └─────────────────────┘ └─────────────────────┘
278
- │ │ │
279
- │ .start() │ .build() │ .run()
280
- │ .addFunction() │ .description │ .getNarrative()
281
- │ .addDeciderFunction() │ .stageDescriptions │ .getSnapshot()
282
- │ .addSubFlowChart() │ │
283
- └────────────────────────────┴────────────────────────────┘
284
- ```
285
-
286
- ---
287
-
288
- ## Documentation
289
-
290
- | Guide | What it covers |
291
- |-------|---------------|
292
- | **[Patterns](docs/guides/patterns.md)** | All 7 flowchart patterns with diagrams |
293
- | **[Scope](docs/guides/scope.md)** | Typed, raw, and Zod scope; recorders; protection |
294
- | **[Execution Control](docs/guides/execution.md)** | breakFn, cancellation, timeout, fail-fast, loops |
295
- | **[Error Handling](docs/guides/error-handling.md)** | Commit-on-error, debug recorder, post-mortem |
296
- | **[Flow Recorders](docs/guides/flow-recorders.md)** | Pluggable observers for control flow narrative — 7 built-in strategies |
297
- | **[Contracts](docs/guides/contracts.md)** | defineContract, OpenAPI 3.1, Zod vs JSON Schema |
298
- | **[Internals](docs/internals/)** | Architecture deep-dives for each library |
299
-
300
- ---
301
-
302
- ## Patterns
303
-
304
- Seven composition patterns &mdash; linear, parallel, conditional, multi-select, subflow, streaming, and loops:
305
-
306
- ```typescript
307
- // Linear: A → B → C
308
- flowChart('A', fnA).addFunction('B', fnB).addFunction('C', fnC).build();
309
-
310
- // Parallel fork
311
- flowChart('Fetch', fetchFn)
312
- .addListOfFunction([
313
- { id: 'html', name: 'ParseHTML', fn: parseHTML },
314
- { id: 'css', name: 'ParseCSS', fn: parseCSS },
315
- ])
316
- .addFunction('Merge', mergeFn)
317
- .build();
318
-
319
- // Conditional branching (decider)
320
- flowChart('Classify', classifyFn)
321
- .addDeciderFunction('Route', routeFn)
322
- .addFunctionBranch('digital', 'DigitalDelivery', digitalFn)
323
- .addFunctionBranch('physical', 'ShipPackage', shipFn)
324
- .setDefault('physical')
325
- .end()
326
- .build();
327
-
328
- // Subflow composition
329
- flowChart('Router', routerFn)
330
- .addSubFlowChart('faq', faqFlow, 'FAQ Handler')
331
- .addSubFlowChart('rag', ragFlow, 'RAG Handler')
332
- .build();
333
-
334
- // Loops
335
- flowChart('Init', initFn)
336
- .addFunction('Retry', retryFn, 'retry')
337
- .addDeciderFunction('Check', checkFn)
338
- .addFunctionBranch('again', 'Process', processFn)
339
- .addFunctionBranch('done', 'Finish', finishFn)
340
- .end()
341
- .loopTo('retry')
342
- .build();
343
- ```
344
-
345
- **[Full patterns guide &rarr;](docs/guides/patterns.md)** &mdash; all seven patterns with diagrams and composition examples
346
-
347
- ---
348
-
349
- ## Scope
350
-
351
- Each stage receives a **scope** &mdash; a transactional interface to shared state:
352
-
353
- ```typescript
354
- // Typed scope (recommended)
355
- class LoanScope extends ScopeFacade {
356
- get creditScore(): number { return this.getValue('creditScore') as number; }
357
- }
358
-
359
- // Validated scope (Zod)
360
- const scopeFactory = defineScopeFromZod(z.object({
361
- creditScore: z.number(),
362
- riskTier: z.string().optional(),
363
- }));
364
-
365
- // Raw scope
366
- scope.setValue('total', 79.98);
367
- scope.updateValue('config', { retries: 3 });
105
+ console.log(executor.getNarrative());
106
+ // Stage 1: The process began with FetchUser.
107
+ // Step 1: Write user = {name: "Alice", tier: "premium"}
108
+ // Stage 2: Next, it moved on to ApplyDiscount.
109
+ // Step 1: Read user = {name: "Alice", tier: "premium"}
110
+ // Step 2: Write discount = 0.2
111
+ // Stage 3: A decision was made, and the path taken was VIPCheckout.
112
+ // Step 1: Write lane = "VIP express"
368
113
  ```
369
114
 
370
- Pluggable recorders observe every operation: `DebugRecorder`, `MetricRecorder`, `NarrativeRecorder`, or bring your own.
371
-
372
- **[Full scope guide &rarr;](docs/guides/scope.md)** &mdash; typed/raw/Zod scope, recorders, protection, provider system
115
+ > **[Try it in the browser](https://footprintjs.github.io/footprint-playground/)** &mdash; no install needed
116
+ >
117
+ > **[Browse 25+ examples](https://github.com/footprintjs/footPrint-samples)** &mdash; patterns, recorders, and a full loan underwriting demo
373
118
 
374
119
  ---
375
120
 
376
- ## Key Features
121
+ ## Features
377
122
 
378
123
  | Feature | Description |
379
124
  |---------|-------------|
380
125
  | **Causal Traces** | Every read/write captured &mdash; LLMs backtrack through variables to find causes |
381
126
  | **Auto Narrative** | Build-time descriptions for tool selection, runtime traces for explanation |
382
- | **Not a DAG** | Supports loops, re-entry, and partial/resumed execution |
383
- | **Parallel Fan-Out/In** | Fork pattern with automatic result aggregation (optional fail-fast) |
384
- | **Cancellation** | AbortSignal and timeout support for long-running LLM calls |
385
- | **Early Termination** | `breakFn()` stops the pipeline after the current stage |
386
- | **Patch-Based State** | Atomic commits, safe merges, no race conditions |
387
- | **Composable Subflows** | Mount entire flowcharts as nodes in larger workflows |
388
- | **Streaming** | Built-in streaming stages for LLM token emission |
389
- | **PII Redaction** | Per-key `setValue(key, value, true)` or declarative `RedactionPolicy` with exact keys, regex patterns, and field-level scrubbing (dot-notation for nested paths) &mdash; plus `getRedactionReport()` audit trail ([guide](docs/guides/scope.md#redaction-pii-protection)) |
390
- | **Pluggable Recorders** | DebugRecorder, MetricRecorder, NarrativeRecorder &mdash; or bring your own |
391
- | **Flow Recorders** | 7 narrative strategies for loop summarization &mdash; Windowed, Silent, Adaptive, Progressive, Milestone, RLE, Separate &mdash; or build custom ([examples](https://github.com/footprintjs/footPrint-samples/tree/main/examples/flow-recorders)) |
392
-
393
- ---
394
-
395
- ## Execution Control & Error Handling
396
-
397
- Three levels of control: `breakFn()` (graceful stop), `throw` (hard abort), `AbortSignal` (external cancellation):
398
-
399
- ```typescript
400
- // Graceful stop — complete this stage, skip remaining
401
- const validate = async (scope: ScopeFacade, breakFn: () => void) => {
402
- if (scope.getValue('amount') > 50_000) { breakFn(); }
403
- };
404
-
405
- // Timeout / external cancellation
406
- await executor.run({ timeoutMs: 30_000 });
407
- await executor.run({ signal: controller.signal });
408
- ```
409
-
410
- When a stage throws, the engine commits the trace *before* re-throwing &mdash; so `getSnapshot()` captures everything up to the failure point, including partial writes and error metadata.
411
-
412
- **[Execution control guide &rarr;](docs/guides/execution.md)** &mdash; breakFn, cancellation, timeout, fail-fast forks, loops
413
-
414
- **[Error handling guide &rarr;](docs/guides/error-handling.md)** &mdash; commit-on-error, debug recorder, error narrative, post-mortem
415
-
416
- ---
417
-
418
- ## API Reference
419
-
420
- ### Builder
421
-
422
- | Method | Description |
423
- |--------|-------------|
424
- | `start(name, fn?)` | Define root stage |
425
- | `addFunction(name, fn?)` | Add linear next stage |
426
- | `addListOfFunction(specs, opts?)` | Add parallel children (fork). Options: `{ failFast? }` |
427
- | `addDeciderFunction(name, fn)` | Single-choice branching (returns one branch ID) |
428
- | `addSelectorFunction(name, fn)` | Multi-choice branching (returns multiple branch IDs) |
429
- | `addSubFlowChart(id, flow)` | Mount subflow as parallel child |
430
- | `addSubFlowChartNext(id, flow)` | Mount subflow as linear next |
431
- | `addStreamingFunction(name, streamId?, fn?)` | Add streaming stage |
432
- | `addTraversalExtractor(fn)` | Register per-stage data extractor |
433
- | `setEnableNarrative()` | Enable runtime narrative generation |
434
- | `loopTo(stageId)` | Loop back to earlier stage |
435
- | `build()` | Compile to FlowChart |
436
- | `execute(scopeFactory?)` | Build + run (convenience) |
437
- | `toSpec()` | Export pure JSON (no functions) |
438
- | `toMermaid()` | Generate Mermaid diagram |
439
-
440
- ### Executor
441
-
442
- | Method | Description |
443
- |--------|-------------|
444
- | `run(options?)` | Execute the flowchart. Options: `{ signal?, timeoutMs? }` |
445
- | `getNarrative()` | Combined narrative (flow + data) with ScopeFacade; flow-only otherwise |
446
- | `getFlowNarrative()` | Flow-only narrative sentences |
447
- | `attachFlowRecorder(recorder)` | Attach a FlowRecorder for pluggable narrative control |
448
- | `detachFlowRecorder(id)` | Detach a FlowRecorder by id |
449
- | `getNarrativeEntries()` | Structured `CombinedNarrativeEntry[]` for programmatic use |
450
- | `getSnapshot()` | Full execution tree + state |
451
- | `getExtractedResults()` | Extractor results map |
452
- | `getEnrichedResults()` | Enriched snapshots (scope state, debug info, output) |
453
- | `getSubflowResults()` | Nested subflow execution data |
454
- | `getRuntimeStructure()` | Serialized pipeline for visualization |
455
-
456
- ---
457
-
458
- ## How FootPrint Compares
459
-
460
- FootPrint is a **code pattern**, not an orchestrator. It runs in your process, not as a separate service.
461
-
462
- | Aspect | MVC / async-await | FootPrint (flowchart pattern) | Temporal / Step Functions |
463
- |--------|-------------------|-------------------------------|--------------------------|
464
- | **What it is** | Code pattern | Code pattern | External orchestrator |
465
- | **Runs where** | In your process | In your process | Separate service |
466
- | **Control flow** | Implicit in code | Explicit graph of functions | External state machine |
467
- | **State** | Manual / global | Transactional scope | Durable storage |
468
- | **AI explains decisions** | Parse logs (hallucination-prone) | Read the causal trace (accurate) | Parse event history |
469
- | **Tool descriptions** | Write by hand | Auto-generated from structure | Write by hand |
470
- | **Debugging** | Stack traces | Time-travel replay | Event history |
471
- | **Complexity** | Low | Low-medium | High |
472
-
473
- ---
474
-
475
- ## Performance
476
-
477
- Measured on Node v22, Apple Silicon. Run `npm run bench` to reproduce.
478
-
479
- | Benchmark | Time | Detail |
480
- |-----------|------|--------|
481
- | **Write 1K keys** | 811µs | ~1.2M ops/s |
482
- | **Write 10K keys** | 5.4ms | ~1.8M ops/s |
483
- | **Read 100K keys** | 8.7ms | ~11.5M ops/s |
484
- | **10 stages (linear)** | 106µs | 0.011ms/stage |
485
- | **200 stages (linear)** | 4.7ms | 0.023ms/stage |
486
- | **500 stages (linear)** | 20ms | 0.040ms/stage |
487
- | **100 concurrent pipelines** | 2.3ms | 3-stage each |
488
- | **1,000 concurrent pipelines** | 24ms | 3-stage each |
489
- | **structuredClone 1KB** | 2µs | per call |
490
- | **structuredClone 100KB** | 76µs | per call |
491
- | **structuredClone 1MB** | 2.5ms | per call |
492
- | **Time-travel 100 commits** | 75µs | 0.001ms/commit |
493
- | **Time-travel 500 commits** | 385µs | 0.001ms/commit |
494
- | **Commit with 100 writes** | 375µs | single stage |
495
-
496
- **Bottom line:** A 200-stage pipeline completes in under 5ms. The primary cost at scale is `structuredClone` — keep state objects under 100KB per stage for sub-millisecond commit overhead.
497
-
498
- ---
499
-
500
- ## Contract & OpenAPI
501
-
502
- Define I/O schemas (Zod or raw JSON Schema) and auto-generate OpenAPI 3.1 specs:
503
-
504
- ```typescript
505
- import { flowChart, defineContract } from 'footprintjs';
506
- import { z } from 'zod';
507
-
508
- const contract = defineContract(chart, {
509
- inputSchema: z.object({ applicantName: z.string(), creditScore: z.number() }),
510
- outputSchema: z.object({ decision: z.enum(['approved', 'rejected']) }),
511
- });
512
-
513
- const spec = contract.toOpenAPI({ version: '1.0.0', basePath: '/api' });
514
- ```
515
-
516
- Zod is an **optional peer dependency** &mdash; zero bundle impact if not used.
517
-
518
- **[Full contracts guide &rarr;](docs/guides/contracts.md)** &mdash; defineContract, OpenAPI generation, Zod vs JSON Schema, builder-level schemas
519
-
520
- ---
521
-
522
- ## Architecture
523
-
524
- FootPrint is the reference implementation of the flowchart pattern &mdash; six independent libraries, each usable standalone:
525
-
526
- ```
527
- src/lib/
528
- ├── memory/ Transactional state (SharedMemory, StageContext, EventLog, TransactionBuffer)
529
- ├── builder/ Fluent flowchart DSL (FlowChartBuilder, DeciderList, SelectorFnList)
530
- ├── scope/ Scope facades, recorders, protection, Zod integration
531
- ├── engine/ DFS traversal, handlers, narrative generators
532
- ├── runner/ Execution convenience (FlowChartExecutor, ExecutionRuntime)
533
- └── contract/ I/O schemas, Zod→JSON Schema, OpenAPI 3.1 generation
534
- ```
535
-
536
- **[Architecture deep-dives &rarr;](docs/internals/)** &mdash; each library has its own README with primitives, design decisions, and dependency graphs
127
+ | **7 Patterns** | Linear, parallel fork, conditional, multi-select, subflow, streaming, loops &mdash; [guide](docs/guides/patterns.md) |
128
+ | **Transactional State** | Atomic commits, safe merges, time-travel replay &mdash; [guide](docs/guides/scope.md) |
129
+ | **PII Redaction** | Per-key or declarative `RedactionPolicy` with audit trail &mdash; [guide](docs/guides/scope.md#redaction-pii-protection) |
130
+ | **Flow Recorders** | 8 narrative strategies for loop compression &mdash; [guide](docs/guides/flow-recorders.md) |
131
+ | **Contracts** | I/O schemas (Zod/JSON Schema) + OpenAPI 3.1 generation &mdash; [guide](docs/guides/contracts.md) |
132
+ | **Cancellation** | AbortSignal, timeout, early termination via `breakFn()` &mdash; [guide](docs/guides/execution.md) |
537
133
 
538
134
  ---
539
135
 
540
136
  ## AI Coding Tool Support
541
137
 
542
- FootPrint ships with built-in instructions for every major AI coding assistant. Your AI tool understands the library's API, patterns, and anti-patterns out of the box.
543
-
544
- ### Quick setup
138
+ FootPrint ships with built-in instructions for every major AI coding assistant. Your AI tool understands the API, patterns, and anti-patterns out of the box.
545
139
 
546
140
  ```bash
547
- # After installing footprintjs, run:
548
141
  npx footprintjs-setup
549
142
  ```
550
143
 
551
- This interactive installer copies the right instruction files for your tool(s):
552
-
553
- | Tool | What gets installed | Format |
554
- |------|-------------------|--------|
555
- | **[Claude Code](https://claude.com/claude-code)** | `.claude/skills/footprint/SKILL.md` + `CLAUDE.md` | Interactive skill + project rules |
556
- | **[OpenAI Codex](https://openai.com/index/codex/)** | `AGENTS.md` | Agent instructions |
557
- | **[GitHub Copilot](https://github.com/features/copilot)** | `.github/copilot-instructions.md` | Custom instructions |
558
- | **[Cursor](https://cursor.com)** | `.cursor/rules/footprint.md` | Project rules |
559
- | **[Windsurf](https://windsurf.com)** | `.windsurfrules` | Project rules |
560
- | **[Cline](https://github.com/cline/cline)** | `.clinerules` | Project rules |
561
- | **[Kiro](https://kiro.dev)** | `.kiro/rules/footprint.md` | Project rules |
144
+ | Tool | What gets installed |
145
+ |------|-------------------|
146
+ | **Claude Code** | `.claude/skills/footprint/SKILL.md` + `CLAUDE.md` |
147
+ | **OpenAI Codex** | `AGENTS.md` |
148
+ | **GitHub Copilot** | `.github/copilot-instructions.md` |
149
+ | **Cursor** | `.cursor/rules/footprint.md` |
150
+ | **Windsurf** | `.windsurfrules` |
151
+ | **Cline** | `.clinerules` |
152
+ | **Kiro** | `.kiro/rules/footprint.md` |
562
153
 
563
- Or install manually:
564
-
565
- ```bash
566
- # Claude Code skill
567
- mkdir -p .claude/skills/footprint
568
- cp node_modules/footprintjs/ai-instructions/claude-code/SKILL.md .claude/skills/footprint/
569
-
570
- # Cursor rules
571
- mkdir -p .cursor/rules
572
- cp node_modules/footprintjs/ai-instructions/cursor/footprint.md .cursor/rules/
573
-
574
- # Any other tool — files are in node_modules/footprintjs/ai-instructions/
575
- ```
154
+ ---
576
155
 
577
- Every file teaches the AI assistant:
578
- - The **Builder**, **Executor**, and **ScopeFacade** APIs
579
- - The **recorder system** (scope + flow, two observer layers)
580
- - The **core principle**: collect during traversal, never post-process
581
- - **Anti-patterns** to avoid (deprecated APIs, wrong state access patterns)
582
- - **Event ordering** that makes inline narrative collection work
156
+ ## Documentation
583
157
 
584
- This means any AI coding tool can help you build flowchart pipelines correctly from day one.
158
+ | Resource | Link |
159
+ |----------|------|
160
+ | **Guides** | [Patterns](docs/guides/patterns.md) &middot; [Scope](docs/guides/scope.md) &middot; [Execution](docs/guides/execution.md) &middot; [Errors](docs/guides/error-handling.md) &middot; [Flow Recorders](docs/guides/flow-recorders.md) &middot; [Contracts](docs/guides/contracts.md) |
161
+ | **Reference** | [API Reference](docs/guides/api-reference.md) &middot; [Performance Benchmarks](docs/guides/performance.md) |
162
+ | **Architecture** | [Internals](docs/internals/) &mdash; six independent libraries, each with its own README |
163
+ | **Try it** | [Interactive Playground](https://footprintjs.github.io/footprint-playground/) &middot; [Live Demo](https://footprintjs.github.io/footprint-demo/) &middot; [25+ Examples](https://github.com/footprintjs/footPrint-samples) |
585
164
 
586
165
  ---
587
166
 
588
- ## License
589
-
590
167
  [MIT](./LICENSE) &copy; [Sanjay Krishna Anbalagan](https://github.com/sanjay1909)