HeapDB is an open-source event-ranking database. When errors spike, users churn or agents need context, it ranks the events that matter and explains each result.

pip install heapdbPythonHTTPTypeScript (coming)Apache-2.0

  1. SQLSELECT * FROM deploys WHERE service = 'checkout' AND at > now() - interval '1 hour'returns matching rows
  2. Vector searchsearch(embed("checkout timeout"), k=5)returns similar items
  3. HeapDBTOP 3 CAUSES OF error_spike FOR checkout EXPLAINreturns ranked causes with evidence
    1PR #412 add orders.region columnscore 0.574
    • merged 40 min before the spike
    • matched: migration, fast review
    • learned from past answers: 0.60

    2 PR #418 refactor retry loop · 0.1813 deploy api@4.2 · 0.071

The same incident asked three ways, on example data scored by heapdb 0.5.0. How scoring works

Ranked results

The earlier events most likely to explain the outcome, best first.

Evidence for every score

When it happened, which features matched, and what was learned. No LLM required.

Learns from feedback

Confirm or reject a result, and the next ranking gets sharper.

Where HeapDB fits

Events in

  • GitHubAvailable on requestMerged PRs, deploys, reverts
  • Alert webhookAvailable on requestSentry, PagerDuty and Datadog templates
  • PostHogAvailable on requestWebhook, backfill, feature-effect report
  • heapdb-memoryOpen sourceAgent memories via MCP, LangGraph, LlamaIndex
  • Your appPython SDK and HTTP; TypeScript client coming

HeapDB

  1. RankEarlier events, by how long before the outcome they happened and which of their features matter
  2. ExplainThe evidence behind every score: timing, matched features and what it has learned
  3. LearnResults you confirm or reject change the next ranking

Results out

  • GitHubAvailable on requestPR comment and check run naming the likely culprit
  • Your appRanked results with explanations via the API
  • Agent contextOpen sourceRecall via MCP, LangGraph, LlamaIndex

Feedback: confirm or reject a result, and the next ranking uses it.

Available on request: working today; ask us for access. Connectors

Coming: native Sentry, PagerDuty and Datadog connectors, GitLab and Linear. Connectors

Keep Postgres, your warehouse and your vector store for records and search. Add HeapDB to rank what explains an outcome.

Code changes and incidents

Which change caused this error spike?

Ten PRs merged to checkout, then errors spiked. HeapDB ranks the merged PRs by when they landed, what they touched and what has broken before. Mark one reverted or cleared, and the ranking learns from it.

PRs merged to checkout, then an error spike at 15:00

ai-authored
  1. PR #4101 Bump eslint to 9.39, 11:20
  2. PR #4102 Docs: checkout README, 11:50, ai-authored
  3. PR #4103 Refactor payment retry client, 12:30, ai-authored
  4. PR #4104 Cart copy changes, 13:05
  5. PR #4105 Index orders.status, 13:40
  6. PR #4106 Retry on 409 with backoff, 14:05, ai-authored, ranked 3
  7. PR #4107 Add idempotency_key column, 14:20, ai-authored, ranked 1
  8. PR #4108 Update lockfile, 14:30, ranked 2
  9. PR #4109 Search ranking tweak, 14:45, ai-authored
  10. PR #4110 CI: cache node_modules, 14:52

TOP 3 CAUSES OF error_spike FOR checkout AT 15:00 EXPLAIN

  1. Likely cause 1: PR #4107 Add idempotency_key columnaiscore 0.85

    • merged 40m before
    • migration 0.50
    • path:payments/retry 0.40
    • review:fast 0.33
    • 140 lines
  2. Likely cause 2: PR #4108 Update lockfilescore 0.70

    • merged 30m before
    • size:large 0.29
    • lockfile 0.14
    • dep_bump 0.14
    • 900 lines
  3. Likely cause 3: PR #4106 Retry on 409 with backoffaiscore 0.69

    • merged 55m before
    • path:payments/retry 0.40
    • config 0.33
    • review:fast 0.33
    • 210 lines

Each result shows how long before the spike the PR merged, which features matched, and, next to each feature, what HeapDB has learned from earlier confirmed answers (0 to 1). These are likely causes with evidence, not proof.

How scoring works

Every result’s score combines three things: how long before the outcome the event happened, how big it was (for a PR, the lines changed), and what HeapDB has learned about its features from answers you confirmed or rejected. Each part is shown with the result, so you can check why it ranked where it did.

The score, defined · How feedback is learned · Core algorithms

Other use cases

The same engine answers questions about any stream of timestamped events.

  • Product analytics

    A user churned. HeapDB ranks the pages, features and errors that came before it, per user and across users, from your PostHog events.

  • Agent memory

    Your agent has a task to complete. HeapDB ranks the memories most useful for this turn and learns from the ones it actually used.

All use cases · RFCs for other domains · Share yours

Get started

heapdb-core: the engine

A Rust engine with a Python API, prebuilt wheels and no runtime dependencies. This example ranks the changes before an error spike on checkout, then confirms the one that was reverted.

# Python 3.10+
pip install heapdb

Building an agent? heapdb-memory is our open-source agent-memory package on top of the engine, with a Python SDK and an MCP server. Agent memory quickstart →

HeapDB is open source (Apache-2.0): a Rust engine with a Python API on PyPI, plus an HTTP server for HeapDB Cloud and self-hosting. On 1M events, a top-causes query runs 16× faster at p50 than the same query in SQLite. Benchmarks and methodology →

from heapdb import HeapDB, LogNormalKernel

M = 60  # times are in seconds
db = HeapDB()
db.register_effect(
    "error_spike",
    kernel=LogNormalKernel(median=30 * M, sigma=0.8),
    priors={"migration": (3, 3), "review:fast": (2, 8)},
)

# Changes to checkout, then an error spike at 15:00 (t = 900 min)
db.insert(entity="checkout", time=780 * M, type="deploy", features={"dep_bump"})
db.insert(entity="checkout", time=840 * M, type="pr", features={"refactor", "review:fast"})
db.insert(entity="checkout", time=860 * M, type="pr", features={"migration", "review:fast"}, weight=1.5)

causes = db.top_causes(entity="checkout", effect="error_spike", at=900 * M, k=3, explain=True)
for c in causes:
    print(c.rank, c.event.short(), round(c.score, 3), c.explanation)

# The revert fixed it: confirm the top result, and the next ranking uses it
db.feedback(entity="checkout", effect_type="error_spike", at_time=900 * M, confirmed_event_id=causes[0].event.id)