---
title: '@runic-labs/ledger'
description: Anhangsbasierte Buchführung über ausgegebene und eingesparte Tokens.
sidebar:
  order: 5
---
`@runic-labs/ledger` ist reine Buchführung — es setzt niemals ein Budget durch, lehnt niemals einen Aufruf ab und schätzt niemals Kosten, die du nicht gemeldet hast. Es beantwortet eine Frage: *Was hat das Auflösen dieser Entscheidungen tatsächlich gekostet, und wie viel davon wurde durch Wiederverwendung vermieden?*

```package-install
npm i @runic-labs/ledger
```

## `createLedger(store?)`

```ts
import { createLedger, FileLedgerStore, defaultLedgerFilePath } from "@runic-labs/ledger";

const ledger = createLedger(new FileLedgerStore({ filePath: defaultLedgerFilePath() }));
```

Verwendet standardmäßig einen `FileLedgerStore` unter `.runic/ledger.json` (oder `$RUNIC_HOME/ledger.json`), wenn kein Store übergeben wird.

| Prop | Type | Default | Description |
| - | - | - | - |
| `recordMiss(signature, tokensSpent)?` | `void` | - | Logs a cache miss — the agent generated its own way and spent tokensSpent. |
| `recordHit(signature)?` | `void` | - | Logs a cache hit, recording the same tokensSpent as the original miss for this signature. |
| `summary()?` | `LedgerSummary` | - | Aggregated totals — see below. |
| `all()?` | `LedgerEvent[]` | - | The full raw event log. |
| `clear()?` | `void` | - | Removes all events. |

## `LedgerSummary`

```ts
interface LedgerSummary {
  totalSpent: number;
  totalSaved: number;
  hitsBySignature: Record<string, number>;
}
```

```ts
const summary = ledger.summary();
const totalHits = Object.values(summary.hitsBySignature).reduce((a, b) => a + b, 0);
const tokensWithoutRunic = summary.totalSpent + summary.totalSaved;
const savingsPercent = Math.round((summary.totalSaved / tokensWithoutRunic) * 100);
```

Dies ist genau die Berechnung, die sowohl `benchmarks/openrouter-savings` als auch `benchmarks/reuse-sweep` verwenden, um ihre endgültigen Zahlen auszugeben — siehe [Benchmarks](/benchmarks).

## Warum `recordHit` kein `tokensSpent`-Argument annimmt

Der Wert eines Hits ist definiert als *was auch immer der ursprüngliche Miss für diese Signatur gekostet hat* — das Ledger schlägt ihn selbst nach, statt darauf zu vertrauen, dass der Aufrufer ihn bei jedem Hit korrekt wiederholt. Wenn für eine Signatur, die irgendwie getroffen wird, kein vorheriger Miss existiert (sollte bei normaler Nutzung nicht passieren, aber das Ledger nimmt nicht an, dass es unmöglich ist), zeichnet es `0` auf, statt zu raten.

## Speicher-Backends

Dasselbe Muster wie bei `@runic-labs/cache`: `MemoryLedgerStore` für Tests und kurzlebige Ausführungen, `FileLedgerStore` für Persistenz über separate Prozessaufrufe hinweg. Implementiere die Schnittstelle `LedgerStore` selbst für ein anderes Backend:

```ts
interface LedgerStore {
  append(event: LedgerEvent): void;
  all(): LedgerEvent[];
  clear(): void;
}
```

## Nächste Schritte

- [Cache](/cache) — der passende signaturbasierte Store
- [CLI](/cli) — `runic ledger status` liest diese Zusammenfassung über die Befehlszeile
