@takk/bayespredicts - v1.0.0 - Apache-2.0

Restart the component before it dies, not after.

Anomaly detection tells you a metric looks wrong now; it does not tell you when the component will fail. BayesPredicts reads the lifecycle history of each component, fits a Bayesian survival model, and forecasts the time to the next failure with calibrated credible intervals, then advises whether to restart.

148tests passing
94%coverage
0runtime deps
14subpaths
What it is

One library, two answers.

In a few words

BayesPredicts is the actuary of your system's components. It reads the life-and-death history of each one, when it started, when it failed, when it is still running, and estimates the expected lifetime, then predicts the time to the next failure with calibrated uncertainty and recommends whether to restart now or keep watching. Your code stays small: you call analyze({ events, age, policy }) and read the forecast and the recommendation.

Technically

A lifetime is a survival function and a hazard. The Exponential model gives the failure rate a Gamma conjugate prior, so the posterior, the mean time to failure, and the lifetime quantiles are closed form. The Weibull model is conjugate at each fixed shape and weights a grid over shapes into a posterior, so it captures wear-out and infant mortality. Right-censored observations, the components still running, contribute through the survival, and a cost-optimal restart advisor, per-cohort estimation, a tamper-evident hash-chained audit trail, and an MCP and LLM tool round it out.

Before and after

The same fleet, two very different reliability bills.

Take a real production scene: a fleet of long-running agents that age and eventually fail, and you must decide when to restart each one, a preventive restart costs uptime, waiting costs an outage.

With a fixed timer or run-to-failure

Restart by the clock, or wait for the page

  1. Choice 1 Restart every component on a fixed timer, paying for uptime you did not need.
  2. Choice 2 Or wait for failure, and pay for the outage when an agent dies in production.
  3. Either way No estimate of how long until the next failure, so the timer is a guess.
  4. Censored data The components still running carry no weight in the decision.
  5. One curve Every cohort is treated alike, so a regressing batch hides in the average.
  6. No interval A point guess with no credible interval invites both over and under reacting.
  7. Postmortem Nobody can reconstruct why the restart was, or was not, scheduled.
With BayesPredicts

Calibrated forecast, the restart pays for itself

  1. Step 1 Each lifecycle event folds into a survival observation, censored ones included.
  2. Step 2 A conjugate update fits the failure rate or the Weibull shape in closed form.
  3. Step 3 The forecast gives the failure probability over the next window, conditional on age.
  4. Step 4 A credible interval on the residual life shows how settled the estimate is.
  5. Step 5 The cost-optimal advisor returns the restart age that minimizes long-run cost.
  6. Decision Restart now or keep monitoring, with the reasoning attached, not a bare timer.
  7. The audit chain records every forecast and decision, sealed and verifiable, for the review.

The "With BayesPredicts" path is the behavior of the fitted survival posterior; the model produces the recommendation, restart now or keep monitoring, and your orchestrator acts on it. On a simulated wear-out fleet the cost-optimal advisor cuts long-run cost 75.3% versus run-to-failure, a number from real execution.

Install

Five minutes from install to your first calibrated forecast.

1. Add the package

pnpm add @takk/bayespredicts
npm install @takk/bayespredicts
yarn add @takk/bayespredicts
bun add @takk/bayespredicts

2. Zero required dependencies

The core has no runtime dependencies and a node-free core. Every @takk sibling is an optional peer; install only what you compose with.

# nothing else is required to start forecasting
              # optional: install a sibling you compose with, for example
              pnpm add @takk/keymesh @takk/modelchain

3. Forecast a failure in a few lines

import { analyze } from '@takk/bayespredicts';

              const result = analyze({
              events: [
              { component: 'agent-7', kind: 'start',   at: 0 },
              { component: 'agent-7', kind: 'failure', at: 41 },
              { component: 'agent-7', kind: 'start',   at: 41 },
              { component: 'agent-7', kind: 'censor',  at: 95 }, // still running
              ],
              age: 35,
              horizons: [10, 30],
              policy: { kind: 'risk-threshold', maxFailureProbability: 0.1, window: 10 },
              });

              console.log(result.meanTimeToFailure);     // expected lifetime
              console.log(result.forecast.failureProbabilityByHorizon);
              console.log(result.recommendation?.action); // 'restart-now' or 'monitor'

4. Let the cost-optimal advisor pick the restart age

import { advise, fitWeibull, optimalRestartAge } from '@takk/bayespredicts';

              const model = fitWeibull(history); // history: { duration, censored }[]

              // The age-replacement model: restart age that minimizes long-run cost,
              // trading a planned restart against a costlier unplanned failure.
              const optimal = optimalRestartAge(model, 1, 25);

              const recommendation = advise(model,
              { kind: 'cost-optimal', plannedRestartCost: 1, failureCost: 25 },
              { age: 60 });
              console.log(optimal.age);            // cost-minimizing restart age
              console.log(recommendation.action);  // 'restart-now' once age reaches it
Features

Nine capabilities, every one tied to a measurable outcome.

Closed-form conjugate updates

The Exponential failure rate has a Gamma conjugate prior, so the posterior, the mean time to failure, the survival curve, and the lifetime quantiles are exact closed forms, not simulated.

You fold in new failures with a one-step update and read an exact mean time to failure, reproducible to the last digit.

Weibull aging model

A hazard that rises with wear-out or falls with infant mortality, inferred over a grid of shapes, with the constant-hazard Exponential recovered automatically when the shape posterior allows it.

You model components that age, the common case, without over-fitting wear-out on thin data.

Censored data, native

A component still running at observation time is a right-censored observation that informs the posterior without being counted as a failure, the way survival analysis is meant to work.

Your estimate stays honest when most of the fleet has not failed yet, instead of ignoring the survivors.

Conditional forecast

Every prediction conditions on the current age, returning the failure probability over the next window, the residual life, and a credible interval, given that the component has already survived this long.

A component past its risky infancy is judged on its remaining risk, not its original risk.

Cost-optimal restart advisor

The classic age-replacement model finds the restart age that minimizes long-run cost, trading a planned restart against a costlier unplanned failure. A memoryless lifetime yields run-to-failure on its own.

On a simulated wear-out fleet, 75.3% lower long-run cost than run-to-failure, ten times fewer unplanned failures.

Per-cohort estimation

Fit a posterior per cohort, model version, hardware batch, or region, pool a fleet baseline, and flag the cohorts that are meaningfully shorter-lived than the fleet.

A regressing batch surfaces as a regression instead of hiding inside a healthy fleet average.

Tamper-evident audit

An append-only log of every forecast and decision, with a SHA-256 hash-chain you append to and verify via the Web Crypto API.

Prove a restart was decided on the recorded forecast, in Node, edge runtimes, or the browser, when a decision is questioned.

A tool a non-human entity can call

The whole pipeline is exposed as a framework-agnostic tool, name, description, JSON Schema, handler, that drops into an MCP server or an LLM tool-calling API, with defensive input validation.

A non-human entity forecasts its own failures from its own telemetry, no SDK to wire in.

SLSA provenance

Every published version signed with npm publish --provenance through GitHub Actions OIDC. Lockfile committed, zero required runtime dependencies, node-free core.

Verify in one command that the tarball you installed was built from the source commit you trust.

Models

Explicit models, never a black box.

Choose the lifetime model, or let the automatic choice decide, and pass your own Gamma prior over the failure rate. The data is yours; the calibration is the library's.

Setting What it encodes When to use it
model: "auto" Fit the Weibull, keep the Exponential when the shape posterior is consistent with a constant hazard. Default. You do not want to decide constant versus aging hazard up front.
model: "exponential" A memoryless, constant-hazard lifetime, the Gamma-conjugate Lomax in closed form. Failures from random external shocks, not from wear, force a constant hazard.
model: "weibull" A hazard that rises with wear-out or falls with infant mortality, the shape inferred over a grid. Components that age, the common case, need an age-dependent hazard.
prior A Gamma prior over the failure rate; the default makes the predictive mean equal exposure over failures, the textbook MTBF estimator. A known base rate should anchor the estimate until enough failures accrue.

Any Gamma prior is accepted, and the Weibull shape grid and its prior are configurable. The conjugate update folds each new failure or censored observation into the posterior in closed form.

Entry points

Fourteen subpaths, import only what you need.

Entry point Subpath export Runtime Use it when
Facade @takk/bayespredicts node-free You want the analyze and MaintenanceMonitor facade and the full toolkit.
Restart advisor @takk/bayespredicts/advisor node-free You want the risk-threshold or cost-optimal restart policy on its own.
Tool adapter @takk/bayespredicts/adapter node-free You want the framework-agnostic MCP and LLM tool a non-human entity can call.
Node loaders @takk/bayespredicts/node Node only You need to load lifecycle history from a JSON or CSV file on disk.
CLI

A command-line tool that runs the real engine.

The bayespredicts binary runs the compiled engine, so every number it prints comes from execution. fit prints the posterior summary; predict forecasts time-to-failure at a current age; advise recommends whether to restart; audit-verify checks an audit-chain file.

Fit a survival model from a history file

# history is a JSON array of events or of { duration, censored }, or a CSV
              npx @takk/bayespredicts fit history.json

Forecast and advise at the current age

npx @takk/bayespredicts predict history.json --age 12 --horizon 6 --horizon 24
              npx @takk/bayespredicts advise history.json --planned-cost 1 --failure-cost 25
          

Verify an audit chain, version, and help

npx @takk/bayespredicts audit-verify chain.json
              npx @takk/bayespredicts --version
              npx @takk/bayespredicts --help

              # exit codes: 0 ok, 2 usage or input error, 10 restart-now, 20 broken chain
Audit and forecast

Prove what you predicted, and read why you acted.

Record every forecast and decision in a tamper-evident, hash-chained log. And because the forecast is explicit, analyze returns the chosen model, the mean time to failure, the failure probability per horizon, and the restart recommendation, so a decision, or a wait, is never a black box. Both are node-free and need no external service.

import { AuditChain, verifyChain } from '@takk/bayespredicts/audit';

              const chain = new AuditChain();

              await chain.append({
              kind: 'forecast', component: 'agent-7',
              failureProbability: 0.14, action: 'restart-now',
              });

              await verifyChain(chain.toArray()); // { valid: true }, until any entry is altered

Every forecast is explicit

const result = analyze({ events, age: 12, horizons: [6, 24], policy });
              // {
              //   model: 'weibull',                 // chosen automatically
              //   meanTimeToFailure: 88.7,
              //   forecast: {
              //     hazard: 0.0092, meanResidualLife: 35.2,
              //     failureProbabilityByHorizon: [
              //       { horizon: 6, probability: 0.066 },
              //       { horizon: 24, probability: 0.358 },
              //     ],
              //   },
              //   recommendation: { action: 'monitor', reason: '...' },
              // }

The model is one of exponential or weibull, chosen automatically, so you can log and alert on exactly which model produced a forecast. The MaintenanceMonitor records every prediction into the hash-chained audit log with no runtime dependency, the governance seam for a non-human entity's own reliability.

Compare

BayesPredicts vs the alternatives.

The other approaches solve part of the problem. The contrast clarifies where BayesPredicts sits.

Capability BayesPredicts Anomaly detection Fixed-timer restart lifelines (Python) Hand-rolled
Distribution npm library hosted service your cron Python package your repo
Calibrated time-to-failure measured coverage no forecast a guess yes rarely
Right-censored data native no no yes rarely
Cost-aware restart advisor yes no fixed only no no
Production NPM, JS/TS yes SaaS API n/a Python only your call
Tamper-evident audit yes partial no no no
Zero deps, node-free yes no n/a NumPy, SciPy varies
License Apache-2.0 proprietary your call MIT your call

The honest summary: anomaly detection is fine for catching a problem in progress, and lifelines is excellent if your stack is Python. Pick BayesPredicts when you need calibrated time-to-failure forecasts and a cost-aware restart decision, with native censored-data support and a tamper-evident trail, in one node-free TypeScript library you embed in a JavaScript or TypeScript production service.

The model, honestly

What the model assumes, and how it stays honest.

BayesPredicts is Bayesian survival analysis, and that has assumptions. They are documented, and where a real fleet strains them, there is an explicit mitigation rather than a silent fudge.

Assumption or property What it means How BayesPredicts handles it
Model family chosen, not discovered You pick Exponential, Weibull, or auto; the library does not invent a failure-mode structure from data. The automatic choice keeps the parsimonious Exponential unless the shape posterior says otherwise.
Closed form where conjugate The Exponential is exact; the Weibull rate is exact given the shape. The shape is inferred over a grid, and quantiles invert the mixture numerically, documented as such.
Calibration is measured A credible interval is only worth its coverage on real data. Simulation-based calibration reports the empirical coverage, 89.2% and 86.8% near a nominal 90%.
Censored data informs the fit Most components have not failed yet, and ignoring them biases the estimate. A still-running component is a right-censored observation that contributes through the survival.
Conditional on current age A component that already survived this long has different remaining risk. Every forecast conditions on the age, so the residual life reflects survival to now.
The cost model is explicit The age-replacement optimum needs an unplanned failure to cost more than a planned restart. A memoryless lifetime yields run-to-failure on its own, and the math says so plainly.
Advises, does not act The library returns a restart recommendation, it does not restart your components. Your orchestrator consumes the decision; turnkey orchestrator integrations are on the roadmap.
Integrity, not identity The audit seal proves a log was not altered after sealing. A SHA-256 hash chain via Web Crypto, an integrity seal, not a signature.
Quality and validation

The receipts behind v1.0.0.

Tests & coverage

148 tests passing under Vitest 4 with 94% coverage (statements 94.70%, branches 86.82%). Simulation-based calibration measures interval coverage. Run pnpm test on a fresh clone to reproduce.

Type safety

TypeScript 6 in maximum strict mode (exactOptionalPropertyTypes, useUnknownInCatchVariables, noUncheckedIndexedAccess, noPropertyAccessFromIndexSignature, noImplicitOverride). Zero errors under tsc --noEmit.

Lint & types-correctness

Biome 2.5 clean across src and tests. publint clean and @arethetypeswrong/cli green across all fourteen subpaths. Dual ESM + CJS with separate .d.ts and .d.cts per subpath.

Calibrated and valuable

Survival functions are verified against Monte Carlo oracles. A 90% interval on the Exponential rate covers the truth 89.2% of the time. On a simulated wear-out fleet, the cost-optimal advisor cuts long-run cost 75.3% versus run-to-failure, every number from real execution.

Distribution smoke

A smoke test exercises the compiled ESM and CJS artifacts and spawns the compiled CLI as a single Node process, run on the Node 20, 22, and 24 matrix.

Supply chain

Committed pnpm lockfile, zero required runtime dependencies, node-free core, and SLSA provenance attestation on every published version. Verify with npm view @takk/bayespredicts@1.0.0 --json | jq .dist.attestations.

Roadmap

What is shipped, what is next, what is later.

Now (1.0)

Shipped in v1.0.0

  • Gamma-Exponential conjugate model, closed form
  • Weibull aging model over a shape grid
  • Native right-censored-data support
  • Conditional time-to-failure and residual-life forecast
  • Cost-optimal and risk-threshold restart advisor
  • Per-cohort estimation, MCP and LLM tool, audit chain, CLI
  • Dual ESM + CJS, node-free core, SLSA provenance
Next

Planned next

  • Incremental, streaming posterior updates
  • Drift and change-point detection on the failure rate
  • Competing risks, a curve per failure mode
  • Turnkey Kubernetes, ECS, and Hermes runtime hooks
  • Signed and timestamped audit seals
Later

On the horizon

  • Covariate-aware (Cox-style) survival models
  • Hosted forecasting service with fleet analytics
  • Federated reliability sharing across organizations
  • Dashboards for fleet predictive maintenance
FAQ

Common questions.

Is BayesPredicts production-ready at 1.0.0?

Yes. 148 tests pass under Vitest 4 with 94% coverage; TypeScript 6 maximum strict mode is clean; Biome 2.5 lint is clean; publint and @arethetypeswrong/cli are clean across all fourteen subpaths. The suite and the distribution smoke test are run on the Node 20, 22, and 24 matrix. Every published release carries SLSA provenance produced by GitHub Actions.

How is this different from anomaly detection?

Anomaly detection tells you a metric looks wrong right now; it does not tell you when the component will fail. BayesPredicts fits a survival model from the lifecycle history and forecasts the time to the next failure, with a calibrated probability over a future window and a credible interval on the remaining life, so you can act before the failure rather than alert during it.

What if most of my components have not failed yet?

That is the normal case and it is handled natively. A component still running at observation time is a right-censored observation that informs the posterior without being counted as a failure. Survival analysis is built precisely for data where most subjects have not yet experienced the event, so a fleet that is mostly healthy still produces a useful estimate.

Exponential or Weibull, which model should I use?

Leave the model on auto. It fits the Weibull and keeps the simpler, constant-hazard Exponential whenever the shape posterior is consistent with a constant hazard, so you do not over-fit wear-out on thin data. Force either with { model: "exponential" } for memoryless failures or { model: "weibull" } for components that age. The choice and its reasoning are returned with the fit.

Does this work in Cloudflare Workers, Vercel Edge, Bun, or Deno?

Yes. The core is node-free; the audit seal uses the Web Crypto API, not node:crypto. Import @takk/bayespredicts or @takk/bayespredicts/edge on any runtime with Web Crypto, and call the tool adapter from a non-human-entity loop. Only @takk/bayespredicts/node requires the Node standard library, for reading history files from disk.

How does BayesPredicts handle my data?

BayesPredicts records the component identifiers, the durations and censored flags, the lifecycle events, and timestamps you supply. It never sees your raw logs or payloads and makes no outbound network calls of its own. With the file loaders, it only reads the history file you point it at; no secrets are involved at any point.

What happens before any component has failed (cold start)?

The default prior contributes one pseudo-failure, so the rate stays finite and positive even before the first real failure, while the data sets the time scale. To anchor the estimate to a known base rate, pass your own Gamma prior; each new failure or censored observation then folds into the posterior in closed form.

Where does the state live?

The posterior is a small set of numbers, the shape and rate of the fitted model, that you can serialize wherever you like. History is read from a JSON or CSV file with the loaders in @takk/bayespredicts/node, or fed in directly as events or observations. For an edge runtime, keep the history in your own KV store between invocations.

Is the audit trail a digital signature?

No, and the docs are explicit about it. The seal is a SHA-256 hash-chain that proves a log was not altered after sealing. It is an integrity seal, not a signature: it does not prove who produced the log. Signed and timestamped seals for stronger third-party evidence are on the roadmap.

What kinds of input can I feed it?

Either raw lifecycle events, start, failure, stop, and censor per component, which fold into observations, or ready-made observations of a duration and a censored flag. A later start for the same component is a renewed life, so repeated failures become repeated observations.

How do I verify a published version's provenance?

Every release is published with npm publish --provenance. Check the attestations with npm view @takk/bayespredicts@<version> --json | jq .dist.attestations. The attestation links the tarball you installed to the GitHub Actions workflow that built it from a specific source commit.

Does it restart my components for me?

No. BayesPredicts produces the recommendation, restart now or keep monitoring, with the reasoning and the optimal restart age. Your orchestrator, Kubernetes, ECS, a Hermes runtime hook, or your own controller, consumes that decision and acts. Turnkey orchestrator integrations are on the roadmap.

What is the policy on breaking changes?

Strict SemVer 2.0.0, starting from 1.0.0. The binding stability surface is documented in SPEC.md section 5. Major bumps require a deprecation cycle; security fixes follow the disclosure flow in SECURITY.md.

Author

Built and maintained by David C Cavalcante.

David C Cavalcante

Founder, Takk Innovate Studio

Product Engineer, ML Engineer, LLM Engineer, LLM Architect, Massive Intelligence (IM) Researcher. Builder of the @takk family of NPM packages for Massive Intelligence (IM) native infrastructure.

BayesPredicts is part of a planned portfolio of NPM libraries targeting Massive Intelligence (IM) native infrastructure for 2026 to 2030. Adjacent research by the author covers systemic intelligence frameworks (MAIC, HIM, NHE) published independently of this codebase, with research notes on PhilPapers and PhilArchive linked from the repository README.

If BayesPredicts forecast a failure for you this quarter, the most useful thing you can do is open a GitHub issue when you find an edge case the test suite missed. The runbook for releases, the threat model, and the contributor agreement all live in the repository.