Client reference

Constructing

const shimmy = new Shimmy();                    // reads the environment
const shimmy = new Shimmy({ apiKey, baseUrl }); // or explicit
OptionDefaultNotes
apiKeySHIMMY_API_KEY, then OPTIMIZER_API_KEYRequired.
baseUrlSHIMMY_BASE_URL, then OPTIMIZER_BASE_URLDefaults to https://rfa-labs.com.
sourceContexttrueAttach file, line and release to each call.
releaseauto-detectedFrom SHIMMY_RELEASE, GITHUB_SHA, GIT_COMMIT, …
objective—cost, quality, or latency.
onErrorwarnWhere telemetry failures go.
phaseSHIMMY_PHASE, else devdev, tuning or production.
devSourceSHIMMY_DEV_SOURCEDev: local (the repo) or remote (Shimmy).
recordingSHIMMY_RECORDINGDev: auto, record or strict.
productionSHIMMY_PRODUCTION, else managedProduction: managed or passthrough.
recordingsDirSHIMMY_RECORDINGS_DIRWhere local Recordings live.
lockfileSHIMMY_LOCKFILEWhat passthrough reads.

Python spells these in snake case (dev_source, recordings_dir); Rust takes them on ShimmyOptions as enums. Defaults, and how test runners change them, are on configuration. settings() returns what a call made now would use.

Scopes

run(name, fn, { id }) — opens a run. id resolves itself (an active OpenTelemetry trace id, else a uuid); pass one only when a request is not one run, such as a batch job where each item is its own.

step(id, options, fn) — opens a step. Options: kind, name, minScore, loopIndex, isRetry, mode ("discover" / "off"), latencyBudgetMs, objective.

TypeScript and Python take a callback or a context manager, so the scope closes itself. Rust returns a guard that closes on drop — RAII rather than a callback, because ? makes early returns idiomatic and a hand-closed scope would leak on the first error path someone wrote.

await shimmy.run('r', async () => {
  await shimmy.step('classify', { kind: 'classification' }, async () => {
    // …
  });
});

Opening a step outside a run starts an implicit single-step run rather than failing — partial instrumentation should degrade, not break.

Decorating a client

wrap(client) (TypeScript, Python) — returns your client, pointed at Shimmy, signed in with your Shimmy key, and annotated. Nothing is reimplemented, so unmodelled features keep working. What a call then does follows the Phase: replay a Recording, search, serve — or, in passthrough, leave the client’s own base URL and key alone and only rewrite each Step’s model from shimmy.lock.

An Anthropic client (anthropic.Anthropic(), new Anthropic()) can be wrapped too. Its messages.create calls are translated to Shimmy and the answer back into an Anthropic Message; in passthrough they go straight to Anthropic. Streaming is passthrough-only for Anthropic clients.

Python rides on extra_body, which is openai-python’s documented channel for unmodelled fields — so it survives version churn that would break a patched method. TypeScript patches the method, because JS has no equivalent.

instrument_openai(shimmy) (Python only) — a global patch for clients constructed inside a framework you do not own. Returns an undo callable, so test suites stay clean. It does not repoint base_url; it cannot know which clients in the process are meant for the optimizer.

decorate(&mut body) (Rust) — merges annotations into a JSON body. Rust has no dominant OpenAI client, so the seam is the request body rather than a wrapper. Attaches the Phase always; returns whether the call was inside a scope.

chat(body) (Rust) — the call itself, following the Phase exactly as wrap() does in the other SDKs: Recordings in Dev, Shimmy in Tuning and managed Production, your provider directly in passthrough.

Reporting

report(signals, { stepId, runId }) — see report outcomes.

verify(fn, kind) — runs fn, reports success or failure, rethrows. For where “did it work” is “did it throw”.

Best-effort: failures are logged, never thrown.

Reading the accounting

import { optimizerMeta } from '@rfa-labs/shimmy';

const meta = optimizerMeta(res);
meta?.saving;             // baseline − actual
meta?.exploration_cost;   // paid to learn; → 0 as the step settles

Escaping the scope

TypeScriptPythonRust
Across awaitautomaticautomaticautomatic
Into a spawned taskautomaticautomaticexplicit parent
Current idscurrentRunId()current_run_id()current()

Rust’s task-locals do not survive tokio::spawn. See instrument an agent.