MainSDK
Search⌘K
How-to

Know what normal looks like for your app

Turn on norms, read what the app has learned, and get an anomaly signal when traffic, errors or loop delay leave their usual range.

Building for 0.4

Status Status is where the work is: Planned (in a milestone, not started), Building (tickets in progress), Preview (usable, may change), then the stability it ships at.

Stability The promise an interface ships with.

  • Stable Follows semantic versioning; breaking changes need a new major, 12 months of overlap and a codemod.
  • Beta Usable in production; may change before it becomes stable.
  • Experimental May change or go away; needs an explicit opt-in in main.yaml.
Stability levels
Updated 2026-10-28

You will add norms to your app, read what it learned and play an afternoon of traffic against it in a test. It takes about 15 minutes.

You need

1. Turn learning on

main.yaml
norms:
  season: hour-of-week
  tz: Asia/Kolkata
  learn: 7d

Run npx mainsdk check. A wrong value is reported as MAIN-NORMS-0001 with the key named.

2. Read what it learned

ts
import { norms } from "mainsdk";

const view = await norms.get("requests");
console.log(view.bucket, view.n, view.p50, view.p99, view.learning);
const page = await norms.list();   // one view per metric

learning stays true until the model is learn old and a bucket has min-samples values.

3. Listen for anomalies

ts
import { signals } from "mainsdk";

signals.on("anomaly.*", (s) => console.log(s.name, s.subject, s.data));

A metric must stay out of range for hold windows before one anomaly.detected is sent.

4. Test it with a simulated afternoon

ts
import { createSim, sine } from "@mainsdk/testing";

const sim = createSim({ apps: { web: { main: "./main.yaml" } }, seed: 42 });
sim.inject.traffic("web", { rps: sine({ min: 1, max: 8, period: "24h" }) });
await sim.run("14d", { step: "1s" });
sim.expect.none("web", "anomaly.detected");

5. Forget a model after a migration

ts
import { norms } from "mainsdk";

await norms.delete("requests", { reason: "migrated to a new checkout" });   // needs norms.manage

Check it worked

Run npx mainsdk norms. It lists each metric with its bucket and count.

Was this page helpful?

↑↓ moveEnter openEsc close

Not decided yet