---
title: Introduction
description: Runic is a cross-session cache and token ledger for an agent's already-resolved decisions.
---

Agents re-decide things they've already decided. The same PR gets summarized twice, the same file gets reviewed twice, the same changelog entry gets generated twice — and each time, the agent pays full price to regenerate an answer it already produced. Runic remembers the answer instead.

:::tip
**Ask once. Pay once.**
:::

## What Runic is

Runic sits next to whatever an agent already uses to act — including MCP tool calls — as an optional check: *"have I already resolved this exact decision before?"*

- **A cache**, keyed on an exact-match, normalized signature of a decision the agent already made — `{ intent, params }`, never raw task text, never a reasoning trace.
- **A ledger**, logging tokens spent (agent-reported) vs. tokens saved on reuse. Pure bookkeeping, no enforcement.
- **Per-session scope.** Cross-session/cross-agent sharing is a later phase, once per-session reuse is proven to matter.

## What Runic deliberately is not

- **Not an execution layer.** Runic never calls a capability, deploys anything, or runs code — the agent does that itself, however it already does it.
- **Not a permissions or sandboxing system.** There's nothing to check if nothing executes.
- **Not a semantic cache.** Matching is exact on the resolved decision, not fuzzy on the phrasing that led to it. See [Scope](/scope) for why that's a constraint, not a shortcut.

## Installation

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

## The loop

```txt
agent resolves a task into a structured decision
        │
        ▼
askRunic({ intent, params })
        │
        ├─ hit  → return cached artifact, log tokens saved
        └─ miss → agent generates its own way (as it does today)
                        │
                        ▼
                storeResult({ intent, params }, artifact, tokensSpent)
```

Two functions are the entire agent-facing contract. Everything else in this repo supports those two calls.

<CodeGroup>

```ts Without Runic
// Every call regenerates the answer, even for a decision you've
// already resolved once today.
async function summarizePr(repo: string, pr: number) {
  const result = await callYourLLM(promptFor(repo, pr));
  return result; // paid full price, every single time
}
```

```ts With Runic
import { askRunic, storeResult } from "@runic-labs/sdk";

async function summarizePr(repo: string, pr: number) {
  const decision = { intent: "summarize_pr", params: { repo, pr } };

  const cached = await askRunic(decision);
  if (cached) return cached.artifact; // no LLM call, no tokens spent

  const result = await callYourLLM(promptFor(repo, pr));
  await storeResult(decision, result, result.tokensUsed);
  return result;
}
```

</CodeGroup>

## Real numbers, not estimates

Runic never measures token cost itself — the agent reports it, using whatever its own provider actually returned. A real run against OpenRouter, resolving 48 decisions where only 8 were actually unique:

```json
{
  "decisions": 48,
  "uniqueDecisions": 8,
  "apiCalls": 8,
  "cacheHits": 40,
  "tokensSpent": 2582,
  "tokensSaved": 12910,
  "tokensWithoutRunic": 15492,
  "savingsPercent": 83
}
```

See [Benchmarks](/benchmarks) for how to reproduce this yourself, plus a synthetic sweep showing the same mechanism holds at 10,000 decisions.

