EZO Watcher

io.github.ezolabsPublished by GitHub account ezolabsv0.1.0Updated Nov 6, 2026

Self-hosted monitoring your coding agent installs, proves and fixes. Alert wall, pager, MCP.

VerifiedSTDIODesktop onlyDeveloper ToolsSecurity & Monitoring

Overview

AI-generated overview

Self-hosted alert wall and pager for one project, letting an assistant read incidents, get fix briefs, and acknowledge, silence, park or resolve them.

What you can do
  • Read the wall: overall state, filtered incident lists, one incident in full, source health and history over a time range
  • Get a structured fix brief for an incident, including the failed assertion, last good and bad readings, and a reproduce command
  • Re-check sources on demand and verify a fix, closing the incident only when the source itself reads healthy
  • Acknowledge, unacknowledge, silence (up to 4 hours) or park (up to 72 hours) an incident
  • Comment on incidents, mark one resolved with a reason, or confirm a resolution the source already reported
When to use it
Use it when a project already runs EZO Watcher and you want a coding agent to triage open incidents, pull a fix brief, ship a fix and close the loop with a recheck, without a person relaying state.
Requirements
A running Watcher server on the same machine, reachable at its local MCP endpoint; the stdio bridge forwards calls to it. Node.js 24+ for the npm package. The WATCHER_MCP_TOKEN secret, read from the project's .watcher/.env when not set in the environment.
Before you install
Most tools write: acknowledge, silence, park, comment, resolve and confirm_resolution change incident state and are recorded in history and the operator log under the agent's name. Silencing hides a problem from the people who would act on it, and resolving can take an incident off the wall. The bridge needs the WATCHER_MCP_TOKEN secret; keep it out of shared configs.

Installation

In SourceWeft

  1. Open EZO Watcher in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.

Other MCP clients

Follow the launch instructions in the repository.

README

[EZO Watcher logo]

EZO Watcher

The open-source AI SRE for your project: monitoring your coding agent installs, proves and fixes.
Agentic LiveOps monitoring: self-hosted, MCP-native, no account, and every check proven to go red before it counts.

[Live demo] [npm] [Node 24+] [TypeScript] [MCP] [No account] [MIT License] [CI]

Live demo · Quickstart · How it works · The fix loop · What agents see · MCP · Hosting · Docs

sh
npm i -g ezo-watcherwatcher init

No global install: npx -y ezo-watcher init


[The EZO Watcher wall: an unattended page for the checkout API, a missed scheduled run, a disk warning an agent acknowledged, a parked webhook and a grid of healthy services]

A health route that answers {"ok": true} proves the process is up. It stays green when the database is down, the queue is stuck or last night's cron job never ran.

EZO Watcher is an alert wall and a pager for one project, built to be set up by the agent that already works on the code. The agent reads the repo, picks the telemetry points that can actually go red, adds each one with the file and line it came from, and proves it: watcher doctor --live --prove pushes every source's own reading past its threshold and fails the install unless the check flips. {"ok": true, "live": true} is the only done.

When something breaks later, the same agent reads the incident, ships a fix and closes it with a recheck. The source decides when it is well again, not the agent.

[!TIP] Open the live demo: a full wall with sample data. Acknowledge, silence, park and recheck incidents; your changes stay in your browser.

How it works

mermaid
flowchart LR    subgraph project["Your project"]        code["Code, cron, configs"]        app["Running app"]    end
    agent(["Coding agent"])    cfg[".watcher/config.json<br/>checks as code"]    server["Watcher server<br/>one Node process + SQLite"]    wall["Alert wall"]    phone["Phone<br/>ntfy · push · SMS · email"]
    agent -- "watcher scan" --> code    agent -- "watcher add --found-at" --> cfg    cfg --> server    server -- "probes · heartbeats<br/>webhooks · host" --> app    server --> wall    server --> phone    server -- "MCP · CLI · hooks" --> agent    agent -- "fix, then recheck --wait" --> app
  1. Scan. watcher scan lists what the repo already exposes: readiness routes, cron entries, scheduled workflows, Sentry, Grafana, Netdata, published ports.
  2. Add. The agent turns each signal into a source. Every source carries the assertion that changes when a dependency is down, plus --found-at file:line so an incident points straight back at the code.
  3. Prove. watcher doctor --live --prove mutates each reading (a bad JSON answer, a missed heartbeat, a disk past its limit) and fails unless the check goes red.
  4. Run. One process serves the wall, pages your phone and speaks MCP.
  5. Fix. An incident hands the agent a fix brief. The agent ships the fix and recheck --wait closes the incident only when the source reads healthy.

[watcher scan finds a readiness route and a nightly cron in a sample repo, watcher add turns the route into a probe, and watcher doctor --live --prove passes 21 checks]

Quickstart

Give this to your agent

text
Set up EZO Watcher for this project. Install the CLI with`CI=1 npm_config_yes=true npm i -g ezo-watcher`, then run`watcher init` and `watcher skills install --target all`, and follow theezo-watcher skill end to end (read `.claude/skills/ezo-watcher/SKILL.md` or`.agents/skills/ezo-watcher/SKILL.md` if the skill is not listed in this session yet).
Follow its ranking: a dependency-gated readiness route first (never a route thatjust returns {"ok": true}), a heartbeat for every scheduled job, then any Sentry,Grafana or Netdata already in the project. Add one alert channel and prove itwith `watcher test-alert`.
Do not stop until `watcher doctor --live --prove --json` prints{"ok": true, "live": true}. If this project has no server and no scheduled job,add `watcher add host --id host` — the machine itself, read locally with nothinginstalled (load, memory, free space, optionally a pid file) — and prove it. Onlyif there is no server, no scheduled job and no host to watch either, run`watcher doctor --no-runtime-surface --json` and tell me instead; a configuredsource always wins over `--no-runtime-surface`. Ask me onlyfor the credential a chosen source or channel needs, and tell me what you watchedand what you skipped.

Claude Code users: after watcher skills install, run /reload-skills so the new skill is picked up in that session.

Or by hand

bash
# Node 24+.npm i -g ezo-watcherwatcher --version
cd my-projectwatcher initwatcher scan --jsonwatcher add http-probe --id app --url http://127.0.0.1:3000/readyz \  --expect-json '{"db.ok":true}' --found-at src/server.ts:42 \  --read "readiness reads the database"watcher add channel ntfy --id ntfy --server https://ntfy.sh --topic-env WATCHER_NTFY_TOPIC# or, with no credential at all: watcher add channel file --id localwatcher run --detachwatcher doctor --live --prove --json    # {"ok": true, "live": true}watcher test-alert

No global install: npx -y ezo-watcher <verb> runs any verb the same way (npx -y ezo-watcher init). Open http://127.0.0.1:7717 for the wall. watcher init writes .watcher/config.json (commit it), .watcher/.env and .watcher/data/ (gitignored), and picks a free port from 7717.

What it sets up

The project hasEZO Watcher adds
A server with a readiness routeAn http-probe asserting the JSON field that changes when a dependency is down, not the status code alone
A scheduled job, cron, timer, workflow or worker loopA heartbeat per job: a missed run is an incident, not silence
A database, cache or published portA tcp-probe (with TLS expiry when the socket is TLS)
Sentry, Grafana, NetdataTheir own sources: read what already exists instead of duplicating it
An inbound sender (Stripe, GitHub, a collector)A webhook source with a staleness window, so a sender that stops is a page
A domaindomain-expiry over RDAP, beside the certificate expiry http-probe already reads
A machine with nothing installed on itA host source: load per core, memory available, free space per mount and optionally one pid file, read locally
A phone that must ringOne channel: ntfy, web push, SMS, email or a webhook, proven with watcher test-alert. No credential? The file channel records every notification as JSONL and needs none

The fix loop

Once the Watcher is running, the prompt is one line:

text
Check the Watcher for open incidents and fix them; verify each fix with a recheck.
mermaid
sequenceDiagram    autonumber    participant S as Source    participant W as Watcher    participant P as Phone    participant A as Agent    S->>W: readiness answers {"db": {"ok": false}}    W->>P: page: Checkout api is down    A->>W: watcher status --brief (session start)    A->>W: get_fix_context    W-->>A: failed assertion, last good and bad reading, found-at server.mjs:35    A->>A: fix the code, redeploy    A->>W: verify_fix / recheck --wait    W->>S: re-run the check now    S-->>W: {"db": {"ok": true}}    W-->>A: resolved, confirmed by the source

[A real session: the database flag flips, status --brief shows the page, incident --fix-context prints the brief with the failed assertion and found-at line, and recheck --wait resolves it after the fix]

The agent drives watcher status --brief for one line at session start, then get_fix_context (or watcher incident <key> --fix-context) for the incident's own brief: the source and target config, the assertion that failed, the last good and last bad observation, and the command that re-runs the check. After the fix and a redeploy, verify_fix (or watcher recheck <key> --wait) closes the incident with the attribution only when the source itself says it is well again. The full loop is watcher skills fix.

Brief the agent at every session start
bash
watcher hooks install --target claude     # SessionStart: watcher status --brief

It writes the SessionStart hook into the project's .claude/settings.json, so a session that opens finds the wall's state in one line without asking. --target codex writes the same instruction into AGENTS.md instead (watcher hooks uninstall takes it back out).

Page when the agent itself stops working

Add one heartbeat (its ping token is generated into .watcher/.env for you) and a Stop hook that pings it after every turn:

bash
watcher add heartbeat --id agent-session --every 30m --grace 15m \  --token-env WATCHER_AGENT_SESSION_TOKEN
json
{  "hooks": {    "Stop": [      { "hooks": [        { "type": "command",          "command": "sh -c 'set -a; . .watcher/.env 2>/dev/null; curl -fsS -X POST -H \"Authorization: Bearer $WATCHER_AGENT_SESSION_TOKEN\" http://127.0.0.1:7717/ingest/heartbeat/agent-session >/dev/null 2>&1 || true'" }      ] }    ]  }}

Any turn inside the grace keeps the heartbeat green; when the agent stops working for longer than that, HeartbeatDown pages. The || true keeps a stopped Watcher from blocking the agent's turn. (Claude Code hooks reference, read 2026-11-04.)

What agents see

An agent dials the Watcher through MCP (/mcp) or the CLI and reads plain text. The demo shows it live: acknowledge or park an incident and every answer below changes. Every incident sheet has the same view under What your agent sees.

[What agents see, in the demo]

At the start of every session, watcher hooks install runs watcher status --brief: one line per open incident, nothing on a quiet wall.

$ watcher status --briefwarning  Billing jobs  HeartbeatDown  50m  Billing jobs|HeartbeatDownpage  Checkout API  ProbeDown  21m  Checkout API|ProbeDownwarning  Worker hosts  HostDiskFree  2h  Worker hosts|HostDiskFreerun `watcher incident <key> --fix-context` or the MCP tool get_fix_context

The first MCP call, watch_state, is the wall in one answer (excerpt):

json
{ "text": "3 firing; 2 unattended, 1 acknowledged, 0 silenced; 1 page, 2 warning, 0 info; 1 parked (not live: an open verdict that is not due yet). Every source is answering.", "counts": { "firing": 3, "unattended": 2, "acknowledged": 1, "silenced": 0, "parked": 1, "page": 1, "warning": 2, "info": 0 }}

Then get_fix_context {"key":"Checkout API|ProbeDown"} (or watcher incident 'Checkout API|ProbeDown' --fix-context --json) returns everything needed to fix it without asking a person (cut here; the real brief is about 200 lines):

jsonc
{ "key": "Checkout API|ProbeDown", "summary": "checkout-api is down: HTTP 503 in 3023ms, expected 200", "state": { "firing": true, "attention": "none", "ackedBy": null, "silencedUntil": null, "parkedState": null, "parkedUntil": null }, // sources[0].target: the config that failed "target": { "id": "checkout-api", "url": "https://api.acme.example/checkout/readyz", "expectJson": { "ok": true, "db.ok": true }, "slowMs": 800 }, "asserts": [{ "asserts": ["status 200", "body.ok = true", "body.db.ok = true"], "failed": ["status 200"],   "failureDetail": "HTTP 503 in 3023ms, expected 200 (25 failed polls in a row)" }], "observations": {  "lastGood": { "at": "2026-11-05T15:06:00.000Z", "status": 200, "body": "{\"ok\":true,\"db\":{\"ok\":true,\"poolInUse\":8}}" },  "lastBad": { "at": "2026-11-05T15:30:00.000Z", "status": 503, "detail": "HTTP 503 in 3023ms, expected 200" } }, "reproduce": {  "command": "curl -sS -m 10 'https://api.acme.example/checkout/readyz' | jq '.ok'", "expect": "true",  "watcher": "watcher recheck 'Checkout API|ProbeDown' --wait --json" }, "next": [{ "action": "fix" }, { "action": "restart-or-deploy" }, { "action": "verify" }]  // each with its detail}

[The brief an agent reads, in the incident sheet]

The wall

Firing tiles take the room; healthy services shrink to a dense grid. A page is red, a warning is amber, an acknowledged incident shows who took it, and a parked one gets its own colour and expires on its own. The look follows ISA-101 high-performance HMI practice: grey by default, colour only for what needs attention (docs/design.md).

MCP

Two forms, stdio first:

bash
watcher mcp-config --client claude     # also: cursor, codex; --show-secret prints the token

The stdio form registers the running CLI itself (node <the install's bin/watcher.mjs> mcp --dir <project>): the client starts a small bridge in the project, the bridge reads WATCHER_MCP_TOKEN from .watcher/.env, and no secret is in the registration. Use it for an agent on the same machine as the Watcher.

The HTTP form is the running server's own endpoint, <baseUrl>/mcp (Streamable HTTP, stateless) behind Authorization: Bearer $WATCHER_MCP_TOKEN. Use it behind your Tunnel so the same agent can work from anywhere the tunnel reaches; put a Cloudflare Access bypass on /mcp if Access is on (the endpoint keeps its own bearer token; see watcher skills cloudflare).

ReadsWrites (each as agent: <who>)
watch_state · list_incidents · get_incident · get_fix_context · incident_history · list_sourcesacknowledge · unacknowledge · silence · park · unpark · comment · recheck · verify_fix · resolve · confirm_resolution

Every input is in docs/mcp.md.

Why it is different

  • Assertion-proven, not status-proven. A 200 proves a socket accepted a connection. The install is green only when each check carries a predicate that flips under mutation (--prove), so a broken database, a stalled queue or a dead job actually pages.
  • Silence-first. In a prototype scan of four hand-labelled repositories, a file scan found most of the HTTP surface but only about a fifth of the silence: schedules generated inside install scripts, launchd/systemd units created at runtime, pull-queue workers, staleness declared in the product's own config, state-dir writability, dependency URLs held as code constants. The skill ships that checklist, and each item becomes a heartbeat or a webhook with a stale window.
  • Local and account-free. One Node process, node:sqlite, config in your git, secrets in a 0600 env file. Nothing to sign up for; it runs on a laptop, a server or behind a Cloudflare Tunnel.
  • Agent-native. The docs ship inside the CLI (watcher skills <topic>), the install loop is written for an agent, and the running Watcher speaks MCP so an agent can read the wall, acknowledge, comment, silence, park and recheck as itself.

Hosting

mermaid
flowchart LR    local["Local process"] --> svc["launchd / systemd<br/>service"] --> vps["Docker or a VPS"] --> tunnel["Cloudflare Tunnel<br/>$0, no port forwarding"] --> containers["Cloudflare Containers<br/>beta"]

Cheapest first. Cloudflare Tunnel is the default for "host it with my Cloudflare key": a hostname on a zone you already have, no port forwarding. watcher cloudflare tunnel --hostname watch.example.com does the tunnel, DNS and run token; watcher cloudflare quick gives an ephemeral public URL for a demo. Cloudflare Containers runs about $9.57/month kept awake and cannot probe your LAN; a Workers edge port is not built yet. Details: watcher skills hosting and watcher skills cloudflare.

Binding off loopback requires WATCHER_ADMIN_TOKEN; the server refuses to start without it.

Docs

skills/ezo-watcher/SKILL.mdThe install loop. Also printed by the CLI: watcher skills lists topics (install, discover, sources, channels, hosting, cloudflare, netdata, operate, fix, telemetry)
skills/ezo-watcher/references/The detail those topics print
docs/mcp.mdConnect an agent to the running wall
docs/doctor-codes.mdEvery watcher doctor code and its fix
docs/embed.mdEmbed the wall or one tile in another page
docs/telemetry.mdWhat anonymous telemetry sends, and how to turn it off
docs/design.mdThe product and visual decisions, with sources
AGENTS.mdHow to work on this repository
llms.txtThe index for an agent reading the repo

Telemetry

The CLI and the server send anonymous usage data (the verb and flag names, exit codes, doctor check codes, internal error types) so we can find failures and fix them first. Never paths, hosts, URLs, config or env values. It is on after a one-time notice; turn it off with watcher telemetry disable or DO_NOT_TRACK=1, and WATCHER_TELEMETRY_DEBUG=1 prints exactly what would be sent. What is sent and where it goes: docs/telemetry.md.

Status

Public preview, published on npm as ezo-watcher. Hosting the wall for someone else's project is supported; multi-tenant hosting is not.

Develop

bash
npm cinpm run buildnpm run typechecknpm test

Node 24+, ESM, TypeScript. See AGENTS.md for the layout, the test rules and the leak gate, and docs/design.md for the product decisions.

License

MIT © EZO Labs Inc.

Source: README.md at commit 4ac8cbb

Tools

16

watch_state

Wall summary

The EZO Watcher wall in one answer: how many incidents are firing (by severity, and by who has them: unattended, acknowledged, silenced), how many are parked (a fix or a verdict that is not due yet: not live, never paged, counted in no firing or unattended number), every incident as one row (key, title, severity, attention: none, acked, silenced or parked, who acknowledged or silenced it or why, by whom and until when it is parked, age, comment count, link), and the sources that have gone stale, are erroring, or are configured but not started on this host (`skipped`, with its reason). Start here. The incident `key` it returns is what every other tool takes.

Takes no parameters.

list_incidents

List incidents

Incidents, filtered. `state`: firing (default: every live incident, parked ones left out), unattended (firing, nobody has it, never a parked one), acknowledged, silenced, parked (a fix or a verdict that is not due yet: `parkedState`, `parkedUntil`, `parkedBy`, `parkedRef`, `parkedNote` say why, by whom and until when), resolved (episodes that ended in the last `hours`), or all (every incident, parked included). Filter by `severity`, `service` (substring) and `source` (the system that raised it: grafana, prod, sweep, netdata-cloud, ...). Resolved rows say whether a source resolved the incident or someone marked it resolved by hand, and who.

Parametershourslimitstatesourceserviceseverity

get_incident

One incident

One incident, whole: its alerts (rule, host, labels, annotations, value, who reports it and when it last did, evidence links and commands), who acknowledged, silenced and parked it, how it ended if it ended (a source, or someone by hand, and any confirmation), its history of acknowledgements, silences, reopens and resolves with who did each, every comment, and the pager's last sends. Works for a firing incident and for one that resolved in the last 30 days. Raw payloads are left out.

Parameterskeyrequired

get_fix_context

Everything needed to fix an incident

One structured brief for fixing an incident without asking a person: the incident (summary, severity, first and last seen, state and who has it), the source and target that raised it (their config, with every credential left as the env-var NAME and never a value), the predicates the rule cell asserts and which one the last run failed, `discovered.foundAt`/`read` (where the endpoint was found in the project and what was read there), the last good observation beside the last bad one (bodies cut), a `reproduce` block with the exact curl/nc/command that re-runs the check locally, the other open incidents on the same service, the evidence links the source offers (a Sentry permalink and culprit, a Netdata chart, Grafana panel links), and `next`: fix, restart/deploy, then verify_fix. Reads only; start here when you are about to fix something rather than triage it.

Parameterskeyrequired

incident_history

Incident history

What ended and what was done in a time range: every incident episode that resolved in it (when it started and ended, how long, who had it acknowledged, whether a source or someone by hand resolved it, any confirmation) and, newest first, the acknowledgements, silences, reopens and confirmations people and agents made, each with who. Give `from` and `to` as ISO times, or `hours` back from now (24 by default). Watch keeps 30 days.

Parameterstofromhourslimitservice

list_sources

Sources

Every source this Watcher reads or is pushed by (Grafana, vmalert, Netdata Cloud and the fleet load poll, Sentry, the HTTP and TCP probes, heartbeat, domain expiry, the feeds, the webhooks): its kind, state (ok, error, stale, idle), when it last answered, the error if any, `skipped` when this host did not start it (`missing <ENV>`; absent on a source that runs), how many alerts it reports firing, how many rules it lists, how many of its cells assert more than a nominal 200 (`asserted`) and, where it records one, `discovered`: where its endpoint was found. A source that has gone quiet or was not started means an all clear is not earned.

Takes no parameters.

acknowledge

Acknowledge an incident

Say you are working this incident: it shows as acknowledged by you on the tile, in the sheet and in History, its age stops counting as unattended, and the pager stops escalating it. Acknowledge only while you are actively working the issue; it does not fix, hide or resolve anything, and a person can take it off. Re-acknowledging replaces the earlier name. Put what you found or did in a comment, not here: the optional note is one line of context.

Parametersbyrequiredkeyrequirednote

unacknowledge

Take an acknowledgement off

Take the acknowledgement (and any silence) off a firing incident, so it counts as unattended again and the pager resumes. Use it when you stop working an issue you acknowledged and no one else has it. `by` is recorded: History shows who handed it back.

Parametersbyrequiredkeyrequirednote

silence

Silence an incident for a while

Pause the pager for one firing incident, for at most 240 minutes (4 hours; more is refused, not shortened). It drops to the quiet tier of the wall and sends nothing until it runs out or someone takes it off. A silence hides a problem from the people who would act on it: use it only for something you know is expected right now (a deploy, a drill, a host you are rebooting), say why in `reason`, and never to make a real problem go quiet. If you are working the incident, acknowledge it instead.

Parametersbyrequiredkeyrequiredreasonrequiredminutesrequired

park

Park an incident after a fix or a verdict

Take a firing incident off the live wall into the Parked section, for at most 72 hours (more is refused, not shortened), once you have FIXED it or reached a VERDICT on it. `state`: fixed_undeployed (the fix is merged and not live yet), awaiting_source (the fix is live and the source's evaluation window has not caught up, so it still reports the alert), deferred (a person decided to handle it at a later date; the note says who and why). It works for any source, Grafana included. Unlike `resolve` it never reopens or pages while the park holds, and unlike `silence` it states a known cause: the tile reads "Parked until <time> by <you>" with your note, it counts as parked and not firing, and nothing is sent. It ends when the source resolves the alert, when `until` passes (the incident comes back unattended and its clock counts from `until`, so the pager treats it as a new problem), on `unpark`, or on a manual `resolve`; an acknowledgement or silence on the incident still wins over it, and a second park replaces the first. Park only after a fix or a verdict, never to hide a live problem you have not looked at or to quiet one you cannot explain. The park covers only the alerts firing when you park (get_incident lists their keys in `park.alertKeys`): an alert that joins the incident later (another host or instance, a new rule on it) ends the park at once, the incident comes back unattended and pages as a new problem, and History says which alert joined. An alert that resolves and fires again keeps the park.

Parametersbyrequiredkeyrequiredrefnoterequiredstaterequireduntilrequired

unpark

End a park now

End a park set by hand with `park` before it runs out: the incident is back in its severity tier, unattended and paging as a new problem would, with its clock starting now. Use it when the fix did not hold or the verdict was wrong. `by` is recorded: History shows who ended it. Refused for an incident that is not firing, one that was not parked by hand (a park the regression sweep states ends when the sweep stops stating it), and one whose park has already ended.

Parametersbyrequiredkeyrequirednote

comment

Comment on an incident

Add a comment to an incident, firing or resolved: what you found, a link, the commit that fixes it, what you ruled out. Markdown, at most 4000 characters (longer is refused, not cut). It is stored on the incident and shows in the incident sheet with your name and the time, and every one is written to the operator log. Comment as you learn things; a comment is the right place for findings, links and fix commits.

Parametersbyrequiredkeyrequiredtextrequired

recheck

Re-check now

Ask the sources again instead of waiting for the next poll: with `incident` (an incident key), re-polls the sources that report its alerts and answers what each alert is now; with `alert` (an alert key such as grafana:1a2b3c4d), the same for one alert; with neither, re-polls every pull source and says how many alerts cleared. At most one poll per source every 10 seconds, so a repeat inside it is answered from the last poll. A pushing sender that takes requests (the regression sweep) is asked to run the check again: each firing alert it reports gets one request, an alert that already has an open one reuses it, and the answer's `pushed[].request` says where it stands (asked, picked up, waiting, ran, failed, cannot, or not picked up within 30 min); a repeat while it is open returns the same request, so it only reads where it stands. Any other pushing sender (webhooks) cannot be forced: the answer says when it last reported, when it reports next if it said, and when the alert clears if it stops sending it. It changes no alert except by the sources' own answers.

Parametersbyrequiredalertincident

verify_fix

Verify a fix and close the incident

Close the fix loop: re-check the sources now, wait up to `timeoutSec` seconds for the source's fresh observation, and answer { resolved, observation, asserts }. When every alert of the incident is resolved by its source, it records the confirmation (the existing confirm_resolution path) with the note "verified by agent", so History reads "resolution confirmed by <you>" and the incident closes with the attribution. When the source still reports an alert firing it resolves nothing and says which assertion failed and why, so the fix can be repaired rather than guessed at. Never resolves an alert itself: only the source (or a person's resolve) ends an alert. Idempotent: after a green answer a repeat reads the resolved episode and records at most another confirmation.

ParametersbyrequiredkeyrequiredtimeoutSec

resolve

Mark an incident resolved by hand

Mark a firing incident resolved now, with a required reason, when you have fixed it and the source has not caught up (a push source repeats only every few hours). It leaves the wall, History records "marked resolved by <you>" with your reason, and the operator log records the write. It does not hide a live problem: if the source reports the alert as firing on its next poll or push, Watch reopens the incident as a NEW firing (unacknowledged, escalating, paging again) and records "reopened: source still firing after manual resolve by <you>". A manual resolve ends any acknowledgement or silence on the incident. You can never resolve, delete or edit an alert itself: only its source resolves alerts. After the source resolves, use confirm_resolution to record that you checked.

Parametersbyrequiredkeyrequiredreasonrequired

confirm_resolution

Confirm an incident is resolved

Record that an incident a source has already resolved is resolved: "resolution confirmed by <you>", with an optional note (the fix commit, the PR, an evidence link). It shows in the sheet and in History, and the operator log records the write. It changes no state, so it cannot hide anything: use it after you checked that the fix held. Refused for an incident that is firing, one that never resolved, and one that was marked resolved by hand while a source still reports it.

Parametersbyrequiredkeyrequirednote

Version history

1
  1. v0.1.0LatestNov 5, 2026

Score

90% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 days25 pts
  • Auth declared10 pts

    Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.

  • Tools listedRequired15 pts
  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts