Footprintjs
БесплатноНе проверенExplainable backend flows — automatic causal traces, decision evidence, and MCP tool generation for AI agents
Описание
Explainable backend flows — automatic causal traces, decision evidence, and MCP tool generation for AI agents
README
FootPrint
The flowchart pattern for backend code — self-explainable systems that AI can reason about.
Part of the footprintjs ecosystem — the self-explaining stack.
MVC is a pattern for backends. FootPrint is a different pattern — the flowchart pattern — 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 — no hallucination.
npm install footprintjs
The Problem
Your LLM needs to explain why your code made a decision. Without structure, it reconstructs reasoning from scattered logs — expensive, slow, and hallucinates.
| MVC / Traditional | Flowchart Pattern (FootPrint) | |
|---|---|---|
| LLM explains a decision | Reconstruct from scattered logs | Read the causal trace directly |
| Tool descriptions for agents | Write and maintain by hand | Auto-generated from the graph |
| State management | Global/manual, race-prone | Transactional scope with per-stage staged commits |
| Debugging | console.log + guesswork |
Time-travel replay to any stage |
How It Works
A loan pipeline rejects Bob. The user asks: "Why was I rejected?"
The runtime auto-generates this trace from what the code actually did:
Stage 1: The process began with ReceiveApplication.
Step 1: Write creditScore = 580, dti = 0.6, employmentStatus = "self-employed"
Stage 2: Next step: Evaluate risk tier from all flags.
Step 1: Read creditScore = 580
Step 2: Write riskTier = "high"
Step 3: Write riskFactors = (3 items)
Stage 3: Next step: Route based on risk tier.
Step 1: Read riskTier = "high"
[Condition]: It evaluated "High risk": riskTier "high" eq "high" ✓, and chose RejectApplication.
Stage 4: Next step: Generate rejection.
Step 1: Write decision = "REJECTED — below-average credit; DTI exceeds 43%; Self-employed < 2yr"
The LLM backtracks through the trace, reading ← as caused-by — each value links to the write that produced it: riskTier="high" ← riskFactors ← creditScore=580, dti=0.6. Every variable links to its cause:
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."
That answer came from the trace — not from the LLM's imagination.
Quick Start
import { flowChart, decide, narrative } from 'footprintjs';
// 1. Define your state
interface State {
user: { name: string; tier: string };
discount: number;
lane: string;
}
// 2. Build the flowchart
const chart = flowChart<State>('FetchUser', async (scope) => {
scope.user = { name: 'Alice', tier: 'premium' };
}, 'fetch-user')
.addFunction('ApplyDiscount', async (scope) => {
scope.discount = scope.user.tier === 'premium' ? 0.2 : 0.05;
}, 'apply-discount')
.addDeciderFunction('Route', (scope) => {
return decide(scope, [
{ when: { discount: { gt: 0.1 } }, then: 'vip', label: 'High discount' },
], 'standard');
}, 'route', 'Route by discount tier')
.addFunctionBranch('vip', 'VIPCheckout', async (scope) => {
scope.lane = 'VIP express';
})
.addFunctionBranch('standard', 'StandardCheckout', async (scope) => {
scope.lane = 'Standard';
})
.setDefault('standard')
.end()
.build();
// 3. Run — capture the narrative recorder so you can read the trace back
const trace = narrative();
const result = await chart.recorder(trace).run();
console.log(result.state.lane); // "VIP express"
console.log(trace.getEntries().map((e) => e.text).join('\n'));
// Stage 1: The process began with FetchUser.
// Step 1: Write user = {name, tier}
// Stage 2: Next, it moved on to ApplyDiscount.
// Step 1: Read user = {name, tier}
// Step 2: Write discount = 0.2
// Stage 3: Next step: Route by discount tier.
// Step 1: Read discount = 0.2
// [Condition]: It evaluated Rule 0 "High discount": discount 0.2 gt 0.1 ✓, and chose VIPCheckout.
// Stage 4: Next, it moved on to VIPCheckout.
// Step 1: Write lane = "VIP express"
Try it in the browser — no install needed
Browse 37+ examples — patterns, recorders, subflows, integrations, and a full loan underwriting demo
Vocabulary
If you know agent or backend systems, you already know these — here's footprint's name for each:
| footprint term | = the thing you already know |
|---|---|
| scope | the run's shared state (an agent's working memory) — but every read/write is tracked |
| stage | a step / node in the flowchart |
| decider / selector | a router (picks one branch) / parallel fan-out (picks many) |
| subflow | a nested flowchart you compose like a function |
| recorder | an observer — called on each read, write, and decision |
| narrative | the execution trace rendered as plain-English sentences (the LLM-readable form) |
| commit log | the ordered record of what each step wrote — powers time-travel replay |
Try With Your LLM
Expose any flowchart as an MCP tool in one line — the description, input schema, and step list are auto-generated from the graph.
const tool = chart.toMCPTool();
// { name: 'AssessCredit', description: 'FlowChart: AssessCredit\nSteps:\n1. AssessCredit\n2. ...', inputSchema: { type: 'object', properties: {} } }
// Register with any MCP server or pass directly to the Anthropic SDK:
const anthropicTool = { name: tool.name, description: tool.description, input_schema: tool.inputSchema };
The LLM calls the tool, gets back the decision and causal trace, and explains the result to the user — all from the same graph that runs in production.
Live demo: Claude calls a credit-decision flowchart as an MCP tool — enter your API key, watch the tool call happen, see the trace.
Features
| Feature | Description |
|---|---|
| Causal Traces | Every read/write captured — LLMs backtrack through variables to find causes |
| Decision Evidence | decide() / select() auto-capture WHY a branch was chosen — operators, thresholds, pass/fail |
| TypedScope<T> | Typed property access — scope.creditScore = 750 instead of scope.setValue('creditScore', 750) |
| Auto Narrative | Build-time descriptions for tool selection, runtime traces for explanation |
| 7 Patterns | Linear, parallel fork, conditional, multi-select, subflow, streaming, loops |
| Transactional State | Per-stage staged commits, safe merges, time-travel replay |
| PII Redaction | Per-key or declarative RedactionPolicy with audit trail |
| Flow Recorders | 7 loop-compression strategies (+ a subflow Manifest recorder) |
| Combined Recorders | Single-hook observers that span data-flow + control-flow — executor.attachCombinedRecorder(r) |
| Deferred observers (new in 9.6) | attach*Recorder(rec, { delivery: 'deferred' }) — observers run "one beat behind" on a bounded queue instead of inside the engine hot path. Honest backpressure (drop-oldest/sample/block), terminal flush at run resolve/reject/pause, snapshot.observerStats. Guide → |
| Contracts | I/O schemas (Zod/JSON Schema) + OpenAPI 3.1 + MCP tool generation |
| Cancellation | AbortSignal, timeout, early termination via scope.$break(reason?) with optional reason |
| Subflow break propagation | Mount a subflow with propagateBreak: true — inner $break terminates the parent loop, with drill-down preserved |
| Emit channel | scope.$emit(name, payload) — user-authored structured events to EmitRecorder, pass-through, zero-allocation when no recorder attached, redactable via emitPatterns |
| Detach (new in 4.17) | scope.$detachAndForget(driver, child, input) and scope.$detachAndJoinLater(driver, child, input) — fire-and-forget child flowcharts via the footprintjs/detach subpath. Six built-in drivers (microtask / immediate / setImmediate / setTimeout / sendBeacon / workerThread) + custom-driver protocol. Builder-native composition (addDetachAndForget / addDetachAndJoinLater) makes detach a labeled chart stage. flushAllDetached() for graceful shutdown. Guide → |
| Recorder storage primitives | BoundaryStateStore<TState> — one of three composable storage shelves alongside SequenceStore<T> (durable ordered, with getEntryRanges()) and KeyedStore<T> (durable 1:1). BoundaryStateStore tracks live transient state DURING a [start, stop] event interval (LLM stream partial, tool args streaming, agent turn state) and clears on stop. O(1) reads via get / hasActive / activeCount. Mental model: recorder interfaces (ScopeRecorder / FlowRecorder / EmitRecorder) are observers; stores are bookkeeping shelves. A real recorder picks ONE observer interface and OWNS the store as a field (composition — "one purpose per recorder"). The Store classes are exported from footprintjs/trace and are the only recorder-storage model — there are no abstract base classes to extend. Guide → |
Tree-shakeable & ESM-first
Import one thing, ship one thing. footprintjs is built so your bundle grows only with what you actually use:
- Dual build, true ESM. Ships CommonJS (
require) and real ECMAScript Modules (import) with TypeScript types. The ESM build is markedtype:moduleand every internal import carries an explicit.jsextension, so it loads as true ESM under Node, Vite, Next, Deno, and Bun — no compatibility shims. - Per-file modules +
sideEffects:false. The dist is emitted file-by-file (never pre-bundled) and declares zero side effects, so bundlers can drop every export you don't touch. - Subpath exports. Pull execution tracing from
footprintjs/trace, fire-and-forget children fromfootprintjs/detach, engine internals fromfootprintjs/advanced— each is independently tree-shakeable.
Proven, not promised. A CI smoke test bundles a minimal import { flowChart } from 'footprintjs' and asserts the recorder, detach, and trace layers are pruned — your flowchart core doesn't drag them in. See test/esm-packaging.test.ts.
// Only flowChart? The recorder/detach/trace layers are tree-shaken away.
import { flowChart } from 'footprintjs';
Dev Mode
footprintjs ships with developer-only diagnostics that are OFF in production (zero overhead). Turn them on during development to catch mistakes early:
import { enableDevMode } from 'footprintjs';
if (process.env.NODE_ENV !== 'production') {
enableDevMode();
}
One flag gates every library dev-only check:
| Check | What it warns about |
|---|---|
| Circular refs | scope.setValue(...) called with an object that references itself |
| Empty recorders | attachCombinedRecorder(r) with r that has no on* handler (likely mistake) |
| Suspicious predicates | decide() / select() rules with shapes that probably won't match |
| Snapshot integrity | getSubtreeSnapshot() asked for a path that doesn't exist |
All dev warnings are console.warn. Use disableDevMode() to silence them at runtime.
AI Coding Tool Support
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.
# Download and run the setup script from GitHub
npx degit footprintjs/footPrint/ai-instructions footprint-ai && bash footprint-ai/setup.sh && rm -rf footprint-ai
| Tool | What gets installed |
|---|---|
| Claude Code | .claude/skills/footprint/SKILL.md + CLAUDE.md |
| OpenAI Codex | AGENTS.md |
| GitHub Copilot | .github/copilot-instructions.md |
| Cursor | .cursor/rules/footprint.md |
| Windsurf | .windsurfrules |
| Cline | .clinerules |
| Kiro | .kiro/rules/footprint.md |
Roadmap — community extension points
These are deliberately deferred ideas where footprintjs aims to be a true developer's friend: ship a great zero-config default, but let teams who need it bring their own implementation. Contributions welcome — open an issue to discuss before a PR.
- Pluggable performance primitives (bring-your-own). Hot-path internals
(
deepEqualfor change-only commits,deepSmartMerge, deep clones) are built-in today. A future opt-in would let extreme-throughput consumers inject their own (e.g. a SIMD fast-deep-equal or structural-sharing clone) while everyone else keeps the default. Must honour the existing structural-equality contract (a wrong comparator could drop real changes), so it ships with a documented contract + dev-mode validation. See Commit change semantics.
FAQ
Are recorders blocking? Do observers slow my chart down?
Inline (default) recorders run synchronously inside the producing statement.
If an observer is heavy, opt it into the deferred tier:
executor.attachScopeRecorder(rec, { delivery: 'deferred' }) — events are
captured into one bounded, totally-ordered queue and delivered at the next
microtask checkpoint ("one beat behind"), fully drained before run()
returns. Same record, same order; the engine stops paying for observation.
Full model + FAQ: Deferred observers guide.
Documentation
| Resource | Link |
|---|---|
| Getting Started | Quick Start · Key Concepts · Why footprintjs? |
| Guides | Building · Decision branching · Recorders · Subflows · Self-describing APIs · Execution model & limits |
| API Reference | flowChart() / Builder · decide() / select() · FlowChartExecutor · Recorders · Contract & Self-describing |
| Try it | Interactive Playground · Try with your LLM · Live Demo |
The footprintjs ecosystem
The self-explaining stack — from backend pipelines to AI agents. → overview
| Project | Role |
|---|---|
| footprintjs ← you are here | the flowchart pattern (core engine) |
| agentfootprint | build self-explaining AI agents |
| Explainable UI | visualize a footprintjs run |
| Lens | debug an agentfootprint run |
| Thinking UI | replay an agent run for non-devs |
Установить Footprintjs в Claude Desktop, Claude Code, Cursor
unyly install footprintjsСтавит в Claude Desktop, Claude Code, Cursor и VS Code — сам разбирается с npx, uvx и сборкой из исходников.
Впервые? Поставь CLI: curl -fsSL https://unyly.org/install | sh
Или настроить вручную
Выполни в терминале:
claude mcp add footprintjs -- npx -y footprintjsFAQ
Footprintjs MCP бесплатный?
Да, Footprintjs MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для Footprintjs?
Нет, Footprintjs работает без API-ключей и переменных окружения.
Footprintjs — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить Footprintjs в Claude Desktop, Claude Code или Cursor?
Открой Footprintjs на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
Fetch
Web content fetching and conversion for efficient LLM usage.
AWS KB Retrieval
Retrieval from AWS Knowledge Base using Bedrock Agent Runtime.
автор: modelcontextprotocolSpring AI MCP Server
Provides auto-configuration for setting up an MCP server in Spring Boot applications.
llm-analysis-assistant
A very streamlined mcp client that supports calling and monitoring stdio/sse/streamableHttp, and can also view request responses through the /logs page. It also
автор: xuzexin-hzCompare Footprintjs with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории ai
