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

@takk/bayescausal

v1.0.0

Published

BayesCausal: declarative Bayesian networks for calibrated incident root cause inference. Model the causal graph between your components once, feed observed evidence from metrics, logs, and alerts, and get a ranked list of probable root causes with calibra

Readme

BayesCausal

status: stable license version node tests coverage runtime deps

Star History Chart

Universal, zero-runtime-dependency NPM library and CLI for declarative Bayesian networks and calibrated incident root cause inference. Model the causal graph between your components once, feed the symptoms you observed as evidence, and get a ranked list of probable root causes with calibrated posteriors, the do-operator for interventional causal queries, and a human-readable explanation, for Massive Intelligence (IM) systems.

BayesCausal is the Sherlock Holmes of incident response. When something breaks in a complex Massive Intelligence (IM) system, wrong output, high latency, anomalous cost, logs show you symptoms, not causes, and engineers burn hours on forensics. BayesCausal lets you declare, once, the causal relationships between your components as a Bayesian network, then read the symptoms of an incident as evidence and compute the most probable root cause given that evidence. It returns calibrated posterior probabilities for every candidate cause, ranked, with the prior and the lift, plus the single most probable joint explanation and a report you can paste into a postmortem.

Core promise: zero required runtime dependencies, single-function setup, exact inference by variable elimination and junction-tree belief propagation, approximate inference for graphs too large to solve exactly, the do-operator that separates seeing from doing, a node-free core that runs in Node, edge runtimes, and the browser, ESM plus CJS dual distribution, and a framework-agnostic observability adapter that binds to any telemetry source with no hard dependency.


Why BayesCausal

A production incident is a question under uncertainty. An SRE says: "Latency rose on Tuesday. Provider degradation, a traffic spike, a silent model deprecation, an infrastructure change? Four hypotheses, five engineers, two days to conclude." That is the manual root cause analysis every team still does by hand, and it does not scale to multi-agent systems whose complexity is factorial. Bayesian networks are the correct primitive: model the causal structure you know, observe the evidence, and let belief propagation compute P(cause | evidence) for every candidate in milliseconds, calibrated, not guessed.

What sets it apart from manual forensics and from the Python-only causal tooling (DoWhy, CausalML, EconML), which has no production-ready NPM equivalent:

  • Declarative causal graph. You declare the directed acyclic graph between your components and the conditional probability tables once. The structure is yours, explicit, and auditable, never a black box.
  • Exact inference, not approximate. Variable elimination and junction-tree belief propagation compute the true posterior. On a sparse incident graph this is exact and runs in milliseconds; the two engines are verified to agree to numerical precision, and against a brute-force oracle.
  • Approximate inference when you need scale. Loopy belief propagation and Monte Carlo (likelihood weighting and Gibbs sampling) handle graphs too large for exact inference, and they report their own convergence and credible intervals rather than pretending to be exact.
  • The do-operator, seeing versus doing. P(Y | do(X = x)) answers what a remediation would actually cause, not just what an observation predicts. In a confounded system the interventional and the observational answer disagree, and only the interventional one tells you whether forcing a config back to known-good will help. This is what makes it causal, not merely Bayesian. Counterfactual queries are on the roadmap.
  • Calibrated, ranked root causes. The diagnosis layer ranks each cause by its posterior probability of being at fault, with the prior and the lift (posterior over prior), so you see not just which cause is most likely now but how much the evidence moved it.
  • Explains itself. A deterministic, templated natural-language report, no Massive Intelligence (IM) model is called, with an honest closing line that the posteriors are only as good as the declared model.
  • Learns its numbers. Online Dirichlet parameter learning fills the conditional probability tables from observed incident history in closed form, with a credible interval per cell. Structure learning, discovering the edges themselves, is on the roadmap.
  • Proves what it concluded. A tamper-evident SHA-256 hash-chained audit trail of the evidence, the diagnosis, and the decision, the evidence a compliance review asks for.

Install

pnpm add @takk/bayescausal
# or: npm install @takk/bayescausal
# or: yarn add @takk/bayescausal
# or: bun add @takk/bayescausal

The core has zero required runtime dependencies. Every @takk sibling is an optional peer; install only what you compose with.


Quickstart

Declare a tiny causal graph, observe a symptom, and ask what most probably broke.

import { createNetwork } from "@takk/bayescausal";

const network = createNetwork({
  nodes: [
    { id: "ProviderDegraded", states: ["yes", "no"], role: "cause", faultStates: ["yes"], cpt: [[0.1, 0.9]] },
    { id: "TrafficSpike", states: ["yes", "no"], role: "cause", faultStates: ["yes"], cpt: [[0.15, 0.85]] },
    {
      id: "Latency",
      states: ["high", "normal"],
      role: "symptom",
      parents: ["ProviderDegraded", "TrafficSpike"],
      cpt: [[0.95, 0.05], [0.7, 0.3], [0.6, 0.4], [0.05, 0.95]],
    },
  ],
});

network.observe("Latency", "high");

for (const cause of network.diagnose().ranked) {
  console.log(`${cause.variable}: ${(cause.posterior * 100).toFixed(1)}% (lift ${cause.lift.toFixed(2)})`);
}
console.log(network.explain());

Each node carries a conditional probability table, P(node | parents). observe records evidence, diagnose ranks the causes by their posterior probability of being at fault, and explain renders the report.


The do-operator, seeing versus doing

Conditioning on an observation, P(Y | X = x), answers "when X is seen to be x". Intervening with the do-operator, P(Y | do(X = x)), answers "when X is forced to x", which is the question incident response actually asks. In a confounded system the two disagree, and only the interventional answer reflects what a remediation would do.

import { createNetwork } from "@takk/bayescausal";

// A confounder Z drives both the treatment X and the outcome Y; X also affects Y.
const network = createNetwork({
  nodes: [
    { id: "Z", states: ["high", "low"], cpt: [[0.5, 0.5]] },
    { id: "X", states: ["on", "off"], parents: ["Z"], cpt: [[0.8, 0.2], [0.2, 0.8]] },
    { id: "Y", states: ["bad", "ok"], parents: ["X", "Z"], cpt: [[0.6, 0.4], [0.4, 0.6], [0.5, 0.5], [0.1, 0.9]] },
  ],
});

const effect = network.causalEffect({ outcome: "Y", outcomeState: "bad", treatment: "X", from: "off", to: "on" });
console.log(effect.observational);  // 0.380, inflated by the confounder Z
console.log(effect.interventional); // 0.200, what forcing X would actually cause
console.log(effect.confounded);     // true

network.intervene({ X: "on" }) returns a new network with the do-operator applied (the incoming edges to X are cut), ready to diagnose or query as usual.


Inference engines

Five engines, the same query, your choice of exactness versus scale. The exact engines are the default and agree to numerical precision; the approximate engines trade a little accuracy for graphs too large to solve exactly.

| Engine | Import | Exact? | Use it for | |---|---|---|---| | Variable elimination | @takk/bayescausal/inference | Yes | a single posterior or the evidence probability | | Junction-tree belief propagation | @takk/bayescausal/junction | Yes | every variable's posterior in one sweep | | Loopy belief propagation | @takk/bayescausal/loopy | No | large or dense graphs, reports convergence | | Likelihood weighting | @takk/bayescausal/sampling | No | very large graphs, credible intervals | | Gibbs sampling | @takk/bayescausal/sampling | No | very large graphs, an independent cross-check |

Select per network with createNetwork({ method: "junction-tree" }) (the default), or call any engine directly.


Prebuilt incident templates

A blank canvas is the hardest part of any modeling tool, so BayesCausal ships a ready noisy-OR causal graph for a Massive Intelligence (IM) serving stack: provider degradation, a traffic spike, a deprecated model, and configuration drift as causes, with latency, error rate, output quality, and cost as observable symptoms.

import { createNetwork } from "@takk/bayescausal";
import { getTemplate } from "@takk/bayescausal/templates";

const network = createNetwork({ nodes: getTemplate("im-serving-incident") });
network.observe("Latency", "high").observe("OutputQuality", "low").observe("CostAnomaly", "no");
console.log(network.diagnose().ranked);

Treat it as a starting point to adapt, not a universal truth: the structure must match your system to be trusted.


Observability adapter

The adapter is the integration seam, dependency injected on purpose: it takes an evidence mapper instead of importing any vendor SDK, so it binds to OpenTelemetry, Prometheus, Datadog, or a non-human entity's own telemetry without a single hard dependency. The threshold mapper turns numeric metrics into observed states by simple bins.

import { createDiagnoser, thresholdMapper } from "@takk/bayescausal/adapter";
import { buildNetwork } from "@takk/bayescausal/network";
import { getTemplate } from "@takk/bayescausal/templates";

const diagnoser = createDiagnoser({
  network: buildNetwork(getTemplate("im-serving-incident")),
  map: thresholdMapper([
    { metric: "p95_latency_ms", variable: "Latency", bins: [{ upTo: 800, state: "normal" }, { upTo: Infinity, state: "high" }] },
    { metric: "judge_score", variable: "OutputQuality", bins: [{ upTo: 0.7, state: "low" }, { upTo: Infinity, state: "ok" }] },
  ]),
});

const diagnosis = diagnoser.diagnoseReadings({ p95_latency_ms: 1500, judge_score: 0.55 });

This is the loop a non-human entity (NHE) closes to diagnose itself: it reads its own metrics, maps them to evidence, and ranks the causes of its own failure.


Entry points

Twenty subpath exports, each importable on its own. The core is node-free; only node touches a Node built-in.

| Import | What it gives you | |---|---| | @takk/bayescausal | The createNetwork facade wiring everything below, plus the full toolkit. | | @takk/bayescausal/factor | The factor algebra: product, marginalization, max-marginalization, reduction by evidence. | | @takk/bayescausal/cpt | Conditional probability tables: validation, builders, and noisy-OR. | | @takk/bayescausal/network | The directed acyclic graph: validation, topological order, factor conversion. | | @takk/bayescausal/evidence | Hard and virtual (likelihood) evidence. | | @takk/bayescausal/inference | Variable elimination: marginals and the evidence probability. | | @takk/bayescausal/junction | Junction-tree belief propagation: all marginals in one sweep. | | @takk/bayescausal/loopy | Loopy belief propagation: the approximate engine for loopy graphs. | | @takk/bayescausal/sampling | Likelihood weighting and Gibbs sampling, with credible intervals. | | @takk/bayescausal/mpe | The most probable explanation: the single most likely joint assignment. | | @takk/bayescausal/intervene | The do-operator: interventions and the causal effect. | | @takk/bayescausal/diagnose | Root cause ranking by posterior, prior, and lift. | | @takk/bayescausal/explain | The natural-language explanation generator. | | @takk/bayescausal/learn | Online Dirichlet parameter learning with credible intervals. | | @takk/bayescausal/templates | Prebuilt incident causal graphs. | | @takk/bayescausal/calculator | Diagnosis evaluation: top-1 accuracy, mean reciprocal rank, Brier score. | | @takk/bayescausal/adapter | The observability evidence-source seam, dependency injected. | | @takk/bayescausal/audit | Append-only SHA-256 hash-chained audit log, via Web Crypto. | | @takk/bayescausal/node | Durable file-backed persistence with atomic writes. | | @takk/bayescausal/edge | The node-free core, re-exported for edge runtimes and the browser. |


Tamper-evident audit trail

import { AuditLog } from "@takk/bayescausal/audit";

const log = new AuditLog();
await log.append({ kind: "evidence", variable: "Latency", state: "high", at: Date.now() });
await log.append({ kind: "diagnosis", cause: "ProviderDegraded", posterior: 0.33, method: "junction-tree", at: Date.now() });

await log.verify(); // true, until any entry is altered

Each event is recorded append-only and chained to the previous one through a SHA-256 hash of its canonical form. Any later edit, deletion, or reordering breaks the chain and verify returns false. The seal is an integrity seal, not a digital signature: it proves the record was not tampered with, and makes tampering detectable, not that the record is unalterable. The chain uses the Web Crypto API, so the audit surface runs in Node, edge runtimes, and the browser.


Governance

Every diagnosis is observable. Pass an observer and the network notifies you of each observation and each diagnosis, so you can emit an OpenTelemetry span, ship the decision to a compliance log, or aggregate across a fleet. Together with the tamper-evident audit trail, this is the governance seam for Massive Intelligence (IM) systems: every root cause a non-human entity acts on is explainable after the fact, with the posterior and the method it was decided on. No runtime dependency is taken; you wire it to your own telemetry stack.


CLI

BayesCausal ships a command-line tool that runs the real engine, with every number produced by execution.

# Diagnose a built-in Massive Intelligence serving incident and print the ranked
# root causes, the most probable explanation, and the report.
npx @takk/bayescausal demo

# Read a JSON network ({ "nodes": [...], "evidence": {...} }) from a file or
# stdin and print the ranked root causes and the explanation.
cat network.json | npx @takk/bayescausal diagnose

# Measure diagnosis accuracy (top-1, mean reciprocal rank, Brier) over simulated
# incidents drawn from the network.
npx @takk/bayescausal evaluate --scenarios 2000

See examples/ for runnable demos, including the do-operator and a non-human-entity self-diagnosis loop, and benchmarks/ for the accuracy and latency benchmark.


The math, in one paragraph

A Bayesian network is a directed acyclic graph whose nodes are discrete variables and whose conditional probability tables specify P(node | parents). The joint distribution factorizes as the product of those tables. Given observed evidence, exact inference (variable elimination, or junction-tree belief propagation for all marginals at once) computes P(cause | evidence) for every variable; for graphs too large to solve exactly, loopy belief propagation and Monte Carlo sampling approximate it with reported convergence and credible intervals. Bayes' theorem is the engine: P(cause | evidence) is proportional to P(evidence | cause) times P(cause). The do-operator mutilates the graph, severing a variable's incoming edges, so P(Y | do(X)) measures the effect of forcing X rather than observing it, and its gap from the observational answer is exactly the confounding the structure encodes. The structure and the tables are yours, explicit and declared; the calibration is the library's.


Benchmark

benchmarks/ runs the engine over many incidents drawn by ancestral sampling from the serving template and reports both diagnosis accuracy and per-call latency. Every number comes from real execution against the compiled dist. On 2000 simulated incidents:

| Engine | Top-1 accuracy | Brier score | ms / 2000 scenarios | |---|---|---|---| | variable elimination | 78.0% | 0.0409 | 1161 | | junction tree | 78.0% | 0.0409 | 199 | | loopy belief propagation | 78.0% | 0.0410 | 570 |

Per-call inference latency on the serving template ranges from about 0.16 ms for the exact engines to about 49 ms for Gibbs sampling, so exact inference is the right default and the samplers are there for graphs that exact inference cannot reach. Run it yourself: pnpm run build && node benchmarks/causal-benchmark.mjs.


Quality

  • 125 tests across 16 suites, all passing under Vitest, including a brute-force oracle that verifies the exact marginals, the evidence probability, and the most probable explanation, and the do-operator verified against a manual backdoor adjustment.
  • Coverage: statements 96.94%, branches 83.36%, functions 96.83%, lines 97.88%.
  • Lint clean under Biome.
  • Typecheck clean under TypeScript in maximum strict mode (exactOptionalPropertyTypes, useUnknownInCatchVariables, noUncheckedIndexedAccess).
  • publint clean and @arethetypeswrong/cli green across all twenty subpaths.
  • size-limit under budget on every bundle (brotli core 7.81 kB).
  • Distribution smoke test exercising the compiled ESM and CJS artifacts and the compiled CLI spawned as a single Node process.
  • Zero required runtime dependencies; a node-free core that runs in Node, edge runtimes, and the browser; dual ESM plus CJS; TypeScript-first.

See SPEC.md for the formal specification, public surface, and stability promise.


FAQ

How is this different from manual root cause analysis? Manual analysis reads symptoms from logs and guesses at causes. BayesCausal encodes the causal structure you already know and computes the calibrated probability of each cause given the symptoms, in milliseconds, with the prior and the lift so you can see how much the evidence implicated each one.

Is this causal inference in the Pearl sense? It is interventional. The do-operator computes P(Y | do(X)) by graph mutilation, which separates seeing from doing and is genuinely causal. It does not yet do counterfactuals (abduction over exogenous noise) or causal structure discovery; both are on the roadmap. The causal graph is declared by you; the package does inference over the structure you give it.

What if I do not know the conditional probability tables? Use the noisy-OR builder for a compact diagnostic graph, or learn the tables from observed incident history with the online Dirichlet learner (@takk/bayescausal/learn), which fills them in closed form with a credible interval per cell.

Exact or approximate inference? Exact by default (variable elimination, junction tree), which is correct and milliseconds-fast on a sparse incident graph. For a graph too large to solve exactly, switch to loopy belief propagation or the samplers, which report their own convergence and credible intervals.

Does this work in Cloudflare Workers, Vercel Edge, Bun, and Deno? Yes. The core is node-free; the audit seal uses the Web Crypto API, not node:crypto. Import @takk/bayescausal or @takk/bayescausal/edge anywhere with Web Crypto. Only @takk/bayescausal/node requires Node.

Where does the state live? The network is defined by its node specifications, which round-trip through a portable JSON snapshot via snapshot() and load(). For durability, use the file-backed store from @takk/bayescausal/node. For an edge runtime, snapshot to your own KV store between invocations.


Contributing

See .github/CONTRIBUTING.md for the contributor guide. Substantive proposals open a GitHub Issue first; trivial fixes can go straight to a PR. All commits require DCO sign-off (git commit -s). Non-trivial contributions are governed by the Contributor License Agreement.

Community and support

  • Issues and feature requests. Open a GitHub issue at davccavalcante/bayescausal/issues. Include the package version, a minimal reproduction, the network and evidence, and where relevant the diagnose() output.
  • Security disclosures. Do not open public issues for vulnerabilities. Follow the responsible-disclosure flow in SECURITY.md, contact [email protected] (or [email protected]) with the [SECURITY] prefix.
  • Code of Conduct. This project follows the Contributor Covenant 2.1. Participation in any BayesCausal space implies agreement.
  • Contributions. All non-trivial contributions go through the Contributor License Agreement. Tests, lint, typecheck, and build must be green before review (pnpm verify).

Author

Created by David C Cavalcante, [email protected] (preferred), [email protected] (Takk relay), linkedin.com/in/hellodav, x.com/davccavalcante, takk.ag.

BayesCausal is part of a broader portfolio of NPM packages targeting Massive Intelligence (IM) native infrastructure for 2026-2030, built at Takk Innovate Studio. Calibrated causal root cause inference is a strong default for that era.


Related research by the author

The architectural philosophy behind BayesCausal, separating the graph, the inference engines, the diagnosis, and persistence into composable, independently-governed layers, echoes the author's research frameworks:

  • MAIC (Massive Artificial Intelligence Consciousness), a systemic intelligence framework designed to coordinate, supervise, and govern large-scale Massive Intelligence ecosystems, providing global context awareness, alignment, and orchestration across multiple models, agents, and decision layers.
  • HIM (Hybrid Entity Intelligence Model), a hybrid intelligence layer that integrates Massive Intelligence systems with human-defined logic, rules, heuristics, and strategic intent, interpreting objectives and structuring decision-making before and after model execution.
  • NHE (Noumenal Higher-order Entity), a non-human cognitive entity with a defined functional identity and operational agency within a Massive Intelligence ecosystem, operating through coordinated intelligence layers while maintaining a non-anthropomorphic identity.

These frameworks are published independently of BayesCausal and are separate works:


Sponsors

Join the journey as the portfolio continues to ship Massive Intelligence (IM) native infrastructure. Your support is the cornerstone of this work.


Privacy

BayesCausal runs entirely inside your own process and infrastructure. It makes no outbound calls to the author, collects no telemetry, and ships no analytics. The only state it holds is the network and the evidence you feed it. See PRIVACY.md for the full data-handling notice, including how the optional file store persists state on disk.


License

Licensed under the Apache License 2.0. See LICENSE for the full text and NOTICE for attribution and third-party component licenses. You may use, modify, and distribute the code under the terms of that license, including its patent grant and attribution requirements.