Monitoring as code: the monitor lives next to the thing it watches.
Monitoring as code means declaring your monitors — what should be watched, on what schedule, how late is too late, and who gets alerted — in version-controlled files rather than in a dashboard. They are reviewed in pull requests alongside the code they describe, and applied by CI. The point is not automation for its own sake. It is that a monitor kept in a different system from the job it watches will, given enough time, end up describing a job that no longer exists.
What it actually means
Three properties. A setup that has all three is monitoring as code; one that has two is a dashboard with extra steps.
- The monitor is declared in a file, in the repo Not clicked into a UI and screenshotted into a runbook. A file, in the same repository as the job — ideally close enough that someone changing the job's schedule physically sees the monitor's schedule on the way past.
- Changes to it go through review Widening a grace period from ten minutes to six hours is a real decision with real consequences, and in a dashboard it is a dropdown nobody sees again. In a pull request it is a diff with a name on it, and someone can ask why.
- CI applies it, not a person If applying is a manual step, it is a step that gets skipped under deadline — and the file becomes documentation of what monitoring should look like rather than what it is. The whole guarantee rests on the file and reality being reconciled automatically.
Why the third property is the one that matters
The first two are hygiene. The third is what turns a config file into a guarantee. Once CI reconciles the file with reality on every merge, "the monitor exists and matches its job" stops being something you hope is true and becomes something that is true by construction — the same shift infrastructure as code made a decade ago, applied to the layer that tells you whether any of it is working.
It also changes what a monitoring gap looks like. It is no longer an invisible absence that someone has to notice; it is a job in the diff with no monitor next to it, which a reviewer can see.
The failure it prevents
Both of these are ordinary. Neither produces an alert, an error, or a red square on a dashboard. That is precisely the problem: the monitoring system is not broken, it is confidently reporting on something that is no longer there.
The monitor that outlived its job
A nightly export is renamed, or moved to a new scheduler, or deleted because the feature it fed was retired. Its monitor is in a different system, so nothing tells it. If the monitor watches for an inbound check-in, it goes red, someone marks it as expected noise, and it is paused forever. If it watches an endpoint that still answers, it stays a reassuring green — reporting on a job that no longer runs.
Six months later the dashboard is a wall of green with an unknown number of squares that mean nothing at all, and nobody can say which.
Result: false confidence
The job that arrived with nothing watching it
A new scheduled task ships. It works, so nobody thinks about it. The "add monitoring" step is not in the deploy checklist, or it is and was skipped, or a ticket was filed and closed as stale. The job runs fine for months, which is exactly what makes it feel safe.
Then it stops — a credential expires, an upstream API changes, the scheduler is disabled for inactivity — and the discovery channel is somebody downstream asking why a report is empty. The gap between "stopped working" and "someone noticed" is measured in weeks.
Result: silent failure
These are the same bug. In both, the set of things that run and the set of things being watched are maintained separately by hand, and hand- maintained sets diverge. Not because anyone is careless — because there is no moment at which the two are forced to agree.
Monitoring as code creates that moment and puts it somewhere it cannot be skipped: the same commit. Delete the job and you delete its monitor in the same diff. Rename it and both names change together. Add one and its absence of a monitor is visible on the screen where someone is already looking.
Why this matters more now that agents write the jobs
Monitoring as code has been a good idea for a long time. What changed is that the informal process holding the old way together has quietly been removed.
The unwritten mechanism was always a person. Someone builds a scheduled job, and at some point — during review, at standup, during an incident three weeks later — a human notices it is unmonitored and does something about it. That step was never in any process document. It ran on somebody feeling uneasy.
When an agent builds the job, nobody feels uneasy. The agent produces a working pipeline, the tests pass, the diff is reviewed for correctness, and it merges. No one files the "add monitoring" ticket, because there is no moment at which a person sat with the job long enough to wonder about it. The job is correct and unwatched, and those two facts are not in tension until the day it stops.
This gets worse with volume, which is the whole point of agents. A team that ships three scheduled jobs a quarter can carry an informal process. A team where agents ship three a week cannot — the informal process was never load-bearing enough to scale, and its failures are invisible by construction.
The fix is not a better checklist
It is making the monitoring something the agent can write, in the same file format as everything else it writes, in the same pull request. An agent is good at producing a correct declarative config from a schema — much better than it is at remembering an unwritten cultural norm. Give it a schema and the monitor gets written. Give it a checklist and it gets skipped, exactly as it did for humans.
And it changes what review catches. A reviewer looking at a diff that adds a nightly job and its monitor together is reviewing a complete change. A reviewer looking at a diff that adds only the job has no way to notice what is missing — absence does not render in a diff.
What changes in practice
The same three events, handled two ways.
Every change is two changes
Ship the job, then remember to open the monitoring tool. Retire the job, then remember to go and delete its monitor. Change a schedule, then remember to update the grace period to match. Each "then remember" is a coin flip, and the failures are silent.
Nobody can answer "which of our jobs are unmonitored?" without reading two lists side by side and comparing them by hand.
Every change is one change
The monitor is in the diff with the job. Deleting the job's declaration deletes the monitor on the next apply. Changing the cron expression changes both, because they are the same file and a mismatch is visible while you are editing it.
"Which jobs are unmonitored?" becomes a question you answer by reading one file — or by writing a test that fails the build.
How to start
You do not need a migration project. Start by adopting what already exists, so the first commit changes nothing.
Export the monitors you already have
The step most teams stall on is the rewrite, so skip it. LastPing's
Export as Terraform renders your
existing monitors, alert destinations, routing, message templates
and status pages as HCL — with a Terraform import
block attached to each one, so Terraform adopts them instead of
proposing to destroy and recreate them.
A successful adoption looks like Plan: 0 to add, 0 to
change, 0 to destroy — your monitoring is now in version
control and nothing about it changed.
Move the file next to the jobs
Committing it to a separate "monitoring" repo recreates the original problem in a new location. The value comes from proximity: put the declaration in the repository that owns the job, close enough that changing one puts the other on screen.
Let CI apply it
Add the apply to the pipeline that already deploys the job. From that point the guarantee holds by construction rather than by anyone remembering, and a monitor can no longer outlive what it watches.
Point your agent at the schema
The provider's schema is public, so a coding agent can write a correct monitor for a job it just built — see the agent workflow. For agents that need to act on the live API mid-conversation rather than write a file, the LastPing MCP server exposes the same capabilities as tool calls, and anything created that way can be exported into code later.
Questions
Front-loaded answers — the most important fact first.
-
What is monitoring as code?
Monitoring as code is the practice of declaring your monitors — what should be watched, on what schedule, how late is too late, and who gets alerted — in version-controlled files rather than in a dashboard. The files are reviewed in pull requests alongside the code they describe, and applied by CI.
The point is not automation for its own sake: it is that the definition of what should be running lives in the same place as the thing that runs, so the two cannot quietly disagree.
-
How is it different from infrastructure as code?
It is the same practice applied one layer up, and usually the same tooling. Infrastructure as code declares the machines, clusters and queues a system runs on. Monitoring as code declares the expectations about that system: this job runs nightly, it may be up to thirty minutes late, and if it is later than that these people should hear about it.
The difference that matters is the failure mode. Infrastructure that drifts from its declaration usually breaks something visibly. Monitoring that drifts from its declaration keeps reporting success — which is worse, because nothing looks wrong.
-
Do I need Terraform to do monitoring as code?
No. The requirement is that monitors are declared in a file that lives with the code, is reviewed, and is applied automatically — an API call from a deploy script satisfies that.
Terraform is the common choice because it already handles the hard parts: knowing what exists, computing a diff, and adopting resources that were created by hand. LastPing publishes an official Terraform provider for that reason, but the idea does not depend on it.
-
Can I move monitors I already have into code?
Yes, and this is the step most teams stall on, because rewriting existing monitors by hand is a day nobody has. Export as Terraform renders your existing monitors, destinations, alert routing, message templates and status pages as HCL, with a Terraform
importblock attached to each one — so the first plan adopts what you already have rather than proposing to destroy and recreate it.A successful adoption looks like a plan with no changes at all. Secrets are the exception: the API never returns them, so each one comes out as a variable reference for you to fill in.
-
Why does this matter more when an AI agent writes the job?
Because the human step that used to catch the gap is gone. When a person builds a scheduled job, someone eventually notices it is unmonitored and files a ticket. When an agent builds one, no one files that ticket — the job ships, works, and is invisible until the day it stops.
If monitoring is a file the agent can write, it becomes part of the same diff, and the reviewer sees the job and its monitor together instead of approving one and never being shown the other.
-
Is LastPing free?
LastPing is free for individuals — no monitor cap, no feature gate — and that includes the Terraform provider and the MCP server. Get an API key at app.lastping.dev.
Put the monitor in the same commit as the job.
LastPing has an official Terraform provider, and exports the monitors you already have as HCL with import blocks — so adopting monitoring as code starts with a plan that changes nothing.