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

promptledger

v0.1.0

Published

Tamper-evident audit trail for LLM calls. Hash-chained logging with verification, compliance export, and SDK middleware.

Readme

PromptLedger

Token counters tell you how much you spent. ContextGuard tells you if it was worth it. PromptLedger proves what happened.

Tamper-evident audit trail for LLM calls. Hash-chained logging with verification, compliance export, and SDK middleware.

The Problem

AI teams log LLM calls to flat files, databases, or observability platforms. None of them can answer: "Has anyone modified a recorded response after the fact?"

When a security analyst flags a CRITICAL finding but someone changes the stored output to LOW, regular logs won't catch it. PromptLedger will — every entry is SHA-256 hashed and chained to the previous entry. Modify anything, and the chain breaks.

PromptLedger proved it: In the tamper detection demo, an attacker modifies a stored severity rating from CRITICAL to LOW. Verification instantly detects the broken hash chain and pinpoints the exact tampered entry.

The Solution

Treat LLM audit trails as a ledger, not a log. Three capabilities:

  • Record — Append-only hash-chained entries for every LLM call
  • Verify — Chain integrity check from genesis to head in milliseconds
  • Export — Compliance-ready JSON with verification proof and statistics

Quick Start

# See the tamper detection demo (records → verifies → tampers → re-verifies)
npx promptledger scenario

# Verify your ledger chain
npx promptledger verify

# Chain statistics
npx promptledger stats

# Recent entries
npx promptledger recent 20

# Export full ledger for compliance
npx promptledger export audit-2026-Q1.json

# JSON output for piping
npx promptledger verify --json

Programmatic Usage

Record LLM Calls

import { LedgerEngine } from 'promptledger';

const ledger = new LedgerEngine({
  agent: 'claims-processor',
  sessionId: 'session-001',
});

// Record any LLM call
const entry = ledger.record({
  provider: 'anthropic',
  model: 'claude-sonnet-4-6',
  operation: 'chat',
  input: [
    { role: 'system', content: 'You are a claims analyst.' },
    { role: 'user', content: 'Review this medical evidence.' },
  ],
  output: [
    { role: 'assistant', content: 'Based on the evidence, I found...' },
  ],
  tokens: { input: 1250, output: 890 },
  latencyMs: 1340,
  tags: ['claims', 'medical-review'],
});

console.log(entry.hash);     // SHA-256 hash of this entry
console.log(entry.sequence);  // Position in chain

Verify Chain Integrity

const result = ledger.verify();

console.log(result.valid);          // true — chain intact
console.log(result.entriesChecked); // 147
console.log(result.headHash);       // Current chain head
console.log(result.verificationMs); // 12ms for 147 entries

// If tampered:
// result.valid === false
// result.brokenAt === 42
// result.brokenReason === "Entry 42 hash mismatch — content was modified"

SDK Middleware (Anthropic)

import Anthropic from '@anthropic-ai/sdk';
import { LedgerEngine, createAnthropicWrapper } from 'promptledger';

const client = new Anthropic();
const ledger = new LedgerEngine({ agent: 'my-app' });
const wrap = createAnthropicWrapper({ ledger, provider: 'anthropic' });

// Wrap any SDK call — automatically recorded to ledger
const request = {
  model: 'claude-sonnet-4-6',
  max_tokens: 1024,
  messages: [{ role: 'user', content: 'Hello' }],
};

const { response, entryId, entryHash } = await wrap(
  () => client.messages.create(request),
  request,
);

// response = normal Anthropic response
// entryId = UUID of the ledger entry
// entryHash = SHA-256 hash for this call

SDK Middleware (OpenAI)

import OpenAI from 'openai';
import { LedgerEngine, createOpenAIWrapper } from 'promptledger';

const client = new OpenAI();
const ledger = new LedgerEngine({ agent: 'my-app' });
const wrap = createOpenAIWrapper({ ledger, provider: 'openai' });

const request = {
  model: 'gpt-4o',
  messages: [{ role: 'user', content: 'Hello' }],
};

const { response, entryId } = await wrap(
  () => client.chat.completions.create(request),
  request,
);

Export for Compliance

const exportData = ledger.export();

// exportData includes:
// - version: '1.0'
// - verification: { valid: true, entriesChecked: 147, ... }
// - stats: { totalEntries: 147, totalTokens: { ... }, ... }
// - entries: [ ... all entries ... ]

// Write to file
import { writeFileSync } from 'fs';
writeFileSync('audit-export.json', JSON.stringify(exportData, null, 2));

Query & Filter

// By agent
const agentCalls = ledger.query({ agent: 'claims-processor' });

// By model
const claudeCalls = ledger.query({ model: 'claude-sonnet-4-6' });

// By time range
const todayCalls = ledger.query({
  since: '2026-04-01T00:00:00Z',
  until: '2026-04-02T00:00:00Z',
});

// Combined
const recent = ledger.query({
  agent: 'security-analyst',
  operation: 'chat',
  limit: 50,
});

How It Works

Entry #0 (Genesis)              Entry #1                       Entry #2
┌─────────────────────┐   ┌─────────────────────┐   ┌─────────────────────┐
│ previousHash: 000…  │   │ previousHash: a3f…  │   │ previousHash: 7d2…  │
│ input: [...]        │   │ input: [...]        │   │ input: [...]        │
│ output: [...]       │   │ output: [...]       │   │ output: [...]       │
│ tokens: {in, out}   │   │ tokens: {in, out}   │   │ tokens: {in, out}   │
│ hash: a3f…     ─────┼──→│ hash: 7d2…     ─────┼──→│ hash: e91…          │
└─────────────────────┘   └─────────────────────┘   └─────────────────────┘

If Entry #1 output is modified after recording:
  → Recomputed hash ≠ stored hash → CHAIN BROKEN at #1
  → Entry #2 previousHash ≠ Entry #1 new hash → CHAIN BROKEN at #2

Each entry's hash covers: sequence + previousHash + timestamp + provider + model + operation + input + output + tokens. Change any field and the hash changes. The chain catches both content tampering and entry reordering.

CLI Reference

promptledger scenario              Tamper detection demo
promptledger verify                Verify chain integrity (exit code 0=intact, 1=broken)
promptledger stats                 Chain statistics
promptledger recent [N]            Most recent N entries (default: 10)
promptledger export [file]         Export ledger as JSON (default: promptledger-export.json)
promptledger --help                Help

Options:
  --db <path>      Database path (default: ~/.promptledger/ledger.db)
  --json           JSON output

Storage

PromptLedger uses SQLite (via better-sqlite3) for storage:

  • Default location: ~/.promptledger/ledger.db
  • WAL mode for concurrent read performance
  • Indexed on: sequence, timestamp, agent, session_id, model
  • Override with --db <path> (CLI) or storagePath option (API)
  • Use :memory: for testing / ephemeral ledgers

Compliance Mapping

| Requirement | Framework | How PromptLedger Addresses It | |------------|-----------|-------------------------------| | Traceability | EU AI Act Art. 12 | Every LLM call recorded with full input/output | | Logging & Monitoring | NIST AI RMF MG-2.2 | Append-only ledger with chain verification | | Audit Trail | ISO 42001 A.6.2.6 | Hash-chained entries with tamper detection | | Audit Record Content | NIST 800-53 AU-3 | Structured records: who, what, when, tokens | | Audit Record Integrity | NIST 800-53 AU-10 | SHA-256 hash chain prevents undetected modification | | Non-repudiation | NIST 800-53 AU-10(2) | Chain verification proves entry authenticity |

License

MIT


Built by ACE — Advanced Consulting Experts

Regular logs tell you what happened. PromptLedger proves nobody changed the story.