---
title: '@runic-labs/ledger'
description: Comptabilité en ajout seul des jetons dépensés et économisés.
sidebar:
  order: 5
---
`@runic-labs/ledger` est un simple outil de comptabilité : il n'applique jamais de budget, ne refuse jamais un appel et n'estime jamais un coût que vous n'avez pas signalé. Il répond à une question : *combien la résolution de ces décisions a-t-elle réellement coûté, et quelle part de ce coût a été évitée grâce à la réutilisation ?*

```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() }));
```

Utilise par défaut un `FileLedgerStore` dans `.runic/ledger.json` (ou `$RUNIC_HOME/ledger.json`) si aucun stockage n'est fourni.

| 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);
```

C'est exactement le calcul utilisé par `benchmarks/openrouter-savings` et `benchmarks/reuse-sweep` pour afficher leurs chiffres finaux ; consultez [Benchmarks](/benchmarks).

## Pourquoi `recordHit` ne prend pas d'argument `tokensSpent`

La valeur d'un hit est définie comme *le coût du miss initial pour cette signature* : le registre le recherche lui-même plutôt que de faire confiance à l'appelant pour le répéter correctement à chaque hit. S'il n'existe aucun miss antérieur pour une signature qui est néanmoins touchée (cela ne devrait pas se produire en utilisation normale, mais le registre ne suppose pas que ce soit impossible), il enregistre `0` plutôt que de deviner.

## Backends de stockage

Même modèle que `@runic-labs/cache` : `MemoryLedgerStore` pour les tests et les exécutions éphémères, `FileLedgerStore` pour la persistance entre des invocations de processus distinctes. Implémentez vous-même l'interface `LedgerStore` pour un autre backend :

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

## Suite

- [Cache](/cache) — le stockage correspondant, indexé par signature
- [CLI](/cli) — `runic ledger status` lit ce résumé depuis la ligne de commande
