npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

footprintjs

v4.17.1

Published

Explainable backend flows — automatic causal traces, decision evidence, and MCP tool generation for AI agents

Readme

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 atomic 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: riskTier="high"dtiStatus="excessive"dtiRatio=0.6app.monthlyDebts=2100. 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 — state + self-generated trace included
const result = await chart.recorder(narrative()).run();

console.log(result.state.lane);     // "VIP express"
console.log(result.narrative);
// [
//   "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


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: '1. AssessCredit\n2. ...', inputSchema: { ... } }

// 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 | Atomic commits, safe merges, time-travel replay | | PII Redaction | Per-key or declarative RedactionPolicy with audit trail | | Flow Recorders | 8 narrative strategies for loop compression | | Combined Recorders | Single-hook observers that span data-flow + control-flow — executor.attachCombinedRecorder(r) | | 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 → |


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 |


Documentation

| Resource | Link | |----------|------| | Getting Started | Quick Start · Key Concepts · Why footprintjs? | | Guides | Building · Decision branching · Recorders · Subflows · Self-describing APIs | | API Reference | flowChart() / Builder · decide() / select() · FlowChartExecutor · Recorders · Contract & Self-describing | | Try it | Interactive Playground · Try with your LLM · Live Demo |


MIT © Sanjay Krishna Anbalagan