Skip to content
Runic
English
Esc
navigateopen⌘Jpreview
On this page

Cache

Signature-keyed artifact storage — in-memory and file-backed.

@runic-labs/cache maps a normalized decision signature to the artifact produced for it. Most integrations don’t need this package directly — @runic-labs/sdk wraps it — but it’s useful for custom store setups or inspecting cache internals.

npm install @runic-labs/cache
pnpm add @runic-labs/cache
yarn add @runic-labs/cache
bun add @runic-labs/cache

signature(decision)

Normalizes a Decision and returns its SHA-256 signature. Object keys in params are sorted recursively so key order never affects the hash. See How it works for the full algorithm.

import { signature } from "@runic-labs/cache";

signature({ intent: "summarize_pr", params: { repo: "acme/widgets", pr: 482 } });
// => same hash regardless of param key order

createCache(store?)

import { createCache, FileCacheStore, defaultCacheFilePath } from "@runic-labs/cache";

const cache = createCache(new FileCacheStore({ filePath: defaultCacheFilePath() }));

Defaults to a FileCacheStore under .runic/cache.json (or $RUNIC_HOME/cache.json) if no store is passed.

PropType
get(decision)?CachedEntry | null

Looks up a decision. Bumps hit stats on a hit.

TypeCachedEntry | null
set(decision, artifact, meta)?CachedEntry

Stores an artifact for a decision. meta = { tokensSpent }.

TypeCachedEntry
list()?CachedEntry[]

All entries currently in the store.

TypeCachedEntry[]
clear()?void

Removes all entries.

Typevoid

Storage backends

MemoryCacheStore

In-memory only, lives for the process’s lifetime. Used by both benchmarks and by tests, so runs are self-contained and repeatable.

import { createCache, MemoryCacheStore } from "@runic-labs/cache";

const cache = createCache(new MemoryCacheStore({ staleAfterMs: 60_000 }));

FileCacheStore

Persists to a JSON file so a CLI process and an agent process can read the same cache without a running server.

import { createCache, FileCacheStore } from "@runic-labs/cache";

const cache = createCache(new FileCacheStore({ filePath: "./my-agent/.runic/cache.json" }));

A corrupt or partially-written file is treated as empty rather than thrown — a crash mid-write should never take down the next read.

Implementing your own CacheStore

Both built-in stores implement the same small interface, so a Redis- or SQLite-backed store is a drop-in replacement:

interface CacheStore {
  get(signature: string): CachedEntry | null;
  set(signature: string, artifact: unknown, meta: { tokensSpent: number }): CachedEntry;
  touch(signature: string): CachedEntry | null;
  list(): CachedEntry[];
  clear(): void;
}

touch is called internally on every cache hit to bump hitCount and lastUsedAt — implement it as a read-modify-write against whatever backing store you choose.

Next

  • Ledger — the matching spent/saved accounting layer
  • SDK — the two-function contract most integrations actually use

Was this page helpful?