---
title: Quickstart
description: Wire askRunic and storeResult into an existing agent in a few minutes.
sidebar:
  order: 1
---

## Install

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

`@runic-labs/sdk` depends on `@runic-labs/cache` and `@runic-labs/ledger` — you don't need to install those separately unless you want to construct custom store instances yourself (see [Cache](/cache) and [Ledger](/ledger)).

## Wrap the call your agent already makes

Find the place in your agent where it turns a task into a call to an LLM or tool, and wrap it with `askRunic` / `storeResult`:

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

async function reviewFile(repo: string, file: string) {
  const decision = { intent: "review_code", params: { repo, file } };

  const cached = await askRunic(decision);
  if (cached) {
    console.log(`cache hit — saved ${cached.tokensSpent} tokens`);
    return cached.artifact;
  }

  const response = await callYourLLM(promptFor(repo, file));
  await storeResult(decision, response.text, response.tokensUsed);
  return response.text;
}
```

That's the whole integration. No configuration is required to get started — `askRunic`/`storeResult` use a default file-backed store under `.runic/` in your working directory.

## Choosing `intent` and `params`

The signature is exact-match, so decide what actually makes two calls "the same decision" for your use case:

- **Good**: `{ intent: "summarize_pr", params: { repo: "acme/widgets", pr: 482 } }` — same repo, same PR number, same intent, every time this exact PR is asked about.
- **Bad**: `{ intent: "summarize_pr", params: { prompt: fullPromptString } }` — including the raw prompt text as a param means any wording change (even whitespace) produces a cache miss, defeating the point.

Put only the parameters that actually identify the decision in `params`. Leave prompt text, reasoning traces, and anything non-deterministic out of the signature entirely — see [How it works](/how-it-works) for why.

## Inspect what's cached

```package-install
npm i -g @runic-labs/cli
```

```bash
runic cache status
runic ledger status
```

See [CLI](/cli) for full output examples.

## Point at a different store location

By default, Runic writes to `.runic/` in `process.cwd()`. Override it with an environment variable if your agent runs from a different working directory than where you want state to live:

```bash
RUNIC_HOME=/var/lib/my-agent/runic node agent.js
```

## Use in-memory storage instead (tests, ephemeral runs)

```ts
import { createRunicClient } from "@runic-labs/sdk";
import { createCache, MemoryCacheStore } from "@runic-labs/cache";
import { createLedger, MemoryLedgerStore } from "@runic-labs/ledger";

const runic = createRunicClient({
  cache: createCache(new MemoryCacheStore()),
  ledger: createLedger(new MemoryLedgerStore()),
});

const cached = await runic.askRunic({ intent: "summarize_pr", params: { repo, pr } });
```

This is exactly what `benchmarks/reuse-sweep` and `benchmarks/openrouter-savings` use, so nothing persists between separate script runs.
