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

@credence/core

v0.6.0

Published

Credence core: the knowledge ledger — claims, evidence, sources, entities, cases.

Readme

@credence/core

The knowledge ledger: claims (with epistemic status), evidence (with locators), sources, entities (with resolution/merge), cases, and decisions. Append-only and content-addressed, so idempotency, supersession, and byte-deterministic rendering come for free. Runs on PGlite (zero-infra) or Postgres.

import { createLedger } from "@credence/core";

const ledger = await createLedger({ ontology });         // in-memory PGlite by default
const kase = await ledger.openCase({ title: "Acme diligence" });
const acme = await ledger.resolveEntity({ type: "company", label: "Acme Inc." });

await ledger.recordClaim({
  caseId: kase.id,
  subjectEntityId: acme.id,
  key: "total_debt",
  value: 410_000,
  status: "verified",                    // 'verified' REQUIRES evidence
  evidence: [{ source: { kind: "document", uri: "balance.pdf" }, locator: { page: 4 } }],
});

// "we checked, nothing there" — distinct from "never checked"
await ledger.recordAbsence({
  caseId: kase.id, subjectEntityId: acme.id, key: "lawsuits",
  evidence: [{ source: { kind: "query", uri: "court-registry" } }],
});

console.log(await ledger.renderCaseIndex(kase.id));       // byte-deterministic

Evidence stance

An evidence row records how the source bears on what it grounds, not only that it is attached:

await ledger.recordClaim({
  caseId: kase.id, subjectEntityId: acme.id, key: "total_debt", value: 410_000,
  status: "verified",
  evidence: [{ sourceId: doc.id, locator: { page: 4 }, stance: "supports" }],
});

supports / contradicts / cited. Omit the field to leave it UNSTATED — never defaulted to supports, and never backfilled on rows written before 0.5.0. cited is the one that earns the enum: the agent read this and it did not bear on the claim. Stance is inside the evidence identity, so the same passage under two stances is two rows, not one mutated row. Credence never infers a stance.

verified still requires evidence, and now also refuses when every attached piece explicitly declines to support. Unstated evidence satisfies the guard exactly as it always has.

Migrations

createLedger() migrates on open. Schema changes ship as ordered migrations recorded in _credence_migrations — not as CREATE TABLE IF NOT EXISTS, which silently skips a table whose shape changed.

import { migrate, pendingMigrations, openDb } from "@credence/core";

const handle = await openDb({ postgres: process.env.DATABASE_URL });
await pendingMigrations(handle);  // -> ids not yet applied
await migrate(handle);            // idempotent; safe on every boot

Migrations are embedded in TypeScript rather than read from a folder: this library runs in-process and gets bundled downstream, where a runtime migrations/ directory silently stops resolving. Author new ones with pnpm db:generate (drizzle-kit) and paste the SQL into src/migrations.ts.

Relations

Entities are linked by typed, evidenced relations — append-only and content-addressed exactly like claims:

await ledger.recordRelation({
  caseId, subjectEntityId: alice.id, predicate: "spouse_of", objectEntityId: bob.id,
  status: "verified",
  evidence: [{ source: { kind: "document", uri: "marriage.pdf" }, locator: { page: 2 } }],
});

The predicate is HARD-validated against ontology.relationPredicates (an empty list means discovery mode). This is deliberately stricter than claim keys, which are soft-normalized through aliases: detection rules key off predicates, so silently accepting married_to where a rule expects spouse_of would stop that rule firing with no error anywhere. Catch UnknownPredicateError per item when ingesting model output so one bad predicate doesn't sink a batch.

Obligations — what is still owed

Every other object records what is true. An obligation records what is still owed — a condition attached to a decision.

const o = await ledger.obligations.open({
  caseId, title: "Register the lien", blocking: true, by: "committee",
});

await ledger.obligations.transition(o.id, "done", {
  by: "analyst",
  evidence: [{ source: { kind: "document", uri: "lien.pdf" }, locator: { page: 1 } }],
});

await ledger.obligations.blockers(caseId);  // still-open blocking obligations

It earns a place in the core because its governing rule is epistemic, not domain-specific: done requires evidence. Marking something fulfilled with nothing to point at is the same unsourced claim the ledger refuses everywhere else — and it is the one that most tempts people, because closing an item feels like progress. Waiving requires a reason, illegal transitions are rejected rather than silently accepted, and every move appends to a transition log.

An obligation is not just stored — it is visible. It appears in the Case Index under Owed, in next_steps, in the snapshot payload (so a pre_decision snapshot records what was still owed, not only what was known), and it is addressable as credence://obligation/…. Something an agent can never see is the same as something you never recorded.

Human oversight — advisory, and never a freeze

Three primitives, no policy: a declared intervention point, a per-case hold, and an advisory autonomy limit.

await ledger.oversight.points.declare({ id: "pre-decision", required: true });
await ledger.oversight.points.list({ required: true });   // what a case must satisfy

await ledger.oversight.hold({ caseId, by: "analyst", reason: "…", pointId: "pre-decision" });
await ledger.oversight.state(caseId);      // { held, holds, since, by, actorKind, reason, pointId, ref }
await ledger.oversight.release({ caseId, by: "analyst", reason: "…" });

await ledger.oversight.setAutonomyLimit({ caseId, maxIterations: 5, by: "analyst" });
await ledger.oversight.recordIteration({ caseId, by: "agent:mcp" });
await ledger.oversight.autonomy(caseId);   // AutonomyReport | null — null when no ceiling was declared
await ledger.oversight.blockers(caseId);   // OversightBlocker[]

A hold never refuses a write. A ledger that stopped recording during a stop would destroy the facts the human was called in to weigh, and the write that matters most is often the one made while someone is looking. What a hold changes is what every read says — the Case Index leads with a banner, next_steps leads with the stop, the snapshot payload carries it — plus one machine-readable signal, blockers(), on the same contract obligations.blockers() already has. Credence reports; the caller enforces.

autonomy() has three states, not two, and returns null when no ceiling was ever declared. within and exceeded are the obvious ones; unreported means a ceiling was declared and no iteration was ever recorded against it — the loop was never instrumented. It is a blocker, and it is rendered without a fraction, because 0/5 reads like a comfortable zero when the truth is that nobody counted.

Four blocker reasons — held, autonomy_exceeded, autonomy_unreported, required_point_unsatisfied — each carrying a printable detail. required on a point is mechanism, not policy: it says a hold must cite this point before the case reads as clear, and says nothing about who acts or under which rulebook. Credence ships zero points, and a catalogue with no required points behaves exactly as if the feature were absent.

A pointId is hard-validated on every write: citing a point that was never declared throws, and nothing is written. That is deliberately unlike relation predicates, where an unrecognised predicate is still recorded — an unusual predicate is a true statement about the world, while a hold citing a point that does not exist is a false statement about governance.

Holds and releases are attributed acts, so they are on the audit chain as oversight_event. Iteration markers are not: a counter is not an act by anyone.

The audit chain — tamper-evidence and attribution

Every claim, relation, decision and obligation transition appends one entry to a per-case, append-only hash chain: dense seq from 1, each entry hashing the one before it. An entry stores the object's content hash, not its values — the chain proves the sequence of writes, and never becomes a second copy of the ledger you would then have to keep in step.

await ledger.chain.list(caseId);          // the entries, in order
await ledger.verifyChain(caseId);
// { status: "ok", entries: 14, head: { seq: 14, entryHash: "…" }, witnessed: false }

verifyChain recomputes every hash, re-walks the links, and checks that every object in the case is covered. It returns one of three verdicts — ok, broken (with the failing seq and one of nine reason codes) or indeterminate — and persists nothing: a stored verdict is a claim about the past that the reader has to trust, which is the thing this chain exists to avoid. There is no backfill, so a case written before chaining existed reads indeterminate forever, never ok.

The chain also answers who. Pass assertedBy on a write (or set the ledger's actor) and the identity lands on the entry — and, for a claim, on the claim itself as assertedBy/modelVersion, which is the first asserter and costs no chain walk to read. Attribution is deliberately outside content-addressed identity: the same fact asserted by two actors stays one claim with two chain entries, rather than forking into two claims.

const checkpoint = await ledger.chain.checkpoint(caseId);
// { caseId, seq, headHash, at, algorithm: "sha256" }  — null if the case has no entries

await ledger.verifyChain(caseId, { witness: checkpoint });   // witnessed: true

cases.chain_head_seq/chain_head_hash anchor the head, but an attacker who can write to the database can rewrite that anchor and re-derive every hash after the edit. That is inherent to a chain living entirely inside the data it attests — and it is precisely why checkpoint() exists: keep the exported head somewhere Credence cannot reach and pass it back as witness, and a truncation that the chain and its local anchor both agree on is caught (truncated_below_witness). Credence does not notarize, sign, or timestamp the checkpoint; where it lives is your control, not this library's.

Key ideas

  • Content-addressed identity. id = <prefix>_<hash(meaning)>. Same assertion → same id → idempotent no-op. A different value → a different claim, never a mutation.
  • Evidence guard. status: "verified" without evidence throws. Evidence that is attached and explicitly and unanimously non-supporting (contradicts / cited) throws too, with EvidenceRequiredError.reason naming which. Unstated evidence still satisfies the guard.
  • unknown vs absent. recordAbsence records evidenced absence via the ABSENT marker (isAbsent(value)), which the matrix and diff treat distinctly.
  • credence:// refs. Every object is addressable; resolveRef powers progressive disclosure (snapshots resolve to meta + counts only).
  • Evidence is polymorphic. It grounds a claim or a relation — both are assertions, both are worthless without provenance. listEvidence(claimId) still works; pass { type: "relation", id } for the other side.
  • Merges keep their promises. Claims and relations re-point on read; findings are migrated explicitly (their identity embeds the entity id) so a merge never resurrects a dismissal a human already closed.
  • Injected ontology. Claim-key catalog (with aliases), entity types, scheme — all yours. The core carries no business vocabulary.

Postgres & pgvector

The same ledger runs on PGlite (dev/test, zero-infra) and Postgres (prod) — one code path. Opt into embeddings with vector: { dimensions } and Credence installs the vector extension and an embeddings table on whichever driver you use.

// Zero-infra dev, with semantic search — pgvector runs inside PGlite:
const dev = await createLedger({ ontology, vector: { dimensions: 1536 } });

// Production — identical API, real Postgres (needs the optional `pg` peer dep):
const prod = await createLedger({
  postgres: process.env.DATABASE_URL,      // e.g. pgvector/pgvector:pg16
  ontology,
  vector: { dimensions: 1536 },
});

await prod.embedClaim(claim.id, { model: "text-embedding-3-small", vector });
const hits = await prod.similarClaims(queryVector, { caseId, limit: 5 });
// → [{ claim, similarity, distance }, ...]  (cosine by default)

Embeddings are addressed by (targetType, targetId, model), so re-embedding is an idempotent upsert. Vectors are entirely opt-in — omit vector and nothing about the zero-infra path changes.

Exports the Drizzle schema at @credence/core/schema.