Sdk
askRunic and storeResult — the entire agent-facing contract.
@runic-labs/sdk is the only package most integrations need to import directly. It wraps @runic-labs/cache and @runic-labs/ledger behind two functions.
npm install @runic-labs/sdkpnpm add @runic-labs/sdkyarn add @runic-labs/sdkbun add @runic-labs/sdkModule-level functions
For the common case — one agent process, default file-backed storage — use the free functions directly:
import { askRunic, storeResult } from "@runic-labs/sdk";
askRunic(decision)
Checks whether this exact decision has already been resolved.
decisionDecision
{ intent: string; params: Record<string, unknown> }
DecisionReturns Promise<CachedEntry | null> — null on a miss, or the cached entry (and logs a hit to the ledger) on a hit.
signature?string
The normalized signature this entry is keyed on.
stringartifact?unknown
Whatever was passed to storeResult() originally.
unknowntokensSpent?number
What producing this artifact cost the first time.
numbercreatedAt?number
Epoch ms when this entry was first stored.
numberlastUsedAt?number
Epoch ms of the most recent hit.
numberhitCount?number
Number of times this entry has been reused.
numberstale?boolean
Advisory only — Runic never acts on this itself.
booleanstoreResult(decision, artifact, tokensSpent)
Records a freshly-generated artifact for a decision, and logs what it cost so a future hit knows how much it saved.
decisionDecision
Same shape as askRunic's argument.
Decisionartifactunknown
Whatever you want returned on a future cache hit.
unknowntokensSpentnumber
Agent-reported cost of producing this artifact. Runic never measures this itself.
numberReturns Promise<void>.
createRunicClient(options?)
Use this instead of the module-level functions when you need multiple independent clients — most commonly for tests, or when explicitly choosing in-memory storage:
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()),
});
await runic.askRunic({ intent: "summarize_pr", params: { repo, pr } });
await runic.storeResult({ intent: "summarize_pr", params: { repo, pr } }, artifact, tokensUsed);
cache?Cache
Defaults to a file-backed cache under .runic/ if omitted.
Cacheledger?Ledger
Defaults to a file-backed ledger under .runic/ if omitted.
LedgerReturns a RunicClient with the same askRunic / storeResult shape as the module-level functions, scoped to whatever cache/ledger instances you passed in.