Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content
Reference

TypeScript SDK

@mubit-ai/minima-sdk is the official TypeScript client for the Minima API: pure fetch, zero runtime dependencies, typed against the same /v1/* wire contract as the Python SDK. It works in Node, Bun, Deno, and edge runtimes.

Install

npm install @mubit-ai/minima-sdk
# or: bun add / pnpm add / yarn add @mubit-ai/minima-sdk

Client

import { MinimaClient } from "@mubit-ai/minima-sdk";
 
const minima = new MinimaClient({
  baseUrl: "https://api.minima.sh",
  apiKey: process.env.MUBIT_API_KEY,   // your Mubit key (mbt_…), sent as Bearer auth
});

MinimaClientOptions also accepts feedbackRetryDelaysMs (default [500, 2000]) and an injectable fetch for hermetic tests.

The full loop: recommend → run → feedback

You run the model — Minima only recommends. Close the loop with realized usage measured from the provider's own response:

import Anthropic from "@anthropic-ai/sdk";
import { MinimaClient } from "@mubit-ai/minima-sdk";
 
const minima = new MinimaClient({
  baseUrl: "https://api.minima.sh",
  apiKey: process.env.MUBIT_API_KEY,
});
const anthropic = new Anthropic();
 
// $/Mtok — from your provider contract, or GET /v1/models (input_cost_per_mtok / output_cost_per_mtok)
const PRICES: Record<string, { in: number; out: number }> = {
  "claude-haiku-4-5": { in: 1.0, out: 5.0 },
  "claude-sonnet-4-6": { in: 3.0, out: 15.0 },
};
 
// 1. recommend
const rec = await minima.recommend(
  { task: "Summarize this incident report into 3 bullets.", task_type: "summarization" },
  { costQualityTradeoff: 3 },
);
const model = rec.recommended_model.model_id;
 
// 2. run the model YOURSELF, measuring real usage
const started = Date.now();
const msg = await anthropic.messages.create({
  model,
  max_tokens: 1024,
  messages: [{ role: "user", content: "Summarize this incident report into 3 bullets." }],
});
const latencyMs = Date.now() - started;
 
// 3. realized cost from the provider's actual token counts × your price table
const p = PRICES[model] ?? { in: 0, out: 0 };
const costUsd =
  (msg.usage.input_tokens / 1e6) * p.in + (msg.usage.output_tokens / 1e6) * p.out;
 
// 4. close the loop with what ACTUALLY happened
await minima.feedback(rec.recommendation_id, model, "success", {
  usage: {
    inputTokens: msg.usage.input_tokens,
    outputTokens: msg.usage.output_tokens,
    costUsd,
    latencyMs,
  },
  qualityScore: 0.95,        // your judge/eval score, if you have one
  evidenceSource: "human",   // gate | judge | human | none — label provenance
});
⚠️Warning

Never echo est_cost_usd back as the actual cost. rec.recommended_model.est_cost_usd is Minima's own prediction; usage.costUsd must be the realized cost of the call. Real numbers are what let the cost basis climb estimate → observed → rescaled — the single biggest accuracy lever of the loop.

recommend(task, opts)

task is a string or a TaskInput ({ task, task_type?, difficulty?, expected_input_tokens?, expected_output_tokens?, tags? }). Options (camelCase; mapped to the wire):

const rec = await minima.recommend("refactor the auth module", {
  costQualityTradeoff: 5,                 // 0..10 (default 5)
  constraints: {                          // hard filters
    candidate_models: ["claude-haiku-4-5", "claude-sonnet-4-6"],
  },
  namespace: "team-payments",
  baselineModelId: "claude-opus-4-8",     // what you'd use without Minima -> honest savings()
  incumbentModelId: undefined,            // session's prompt-cache holder, if any
  phase: "interactive",                   // rides as a `phase:<value>` tag
  signal: undefined,                      // per-call AbortSignal
});

recommend fails fast and never retries — catch the error and fail open to your default model; your LLM call must never block on Minima.

feedback(recommendationId, chosenModelId, outcome, opts)

outcome is "success" | "partial" | "failure". Options: usage ({ inputTokens, outputTokens, costUsd, latencyMs } — all realized), qualityScore, evidenceSource ("gate" | "judge" | "human" | "none"), errorCause ("infra" | "quality"), chosenEffort, iterations, notes, idempotencyKey, signal.

Feedback retries transparently on transient faults (transport errors, 502/503/504) with the feedbackRetryDelaysMs schedule; the server dedupes via the idempotency key. For wire-level fields like step_outcomes, use feedbackRaw(req) — the raw request shape with the same retry behavior.

ℹ️Note

evidenceSource: "none" marks an unlabeled outcome — it rides as cost/latency telemetry only and never teaches the success posterior. "gate" (a deterministic check passed) is the only origin that may claim verified-in-production. For provider faults pass errorCause: "infra" so a rate limit never reads as model quality.

Reporting and catalog

await minima.savings({ days: 30, group_by: "task_type" });  // SavingsResponse
await minima.calibration({ days: 30 });                     // CalibrationResponse
await minima.policyValue({ days: 30 });                     // doubly-robust regret-vs-oracle
await minima.strategies({ namespace: "team-payments" });    // promoted rules
await minima.diagnose({ error_text: "TypeError: …" });      // failure lessons
await minima.memoryHealth({ namespace: "team-payments" });  // memory hygiene
await minima.models({ provider: "anthropic" });             // catalog with $/Mtok prices
await minima.capabilities();                                // feature handshake
await minima.health();

Errors

Non-2xx responses throw a typed ladder: MinimaRateLimited (429, with retryAfter seconds when the server provides it), MinimaUnavailable (502/503/504), and MinimaError (everything else — carries status and the problem+json body).

import { MinimaError } from "@mubit-ai/minima-sdk";
 
try {
  const rec = await minima.recommend(task);
} catch (exc) {
  // fail open: fall back to your default model
}

Where to go next

  • SDK architecture — how both SDKs encode the loop: the wire contract, retry discipline, label honesty, and the differences between TypeScript and Python.
  • Using Minima correctly — the golden rules of the loop in one place.
  • API Reference — every field on the wire.