Supervision

Pings perfectly, does nothing.

That phrase started as a note in our own source code about a workflow that reports in on time while the work behind it has stopped. It is the failure a deadline cannot catch, because everything a deadline can see is fine.

Agents made it the common case. An agent rarely crashes. It returns confidently, reports success, emits a clean 200, and the invoice went in with the wrong total, or the account was created without its permissions, or the record was never written at all. There is no error to catch. Nothing goes red. The run looks exactly like every run that worked.

Supervision is the third question this product asks: not did it run, and not did it run when it normally does, but did the work actually happen.

Every one of these is the same shape

Something the automation claims it did. Something in another system that either confirms it or does not. An alert when those two stop agreeing.

That is the whole idea, and it is worth naming because once you see it you start finding it everywhere. Here are five from the work people actually run.

Accounts payable

The invoice posts with the wrong total

The claim
The run reports that invoice INV-4471 was filed, for 4,182.50.
The evidence
One record in the ledger with that invoice number, and its total.

The invoice is there and the total is not the one that was approved, or it is there twice. Both of those are a successful run by every measure the automation has.

Joiner provisioning

The account exists with no group memberships

The claim
The run reports that an account was created for the new starter.
The evidence
The directory record, and the number of groups attached to it.

The account is real and has nothing on it, so the person cannot work on their first day. Creation succeeded; the part that mattered was the second call.

CRM enrichment

A renamed field turns writes into no-ops

The claim
The run reports that it enriched 240 records.
The evidence
Those records, and whether the enriched field is actually populated.

A field was renamed upstream, so every write lands on a property that no longer exists. The API accepts them. The count is correct. Nothing was written.

Regulatory filing

The submission transmits and arrives empty

The claim
The run reports a successful submission and the receipt id it was given.
The evidence
The filing as the receiving system holds it, and whether it has any line items.

The transport worked perfectly and the receipt is genuine. The document behind it is blank, and the deadline for noticing is the one in the regulation.

How it actually works

A model is involved exactly once, at setup, and it is a translator rather than a judge. That distinction is the product, so it is worth being precise about.

01

Describe the job in plain English

One or two sentences about what a successful run leaves behind. Name the fields your workflow reports and the records it should be able to point at.

02

A model compiles it, once

Your sentence becomes a small set of structured checks. This happens at setup time and nowhere else. The model translates; it never judges a run.

03

You read the checks and approve them

Not the JSON. The checks in the same plain English, next to the sentence you wrote, with a box to try them on an example first. Nothing judges anything until you say yes.

04

Every run after that is judged by code

Deterministic code, in your own process, against the checks you approved. Same input, same verdict, every time. No model is consulted again.

Why that matters when something fires at 3am

Because the alert can tell you which rule caught it, and which version of that rule, and who approved it. You can read the check in the same words you approved, and if it was wrong you can point at the exact sentence that produced it.

An alert that says a model thought something looked wrong is not something anybody can act on at 3am, and it is not something you can argue with. Ours names a check. Rules are versioned and never edited in place, so last week's alert is still explained by the rule that produced it rather than by whatever the rule says today.

A single bad verdict does not wake anybody either. We alert on two failures in a row, because one is more often a blip than a problem.

The checking happens on your machine

Supervision runs inside your own process, through the SDK. Your code gathers the evidence, from your ledger or your database or your API, and the checks run there, next to the data. That is not a deployment preference. It is the reason we can say the next sentence.

A check that runs on your machine sends a verdict and nothing else. What reaches us is that check three failed and the reason was a value mismatch. Not the total, not the invoice number, not the record. There is no field in the format we accept that an invoice total would fit in, and a report carrying one is refused at the door rather than quietly stored.

There is one exception, and it is the whole of it. Some questions cannot be settled by comparing values. Whether a summary reflects the email it came from, whether a reply answers what was asked, whether one document agrees with another: those need reading, not comparing, so we read them. A rule can include a check like that, and when it does, the fields it names are sent to us so our model can answer the question.

You see that list before you approve the rule, written out field by field, and a rule is not in force until you do. The check sends those fields and no others: it is capped at six of them, our server compares what arrives against the list you approved, and a report that sends anything else is refused rather than judged. If you would rather nothing left at all, approve only the checks that compare, and the sentence above this one is the whole story for your account.

If you want a comparison without sending us even a hash of the thing being compared, rules can match on fingerprints, so an account number is checked without either side ever holding it.

And we delete what we do not need. Verdicts are kept per monitor and trimmed, ping history is capped, and the counts on your dashboard survive the trimming because they are counters rather than a sum over rows we are about to delete.

Node

import { Supervisor } from "@silentfail/node";

const supervisor = await Supervisor.start({
  apiKey: process.env.SILENTFAIL_API_KEY,
  monitorId: "your-monitor-id",
});

// at the end of the run
await supervisor.check({
  claim: { status: "success", reference: invoiceNumber },
  evidence: () => ledger.find({ invoiceNo: invoiceNumber }),
});

npm install @silentfail/node · pip install silentfail-sdk

The Python package has the same shape. Both run the same checks and agree on the same verdicts, which is enforced by a shared suite of fixtures rather than by hoping.

Three outcomes, and the third is the important one

A check passes, fails, or could not be run. That third state is the whole reason this is trustworthy. If the ledger was unreachable, or a field was missing, or the rule could not be read, you are told that. It is never counted as a pass and never counted as a failure.

It does not wake anybody either. A failure is a finding; not knowing is not. It shows on the monitor and in the logs, and the difference between those two is the difference between a monitoring tool you can rely on and one you learn to ignore.

We sell catching silent failures. Our own silent failure would be the worst defect this product could have, so a check that did not run is never shown as green.

Including when supervision itself stops

If runs keep arriving and verdicts stop, something in your deploy removed the SDK, or it is erroring before it reports, or its key was revoked. Your monitor would be green and nothing would be checking anything, which is the same failure one level up. The monitor shows runs seen against runs verified as two numbers side by side, and a sustained gap is an email of its own.

What it does not do

Supervision needs the SDK, because the checking happens where your data is. If your automation lives entirely in n8n, Make or Zapier and you have nowhere to run code, the deadline is still the right tool and it is unchanged: one URL at the end of the workflow, an email when the pings stop. That product is not going anywhere and it is what most people here need.

The checks are a deliberately small vocabulary: fields present or absent, exact values, number comparisons, counts, whether a run that started also finished, and joining what the run claimed to a record that confirms it. There is no regex, no date arithmetic, no summing, and no comparison against previous runs. If your sentence asks for something the vocabulary cannot express, the compiler leaves it out rather than approximating it, and you will see that when you read the checks.

If a model is not available when you press compile, you get no rule and a sentence saying so. You never get a rule we guessed at. A wrong rule that looks right is worse than no rule.

The first question, did it run, is answered by the deadline every monitor already has. Supervision is a mode on top of it, so a supervised monitor still tells you when the runs stop entirely.

Start with one monitor

Create a monitor, paste its URL into the last step of the workflow you most rely on, and leave it. If it stops, you will know the same day rather than the same week.

We would like to set optional cookies to understand how the site is used. They are off unless you agree, and the site works exactly the same either way. What this covers

Catching an automation that reports success and did nothing · Silent Fail