LastPing
LastPing's MCP server lets an AI agent set up, read, and manage its own uptime monitoring — heartbeats, cron jobs, CI/CD runs, HTTP probes, traces, and incident follow-up — without a human opening a dashboard.
Monitors: create/update (slug upsert), read, list, delete, pause, resume, set maintenance windows; configure schedule (simple/cron/on_demand), grace, thresholds, silence floor, stall/overrun budgets, runaway rate ceiling, and output assertions or metric guards.
Reporting setup: get ping URLs and check-in snippets (
get_ping_instructions) and declare a run's success criteria up front (declare_run_expectations).Discovery: reconcile a scan of a repo or host (crontab, GitHub Actions, k8s CronJob, systemd timer) into monitors and get a created/existing/orphaned drift diff.
Incidents & runs: read open/recent incidents, timelines, and run history or full run detail (steps, spans, assertion verdicts); write append-only notes back to incidents.
Tracing: get per-tool OpenTelemetry setup steps, mint monitor-bound ingest keys, and diagnose why spans were refused.
Agent observability: registry of agents, adopt discovered trace sources, and query per-agent or project-wide dependencies, tokens, and cost.
Alerting: manage destinations (webhook, Slack, Discord, Telegram, email, etc.), route event types, test delivery, set message templates, and inspect recent deliveries.
Status pages: create, update, list, and delete public or private status pages.
API keys: create, list, regenerate, and revoke (with cascade) scoped credentials.
Terraform: export existing config as HCL with import blocks.
Allows monitoring GitHub Actions workflows by adding LastPing pings so CI jobs report their start, success, and failure.
Allows monitoring Kubernetes jobs and cron jobs by creating LastPing monitors and wiring ping URLs to report start, success, and failure.
Allows monitoring Python scripts and ETL jobs by wrapping them with LastPing pings to report completion and failures.
Provides exporting LastPing monitor configuration as Terraform HCL for infrastructure-as-code management.
Most monitoring watches a thing and tells you when it looks wrong. LastPing waits for a thing to check in and tells you when it doesn't. That inversion is the whole product: a job that breaks can't send you an error, but it can fail to send you anything — and absence is the one signal a broken process can still produce.
This repository holds the open-source pieces: the lastping CLI, which wraps
any command and reports its start, exit code and traces, and the MCP server,
which lets an AI agent set up and read its own monitoring. The hosted service
they talk to is at lastping.dev, free for
individuals.
Quick start
# 1. Install the CLI (macOS and Linux, amd64 and arm64)
curl -fsSL https://raw.githubusercontent.com/lastping-dev/lastping-app/main/install.sh | sh
# 2. Wrap a job: a start ping, your command untouched, then its exit code
lastping run --monitor <monitor-id> -- ./backup.sh# 3. Or give your AI assistant the hosted MCP server, and sign in
https://mcp.lastping.dev/mcpCreate the monitor, and get its id, at app.lastping.dev, or let your assistant do it over MCP. Connect steps for each client are at lastping.dev/mcp/.
Related MCP server: UNITARES
Install
curl -fsSL https://raw.githubusercontent.com/lastping-dev/lastping-app/main/install.sh | shNo Go toolchain needed — that pulls a prebuilt binary for macOS and Linux, on amd64 and arm64, and verifies its checksum. Windows builds are on the releases page.
If you do have Go:
go install github.com/lastping-dev/lastping-app/cmd/lastping@latestlastping run — reporting you can't forget
Put it in front of whatever you already run:
lastping run --monitor <monitor-id> -- python nightly_etl.py
lastping run --monitor <monitor-id> -- ./backup.sh
lastping run --monitor <monitor-id> -- claudeIt sends a start ping, runs your command untouched, and reports the exit code when it finishes — success on 0, failure on anything else, with the tail of stderr attached so the alert says why.
Three properties worth knowing, because they are the difference between a monitoring wrapper you can trust in production and one you remove after a bad night:
Your exit code always propagates. The wrapper exits with whatever your command exited with, so CI behaves exactly as it did before you added it.
A failed ping never touches your command. If LastPing is unreachable, your job still runs, still writes its output, still exits normally.
Interactive stays interactive. stdin and stdout are handed over as file descriptors, so wrapping a REPL or an agent session works.
Why a wrapper rather than an instruction? Because anything advisory decays. An
AI agent told to report on every task will stop doing it, and a cron line you
meant to add a curl to never gets it. A wrapper reports from the process
lifecycle, so nothing depends on anybody remembering.
Traces
lastping run always configures your wrapped command's OpenTelemetry
exporter, in its environment only, so an auto-instrumented agent can export
its own trace spans with no code change:
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT— the header-free monitor-URL form (<ping url>/v1/traces) whenLASTPING_API_KEYis not set, so a headerless exporter can still authenticate; the ping host's/v1/traces(the Bearer form) when it is set.OTEL_RESOURCE_ATTRIBUTES—lastping.monitor_id=<id>,lastping.run_id=<rid>appended to whatever you already set, so a trace's spans join the same run the surrounding pings report.OTEL_EXPORTER_OTLP_HEADERS—Authorization=Bearer <your key>, only whenLASTPING_API_KEYis set and you have not already set that variable yourself.
Any of the three you already set is left alone. The key is never used to authenticate a ping; the ping URL stays unauthenticated by design, as above.
MCP server — let an agent set up its own monitoring
Claude Desktop extension
A one-click install for Claude Desktop on macOS and Windows that keeps your key in the system keychain. It needs no Node.js.
Download lastping.mcpb.
Double-click it; Claude Desktop opens its install dialog.
Paste a write-scope key from Settings, API keys at app.lastping.dev.
The extension runs this repository's stdio binary (below) on your computer.
It is built by mcpb/build.sh when a version is tagged, and every release is
signed; the release build fails rather than ship an unsigned bundle. The
certificate is self-signed, so Claude Desktop shows the extension as
unverified. The signature still proves the bundle came from this repository's
release pipeline and was not altered after it was signed. A local build of
mcpb/build.sh without the signing secrets is unsigned and says so.
MCPB_CERT_CA_ISSUED is kept for a future certificate from a public CA.
Claude Desktop through the mcp-remote bridge
Claude Desktop's config file runs local programs only, so LastPing connects
through the mcp-remote bridge. Add this to claude_desktop_config.json
(macOS: ~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\):
{
"mcpServers": {
"lastping": {
"command": "/ABSOLUTE/PATH/TO/npx",
"args": [
"-y", "mcp-remote",
"https://mcp.lastping.dev/mcp",
"--header", "Authorization:${LASTPING_AUTH}"
],
"env": {
"PATH": "/FOLDER/THAT/HOLDS/npx:/usr/bin:/bin",
"LASTPING_AUTH": "Bearer lp_your_key"
}
}
}
}Needs Node.js. Claude Desktop does not read your shell's PATH, so give it the full path: run
which npxin a terminal and put the result incommand(with nvm it looks like/Users/you/.nvm/versions/node/v22.11.0/bin/npx), and its folder at the front ofPATHinenv.Quit and reopen Claude Desktop; it reads the file only at start-up. Settings, Connectors then lists lastping.
Without a key, add LastPing as a custom connector instead (Customize, Connectors, Add custom connector, then paste
https://mcp.lastping.dev/mcp) and sign in to LastPing in the browser. The same connector covers claude.ai, the Claude mobile apps and Cowork.
Other clients
Claude Code connects directly, no bridge:
claude mcp add --transport http --scope user lastping https://mcp.lastping.dev/mcp --header "Authorization: Bearer <key>".
Cursor, Windsurf, Codex CLI, Gemini CLI and other clients:
lastping.dev/mcp/#connect.
The hosted server is the recommended path, and it always carries the current tool set. Most clients connect by adding the URL and signing in to LastPing, with nothing to install; Cursor and Windsurf use the URL and an API key. With a key, Claude Desktop connects through the extension or the mcp-remote bridge above.
A stdio binary is also here if you would rather run it yourself:
go install github.com/lastping-dev/lastping-app/cmd/lastping-mcp@latestMonitors: create_monitor · get_monitor · list_monitors ·
update_monitor · delete_monitor · pause_monitor · resume_monitor ·
snooze_monitor
Discovery: discover_monitors_reconcile
Reporting: get_ping_instructions · declare_run_expectations
Incidents & runs: list_incidents · get_run_history · get_run
(one run's full timeline, assertion verdicts and spans) · list_runs
(runs across every monitor, traced runs included, with filters) ·
get_incident (one incident's recorded timeline)
Tracing: get_trace_setup (the set-up steps for one tool, from the server) ·
create_ingest_key (a tracing key bound to one monitor; a write key is
enough) · get_trace_diagnostics (why a sent span was refused)
Agent observability: get_agent_dependencies · get_agent_usage ·
list_dependencies · list_discovered_agents · adopt_discovered_agent
The failure loop: list_open_incidents · add_incident_note
Alert routing: set_route · delete_route
Delivery log: list_deliveries, recent alert deliveries across every
monitor, no paging
Destinations: list_destinations · create_destination ·
update_destination · test_destination · delete_destination
Alert templates: get_alert_templates · set_alert_template
Agent registry: register_agent · list_agents · get_agent ·
update_agent · delete_agent
Status pages: list_status_pages · create_status_page ·
update_status_page · delete_status_page
API keys: create_api_key (optional scope: read / write / admin / ingest) ·
list_api_keys · regenerate_api_key (new secret, same key; does not
cascade) · revoke_api_key (cascades to every key it created)
Terraform: export_terraform
This binary carries the same tool set as the hosted server at
mcp.lastping.dev. It is a thin REST client throughout: every tool is a
direct HTTP call to the management API, so it stays free to run yourself with
no lag behind the hosted surface beyond a new release.
The one that matters most is get_ping_instructions: an agent calls
create_monitor, then asks for its own ping commands, and wires them into its
own work — in one conversation, without a human opening a dashboard.
Ping API
Every monitor gets a URL. There is nothing to install and no library to keep current; anything that can make an HTTP request can report.
What happened | Request |
finished successfully |
|
started a run |
|
failed |
|
exited with a code |
|
waiting on a human |
|
progress worth recording |
|
Add ?rid=<id> to pair a run's start with its result, so LastPing can group a
run's pings and time it.
# The classic one-liner, at the end of a cron job:
curl -fsS -m 10 --retry 3 https://ping.lastping.dev/<monitor-id>Traces
POST https://ping.lastping.dev/v1/traces accepts an OTLP/HTTP export
(application/x-protobuf or application/json, gzip accepted) with a
Bearer key (an ingest key bound to the monitor, from create_ingest_key;
a write or admin key also works), or POST <ping-url>/v1/traces for exporters that
cannot set headers. Spans need the resource attribute lastping.monitor_id;
with lastping.run_id they join that run, and without it each trace becomes a
run of its own. A payload is capped at 1 MiB decompressed,
500 spans per request and 2,000 spans per run. lastping run sets all of
this up for you — see Traces above.
Monitoring as code
resource "lastping_monitor" "nightly_etl" {
name = "nightly-etl"
slug = "nightly-etl"
schedule_kind = "cron"
cron_expr = "0 3 * * *"
tz = "Europe/Berlin"
grace_s = 900
}The provider is on the
Terraform Registry
as lastping-dev/lastping, with source at
lastping-dev/terraform-provider-lastping.
Links
lastping.dev — the hosted service, free for individuals
AI agent monitoring — the agent-first guide
MCP server — connect configs per client
Terraform provider — monitoring as code
Integration guides — cron, Kubernetes, systemd, GitHub Actions, Python, Node
License
MIT. See LICENSE.
Available Tools
50 toolsadd_incident_noteAdd incident noteAInspect
Requires the write scope or higher. Adds a diagnosis note to an incident; it appears on the incident's page in order, stored with author 'agent' (no author argument exists). Notes are append-only: no edit or delete exists, so a correction is a new note and the history stays evidence. Several notes per incident are normal, up to a cap of 50, and a closed incident still accepts them. A note can record a failure that was not fixed as well as one that was. Without a note, the incident page shows only the alert.
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | The diagnosis in plain words: what failed, whether it matches earlier failures (failure_signature.occurrences from list_open_incidents) and what was done, e.g. 'failed because the upstream API returned 503; same as the last three nights; retried twice'. Non-empty, not whitespace-only, at most 8192 bytes; an oversized body is rejected, never truncated. The full failure output already lives on the run. | |
| incident_id | Yes | The incident's numeric id, an entry's incident_id in list_open_incidents. An integer, not a UUID. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnlyHint=false, idempotentHint=false, destructiveHint=false, openWorldHint=false), it discloses the auth requirement (write scope or higher), the append-only nature with no edit/delete path, the 50-note cap, acceptance on closed incidents, and the author value. This is exactly the mutation-behavior context annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Six sentences, each carrying distinct information, with the action and permission prerequisite front-loaded before the behavioral details. No restatement of the name or title and no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter mutation tool with no output schema, the description covers permissions, mutation semantics, capacity limits, edge cases (closed incidents), and the value proposition of the note. Nothing an agent needs in order to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds one genuinely useful clarification the schema cannot: there is no author argument, so the agent should not attempt to supply one. The remaining parameter meaning (incident_id integer, body content/limits) is already fully documented in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first operative sentence states a specific verb and resource ('Adds a diagnosis note to an incident') and immediately pins down the unique semantics of the operation (append-only, stored with author 'agent'). No sibling tool overlaps with adding notes, so an agent can place this without ambiguity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives strong contextual guidance on when this applies: several notes per incident are normal, a closed incident still accepts notes, and a note may record an unfixed failure. It never names an explicit alternative or exclusion, but the write-scope prerequisite and the 'without a note the page shows only the alert' framing make the trigger condition clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
adopt_discovered_agentAdopt discovered trace sourceAIdempotentInspect
Requires the write scope or higher. Counts a discovered trace source's traces under an agent from now on. Without agent_id, a new agent named after the source is created (409 AGENT_EXISTS when its slug is taken). With agent_id (e.g. a suggested_agent_id), the source merges into that agent. Earlier traces stay where they are (backfilled is false). Re-adopting into the same agent changes nothing; into a different one is 409 ALREADY_ADOPTED. untrusted_fields names the data fields LastPing did not write (job output, exporter data or user-supplied names).
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Discovered source UUID (from list_discovered_agents). | |
| agent_id | No | Optional agent UUID (from list_agents) to merge the source into. Omitted: a new agent is created. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: it states the required write scope, discloses that earlier traces are NOT backfilled, and documents the specific 409 failure modes (AGENT_EXISTS, ALREADY_ADOPTED) that an agent must anticipate. The idempotency nuance matches idempotentHint=true without contradicting it.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the permission requirement and the core behavior, and most sentences carry actionable semantics. The closing sentence about `untrusted_fields` names no parameter in the input schema, making it the one item whose placement is questionable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter mutation with no output schema, the description covers auth scope, backfill behavior, and error conditions thoroughly. It never says what the call returns (e.g. the adopted or created agent id), and the `untrusted_fields` reference is unexplained, so a small gap remains.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so the baseline is 3; the description adds value by clarifying the merge-versus-create decision, the 409 AGENT_EXISTS consequence of omitting agent_id, and where a suggested id can come from. It does not add anything about the `id` parameter beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource+effect: 'Counts a discovered trace source's traces under an agent from now on.' This clearly distinguishes it from register_agent (manual) and list_discovered_agents (read), and the title reinforces the same idea.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly branches on the primary decision: 'Without agent_id, a new agent named after the source is created' versus 'With agent_id (e.g. a suggested_agent_id), the source merges into that agent,' and it names the alternative source of a suggested id. It further covers re-adoption cases and their outcomes, leaving little to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_api_keyCreate API keyAInspect
Requires the admin scope or higher. Creates an API key. The plaintext key appears only in this result and cannot be retrieved again. expires_at makes a short-lived key. create_ingest_key, which needs only the write scope, mints a single-monitor tracing key.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Label for the key, e.g. "github-actions". | |
| scope | No | What the new key may do. "read" is every GET; "write" (the default) is everything except managing API keys, so a key at that tier cannot mint itself a replacement; "admin" is everything. A scope above the creating key's is refused, and the refusal names the ceiling. "ingest" only sends pings and telemetry (traces, metrics, logs) and cannot call the REST API, for a key kept in a dotfile or an exporter's config. | |
| check_id | No | Only with scope "ingest": binds the key to this one monitor (UUID from list_monitors), so it sends telemetry for that monitor alone. An exporter that cannot name its monitor, such as Codex, needs it. | |
| expires_at | No | Optional RFC 3339 expiry, e.g. "2026-12-31T00:00:00Z". Omitted: 90 days. Either way it is capped at the creating key's own expiry. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only cover the safe-write profile (destructive=false, idempotent=false); the description goes well beyond them by disclosing that the plaintext key is shown once and is unrecoverable, that expires_at defaults to 90 days and is capped at the creating key's expiry, and that a scope above the creating key's is refused with the ceiling named in the error.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, front-loaded with the scope prerequisite followed by behavior and the alternative route. Every sentence carries a distinct fact (permission, effect, one-time secret, routing), with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description carries the return-value burden and does so by explaining that the plaintext key appears only in this result. Combined with the scope precondition, expiry defaults and sibling routing, an agent has everything needed to call this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents name, scope, check_id and expires_at in depth (including the 90-day default, the expiry cap, and the ingest/check_id binding). The description largely restates that ("expires_at makes a short-lived key"), adding little semantic meaning the agent could not read from the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Creates an API key") and immediately differentiates it from the sibling create_ingest_key, which mints a narrower single-monitor key. An agent can pick between the two credential-creation tools without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"Requires the admin scope or higher" sets the precondition up front, and the closing sentence names the alternative (create_ingest_key) plus the condition that selects it (only the write scope, single-monitor tracing). That is explicit when-to-use and when-to-use-something-else guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_destinationCreate alert destinationAInspect
Requires the write scope or higher. Creates a notification destination (channel) that monitors can route alerts to, from the fields of the chosen kind; unrelated fields are ignored. Non-email kinds are usable immediately; an email destination starts unverified, sends a confirmation link, and can join a route once the link is clicked. A project holds at most 25 destinations (DESTINATION_CAP_REACHED beyond that). Returns the new channel id, which set_route takes.
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | webhook: the POST target URL. | |
| kind | Yes | One of: webhook, telegram, discord, slack, ntfy, pushover, msteams, googlechat, email. Every destination URL has to be https, and a branded kind has to point at its vendor's host: discord at discord.com or discordapp.com, slack at hooks.slack.com, msteams at webhook.office.com or outlook.office.com or logic.azure.com or logic.azure.us or environment.api.powerplatform.com, googlechat at chat.googleapis.com. Any other endpoint fits kind "webhook", which accepts any https host; ntfy is unpinned too, so a self-hosted ntfy server works. A pin narrows the destination to the vendor's platform; it does not prove who owns the endpoint, since every pinned domain is multi-tenant. | |
| name | Yes | Human-readable destination name, e.g. 'On-call Slack'. | |
| token | No | pushover: the application API token. | |
| secret | No | webhook: shared secret used to sign the HMAC-SHA256 payload. | |
| address | No | email: the destination email address (a confirmation link is sent). | |
| chat_id | No | telegram: the target chat id. | |
| user_key | No | pushover: the user or group key. | |
| bot_token | No | telegram: the bot token from @BotFather. | |
| topic_url | No | ntfy: the full topic URL, e.g. 'https://ntfy.sh/my-topic'. | |
| webhook_url | No | slack / discord / msteams / googlechat: the incoming-webhook URL. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: discloses the 25-destination cap and DESTINATION_CAP_REACHED error, the email verification flow, the 'unrelated fields are ignored' behavior, and the returned channel id. These are exactly the operational facts an agent needs that annotations do not provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the scope requirement, then the core behavior, verification nuance, cap, and return value in four tight sentences. Slightly dense but no wasted clauses.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers auth requirement, kind-dependent behavior, cap/error, and return value — the essential facts for an 11-param creation tool. Missing only minor details like whether the returned id is used elsewhere beyond set_route, but it is essentially complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the schema already documents each field per-kind in detail. The description adds the useful 'from the fields of the chosen kind; unrelated fields are ignored' rule, but otherwise defers to the schema. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Creates a notification destination (channel) that monitors can route alerts to') and ties it to siblings like set_route and list_destinations. An agent can immediately distinguish this from update_destination or test_destination.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explains prerequisites ('Requires the write scope or higher'), the kind-dependent immediate-vs-verification flow, and mentions set_route as the consumer of the returned id. It does not explicitly name create vs update alternatives, but the routing to set_route gives clear downstream context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_ingest_keyCreate tracing keyAInspect
Requires the write scope or higher. Creates a tracing key: an ingest-scoped key bound to one monitor, able to send traces, metrics, logs and pings for it and nothing else; every REST call refuses it. For automation that stores the key itself (a CI secret, a deployment's secret store). The plaintext key appears only in this result, which puts it in the conversation; the console's Create a tracing key keeps it out of chat.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Optional label for the key. Defaults to "Tracing:" followed by the monitor's name. | |
| expires_at | No | Optional RFC 3339 expiry, e.g. "2026-12-31T00:00:00Z". Omitted: 90 days. Either way it is capped at the creating key's own expiry. | |
| monitor_id | Yes | Monitor UUID the key is bound to (from create_monitor or list_monitors). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well past the annotations (which only supply readOnly/destructive/idempotent hints) by disclosing the required write scope, the constrained capability of the resulting key, and the security-relevant fact that the plaintext key is returned exactly once and lands in the conversation. This is exactly the kind of side-effect context an agent needs before invoking a mutation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the permission requirement, then the artifact definition, then the use case, then the exposure caveat. Every clause carries distinct information; there is no filler despite the density.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by describing the return ('the plaintext key appears only in this result'), plus scope, lifetime behavior implied by the schema, and the comparison to the console path. An agent has everything needed to call this safely and correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so name, expires_at and monitor_id are already fully documented with formats and defaults. The description reinforces the one-monitor binding but adds no syntax or format detail beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource and then defines the artifact precisely ('an ingest-scoped key bound to one monitor, able to send traces, metrics, logs and pings for it and nothing else; every REST call refuses it'). This definition cleanly separates it from the sibling create_api_key without requiring the agent to open either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear when-to-use condition ('For automation that stores the key itself (a CI secret, a deployment's secret store)') and an explicit when-not via the console alternative that keeps the plaintext out of chat. It does not, however, contrast against the sibling create_api_key, so routing between MCP options is left partly to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_monitorCreate or update monitorADestructiveIdempotentInspect
Requires the write scope or higher. Creates a monitor, or updates the existing one when slug matches (an upsert; the result says 'updated'). Heartbeat and ci monitors take schedule_kind: 'simple' with period_s, 'cron' with cron_expr, or 'on_demand' with neither. http monitors take probe_url and probe_interval_s; probe_expected_status and probe_expected_body define a healthy response, and a probe with neither only checks that something answered. ci_provider can be set only here, and the webhook secret it returns appears only in this result.
| Name | Required | Description | Default |
|---|---|---|---|
| tz | No | IANA timezone for cron evaluation. Defaults to UTC. | |
| name | Yes | Human-readable monitor name, e.g. 'Daily backup job'. | |
| slug | No | Optional stable ID; when a monitor with this slug exists it is updated (upsert). Trimmed and lowercased, then it has to match ^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$ (3-50 chars, lowercase alphanumeric and hyphens). UUID-shaped slugs are rejected (ambiguous with a monitor id in a Terraform import). Omitted: no slug. | |
| tags | No | Comma-separated labels for namespace scoping, e.g. 'agent:claude,env:prod'. Max 20 tags, each max 50 chars. | |
| grace_s | No | Grace period in seconds after a ping is due before alerting. Omitted on an on_demand monitor, LastPing uses 300 seconds; on_demand has no cadence, so grace only sets the first-run deadline and the overrun fallback. On an upsert (existing slug), omitting it on an on_demand monitor sets 300. | |
| agent_id | No | Attaches the monitor to a registered agent, by the agent's id or slug (register_agent returns both). An agent that does not exist is an error (400 UNKNOWN_AGENT); no agent is created implicitly. Omitted on a create: no owning agent. On an upsert (existing slug), omitting it leaves the current attachment unchanged, and supplying it re-applies the attachment, so a repeated registration converges to 'attached'. | |
| period_s | No | Ping interval in seconds. Required when schedule_kind='simple'. | |
| ci_branch | No | CI filter: only runs on this branch count, e.g. 'main'. Needs ci_provider (400 FIELD_NOT_IN_SHAPE without a CI binding). Same upsert exception as ci_workflow: create_monitor on an existing slug never writes it; update_monitor does. Unset, a run on any branch, a fork's pull request included, reports to the monitor. | |
| cron_expr | No | 5-field cron expression, e.g. '0 3 * * *'. Required when schedule_kind='cron'. | |
| probe_url | No | http monitors only: the absolute http/https URL to probe. Required when monitor_type='http'. The host is resolved at write time and rejected if it resolves only to private/link-local addresses. | |
| ci_provider | No | Binds the monitor to a CI system ('github', 'gitlab' or 'jenkins'), whose webhook then reports every run with no ping code in the job. Fixed at creation: update_monitor cannot change or remove it. The webhook secret and URL appear only in this call's result; no tool or API read returns the secret again. Not accepted on monitor_type='http' (400 FIELD_NOT_IN_SHAPE). ci_workflow and ci_branch narrow which runs count. | |
| ci_workflow | No | CI filter: only runs of the workflow, pipeline or job with this exact name count. Needs ci_provider: without a CI binding it is refused with 400 FIELD_NOT_IN_SHAPE (monitor_type='ci' alone binds nothing). Exception: create_monitor on an existing slug (an upsert) never writes it, and with ci_provider in the same call it is accepted and discarded; update_monitor persists it. Unset, every workflow in the repository reports to the monitor, so an unrelated workflow's failure opens an incident and its success clears one. | |
| monitor_from | No | Dormant until: an RFC 3339 timestamp before which no deadline is computed and no incident opens, for a monitor provisioned ahead of its job. The first-run deadline is monitor_from + grace_s. Unset (default): deadlines start immediately. Example: '2026-01-01T00:00:00Z'. On an upsert (existing slug), omitting it clears the value and arms the monitor immediately. | |
| monitor_type | No | 'heartbeat' (default), 'ci' or 'http'; any other value is refused with 400 UNKNOWN_MONITOR_TYPE. 'ci' is a label, not a binding: without ci_provider it creates an ordinary heartbeat, and ci_workflow/ci_branch are refused. | |
| probe_method | No | http monitors only: the HTTP method the probe sends: 'GET' (default), 'HEAD' or 'POST'. 'HEAD' returns no body, so probe_expected_body cannot match with it. | |
| max_runtime_s | No | Maximum seconds one run may take, from its start ping, before it is reported overdue (the 'overrun' rule). Unset falls back to grace_s. Example: grace_s=600 with max_runtime_s=14400 alerts 10 minutes after a missed ping but tolerates a 4-hour run. It replaces grace_s for the overrun deadline only; the silence rule and the first-run deadline still use grace_s. Range 60-31536000. Not supported on http monitors (400 MAX_RUNTIME_NOT_SUPPORTED); probe_timeout_s bounds a probe. On an upsert (existing slug), omitting it clears the value. | |
| schedule_kind | No | 'simple' (with period_s), 'cron' (with cron_expr) or 'on_demand' (neither). Required for heartbeat and ci monitors. Not accepted on an http monitor, and neither are period_s, cron_expr and tz: its schedule comes from probe_interval_s (400 FIELD_NOT_IN_SHAPE). 'on_demand' has no cadence (period_s or cron_expr with it is a 400) and arms no absence deadline between runs: an agent that is never invoked again raises nothing unless expect_every_s is set, and an idle healthy agent never raises a false 'late'. Once a run starts, max_runtime_s, step_timeout_s and blocked_timeout_s still apply. 'simple'/'cron' fit work on a cadence; 'on_demand' fits irregular invocation. | |
| trace_content | No | What this monitor's traces keep of prompt, command and tool content: 'dropped' (the default) removes it; 'redacted' stores prompt, command and tool content from the traced sessions, with secret-shaped values redacted on arrival. Omitted on a create: dropped; on an upsert (existing slug), omitting it leaves the stored value unchanged. | |
| expect_every_s | No | Silence floor in seconds: a 'silence' incident opens when no ping of any kind (success, start, fail, step) arrives within this window, timed from the monitor's last activity. It is the only absence rule an 'on_demand' monitor has. It stands down while a run is in flight (the run clock owns that), and a 'blocked' ping pauses it up to blocked_timeout_s. On 'simple'/'cron' monitors it joins the schedule deadline as whichever is sooner, so it can only tighten detection. Unset (default): no floor. Range 60-31536000. Accepted on every monitor_type and schedule_kind. On an upsert (existing slug), omitting it clears the value and turns the silence floor off. | |
| step_timeout_s | No | Seconds an armed run may go without a step before a 'stalled' incident opens, timed from the later of its start ping and its latest step. Steps are POST <ping_url>/step?rid=<run-id>&step=<name> (curl_step in get_ping_instructions). When set, a job that sends no steps opens a stalled incident on every run. The Claude Code hook and the reporting prompt send no steps. Unset (default): no stall detection. Range 10-86400, strictly below COALESCE(max_runtime_s, grace_s) (400 STEP_TIMEOUT_EXCEEDS_BUDGET). Not supported on http monitors (400 STEP_TIMEOUT_NOT_SUPPORTED). A step never extends max_runtime_s. On an upsert (existing slug), omitting it clears the value and turns stall detection off. | |
| probe_timeout_s | No | http monitors only: seconds one probe may take before it counts as a failure. Range 1-30, default 10. The http counterpart of max_runtime_s, which http monitors reject. | |
| runaway_ceiling | No | Ping-rate ceiling: the most pings this monitor may receive in a rolling hour; exceeding it opens a 'runaway' incident. It catches a job or agent stuck in a loop, which keeps pinging and otherwise reads 'up'. A job every 15 minutes sends about 4 pings an hour, so 20 leaves room for retries. Rate-based: failure_threshold and run budgets do not gate it. Unset (default): the rule is off. On an upsert (existing slug), omitting it clears the ceiling and turns the runaway rule off. | |
| notify_min_run_s | No | Notification duration floor in seconds: a run shorter than this sends no info-class notification (success, every-run, note), so a trivial agent run does not notify a destination those events are routed to. It never suppresses a failure: down, fail, recovery, blocked and started always notify, as does an event whose duration was not measured (such as a success with no start ping). Unset (default): no floor. Range 60-31536000. Not supported on http monitors (400 NOTIFY_MIN_RUN_NOT_SUPPORTED). On an upsert (existing slug), omitting it clears the value and turns the floor off. | |
| probe_interval_s | No | http monitors only: how often to probe, in seconds. Required when monitor_type='http'. Range 30-86400. | |
| blocked_timeout_s | No | Seconds a run may stay 'blocked' (an agent reported it is waiting on a human) before a 'blocked' incident opens. Unset means the 24-hour default, not no limit. Separate from the 'blocked' notification a route delivers (held 10 minutes, sent at most once per blocked stretch of a run). Accepted on every monitor_type. On an upsert (existing slug), omitting it clears the value back to the 24h default. | |
| failure_threshold | No | Consecutive failures required before an incident opens; default 1 (the first failure). 2-5 absorbs a job's occasional self-resolving failure. Any success resets the count. It gates only the 'fail' cause: silence, overrun, never_started and runaway are time- or rate-based and never delayed by it. A run ending on the model provider's API error (server_error, overloaded, rate_limit) neither counts nor resets it; 3 such runs in a row, or this many when higher, open an 'upstream' incident. Range 1-100. On an upsert (existing slug), omitting it resets the threshold to 1. | |
| probe_expected_body | No | http monitors only: a substring the response body has to contain for the probe to pass, e.g. '"status":"ok"'. A broken app's error page can still return 200 and pass a status-only check; this catches it. Case-sensitive substring, not a regex. Default empty: the body is not inspected. | |
| probe_expected_status | No | http monitors only: the exact HTTP status that counts as healthy; default 200, any other code fails the probe. E.g. 204 for a no-content endpoint, or 301 to check that a redirect still exists (with probe_follow_redirects=false; otherwise the probe sees the destination's status). | |
| probe_follow_redirects | No | http monitors only: whether the probe follows 3xx redirects; default false. When false, the redirect itself is compared with probe_expected_status, so a site that starts redirecting to a login wall or a parking page fails the probe instead of passing on the destination's 200. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (destructive, idempotent), yet the description adds real value beyond them: the write-scope requirement, the upsert result signaling 'updated', that ci_provider is settable only here, and that the webhook secret is returned only in this result and never readable again.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the scope requirement and the core upsert behavior, then grouped by monitor type. Dense but every sentence carries information; a slight compression could improve scannability given the sentence count.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 29-parameter tool with no output schema, the description covers the critical one-time-secret behavior and the upsert result, and the 100%-covered schema plus annotations handle parameters and safety. It could note pagination/return shape, but the essentials for correct invocation are present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, but the description adds cross-parameter semantics beyond any single field: the schedule_kind-to-type mapping and the healthy-response logic when neither probe_expected_status nor probe_expected_body is set. It earns above baseline without fully restating the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Creates a monitor') and precisely extends it with upsert semantics keyed on slug. It is clear what the tool does, but it never explicitly differentiates itself from the sibling update_monitor (e.g. 'use update_monitor to modify without creating'), leaving the boundary to be inferred.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Requires the write scope or higher' gives a clear permission prerequisite, and it explains which parameters apply per monitor_type/schedule_kind, giving strong context for correct invocation. It stops short of naming the alternative tool (update_monitor) or stating when NOT to use this one.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_status_pageCreate status pageAInspect
Requires the write scope or higher. Creates a status page: one page showing the current status and recent history of a chosen set of monitors, for people who cannot log in to the project. Pages are private unless visibility is 'public', which publishes every monitor name on the page.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | No | Optional URL slug, shown in the public link (/status/<slug>). Has to match ^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$ (3-50 chars, lowercase alphanumeric and hyphens). Slugs are unique across all projects, so a taken one returns 409. Omitted: a random unguessable slug, the safer default for a public page. | |
| title | Yes | Human-readable page title, e.g. 'Acme API Status'. Shown at the top of the page, and to anyone the page is shared with. | |
| check_ids | No | Comma-separated monitor UUIDs to show on the page, in no particular order, from list_monitors. Every id has to belong to this project: an unknown or cross-project id returns 400 and nothing is saved. An empty value is legal and produces a page with no monitors. | |
| visibility | No | 'private' (default) or 'public'. A public page is served at an unguessable but unauthenticated URL: anyone with the link sees the title, every monitor's name (often internal, such as 'billing-reconciler') and its up/down history. The free tier allows one public page per project; a second returns 403. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare it is a non-readonly, non-idempotent, non-destructive write. The description adds genuinely new behavior: the write-scope auth requirement and the significant side effect that 'public' publishes every monitor name. It does not mention uniqueness/409 behavior or irreversibility, keeping it below 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with the auth prerequisite, then purpose, then the visibility caveat. No filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 4-param mutation tool with full schema coverage and annotations but no output schema, the description supplies prerequisites and side effects an agent needs. Return-value expectations are the only real gap, which is minor here.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all four parameters are fully documented in the schema (slug rules, title, check_ids cross-project constraint, visibility semantics). The description adds no parameter detail beyond what the schema already provides, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb+resource, and it goes beyond the name by defining what a status page is: a page showing current status and recent history of chosen monitors, aimed at people who cannot log in. This is clearly distinguishable from create_monitor or update_status_page.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
States the prerequisite 'Requires the write scope or higher' and gives the key decision context (private vs public visibility and its exposure consequence). It does not explicitly name alternatives like update_status_page, so it falls short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
declare_run_expectationsDeclare run expectationsAIdempotentInspect
Requires the write scope or higher. Declares, at the start of a run, the criteria its success ping body is judged by when the run closes, so the run does not grade itself: a success whose body fails any declared criterion is recorded as a failed run with cause 'assertion', whatever the exit code. One declaration per rid, immutable (a second call is a conflict). For use right after the run's /start ping; get_ping_instructions' expectations_how_to has a worked example.
| Name | Required | Description | Default |
|---|---|---|---|
| rid | Yes | The run id exactly as sent on this run's /start ping, the same rid used on every step and the terminal ping. | |
| check_id | Yes | Monitor UUID (from create_monitor or list_monitors). | |
| assertions | Yes | The run's complete criteria, as a JSON array string, e.g. '[{"kind":"json_path","path":"result.rows_processed","op":"gt","value":"0"}]'. Fields: kind (required), value, path, op; no name. kind: contains, not_contains, matches (RE2, max 1000 bytes) or json_path (the value at a dotted path, e.g. 'a.b.c', compared with op: eq, ne, gt, gte, lt, lte). Only not_contains entries, or a matches pattern that accepts an empty body ('.*', '^$'), pass on empty output; a contains, json_path or empty-rejecting matches entry catches a run that produced nothing. At most 20; one malformed entry rejects the whole declaration. Runs with no declaration keep the monitor's own assertions. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations it discloses a lot: the required write scope, the grading consequence (a success failing any criterion is logged as a failed run with cause 'assertion' regardless of exit code), immutability and one-declaration-per-rid, and the dependency on the /start ping. This is exactly the behavioral context annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the scope requirement, then behavior, then constraints and usage in a few dense sentences, each earning its place. Slightly long/compound sentences keep it from a 5, but there is no wasted filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a declaration tool with no output schema, the description covers scope, timing, semantics, immutability and a pointer to an example, which is nearly everything needed to invoke it correctly. It does not describe the success response or error surface beyond the conflict case, a minor gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the schema already exhaustively documents rid, check_id and assertions (kinds, ops, limits, malformed handling). The description adds framing ('criteria its success ping body is judged by') but no parameter syntax or format beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: it 'Declares, at the start of a run, the criteria its success ping body is judged by when the run closes.' An agent can immediately tell this is a run-scoped assertion-registration tool, distinct from siblings like get_run, list_runs or get_ping_instructions.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear timing ('right after the run's /start ping') and points to 'get_ping_instructions' expectations_how_to' for a worked example, which is strong routing context. It stops short of an explicit when-not-to-use or alternative-tool exclusion, so it falls just below the top band.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_agentDelete agentADestructiveIdempotentInspect
Requires the write scope or higher. Permanently deletes an agent from the registry by UUID; cannot be undone. Its monitors are not deleted: each survives with its ping history and incidents, becomes unowned (agent_id null) and keeps running. update_monitor can attach a survivor to another agent, and delete_monitor removes a monitor.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Agent UUID (from register_agent or list_agents). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial context beyond the destructiveHint/idempotentHint annotations: the required scope, the irreversibility ('cannot be undone'), and the non-obvious cascading behavior that monitors survive, become unowned (agent_id null), and keep running with history intact. That cascade is precisely what an agent needs before calling a destructive tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two dense sentences with zero filler: authorization and irreversibility lead, then the monitor-survival consequence and the tools that handle survivors. Nothing is repeated or padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description nevertheless explains the post-deletion state of dependent resources and which tools act on them. For a one-parameter destructive tool, an agent has everything needed to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% for the single 'id' parameter, and the schema already documents that it is an agent UUID from register_agent or list_agents. The description adds only 'by UUID', so the schema does the heavy lifting and the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Permanently deletes an agent from the registry by UUID'), which cleanly separates it from get_agent, update_agent, and list_agents. The 'permanently' qualifier also distinguishes it from reversible mutations like update_agent.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the prerequisite ('Requires the write scope or higher') and routes the agent for the follow-on case, naming update_monitor and delete_monitor for surviving monitors. It never explicitly says when not to use this tool (e.g. prefer update_agent to merely change an agent), so it falls just short of 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_destinationDelete alert destinationADestructiveIdempotentInspect
Requires the write scope or higher. Permanently deletes a notification destination (channel); cannot be undone. It is removed from every monitor's routing, so an event type routed only to it stops notifying anyone, with no incident to show for it. get_monitor's routes shows which event types route to it, and set_route changes routing without deleting the destination.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Destination (channel) UUID, from list_destinations. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=true, but the description adds substantially more: the write-scope auth requirement, irreversibility ('cannot be undone'), and the crucial consequence that routing removal causes silent non-notification with no incident. That silent-failure warning is exactly the kind of behavioral context annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four tight sentences, front-loaded with the scope requirement, then consequence, then alternative. No sentence is filler; each adds auth, risk, or routing context.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive one-param tool with no output schema, the description supplies everything needed: permission level, reversibility, blast radius, silent-failure risk, diagnostic sibling, and a non-destructive alternative.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% for the single `id` parameter, which the schema itself documents as a Destination UUID from list_destinations. The description adds no syntax or format detail beyond that, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (permanently deletes) and resource (notification destination/channel), with a parenthetical clarifying what a destination is. It is distinguishable from siblings like delete_route, update_destination, and set_route without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It routes the agent to alternatives: get_monitor's `routes` to inspect what points at the destination, and set_route to change routing without deleting. It implies when to delete versus re-route, though it never states an explicit 'when to use this' or an exclusion case.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_monitorDelete monitorADestructiveIdempotentInspect
Requires the write scope or higher. Permanently deletes a monitor by UUID; this cannot be undone. Its pings, run steps, traces, incidents, routes, alert templates, assertions and delivery history are deleted with it, and the ingest keys bound to it (from create_ingest_key) are deleted too, so they stop working.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Monitor UUID. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and idempotentHint=true, but the description goes well beyond them by enumerating the exact cascade: pings, run steps, traces, incidents, routes, alert templates, assertions, delivery history, plus bound ingest keys that stop working. That is precisely the 'what gets destroyed' context an agent needs before calling a destructive tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single dense sentence pair with zero filler; the permission prerequisite and irreversibility warning are front-loaded, and the cascade list is the longest part because it carries the most decision value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-param destructive tool with no output schema, the description covers permissions, reversibility, and full cascade impact, while annotations cover the safety profile. Nothing an agent needs in order to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single parameter is already documented as 'Monitor UUID.' The description only restates 'by UUID,' adding no format, source, or lookup guidance beyond the schema - baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Permanently deletes a monitor by UUID') with the scope of the operation made explicit. This cleanly separates it from the other delete_* siblings (delete_agent, delete_route, delete_destination, delete_status_page) without needing to name them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the prerequisite ('Requires the write scope or higher') and a strong irreversibility warning, which implies caution before use. However, it never addresses the obvious less-destructive alternatives in the sibling set - pause_monitor, snooze_monitor, or update_monitor - which an agent should consider before a permanent delete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_routeDelete alert routeADestructiveIdempotentInspect
Requires the write scope or higher. Stops routing one event type of a monitor to any destination, so its alerts for that event go nowhere; every other event type's routing is unchanged. set_route with the remaining ids drops a single destination instead. An event type with no routing answers "route not found".
| Name | Required | Description | Default |
|---|---|---|---|
| event_type | Yes | The event type to unroute: down, recovery, fail, every-run, success, started, blocked or note. | |
| monitor_id | Yes | Monitor (check) UUID. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint and idempotentHint, and the description adds real context beyond them: the required auth level ('write scope or higher'), exactly what is destroyed (routing for one event type, alerts going nowhere), and what is explicitly left untouched (every other event type's routing). It also documents the failure response text, which annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences with no filler, each carrying distinct information (auth, effect, alternative, error). It is slightly back-loaded: the leading permission note delays the core purpose statement, which would be stronger front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, yet the description covers auth requirements, the exact destructive scope, the unaffected state, the alternative tool, and the error surface. Combined with annotations covering idempotency, an agent has everything needed to call this correctly and safely.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the event_type enum is fully documented in the schema, so the baseline is 3. The description does add semantics by framing the pair as the monitor/event-type key into a routing mapping and by explaining what a missing route means, but it adds no format or value-level detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource with precise scope: 'Stops routing one event type of a monitor to any destination.' It clearly distinguishes itself from set_route by contrasting scope (whole event type vs. a single destination), so an agent can select it without opening the sibling schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the alternative explicitly ('set_route with the remaining ids drops a single destination instead') and describes the no-op/error condition ('An event type with no routing answers "route not found"'). It lacks an explicit when-to-use scenario (e.g., permanently stop alerting for an event type), but the routing between the two tools is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_status_pageDelete status pageADestructiveIdempotentInspect
Requires the write scope or higher. Permanently deletes a status page; cannot be undone, and its public URL stops working immediately. The monitors on it are unaffected and keep running and alerting. update_status_page with visibility 'private' stops sharing without deleting.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Status page UUID, from list_status_pages. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, it discloses that deletion is permanent and irreversible, that the public URL stops working immediately, and that monitors continue running and alerting. It also states the required write scope, giving the agent a complete behavioral picture for a destructive operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is four short sentences with no waste, front-loading scope and permanence before side effects and the alternative. Every sentence carries actionable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple, one-parameter delete tool with annotations and full schema coverage, the description supplies the missing behavioral context: auth scope, irreversibility, URL impact, monitor impact, and the safer alternative. No output schema exists, so return values do not need explanation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, and the single id parameter is already documented in the schema as coming from list_status_pages. The description adds no further parameter meaning, which is acceptable given the high schema coverage but does not raise it above the baseline of 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb (permanently deletes) and resource (status page), clearly distinguishing this tool from list_status_pages, create_status_page, and update_status_page. It also names the sibling update_status_page as the non-destructive alternative, so an agent can route correctly without opening other schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly gives the alternative: update_status_page with visibility 'private' stops sharing without deleting. This tells the agent when to choose deletion versus a reversible change, and the required scope is stated up front.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
discover_monitors_reconcileReconcile discovered jobs as monitorsAIdempotentInspect
Requires the write scope or higher. Turns a scan of a repository or host (sources, every scheduled job found) into monitors. Creates one monitor per source not already monitored; never deletes, pauses or edits existing monitors, so a scheduled re-run is safe drift detection. Returns created, existing (unmodified, hand-tuned values intact) and orphaned (source not in this scan; still running and alerting). Each created monitor can page a person; this endpoint has no delete path. source_kind plus source_ref is the diff key, so source_ref has to stay stable: a changed ref creates a duplicate; a crontab ref names the file and the command, so each line is its own source. Kinds: 'crontab' (crontab -l, /etc/cron.d/*, /etc/crontab), 'github-actions' (on.schedule.cron), 'k8s-cronjob' (spec.schedule), 'systemd-timer' (OnCalendar=). A source without schedule_cron becomes on-demand. crontab and systemd-timer fire in the host's local time (timedatectl show -p Timezone --value or readlink /etc/localtime prints it); github-actions and k8s-cronjob in UTC. A stated tz is stored as given: the API cannot tell a guessed 'UTC' from one read from the host. list_monitors shows each source.
| Name | Required | Description | Default |
|---|---|---|---|
| sources | Yes | The full scan as a JSON array string, e.g. '[{"source_kind":"crontab","source_ref":"/etc/cron.d/backup:/usr/local/bin/backup.sh","schedule_cron":"0 3 * * *","tz":"Europe/Berlin"}]'. Fields: source_kind, source_ref (required), name (default source_ref), schedule_cron (5-field, when one was read), tz (IANA zone the cron fires in; required on a crontab or systemd-timer entry with schedule_cron), suggested_expect_every_s (overrides the silence floor). An omitted source is reported orphaned; '[]' orphans every discovered monitor, deleting none. At most 1000 entries; a repeated source_kind/source_ref pair is rejected. The 100-monitor cap covers the whole batch; one invalid entry rejects it all. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (idempotentHint, destructiveHint=false) by spelling out that no existing monitor is deleted, paused, or edited, that hand-tuned values stay intact, that orphaned sources keep running/alerting, and that there is no delete path. It also discloses the source_ref stability trap that silently creates duplicates.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the scope requirement and the core action, and every sentence carries information. It is dense to the point of being a wall of text, and some tz detail sits awkwardly after the kind list, but nothing is truly wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter tool with no output schema, the description supplies the return contract (created/existing/orphaned) and the safety profile an agent needs. Batch limits live in the schema and the destructive/idempotency picture is fully covered, leaving no material gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so the baseline is 3, but the description adds meaning the schema lacks: source_kind+source_ref as the diff key, the stability requirement on source_ref, the enumerated kind values, and the local-time vs UTC firing rules per kind.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: turning a scan of a repo/host into monitors, creating one per unmonitored source. It distinguishes itself from single-target siblings like create_monitor by describing the batch diff/reconcile semantics and naming list_monitors for the read-side view.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear context (after a repository/host scan) and the recommended cadence (a scheduled re-run is safe drift detection), plus the write-scope prerequisite. It stops short of explicitly naming when to prefer create_monitor instead, so no explicit exclusion is provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
export_terraformExport Terraform configurationARead-onlyIdempotentInspect
Requires the read scope or higher. Exports existing monitors, destinations, routes, alert templates and status pages as Terraform HCL, with import blocks so they are adopted rather than recreated. Secrets are not exported; the output references Terraform variables that hold them.
| Name | Required | Description | Default |
|---|---|---|---|
| tag | No | Optional tag to filter monitors by, e.g. 'agent:claude'. Only monitors carrying this tag (and their routes/templates) are exported. | |
| include | No | Optional comma-separated subset of monitors,destinations,routes,templates,status_pages. Omitted: everything. | |
| monitor_slug | No | Optional slug to export a single monitor by. Combines with tag if both are given. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the safety profile is covered. The description goes beyond them by disclosing that secrets are omitted and surfaced as Terraform variable references, and that import blocks exist to adopt rather than recreate resources — real behavioral context an agent could not infer.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences; the permission prerequisite is front-loaded, followed by scope, then the secret-handling caveat. No filler and every sentence carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by characterizing the return (HCL plus import blocks, secrets replaced by variable references) and the auth requirement. Nothing essential to correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so tag, include, and monitor_slug are fully documented in the schema. The description contributes no additional parameter semantics beyond what the schema already states, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb (Exports) plus enumerated resources (monitors, destinations, routes, alert templates, status pages) and the output format (Terraform HCL). No sibling tool does export, so it is trivially distinguishable from the create/update/list/delete family.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
States a prerequisite ('Requires the read scope or higher') and frames the intended outcome (adopted rather than recreated). It does not name when-not to use it or point at a sibling alternative, but for a unique export capability that guidance is largely unnecessary.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_agentGet agent detailsARead-onlyIdempotentInspect
Requires the read scope or higher. Gets one agent by UUID, with the same fields as list_agents: its live status rollup, usage_24h and top_dependencies. untrusted_fields names the data fields LastPing did not write (job output, exporter data or user-supplied names).
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Agent UUID (from register_agent or list_agents). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnly, idempotent, non-destructive), so the bar is lower. The description adds genuinely useful non-obvious context: the required read scope, the field shape including live status rollup and usage_24h, and especially the semantics of `untrusted_fields` explaining provenance. That last detail is behavioral context an agent couldn't infer from the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the permission requirement, then the return shape, then the untrusted_fields caveat. Efficient and each sentence carries distinct information, though the untrusted_fields sentence is denser than needed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-entity read with full schema coverage and full annotations, the description adds the return-shape summary and the provenance caveat, which is more than most tools at this level. Without an output schema the untrusted_fields note is particularly valuable. Missing only explicit guidance on when to prefer get_agent_usage/get_agent_dependencies.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single param is documented ('Agent UUID, from register_agent or list_agents'). The description repeats the UUID-source hint but adds no format or validation details. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Gets one agent by UUID') and names the field set it returns, which ties it to list_agents. It distinguishes itself from get_agent_usage and get_agent_dependencies by mentioning those fields inline, but doesn't explicitly rule out those siblings as alternatives.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage ('gets ONE agent by UUID' vs list_agents' plural) and notes the UUID comes from register_agent or list_agents. But it doesn't explicitly state when to use this vs get_agent_usage or get_agent_dependencies, which likely return overlapping subsets of the same data.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_agent_dependenciesGet one agent's dependenciesARead-onlyIdempotentInspect
Requires the read scope or higher. What one agent calls, heaviest first, from its traces: each model, tool, HTTP host, database, queue, RPC endpoint or agent: calls, errors, error_rate (0-1), p50_ms, p95_ms (bucket ceiling; p95_is_floor: over 60s), daily series, and for a model tokens, cost_usd and cost_source (client, estimated or mixed). operations: up to five span names per outgoing row, sampled from the ten newest traced runs. At most 50 rows; more counts the rest. untrusted_fields names the data fields LastPing did not write (job output, exporter data or user-supplied names).
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Agent UUID or slug (from list_agents). | |
| range | No | Time window: 24h, 7d (the default) or 30d. It covers every UTC day that overlaps it, so 24h spans two days. | |
| direction | No | out (the default): what this agent calls. in: who calls it. all: both. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnly/idempotent annotations: it discloses the 50-row cap with a `more` counter, that `operations` are sampled from the ten newest traced runs (up to five span names per row), the p95 floor caveat above 60s, and that `untrusted_fields` marks externally-written `data`. These are exactly the operational traits an agent needs and cannot get from annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the scope requirement and is dense but earns most of its length by enumerating return fields in the absence of an output schema. The single long clause-list is efficient, though slightly hard to scan.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the full burden of describing return values and does so thoroughly: field list, metric semantics, sampling, truncation, and data-provenance caveats. Combined with the auth requirement, an agent has everything needed to call and interpret it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so `id`, `range` (with default and UTC-day overlap behavior) and `direction` are fully documented in the schema. The description adds no parameter-level meaning, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource and scope ('What one agent calls, heaviest first, from its traces'), so an agent knows this is a per-agent dependency listing rather than a global one. It implies the singular scope that separates it from list_dependencies, but never names that sibling explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides the access precondition ('Requires the read scope or higher'), which is genuine usage guidance, but gives no when-to-use/when-not framing or routing to alternatives like list_dependencies or get_agent_usage. Usage is implied rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_agent_usageGet agent model usageARead-onlyIdempotentInspect
Requires the read scope or higher. Model usage, one row per model per UTC day: tokens_in (cache reads included, so tokens_cache_read is not added to it), tokens_out, tokens_cache_read, tokens_cache_write, cost_usd (decimal text) and cost_source: client (the tool reported its cost), estimated (LastPing priced tokens at API list prices), mixed (a traced day holds both) or empty (unknown). origin is traces or metrics; a day and model can have one of each, never summed. With id, one agent's usage; without, the project's, traces only, plus by_agent (costliest first). Both carry by_project: per project (a Claude Code session's folder) its runs, tokens and cost from traced runs only (project_scope traces_only). by_project sums each run's traced totals, while one agent's days prefer a Claude Code metrics export's reported cost, so the two need not match. With project, days become one row per UTC day with model and provider empty; project narrows days and by_project, not by_agent. untrusted_fields names the data fields LastPing did not write (job output, exporter data or user-supplied names).
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Agent UUID or slug (from list_agents). Omitted: every agent in the project. | |
| range | No | Time window: 24h, 7d (the default) or 30d. It covers every UTC day that overlaps it, so 24h spans two days. | |
| project | No | Only usage from traced runs of this project; metrics-only usage has no project and is left out. days then hold one row per UTC day with model and provider empty (a run's totals are not split by model); by_agent is not narrowed. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only cover the read-only/idempotent safety profile, yet the description adds substantial non-obvious behavior: cost_source enumeration, origin traces/metrics being never summed, the by_project vs. per-agent cost mismatch, project_scope traces_only, and the meaning of untrusted_fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The permission requirement is front-loaded, but the remainder is a single semicolon-chained wall of text that is hard to parse. Every clause carries information, yet the lack of segmentation hurts scanability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description fully carries the burden of explaining the return shape: the field list, cost_source values, origin semantics, by_agent/by_project structure, and untrusted_fields. Nothing essential for correct interpretation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description goes further by explaining interactions the schema omits: project narrows days and by_project but not by_agent, and id scopes to one agent's usage (traces only) versus the project's.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource with its granularity: 'Model usage, one row per model per UTC day', then enumerates the exact returned columns. An agent can tell this apart from get_agent or list_agents immediately.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the precondition ('Requires the read scope or higher') and the branching behavior of id vs. no id, plus the project scoping rule. It does not explicitly name a sibling alternative, but the conditional scoping guidance is unusually clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_alert_templatesGet alert templatesARead-onlyIdempotentInspect
Requires the read scope or higher. Gets a monitor's custom alert message templates: a map of event-type (or event-type/cause) keys to template strings. Keys: 'down', 'recovery', 'fail', 'every-run', 'success', 'started', 'blocked', 'note', or 'event_type/cause' (e.g. 'down/silence'). An empty result means every alert uses the built-in plain-language defaults.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Monitor UUID. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, non-destructive and non-open-world, so the safety profile is covered. The description adds real value beyond that: the auth scope requirement, the exact return structure, and crucially the semantics of an empty result ('every alert uses the built-in plain-language defaults'), which is a diagnostic insight an agent cannot get from the schema or annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the auth requirement, then the return shape, then the key enumeration, then the empty-result meaning. The key list is long but each enumeration maps directly to a possible template key, so it earns its space. Slightly dense, but no wasted sentence.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description fully compensates by explaining the return value as a key-to-template-string map, enumerating the valid keys and cause format, and describing the empty-result case. An agent has everything needed to interpret the response without opening anything else.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% with a single fully-documented parameter ('id': 'Monitor UUID.'), so the schema carries the parameter burden. The description adds no extra meaning about the id beyond what the schema already says, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Gets a monitor's custom alert message templates') and immediately defines the concrete return shape as a map of event-type keys to template strings. It is clearly distinguishable from the sibling set_alert_template, which is the write counterpart.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives a prerequisite ('Requires the read scope or higher') but never states when to call this versus set_alert_template or update_monitor, nor any when-not condition. Usage is implied by the tool name and the read-only nature of the operation rather than being spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_incidentGet incident timelineARead-onlyIdempotentInspect
Requires the read scope or higher. Gets one incident and its ordered timeline: run_started, step, run_failed/cancelled/blocked, incident_opened, alert_delivered/failed/suppressed/pending (destination and attempts; down and fail alerts only), note, incident_resolved. For what the run was doing, who was paged and what was tried. run_* events are matched on the run id recorded at opening, so none means no run was recorded. Delivery error text is omitted. untrusted_fields names the data fields LastPing did not write (job output, exporter data or user-supplied names).
| Name | Required | Description | Default |
|---|---|---|---|
| incident_id | Yes | The incident's numeric id, from list_incidents, list_open_incidents or add_incident_note. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/idempotent annotations, the description discloses non-obvious behaviors: the required read scope, the fact that run_* events are matched on the run id captured at opening (so absence means no run was recorded), that delivery error text is deliberately omitted, and that untrusted_fields flags data LastPing did not write. These are exactly the kind of gotchas annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the precondition, then purpose, then behavioral caveats; every sentence carries information. The mid-sentence enumeration of timeline event types is dense but earns its place by telling the agent what to expect in the response.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description itself must describe the return shape, and it does: the ordered event vocabulary, the destination/attempts detail, the alerts-only caveat, and the untrusted_fields semantics. An agent has enough to call and interpret this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
A single parameter with 100% schema coverage, so the schema already documents incident_id and even its source (list_incidents, list_open_incidents, add_incident_note). The description adds no format or edge-case meaning for the id, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource — 'Gets one incident and its ordered timeline' — and enumerates the timeline event types, which separates it from the run-history siblings like get_run and get_run_history. It never names a sibling explicitly, so the differentiation is inferable rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The framing 'For what the run was doing, who was paged and what was tried' implies the investigative use case, and the read-scope prerequisite is stated. However, there is no explicit when-to-use guidance versus list_incidents, list_open_incidents, or get_run, leaving the agent to infer which tool answers which question.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_monitorGet monitor detailsARead-onlyIdempotentInspect
Requires the read scope or higher. Gets one monitor by UUID with its full configuration, including assertions (conditions a successful run's ping body has to satisfy), guards (ceilings on a number the job reports) and routes (which destinations receive which event type); each is absent when empty. update_monitor's assertions and guards and set_route each replace a whole set, and this result holds the current sets.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Monitor UUID. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds useful context beyond annotations: it mentions the read scope requirement, the exact fields returned (assertions, guards, routes), their semantics, and the fact that they are absent when empty. It also notes how update_monitor and set_route interact with these sets, which helps understand read-before-write patterns. Annotations already cover read-only, idempotent, non-destructive, so the bar is lower, and this adds meaningful detail.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and scope requirement. The description is dense but information-rich, with no obvious filler. Slightly longer than necessary but each sentence contributes useful context.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given a simple read tool with one parameter, full schema coverage, and annotations covering safety, the description is nearly complete. It explains the returned fields and their relevance to update operations. It does not describe output format (no output schema), but for this read tool that is a minor gap, hence not a 5.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single parameter id is fully documented in the schema as 'Monitor UUID.' The description does not elaborate on the id parameter beyond what the schema provides, so baseline 3 is correct.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource: 'Gets one monitor by UUID with its full configuration.' This distinguishes it from list_monitors, create_monitor, update_monitor, etc. However, it does not explicitly name sibling alternatives for comparison, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clearly implied when to use: when you need a monitor's current configuration by UUID. It also implicitly contrasts with update_monitor and set_route by noting that those replace whole sets while this returns current sets, which helps an agent decide whether to read first. No explicit exclusions or prerequisites beyond scope requirement.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_ping_instructionsGet ping instructionsARead-onlyIdempotentInspect
Requires the read scope or higher. Returns what a monitor needs in order to report: its ping URLs, copy-paste snippets (curl_success, curl_start, curl_fail, curl_step, run_example) and three reporting mechanisms, for wiring up a new monitor. reporting_options holds the rule for choosing between them: how_to is the manual protocol and works in any agent with no prerequisite (with expect_every_s, a lapse opens an incident); hook_install is a one-time install that automates the same protocol through hooks and alone sends every state, blocked and note included; it is returned only when tool is set (claude-code, codex or antigravity), otherwise hook_install_note says so; run_wrapper puts lastping run before a launched command (cron job, CI step, script) and reports start, success, fail and cancel. Also returned: failure_inbox_how_to, expectations_how_to (declare_run_expectations), tracing_how_to (OpenTelemetry, detailed by get_trace_setup), otel_env_lines, export lines whose key placeholder stands for the person's tracing key, and docs_url. An exporter that cannot set headers can POST to <ping_url>/v1/traces, which needs no Authorization header.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Monitor UUID (from create_monitor or list_monitors). | |
| tool | No | Which tool's install `hook_install` carries: claude-code, codex or antigravity. `hook_install` is returned only when this is set. Everything else in the result is the same. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, yet the description adds substantial behavioral context: the read-scope auth requirement, the conditional return of hook_install (only when `tool` is set, otherwise hook_install_note), the hook_install_note fallback, and the headerless /v1/traces POST endpoint. This is exactly the extra context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The auth requirement is front-loaded, but the body is a dense wall of nested parentheticals and semicolon clauses that is hard to parse in one pass. Most content is informative, but the packaging costs readability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must carry the return-value burden, and it does: it enumerates ping URLs, the snippet names, the three reporting mechanisms, and auxiliary fields (failure_inbox_how_to, expectations_how_to, tracing_how_to, otel_env_lines, docs_url). An agent can act on this without further context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and both params (including the `tool` enum) are documented in the schema itself, so the baseline is 3. The description largely restates the schema's conditional `tool` behavior ('hook_install is returned only when this is set') rather than adding new parameter meaning.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific resource: the reporting instructions a monitor needs (ping URLs, snippets, and three reporting mechanisms) and ties it to wiring up a new monitor. It is clearly distinct from read-side siblings like get_monitor or list_monitors, though it never explicitly contrasts itself with them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear context ('for wiring up a new monitor') and routes the agent onward by naming get_trace_setup for tracing detail and declare_run_expectations for expectations. It does not state when NOT to call it or name a competing alternative for basic monitor inspection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_runGet run detailsARead-onlyIdempotentInspect
Requires the read scope or higher. Gets one run's full timeline: every recorded event (start, step, log, success/fail/cancel, incident_opened) in time order, its declared assertions with pass/fail/not_evaluated verdicts against the terminal ping body, the terminal output excerpt, CI metadata when present, and its OTLP spans (spans[], parents before children, siblings by start time) when traced. A current Claude Code hook's run holds its turns' traces; a prompt after an interrupt or a blocked turn continues the open run. Also carries project, receiving_spans, in_hook_session, is_test, failure_cause and upstream_error (as in list_runs). For the detail behind a run (id + rid) found elsewhere. outcome: succeeded, failed, cancelled, blocked, running or unfinished (no end ping, no incident, not blocked, older than max_runtime_s or 24h; never pages). Caps: 200 events (events_truncated; the terminal event is kept), 2,000 spans (spans_truncated, spans_dropped). A span's gen_ai block (system, model, tokens, cost_usd) is present only on GenAI calls. untrusted_fields names the data fields LastPing did not write (job output, exporter data or user-supplied names).
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Monitor UUID. | |
| rid | Yes | The run id as sent on the ping. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only cover the safety profile (readOnly, idempotent, non-destructive), and the description adds substantial behavior beyond that: scope requirement ('read scope or higher'), hard caps of 200 events / 2,000 spans with corresponding *_truncated / spans_dropped flags, the six outcome values with the 'unfinished' definition and 'never pages' note, span ordering rules, and the presence-only-on-GenAI-calls condition for gen_ai. This is rich disclosure an agent cannot infer elsewhere.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the scope requirement and primary purpose before the detail. It is, however, a single very long run-on block where low-frequency details (untrusted_fields, span caps) are buried at the end, slightly hurting scannability, but nearly every clause carries factual weight.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the full return-value burden and does so thoroughly: event types, assertion verdicts, terminal output excerpt, CI metadata, OTLP spans, outcome enumeration, and the untrusted_fields caveat. Nothing an agent needs to interpret or call the tool correctly appears missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both parameters (id = Monitor UUID, rid = run id) are already documented in the input schema. The description adds only the indirect hint that id+rid are 'found elsewhere', not new per-parameter semantics, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Gets one run's full timeline' with an enumerated content list. It distinguishes itself from siblings by scoping to the single-run detail ('For the detail behind a run (id + rid) found elsewhere'), which separates it from list_runs. An agent can identify the tool without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The line 'For the detail behind a run (id + rid) found elsewhere' clearly implies the caller obtains id/rid from list_runs first, giving real usage context. However, it never explicitly excludes alternatives (get_run_history, get_trace_diagnostics) or states when-not-to-use, so it stops short of full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_run_historyGet run historyARead-onlyIdempotentInspect
Requires the read scope or higher. Gets a monitor's run history from pings, CI and agent runs alike (no filters; trace-only runs are in list_runs). Each run has rid, kind, received_at, steps (seq, name, at; matched on rid), title and incident_detail. CI runs add failing_stage, actor, commit_sha, run_url, branch, duration_s and outcome. A ping with neither ci_meta nor a rid is excluded. duration_ms is LastPing's own /start-to-success timing, separate from CI's duration_s. untrusted_fields names the data fields LastPing did not write (job output, exporter data or user-supplied names).
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Monitor UUID. | |
| limit | No | Max runs to return (default 20, max 100). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, and the description adds substantial behavior beyond them: the exclusion rule ('a ping with neither ci_meta nor a rid is excluded'), the distinction between duration_ms and CI's duration_s, and the meaning of untrusted_fields. This is well past the lowered bar annotations set.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense and front-loaded: the auth requirement and scope come first, then the returned shape. It is long, but nearly every clause carries non-obvious information (field lists, exclusions, duration semantics), so little is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of describing return values and does so thoroughly — base fields, CI-only fields, the exclusion rule, and untrusted_fields. An agent has what it needs to call and interpret this tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with only id and limit, both documented in the schema (monitor UUID; default 20, max 100). The description adds no syntax or format detail for either parameter, so the baseline 3 applies; its field-level detail describes returns, not inputs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb and resource ('Gets a monitor's run history') and immediately bounds the scope ('from pings, CI and agent runs alike'), explicitly excluding trace-only runs and pointing to list_runs. An agent can distinguish this from get_run and list_runs without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
States the prerequisite ('Requires the read scope or higher') and names the alternative for a related case ('trace-only runs are in list_runs'), plus the 'no filters' constraint. It stops short of a full when-to-use-this-vs-that rule for the common case, but the routing context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_trace_diagnosticsGet trace diagnosticsARead-onlyIdempotentInspect
Requires the read scope or higher. Why traces, metrics or logs sent to one monitor did or did not arrive: the newest 20 ingest attempts (kept 7 days), last_accepted_at, and the newest traced run's summary. For checking a test span, or telemetry sent with nothing showing. Each attempt: outcome (accepted; refused: something to fix; dropped: routine, answered 202), reason, span_count, bytes, protocol, user_agent, signal. Rejections: unsupported_media_type (not http/protobuf, e.g. gRPC to the HTTP URL), body_too_large (over 1 MB), too_many_spans or too_many_records (over 500 per batch), unknown_monitor (lastping.monitor_id missing or outside the project), expired_key (a new tracing key comes from the Connect page), wrong_scope (not a tracing key), wrong_project, monitor_mismatch, over_budget/over_log_budget (daily, resets 00:00 UTC), rate_limited, busy, malformed. Refused after a 202: future_start (sender clock), too_many_series. Dropped: unknown_event, unknown_metric, cumulative_temporality, invalid_point. No row: gRPC to the gRPC port, or a missing or wrong key. untrusted_fields names the data fields LastPing did not write (job output, exporter data or user-supplied names).
| Name | Required | Description | Default |
|---|---|---|---|
| monitor_id | Yes | Monitor UUID (from create_monitor or list_monitors). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover safety (readOnly, idempotent, non-destructive), but the description adds substantial non-obvious behavior: the required read scope, a 7-day / 20-attempt retention window, the full outcome taxonomy, per-code meanings, and what untrusted_fields signifies. This is exactly the kind of context the annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The scope requirement and the purpose statement are front-loaded before the detail, which is correct. The long fragmented enumeration of rejection/drop codes is dense but largely earns its place because there is no output schema and the agent needs to interpret the returned reason values.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description fully carries the burden of explaining returns: it lists each attempt's fields (outcome, reason, span_count, bytes, protocol, user_agent, signal) and enumerates the possible outcome/reason values. Nothing an agent needs to call or interpret this tool is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter (monitor_id) and the schema already documents it at 100% coverage, including its source (create_monitor or list_monitors). The description adds no additional meaning about the parameter, so the baseline 3 for schema-covered params applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (get trace diagnostics) and immediately defines scope: the newest 20 ingest attempts, last_accepted_at, and the newest traced run's summary. An agent can distinguish this from setup siblings like get_trace_setup or get_ping_instructions without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete trigger conditions: 'For checking a test span, or telemetry sent with nothing showing.' That tells the agent when this tool is the right pick, but it never names an alternative (e.g. setup instructions) or states when not to use it, so it stops short of the top band.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_trace_setupGet tracing setup stepsARead-onlyIdempotentInspect
Requires the read scope or higher. Returns the steps that make a tool send OpenTelemetry traces to one monitor: what to write and where, how to verify it, and the tool's limits. For setting up tracing, observability or telemetry. prompt is the full set-up procedure for the named tool, credential handling included. Each block has files, a key_line (the terminal line that stores the tracing key the person creates on the monitor's Connect page) and, for Claude Code and Codex, a reviewable bang_script run with bang_command.
| Name | Required | Description | Default |
|---|---|---|---|
| tool | No | Which tool sends the traces: claude-code, codex, gemini, antigravity, cursor, python, node, otel-sdk or collector. Omitted: every block. | |
| monitor_id | Yes | Monitor UUID (from create_monitor or list_monitors). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive/openWorld=false, so the safety profile is covered; the description adds real value beyond that by naming the required scope and disclosing credential handling (the tracing key the user creates on the Connect page). It stops short of describing failure modes or rate limits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the permission requirement, then purpose, then return shape; every sentence carries information and nothing is padded. It is a single dense paragraph, so scannability is slightly reduced but not wasteful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by spelling out the returned blocks and their fields (`files`, `key_line`, `bang_script`/`bang_command`), so an agent knows exactly what it will get. Combined with the stated prerequisite and tool-targeting behavior, nothing needed to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters are already documented (including the 'Omitted: every block' behavior for `tool`), which sets the baseline at 3. The description's detail about `prompt`, `key_line` and `bang_script` describes return fields rather than adding parameter semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb and resource: 'Returns the steps that make a tool send OpenTelemetry traces to one monitor,' then enumerates the content (what to write and where, how to verify, limits). This is clearly distinguishable from adjacent tools like get_ping_instructions or get_trace_diagnostics without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit usage context ('For setting up tracing, observability or telemetry') and a prerequisite ('Requires the read scope or higher'), which tells the agent when this tool applies. It does not name an alternative or state when-not to use it, so it falls short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_agentsList agentsARead-onlyIdempotentInspect
Requires the read scope or higher. Lists the project's agents: id, slug, name, status, monitor_count, last_seen. status is rolled up live from the agent's monitors, worst first: down, blocked (a run needs a human), late, running, up, pending (no report yet) or idle (no monitors, or all paused or in maintenance). usage_24h: model tokens and cost over 24 hours (null with no model call); top_dependencies: its five heaviest outgoing dependencies. untrusted_fields names the data fields LastPing did not write (job output, exporter data or user-supplied names).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnly/idempotent annotations: it explains that status is rolled up live from monitors, gives the full worst-first ordering and the meaning of each status value, notes that usage_24h is null with no model call, specifies top_dependencies is the five heaviest, and discloses untrusted_fields provenance. This is exactly the behavioral context an agent needs to interpret results.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the scope requirement and purpose, then spends its sentences on field semantics that the agent cannot get elsewhere. Reasonably sized and every sentence carries information, though the status enumeration is dense.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the return-shape burden and does so by enumerating fields including usage_24h, top_dependencies, and untrusted_fields. Minor gaps remain (e.g., format of monitor_count/last_seen), but it is largely complete for a zero-parameter list tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes no parameters, so the baseline is 4. The schema is empty and the description correctly focuses on output semantics rather than inventing parameter behavior.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Lists the project's agents') and enumerates the returned fields, so the purpose is unambiguous. It does not, however, distinguish itself from siblings like get_agent, get_agent_usage, or get_agent_dependencies, which cover overlapping data for a single agent.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The only usage signal is the prerequisite 'Requires the read scope or higher.' There is no statement of when to call this versus get_agent (single agent) or versus the dedicated usage/dependency tools, even though list_agents appears to inline usage_24h and top_dependencies. No exclusions or alternatives are given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_api_keysList API keysARead-onlyIdempotentInspect
Requires the admin scope or higher. Lists the project's API keys without plaintext values. Each has its non-secret prefix, scope (read, write or admin), created_by_key_id (the key that minted it, absent for a dashboard key; revoking a key revokes every key below it), last_used_at and last_used_surface (mcp, terraform or api; both absent when never used). last_used_surface comes from the caller-controlled User-Agent header: a hint, not proof of identity.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/destructive-free/idempotent, and the description adds substantive context beyond them: the admin-scope requirement, the guarantee that plaintext secrets are never returned, the cascade rule that revoking a key revokes every key minted below it, and the caveat that last_used_surface is derived from a caller-controlled User-Agent header and is 'a hint, not proof of identity'. That last point is exactly the kind of trust caveat an agent needs and cannot get from annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded and dense: the auth requirement and the no-plaintext guarantee come first. The long middle sentence carries heavy parentheticals (created_by_key_id, last_used_surface) that are informative but make the structure slightly harder to scan than a shorter enumeration would.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must document the return shape, and it does: prefix, scope enum values, created_by_key_id with its cascade semantics, last_used_at, and last_used_surface with its source and trust caveat. Combined with the auth prerequisite and secret-redaction guarantee, nothing material is left out.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With zero parameters and 100% schema coverage, the baseline is 4. The description does not need to explain inputs, and instead spends its space on return-field semantics, which is appropriate here.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Lists the project's API keys') and immediately narrows scope with 'without plaintext values', which cleanly separates it from create_api_key, revoke_api_key and regenerate_api_key among the siblings. An agent can identify the operation without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a concrete precondition ('Requires the admin scope or higher'), which tells the agent whether it is even eligible to call the tool. There is no explicit when-not-to-use or named alternative, but the list-only nature and the permission gate make the usage context clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_deliveriesList alert deliveriesARead-onlyIdempotentInspect
Requires the read scope or higher. Lists recent alert deliveries across the project's monitors: whether an alert fired, failed or was suppressed, and to which destination. Each row is one (incident event, destination) outcome: pending (attempt in flight), delivered, dead (per-channel attempt ceiling reached) or suppressed (the destination's rate cap dropped it). Covers 30 days and returns only the newest page; the dashboard's delivery log has the archive. untrusted_fields names the data fields LastPing did not write (job output, exporter data or user-supplied names).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max deliveries to return (default 20, max 100). | |
| status | No | Restrict to one delivery status: pending, delivered, dead, or suppressed. | |
| monitor | No | Restrict to one monitor's deliveries (UUID). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, non-destructive behavior, and the description adds genuinely new context beyond them: the meaning of each status value (pending/delivered/dead/suppressed), the 30-day retention window, newest-page-only pagination, and an explanation of `untrusted_fields` as data LastPing did not write. This is exactly the behavioral detail the annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the scope requirement, then the resource, then status semantics, then coverage limits. Dense and largely waste-free, though the parenthetical status glosses and the untrusted_fields sentence make it longer than strictly necessary.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description still conveys the row shape (incident event + destination), the possible outcome values, and the retention/pagination envelope, and it flags the untrusted_fields caveat. Nothing an agent needs to call and interpret this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the prose enriches the semantics of the `status` filter by defining what dead ('per-channel attempt ceiling reached') and suppressed ('destination's rate cap dropped it') actually mean, and explains the row grain the limit/status/monitor filters operate over.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb+resource ('Lists recent alert deliveries across the project's monitors') with the row grain made explicit — one (incident event, destination) outcome. This is clearly distinguishable from siblings like list_incidents, list_monitors, or list_destinations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
States an access prerequisite ('Requires the read scope or higher') and scopes usage in time and pagination ('Covers 30 days and returns only the newest page'), pointing to the dashboard's delivery log for the archive. It doesn't explicitly contrast with sibling list tools (e.g. list_incidents), so it stops short of full when/when-not routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_dependenciesList project dependenciesARead-onlyIdempotentInspect
Requires the read scope or higher. Everything the project's agents call, across every agent, most calls first: each dependency with the same figures as get_agent_dependencies plus agents (which agents call it, and how often). Answers questions such as which agents call postgres or use a model. At most 50 rows; more counts the rest. untrusted_fields names the data fields LastPing did not write (job output, exporter data or user-supplied names).
| Name | Required | Description | Default |
|---|---|---|---|
| kind | No | Only one kind of dependency: model, tool, http, database, queue, rpc or agent. Omitted: all. | |
| range | No | Time window: 24h, 7d (the default) or 30d. It covers every UTC day that overlaps it, so 24h spans two days. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial context beyond the annotations: the required auth scope (read or higher), a hard row cap of 50 with a `more` overflow count, and the meaning of `untrusted_fields` (data fields LastPing did not write). Annotations cover the safety profile, and the description layers on the operational constraints that matter for calling it correctly.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but front-loaded: the ordering, scope, and auth requirement come first, followed by pagination and untrusted-field notes. Each sentence carries information, though the passage is longer than strictly necessary for a two-parameter read tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the return-shape burden and does so: per-dependency figures, the nested agents breakdown with call counts, the 50-row cap, and untrusted field notice. Nothing an agent needs to interpret results is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and both enums are already documented (kind omitted = all, range default 7d with the UTC-day overlap note). The description does not add format or semantics beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (dependencies the project's agents call) and an explicit scope distinction from the sibling get_agent_dependencies ('same figures as get_agent_dependencies plus agents'). An agent can tell it apart from the per-agent variant without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete usage contexts ('which agents call postgres or use a model') and implicitly routes per-agent needs to get_agent_dependencies by contrasting the two. It stops short of an explicit when-not-to-use-this statement, so it lands just below the top band.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_destinationsList alert destinationsARead-onlyIdempotentInspect
Requires the read scope or higher. Lists the project's notification destinations (channels) of every kind (webhook, telegram, discord, slack, ntfy, pushover, msteams, googlechat, email). Their ids are what set_route takes.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds non-redundant context: the required read scope (an auth constraint not exposed in annotations) and the exhaustive set of destination kinds returned, so the agent knows nothing is filtered out.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, each earning its place: scope prerequisite, what is listed (with kinds), and how the result is consumed. The permission constraint is front-loaded and nothing is padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter, read-only list tool with no output schema, the description covers purpose, permission, scope, and downstream use adequately. Only minor gaps remain, such as whether results are paginated or what fields each destination carries, which the absence of an output schema leaves slightly open.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is no parameter semantics to explain and the baseline is 4. The description correctly implies an unfiltered full listing rather than misrepresenting an absent filtering capability.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Lists the project's notification destinations (channels)') and enumerates all covered kinds (webhook, telegram, discord, slack, ntfy, pushover, msteams, googlechat, email). This clearly separates it from the sibling mutators create_destination, update_destination, delete_destination, and test_destination.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clearly signals the access prerequisite ('Requires the read scope or higher') and states the downstream purpose ('Their ids are what set_route takes'), which is genuine when-to-use context linking it to set_route. It stops short of naming explicit alternatives or exclusions, but an agent knows exactly why and when to call it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_discovered_agentsList discovered trace sourcesARead-onlyIdempotentInspect
Requires the read scope or higher. Trace sources that sent spans but match no registered agent: id, source_name (the OpenTelemetry service.name), first and last seen, span_count, and suggested_agent_id when a registered agent's slug or name now matches. For traces that arrive while no agent shows them; adopt_discovered_agent counts a source under an agent. At most 200, most recently seen first. untrusted_fields names the data fields LastPing did not write (job output, exporter data or user-supplied names).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnly, idempotent, non-destructive), and the description adds genuinely useful behavior beyond them: the required read scope, a hard cap of 200 results, the most-recently-seen ordering, and an explanation of what untrusted_fields means (fields LastPing did not write). That is real context an agent cannot get from the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the auth requirement and then the resource definition, and every clause carries information. Slightly penalized for the broken fragment about 'traces that arrive while no agent shows them', which adds words without adding clarity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter, no-output-schema tool, the description does the heavy lifting: it defines the resource, the returned fields, the cap, the ordering, and the untrusted-field caveat. Only the muddled usage sentence and the absence of any pagination/continuation guidance keep it from a 5.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With zero parameters declared, the baseline is 4. The description compensates by documenting the shape and semantics of the response payload, including the meaning of suggested_agent_id and untrusted_fields, which is more than the empty schema supplies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb+resource and narrows scope precisely: 'Trace sources that sent spans but match no registered agent', which cleanly distinguishes this tool from list_agents and the rest of the sibling list. It even enumerates the returned fields (id, source_name, first/last seen, span_count, suggested_agent_id), so an agent knows exactly what it gets.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It references the alternative ('adopt_discovered_agent counts a source under an agent') and gestures at the operational context, but the pivotal sentence — 'For traces that arrive while no agent shows them' — is a fragment that never states a clean when-to-use condition versus list_agents. Usage is implied rather than spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_incidentsList monitor incidentsARead-onlyIdempotentInspect
Requires the read scope or higher. Lists a monitor's recent incidents, newest first; an open incident has closed_at=null. untrusted_fields names the data fields LastPing did not write (job output, exporter data or user-supplied names).
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Monitor UUID. | |
| limit | No | Max incidents to return (default 50, max 200). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive), so the description's added value is the auth scope requirement, the ordering guarantee, and the closed_at=null open-incident convention. It also explains what untrusted_fields means, which is genuine behavioral context beyond the annotations, though pagination/truncation behavior with limit is not discussed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Compact and front-loaded with the access prerequisite, then the core behavior, then the untrusted_fields note. Every clause carries information, though the last clause is somewhat densely packed and mixes a return-field concept into a description that leads with invocation requirements.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully compensates by explaining the closed_at=null convention and the meaning of untrusted_fields in the returned data, and it states the auth requirement. What is missing is any note on ordering/pagination interaction with limit or how many incidents constitute a page.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both id and limit are already fully documented with defaults and max. The description adds nothing about parameter syntax or interaction (e.g. behavior at the 200 cap), so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Lists a monitor's recent incidents') with useful scope detail: newest-first ordering and the closed_at=null convention for open incidents. It does not name or contrast the obvious sibling list_open_incidents, so an agent must infer the boundary itself, which keeps it out of the top band.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives one concrete prerequisite ('Requires the read scope or higher'), which is real usage guidance. However it never says when to choose this over list_open_incidents or get_incident, and gives no exclusions, so the routing decision is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_monitorsList monitorsARead-onlyIdempotentInspect
Requires the read scope or higher. Lists every monitor in the project with id, name, slug, status and ping_url. tag narrows the list to monitors carrying one tag.
| Name | Required | Description | Default |
|---|---|---|---|
| tag | No | Optional tag to filter by, e.g. 'agent:claude'. Only monitors with this tag are returned. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint=false, so the safety profile is covered. The description adds value beyond that with the auth scope requirement and the concrete return fields, but says nothing about result limits, ordering, or pagination for a tool that returns 'every monitor'.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences with no filler, and the access prerequisite is front-loaded before the behavior and the filter. Every sentence carries distinct information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully compensates by enumerating the returned fields, and the auth requirement is stated. The only gap is the absence of pagination, result-size, or ordering details for a list-everything tool, which is minor for a project-scoped listing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the sole parameter 'tag' is fully documented in the schema. The description's note that 'tag narrows the list to monitors carrying one tag' largely restates the schema rather than adding syntax, matching behavior for multiple tags, or error conditions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Lists every monitor in the project') and enumerates the fields returned (id, name, slug, status, ping_url), which makes the bulk-listing behavior unmistakable. It never names a sibling, so the contrast with get_monitor for a single monitor is left implicit rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description supplies a real prerequisite ('Requires the read scope or higher') but no explicit when-to-use guidance or when-not-to-use exclusions relative to siblings like get_monitor or list_discovered_agents. Usage is only implied by the word 'Lists every monitor in the project'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_open_incidentsList open incidentsARead-onlyIdempotentInspect
Requires the read scope or higher. Returns an agent's failure inbox: every open incident on the monitors it owns, newest first, with context no single failure body carries. For learning, at a run's start, what broke meanwhile. failure_signature.occurrences: how often this exact failure has been seen (first_seen, last_seen, fingerprint), which separates retry from escalate. failed_step: the last step reported (for 'stalled', where the live run is stuck). exit_code: 137 (usually OOM) and 1 differ. duration_vs_normal: e.g. '8.2x the typical run (41m vs 5m), from 30 archived days', plus run_ms, typical_ms, ratio, days_sampled (0: the norm is the median of 5+ recent runs). cause: 'fail' (the job reported an error), 'silence' (it never reported; usually the scheduler or host) or 'upstream' (consecutive model-provider API errors; detail names the last). Also body_excerpt, run_id, ci.run_url. A missing field is no evidence, not none, normal or a clean exit; exit_code 0 marks a success that failed its expectations. add_incident_note takes an entry's incident_id. untrusted_fields names the data fields LastPing did not write (job output, exporter data or user-supplied names).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max incidents to return (default 50, max 200). Newest first, so a small limit drops the oldest open incidents, not the newest. | |
| agent_id | Yes | Agent UUID (from register_agent or list_agents). The inbox covers every monitor this agent owns. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the read-only/idempotent profile, and the description still adds the auth requirement ('Requires the read scope or higher'), the field-level semantics of the return payload, and an important caveat that a missing field is 'no evidence, not none, normal or a clean exit.' It also flags `untrusted_fields` as data LastPing did not write -- meaningful context not present in structured data.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and auth are front-loaded, but the body collapses into a dense run-on field reference spanning failure_signature, exit_code, duration_vs_normal, cause and untrusted_fields with little structural separation. Length is partly justified by the absent output schema, but readability suffers.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and only two params, the description carries the return-value burden thoroughly: ordering, per-field meaning, numeric codes (137 vs 1), sample sizes, and cause categories are all explained. An agent has enough to interpret results correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with both parameters fully documented, including defaults and max. The description only echoes this ('an agent's failure inbox', 'newest first') without adding format or syntax beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a concrete verb+resource and precise scope: 'Returns an agent's failure inbox: every open incident on the monitors it owns, newest first.' The 'open' qualifier implicitly separates it from list_incidents, though no sibling is named explicitly, keeping it short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'For learning, at a run's start, what broke meanwhile' gives a clear usage context and timing. It stops short of naming alternatives (list_incidents, get_incident) or stating when not to use it, so no exclusions are provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_runsList runsARead-onlyIdempotentInspect
Requires the read scope or higher. Lists runs across every monitor in the project, newest started first, including runs that exist only as OpenTelemetry traces (traced: true). Each run carries check_id, check_name, rid, title, outcome, started_at, ended_at, duration_ms, step_count, exit_code, its incident, and when traced span_count, tokens, cost_usd and cost_source (client, estimated or mixed); plus agent_id, agent_name, source_name, multi_trace, project (the Claude Code session's folder), receiving_spans (spans in the last 2 minutes), in_hook_session, is_test (excluded from counts). failure_cause is 'upstream' when the run ended on the model provider's API error (pages after 3 in a row, or failure_threshold when higher; upstream_error names it) or 'assertion' when a success failed an output assertion or declared expectation. outcome: succeeded, failed, cancelled, blocked, running or unfinished (started, never ended within max_runtime_s or 24h; never pages). Filters combine and also narrow counts (per-outcome totals). Pages with next_cursor. untrusted_fields names the data fields LastPing did not write (job output, exporter data or user-supplied names).
| Name | Required | Description | Default |
|---|---|---|---|
| q | No | Only runs whose run id (rid) contains this text. | |
| agent | No | Only runs of this agent (agent UUID or slug). | |
| limit | No | Runs per page (default 20, max 100). | |
| model | No | Only runs that called this model, by exact model id. | |
| since | No | RFC 3339 start of the window, e.g. 2026-09-01T00:00:00Z. Default 7 days ago; at most 90 days back. | |
| until | No | RFC 3339 end of the window. Default now. | |
| cursor | No | next_cursor from the previous page, verbatim. | |
| traced | No | true: only runs that hold spans. Omitted or false: every run. | |
| monitor | No | Only this monitor's runs (monitor UUID). | |
| outcome | No | Only runs with this outcome. | |
| project | No | Only runs whose Claude Code hook start carried this project label: the name of the folder the session worked in. | |
| trace_id | No | Only the run a trace became: 8 to 32 hex digits of its trace id. Finds runs made from a trace with no run id, not runs that named their own. | |
| has_error | No | true: only runs with a span that reported an error. false: only runs without one. | |
| operation | No | Only runs with a span whose name starts with this text. | |
| dependency | No | Only runs that called this dependency, by its exact name as get_agent_dependencies reports it (e.g. api.github.com). | |
| min_cost_usd | No | Only runs whose cost is at least this many US dollars, as a decimal string, e.g. "0.25". | |
| min_duration_ms | No | Only runs that took at least this many milliseconds. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive, and closed-world. Beyond that, the description discloses auth scope, default ordering, inclusion of trace-only runs, pagination, per-outcome count narrowing, and detailed failure_cause/untrusted_fields semantics—substantial behavior not covered by annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense but front-loads the verb and scope, and nearly every clause carries necessary return-field or filtering information absent from any output schema. It is long and could be sectioned better, but there is little filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 17-parameter, zero-required list tool with no output schema, the description covers purpose, auth, return fields, outcome/failure semantics, filtering, and pagination. An agent has enough to call and interpret the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaningful semantics for the outcome enum (defining 'unfinished' and its pagination behavior) and notes how filters combine to narrow per-outcome counts. It does not add per-parameter syntax beyond that.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Lists) and resource (runs) plus scope (across every monitor in the project), ordering (newest started first), and an inclusion rule (traced-only runs). This clearly separates it from single-run siblings like get_run.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives a prerequisite ('Requires the read scope or higher') and filter/pagination mechanics, implying usage, but never states when to choose this over get_run, get_run_history, or other list tools. No exclusions or explicit alternative routing are provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_status_pagesList status pagesARead-onlyIdempotentInspect
Requires the read scope or higher. Lists the project's status pages: id, slug, title, the monitors on each, visibility, and the public URL of any public page. A status page shows a monitor's health to people outside the project, such as customers or another team. update_status_page's check_ids replaces a page's monitor set, and this result holds the current set.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), so the description only needs to add context — and it does, disclosing the required auth scope and the fact that the returned monitor set reflects the current state that update_status_page would replace. It omits pagination or rate-limit behavior, keeping it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The scope prerequisite is front-loaded and the field list is dense and useful. The explanatory sentence defining what a status page is borders on filler, but it supports disambiguation and the whole entry stays short.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and zero parameters, the description carries the burden of describing the return payload — and it does so field by field, plus the auth requirement and cross-tool relationship. Nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes no parameters, so the baseline of 4 applies; there is no parameter meaning for the description to add or omit.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with the exact verb+resource ('Lists the project's status pages') and then enumerates the returned fields (id, slug, title, monitors, visibility, public URL), so the agent knows precisely what it gets back. It also differentiates itself from update_status_page by contrasting this read result with that tool's mutation of the monitor set.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
States the prerequisite ('Requires the read scope or higher') and clarifies the tool's role relative to update_status_page. It does not give an explicit when-not-to-use case or name an alternative lister, but there is no competing status-page list tool among the siblings, so the guidance is adequate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pause_monitorPause monitorAIdempotentInspect
Requires the write scope or higher. Pauses a monitor (paused=true): it still receives pings but raises no alert.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Monitor UUID. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover safety (readOnlyHint=false, idempotentHint=true, destructiveHint=false), and the description adds genuinely new operational context: the required write scope, and the non-obvious behavior that pings continue to arrive while alerting stops. That effect (reversible, non-destructive silencing) is not derivable from the annotations alone.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with no filler. The permission prerequisite is front-loaded, followed by the effect, which is the order an agent needs to evaluate before calling.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-id idempotent mutation with an existing safety annotation set and no output schema, the description supplies the auth prerequisite and the operational consequence of pausing. Only the relationship to sibling state-changing operations (resume/snooze) is absent, which is a minor gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single parameter (id) with 100% schema description coverage, so the schema already documents it as the monitor UUID. The description adds no parameter-level detail beyond that, which is the expected baseline for a fully covered single-param tool.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Pauses a monitor") and clarifies the resulting state with "paused=true". It is clearly distinguishable from delete_monitor or update_monitor, but it never names the closely related siblings resume_monitor or snooze_monitor, so the boundaries between those operations are left implicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: an agent can infer you pause when you want alerts silenced. There is no explicit when-to-use guidance and no differentiation from snooze_monitor, which is the natural alternative an agent would want compared against pause_monitor.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
regenerate_api_keyRegenerate API keyADestructiveInspect
Requires the admin scope or higher. Replaces an API key's secret: a new key, with a new id and the same name, scope and (for a tracing key) monitor. The old key stops working immediately wherever it is held, including when it is the calling key. No expiry stays no expiry; an expiring key gets a fresh 90 days, capped at the calling key's expiry. Keys the old key created keep working (no cascade). Refused (403, with max_scope) for a key scoped above the caller's. The plaintext key appears only in this result.
| Name | Required | Description | Default |
|---|---|---|---|
| api_key_id | Yes | UUID of the key to regenerate, from list_api_keys. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructive/non-idempotent, and the description goes well beyond them: the old key dies immediately (even the calling key), expiry semantics are spelled out (no-expiry stays, expiring gets a fresh 90 days capped at the caller's expiry), no cascade to child keys, and the auth failure mode with the max_scope error. Full behavioral disclosure for a destructive mutation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but every clause carries distinct operational information with no filler. Mild penalty for front-loading the auth prerequisite ahead of the action statement, which delays the core purpose by one sentence.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-param destructive mutation with no output schema, the description covers prerequisites, side effects, expiry rules, cascade behavior, error handling, and the fact that the plaintext key is returned only here. Nothing an agent needs to call this safely is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter and schema coverage is 100%, so the schema already explains api_key_id as a UUID sourced from list_api_keys. The description adds no additional meaning about the parameter, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (replaces/regenerates) on a specific resource (an API key's secret) and spells out the resulting object identity: a new key with a new id but the same name, scope and monitor. An agent can distinguish this from create_api_key (new key) and revoke_api_key (removal) purely from the text.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a hard prerequisite ('Requires the admin scope or higher') and an explicit when-not case ('Refused (403, with max_scope) for a key scoped above the caller's'). It never names sibling tools like create_api_key or revoke_api_key as alternatives, so routing is inferred rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
register_agentRegister agentAInspect
Requires the write scope or higher. Registers an autonomous agent in the project's agent registry and returns its id, slug and wire-up steps. One agent stands for one autonomous worker, which can own many monitors: create_monitor and update_monitor attach a monitor through agent_id (the id or the slug). An agent_id that does not exist is an error (400 UNKNOWN_AGENT), never an implicit create. The slug is derived from the name, so registering the same name again is refused (409) rather than creating a second agent.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Human-readable agent name, e.g. 'Deploy Bot'. Used to derive the agent's slug. | |
| description | No | Optional free-text description of what this agent does. Omitted: none. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this is a non-read-only, non-destructive, non-idempotent, closed-world write; the description goes well beyond them with the auth scope requirement, the idempotency-adjacent uniqueness rule (same derived slug → 409), concrete error codes (400 UNKNOWN_AGENT, 409), and the shape of the response (id, slug, wire-up steps) despite there being no output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four tight sentences with the scope requirement front-loaded, then purpose, then conceptual model and monitor relationship, then uniqueness/error behavior. No sentence is redundant and each adds a fact an agent needs to call this correctly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Complete for a two-parameter, no-output-schema write tool: auth, return payload, relationship to monitor tools, failure modes, and duplicate-name behavior are all covered, leaving nothing material for the agent to infer.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning beyond the schema: it explains the consequence of slug derivation (duplicate names are refused rather than creating a second agent) and how the returned id/slug are consumed downstream by agent_id. It still doesn't elaborate on the optional description field, which the schema already covers.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Registers an autonomous agent in the project's agent registry') and even names the created artifact and return values (id, slug, wire-up steps). It distinguishes itself from siblings by explaining that this is not an implicit create path (agent_id pointing at a missing agent is a 400, not a create), separating it from create_monitor/update_monitor which only attach monitors to an existing agent.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit prerequisite ('Requires the write scope or higher') and clear when-to-use context: call this to create the agent, then use create_monitor/update_monitor to attach monitors via agent_id. It also states when NOT to expect creation (unknown agent_id is never an implicit create) and that re-registering an existing name is refused with 409.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resume_monitorResume monitorAIdempotentInspect
Requires the write scope or higher. Resumes a paused monitor (paused=false); alerting resumes from the next missed ping.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Monitor UUID. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds real context beyond the annotations: a required authorization scope ('write scope or higher') and the alerting behavior ('alerting resumes from the next missed ping'), which tells the agent about downstream effects. The annotations already cover idempotency and non-destructiveness, so this is a solid supplement rather than a full behavioral spec (no error behavior if already active).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with no filler, and the authorization requirement is front-loaded. The '(paused=false)' parenthetical is slightly redundant but compact and clarifies the state transition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter toggle with no output schema, the description covers the authorization prerequisite, the state change, and the alerting side effect. It is nearly complete, missing only failure/already-active behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for the single 'id' parameter, so the schema already documents the monitor UUID. The description adds no parameter-specific syntax or format detail, so the baseline 3 applies; 'paused=false' describes the resource effect, not the parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (resumes) and a specific resource (a paused monitor), plus the resulting state (paused=false). This is unambiguously the inverse of the pause_monitor sibling, so an agent can select it without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'Resumes a paused monitor' implies the precondition (the monitor must be paused), which is useful implied usage guidance. However, it never names pause_monitor as the counterpart or states what to do if the monitor is not paused, leaving routing inference to the agent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
revoke_api_keyRevoke API keyADestructiveIdempotentInspect
Requires the admin scope or higher. Permanently revokes an API key and every key it created, recursively; all of them stop authenticating immediately. This cannot be undone; list_api_keys' created_by_key_id shows which keys a revoke reaches.
| Name | Required | Description | Default |
|---|---|---|---|
| api_key_id | Yes | UUID of the key to revoke, from list_api_keys. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and idempotentHint=true, and the description adds materially more: the recursive reach into child keys, that all of them stop authenticating immediately, the irreversibility, and the required privilege level. That is the kind of consequence disclosure a destructive tool needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense clauses with zero filler, ordered by what the agent must know first (permission), then effect (recursive, immediate), then consequence (irreversible). Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter destructive tool with no output schema and full safety annotations, the description covers authorization, blast radius, timing of effect, and irreversibility — everything needed to call it safely. Nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single parameter is fully documented in the schema, including its source (list_api_keys). The description adds no syntax or format detail about api_key_id, so baseline 3 applies; the cascade information is about tool scope, not the parameter itself.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (revokes) and resource (API key) plus the recursive scope, which clearly separates it from regenerate_api_key, delete_agent and other mutation siblings. An agent can identify this as the destructive key-removal tool without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the precondition up front ('Requires the admin scope or higher') and points at list_api_keys as the place the id comes from, plus created_by_key_id to preview the cascade. It stops short of explicit when-not-to-use vs regenerate_api_key, but the context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_alert_templateSet alert templateADestructiveIdempotentInspect
Requires the write scope or higher. Sets or clears one alert message template on a monitor; every other template is kept (read-modify-write). The template is validated for allowed variables before saving, and an empty template resets that entry to the built-in default. Event types: 'down', 'recovery', 'fail', 'every-run', 'success', 'started', 'blocked', 'note'. The template argument lists the variables.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Monitor UUID. | |
| cause | No | Optional cause for a per-cause override (e.g. 'silence', 'overrun', 'never_started', 'stalled', 'runaway', 'upstream'). Omitted or empty: an event-type-wide template. | |
| template | Yes | Template text with {variable} placeholders; an empty string resets to the built-in default. Variables: {check_name}, {event}, {status}, {cause}, {last_ping}, {schedule}, {incident_url}, {run_url}, {branch}, {commit}, {actor}, {failing_stage}, {duration}, {latency}, {status_code}, {url}, {last_step}, {step_count}, {run_duration}, {body}, {detail}, {title}. {failing_stage}: CI only; GitLab, GitHub when the webhook subscribes to workflow_job, not Jenkins. {body} is the triggering ping's text, which carries a 'blocked' or 'note' reason. {title} is the run's title (its /start body or /title), filled for 'fail', 'stalled' and 'overrun' when the run is identified; else empty. | |
| event_type | Yes | Event type: 'down', 'recovery', 'fail', 'every-run', 'success', 'started', 'blocked', 'note'. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing the write-scope auth requirement, the read-modify-write semantics ('every other template is kept'), pre-save validation of allowed variables, and the reset-to-default behavior on empty input. It also usefully clarifies that the destructiveHint applies only to the single targeted entry, not the whole template set.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Auth requirement and behavior are front-loaded, followed by validation, reset semantics, and event types. The trailing 'The template argument lists the variables' sentence is largely redundant with the schema's parameter descriptions and is the one line that does not fully earn its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no output schema, the description covers everything an agent needs: auth scope, idempotency implications, partial-write behavior, validation failure mode, default-reset behavior, and the enumerated event types. Nothing essential to correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents every parameter including the variable list and cause overrides. The description's 'The template argument lists the variables' merely points back at the schema rather than adding format or syntax detail, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Sets or clears one alert message template on a monitor') and scopes it to a single entry. It is clearly distinguishable from the sibling get_alert_templates reader without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explains when behavior applies: empty string resets to built-in default, cause omitted means event-type-wide, and the write-scope prerequisite is stated. It does not explicitly name get_alert_templates as the read counterpart or state when not to use this tool, so it stops short of routing-level guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_routeSet alert routeADestructiveIdempotentInspect
Requires the write scope or higher. Routes a monitor's alerts for one event type to a set of destinations (channels). Replaces the whole destination set for that event type: destinations not listed stop receiving it, including ones someone else configured. get_monitor's routes field holds the current set, so adding a destination means sending the existing ids plus the new one. An empty channel_ids removes all routing for the event. Destinations have to be verified and enabled (an email one confirmed). list_destinations returns the ids.
| Name | Required | Description | Default |
|---|---|---|---|
| event_type | Yes | down (incident opened), recovery (incident cleared), fail (failure ping), every-run (each completed run), success, started (GitHub's requested and in_progress each send one, so one CI run can notify twice), blocked (an agent awaits a human: held 10 minutes, cancelled by a ping or step of the same run in that time; sent once per blocked stretch; not the 'blocked' incident of blocked_timeout_s), note (an annotation). down, recovery and fail fire only on a state change. every-run, success, started and note share a separate per-channel rate cap (60/hour default) and are not flap-damped, so one chatty route can suppress the group; blocked draws on the protected down/fail/recovery budget. | |
| monitor_id | Yes | Monitor (check) UUID. | |
| channel_ids | No | Comma-separated destination (channel) UUIDs to notify. An empty string clears the route. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (destructiveHint=true, idempotentHint=true), the description discloses the exact destructive semantics: the whole destination set is replaced, unlisted destinations stop receiving, including ones configured by others, and an empty string clears all routing. It also states auth (write scope) and precondition (destinations must be verified and enabled) details the annotations do not carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The prerequisite is front-loaded, followed by purpose, destructive semantics, and practical guidance. Sentences are dense but each earns its place — nothing is redundant with the schema or annotations.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive replace operation with no output schema, the description covers prerequisites, replacement behavior, empty-value behavior, destination verification requirements, and pointers to related tools. An agent has everything needed to invoke it correctly and safely.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so the baseline is 3, but the description adds real meaning: channel_ids is a wholesale replacement set rather than an additive list, and an empty value removes routing. This clarifies the mental model of the parameter beyond the schema's plain wording.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: it 'Routes a monitor's alerts for one event type to a set of destinations (channels).' This is a distinct, unambiguous purpose that any agent can distinguish from siblings like delete_route or list_destinations without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear operational context: the write scope requirement, that adding a destination means sending existing ids plus the new one, and that an empty channel_ids removes all routing. It also points to get_monitor and list_destinations for supporting data. It stops short of explicitly naming when to prefer this over delete_route for clearing a route, so it is strong but not fully exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
snooze_monitorSet or clear maintenance windowAIdempotentInspect
Requires the write scope or higher. Sets or clears a maintenance window on a monitor. During it, deadline incidents (a missed or never-started run, an overrun, a stall, a blocked run outliving blocked_timeout_s) and, on an HTTP monitor, failing probes (any fail there counts as a probe's) are recorded but open no incident; a site still failing afterwards opens one on its next failure. Still notified: the job's own fail ping, the page a blocked ping queues, a runaway ping rate, and routed note, started, success and every-run events. Takes exactly one of duration, until or clear=true.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Monitor UUID. | |
| clear | No | true removes the active maintenance window. | |
| until | No | RFC 3339 end timestamp. One of duration, until or clear. | |
| duration | No | Go duration string, e.g. '1h' or '24h'. One of duration, until or clear. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by spelling out what is suppressed (deadline incidents, HTTP failing probes), the exact exception semantics ('a site still failing afterwards opens one on its next failure'), and what is explicitly still notified (fail pings, queued blocked pages, runaway ping rate, routed note/started/success/every-run events). That is the behavioral detail an agent needs to predict side effects before mutating state.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the auth requirement and the core action, and every sentence carries non-redundant content. The second sentence is a dense run-on with nested parentheticals (the blocked_timeout_s aside, the probe-counting clause), which costs readability but not correctness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no output schema, the description is complete: authorization requirement, valid parameter combinations, suppression scope, notification carve-outs, and post-window failure behavior are all present. Nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and each parameter is already documented with its format (RFC 3339, Go duration string), so the schema carries the burden. The description only reinforces the mutual-exclusivity rule with 'exactly one', adding marginal semantics over the per-parameter 'One of duration, until or clear' notes.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('sets or clears') and resource ('a maintenance window on a monitor'), so an agent knows exactly what state it manipulates. It does not, however, distinguish itself from the closely related pause_monitor/resume_monitor siblings, which an agent could plausibly confuse with a suppression mechanism.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives real preconditions ('Requires the write scope or higher') and a hard selection rule ('Takes exactly one of duration, until or clear=true'), which tells the agent how to shape the call. It stops short of saying when to prefer this over pause_monitor or resume_monitor, so alternative selection is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
test_destinationTest alert destinationAInspect
Requires the write scope or higher. Sends something through a destination now. By default it delivers a synthetic 'LastPing test alert', which confirms a new destination's credentials. With resend_verification=true it instead re-sends an unverified email destination's confirmation link, for when the first one never arrived or expired; an unverified email cannot join a route, and a test alert does not change that.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Destination (channel) UUID, from list_destinations or create_destination. | |
| resend_verification | No | true re-sends the email confirmation link in place of a test alert. Email destinations only (any other kind returns 400). Idempotent: an already-verified destination reports verified and nothing is sent. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (destructive=false, openWorld=true), and the description adds value beyond them: the required write scope, what actually gets delivered ('LastPing test alert'), and the important side-effect clarification that a test alert does not verify an unverified email or let it join a route.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the permission requirement, then the default behavior, then the alternate mode. No filler; each clause carries invocation-relevant information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter action tool with no output schema, the description covers auth, payload semantics, both modes, and the key side-effect caveat. It stops short of describing the response an agent should expect, but that is a minor gap given the thorough coverage elsewhere.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: it explains the default send behavior versus the resend_verification=true path and why you would choose the latter. It complements rather than repeats the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Sends something through a destination now') and immediately qualifies it as a synthetic test alert rather than a real notification. This clearly separates it from create_destination, update_destination, and delete_destination without naming them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use for both modes: the default for confirming a new destination's credentials, and resend_verification=true for when a confirmation link never arrived or expired. It does not name alternative tools or state exclusions, but the context for invoking it is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_agentUpdate agentADestructiveIdempotentInspect
Requires the write scope or higher. Updates an agent's name, description or slug by UUID with merge-patch semantics: supplied fields change, omitted ones keep their value. Renaming never changes the slug. A new slug has to be unique in the project; saved links, Terraform references and trace sources (service.name) naming the old slug then stop matching the agent unless they equal its name (case-insensitive), past traced runs included, and a slug equal to a source another agent receives takes that source's traces, past runs included. Attached monitors stay attached.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Agent UUID (from register_agent or list_agents). | |
| name | Yes | Human-readable agent name, e.g. 'Deploy Bot'. | |
| slug | No | New slug for the agent, e.g. 'reddit-bot': 3-50 characters, lowercase letters, digits and hyphens. Omitted: unchanged. After a change, references to the old slug (links, Terraform, trace sources and their past runs) stop matching this agent unless they equal its name (case-insensitive). | |
| description | No | Free-text description of what this agent does. Omitted: unchanged. An explicit empty string clears it. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (destructiveHint, idempotentHint, openWorldHint), and the description adds substantial context beyond them: merge-patch semantics, that renaming never changes the slug, slug uniqueness constraints, the downstream impact on links/Terraform/trace sources and past runs, and that monitors stay attached. These are exactly the side effects an agent needs before invoking a destructive mutation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the permission requirement and the action, and every clause carries information. The final slug-consequence sentence is dense and long, but none of its content is redundant with the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, idempotent mutation with no output schema, the description covers auth scope, update semantics, uniqueness constraints and all downstream side effects. Nothing an agent needs to call it safely is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning beyond the schema by explaining merge-patch behavior (supplied fields change, omitted ones keep their value) and the cross-parameter consequence of changing slug on the name field's matching semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Updates), resource (an agent), identified by UUID, and enumerates the mutable fields (name, description, slug). An agent can distinguish it from register_agent, get_agent and delete_agent without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear prerequisite ('Requires the write scope or higher') and describes update semantics, so the agent knows the context in which it applies. It does not, however, explicitly name an alternative tool or a when-not-to-use condition.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_destinationUpdate alert destinationADestructiveIdempotentInspect
Requires the write scope or higher. Updates a notification destination's name and/or config in place; only the supplied fields change. The kind cannot change (delete and recreate instead). A new email address resets verification and sends a new confirmation email.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | New human-readable label. Omitted: unchanged. | |
| config | No | Replacement config for the destination's existing kind (webhook, telegram, discord, slack, ntfy, pushover, msteams, googlechat, email), naming only that kind's fields, each once: {"url":…,"secret":…} for webhook, {"bot_token":…,"chat_id":…} for telegram, {"webhook_url":…} for slack/discord/msteams/googlechat, {"topic_url":…} for ntfy, {"token":…,"user_key":…} for pushover, {"address":…} for email. Omitted: unchanged. A supplied URL is re-checked against the kind's allowed hosts and has to be https; a destination created before that rule keeps working until its config is replaced. The host rule does not prove who owns the endpoint. | |
| destination_id | Yes | UUID of the destination to update, from list_destinations. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare idempotent/destructive/not-read-only, and the description adds substantial context on top: the required write scope, that only supplied fields are mutated (partial update, a real behavioral trait), that 'kind' is immutable, and that supplying a new email resets verification and triggers a confirmation email.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four tight sentences, front-loaded with the scope requirement, then update semantics, then the immutability constraint, then the side effect. No filler; each sentence contributes a distinct operational fact.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no output schema, the description covers auth, mutation semantics, constraints, and side effects well. It stops short of describing the response shape or what the updated destination returns, which is the only notable gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so per-parameter documentation is already carried by the schema (baseline 3). The description adds cross-parameter semantics the schema does not: partial-update behavior ('only the supplied fields change') and the kind-immutability constraint tying config changes to the existing kind.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('updates a notification destination's name and/or config in place') with field-level scope, and explicitly carves out what it is not: the kind cannot change. An agent can distinguish it from delete_destination/create_destination without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear prerequisite ('Requires the write scope or higher') and names the alternative path when the change isn't supported ('delete and recreate instead'). It doesn't broadly contrast with create_destination for new destinations, but the routing guidance is concrete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_monitorUpdate monitorADestructiveIdempotentInspect
Requires the write scope or higher. Updates a monitor by UUID with merge-patch semantics: supplied fields change, omitted fields keep their stored value. tags, assertions (conditions a successful run's ping body has to satisfy, which catch a job that exits 0 having done nothing) and guards (ceilings on a number the job reports, which catch a looping agent) each replace the whole set; get_monitor returns the current sets. slug and ci_provider are immutable; only the ci_workflow and ci_branch filters change here.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Monitor UUID. | |
| tz | No | IANA timezone for cron evaluation. | |
| name | Yes | Human-readable monitor name. | |
| tags | No | Comma-separated labels to set on this monitor, e.g. 'agent:claude,env:prod'. Replaces existing tags. Max 20 tags, each max 50 chars. | |
| guards | No | Metric guards: ceilings on a number the job reports, checked on every ping; a total above the ceiling (equal does not trip) opens a 'runaway' incident. A JSON array as a string, e.g. '[{"name":"daily spend","path":"cost.usd","window_s":86400,"ceiling":50,"aggregation":"sum"}]'. The array replaces the whole set; '[]' removes all, omitted leaves it. Every entry needs name, path (dotted), window_s (trailing seconds), ceiling and aggregation ('sum', 'max' or 'avg'). Pings with no number at the path are skipped, not counted as zero. At most 5 guards, window_s at most 604800 (7 days); a malformed entry is rejected by name; the set stays as is. | |
| grace_s | No | Grace period in seconds. | |
| agent_id | No | Attaches the monitor to a registered agent, by the agent's id or slug (register_agent returns both). An agent that does not exist is an error (400 UNKNOWN_AGENT); no agent is created implicitly. Omitted: the current attachment (or lack of one) is unchanged. | |
| period_s | No | Ping interval in seconds (for schedule_kind='simple'). | |
| ci_branch | No | CI filter: only runs on this branch count, e.g. 'main'. Needs ci_provider (400 FIELD_NOT_IN_SHAPE without a CI binding). Same upsert exception as ci_workflow: create_monitor on an existing slug never writes it; update_monitor does. Unset, a run on any branch, a fork's pull request included, reports to the monitor. Omitted or an empty string (an API compatibility rule): unchanged; an explicit JSON null removes the filter. | |
| cron_expr | No | 5-field cron expression (for schedule_kind='cron'). | |
| probe_url | No | http monitors only: the absolute http/https URL to probe. Required when monitor_type='http'. The host is resolved at write time and rejected if it resolves only to private/link-local addresses. Omitted: unchanged. | |
| assertions | No | Output assertions: conditions a successful run's ping body has to satisfy; one that fails opens an incident with cause 'assertion' naming it. A JSON array as a string, e.g. '[{"name":"rows written","kind":"json_path","path":"result.rows_processed","op":"gt","value":"0"}]'. The array replaces the whole set; '[]' removes all, omitted leaves it. Fields: name, kind (both required), value, path, op. kind: contains, not_contains, matches (RE2, max 1000 bytes) or json_path (compares the value at a dotted path, e.g. 'a.b.c', with op: eq, ne, gt, gte, lt, lte; numeric when both sides are numbers, otherwise compared as strings). At most 20; a malformed entry is rejected by name; the set stays as is. | |
| ci_workflow | No | CI filter: only runs of the workflow, pipeline or job with this exact name count. Needs ci_provider: without a CI binding it is refused with 400 FIELD_NOT_IN_SHAPE (monitor_type='ci' alone binds nothing). Exception: create_monitor on an existing slug (an upsert) never writes it, and with ci_provider in the same call it is accepted and discarded; update_monitor persists it. Unset, every workflow in the repository reports to the monitor, so an unrelated workflow's failure opens an incident and its success clears one. Omitted or an empty string (an API compatibility rule): unchanged; an explicit JSON null removes the filter. | |
| monitor_from | No | Dormant until: an RFC 3339 timestamp before which no deadline is computed and no incident opens, for a monitor provisioned ahead of its job. The first-run deadline is monitor_from + grace_s. Unset (default): deadlines start immediately. Example: '2026-01-01T00:00:00Z'. Omitted: unchanged. | |
| probe_method | No | http monitors only: the HTTP method the probe sends: 'GET' (default), 'HEAD' or 'POST'. 'HEAD' returns no body, so probe_expected_body cannot match with it. Omitted: unchanged. | |
| max_runtime_s | No | Maximum seconds one run may take, from its start ping, before it is reported overdue (the 'overrun' rule). Unset falls back to grace_s. Example: grace_s=600 with max_runtime_s=14400 alerts 10 minutes after a missed ping but tolerates a 4-hour run. It replaces grace_s for the overrun deadline only; the silence rule and the first-run deadline still use grace_s. Range 60-31536000. Not supported on http monitors (400 MAX_RUNTIME_NOT_SUPPORTED); probe_timeout_s bounds a probe. Omitted: unchanged; 0 clears it (falls back to grace_s). | |
| schedule_kind | No | 'simple', 'cron' or 'on_demand'. Not accepted on an http monitor, and neither are period_s, cron_expr and tz: its schedule comes from probe_interval_s (400 FIELD_NOT_IN_SHAPE). 'on_demand' has no cadence (period_s or cron_expr with it is a 400) and arms no absence deadline between runs: an agent that is never invoked again raises nothing unless expect_every_s is set, and an idle healthy agent never raises a false 'late'. Once a run starts, max_runtime_s, step_timeout_s and blocked_timeout_s still apply. 'simple'/'cron' fit work on a cadence; 'on_demand' fits irregular invocation. | |
| trace_content | No | What this monitor's traces keep of prompt, command and tool content: 'dropped' (the default) removes it; 'redacted' stores prompt, command and tool content from the traced sessions, with secret-shaped values redacted on arrival. Omitted: unchanged. | |
| expect_every_s | No | Silence floor in seconds: a 'silence' incident opens when no ping of any kind (success, start, fail, step) arrives within this window, timed from the monitor's last activity. It is the only absence rule an 'on_demand' monitor has. It stands down while a run is in flight (the run clock owns that), and a 'blocked' ping pauses it up to blocked_timeout_s. On 'simple'/'cron' monitors it joins the schedule deadline as whichever is sooner, so it can only tighten detection. Unset (default): no floor. Range 60-31536000. Accepted on every monitor_type and schedule_kind. Omitted: unchanged; 0 clears it and turns the silence floor off. | |
| step_timeout_s | No | Seconds an armed run may go without a step before a 'stalled' incident opens, timed from the later of its start ping and its latest step. Steps are POST <ping_url>/step?rid=<run-id>&step=<name> (curl_step in get_ping_instructions). When set, a job that sends no steps opens a stalled incident on every run. The Claude Code hook and the reporting prompt send no steps. Unset (default): no stall detection. Range 10-86400, strictly below COALESCE(max_runtime_s, grace_s) (400 STEP_TIMEOUT_EXCEEDS_BUDGET). Not supported on http monitors (400 STEP_TIMEOUT_NOT_SUPPORTED). A step never extends max_runtime_s. Omitted: unchanged; 0 clears it and turns stall detection off. | |
| probe_timeout_s | No | http monitors only: seconds one probe may take before it counts as a failure. Range 1-30, default 10. The http counterpart of max_runtime_s, which http monitors reject. Omitted: unchanged. | |
| runaway_ceiling | No | Ping-rate ceiling: the most pings this monitor may receive in a rolling hour; exceeding it opens a 'runaway' incident. It catches a job or agent stuck in a loop, which keeps pinging and otherwise reads 'up'. A job every 15 minutes sends about 4 pings an hour, so 20 leaves room for retries. Rate-based: failure_threshold and run budgets do not gate it. Unset (default): the rule is off. Omitted: unchanged; 0 clears it and turns the runaway rule off. | |
| notify_min_run_s | No | Notification duration floor in seconds: a run shorter than this sends no info-class notification (success, every-run, note), so a trivial agent run does not notify a destination those events are routed to. It never suppresses a failure: down, fail, recovery, blocked and started always notify, as does an event whose duration was not measured (such as a success with no start ping). Unset (default): no floor. Range 60-31536000. Not supported on http monitors (400 NOTIFY_MIN_RUN_NOT_SUPPORTED). Omitted: unchanged; 0 clears it and turns the floor off. | |
| probe_interval_s | No | http monitors only: how often to probe, in seconds. Required when monitor_type='http'. Range 30-86400. Omitted: unchanged. | |
| blocked_timeout_s | No | Seconds a run may stay 'blocked' (an agent reported it is waiting on a human) before a 'blocked' incident opens. Unset means the 24-hour default, not no limit. Separate from the 'blocked' notification a route delivers (held 10 minutes, sent at most once per blocked stretch of a run). Accepted on every monitor_type. Omitted: unchanged; 0 clears it (the 24h default applies). | |
| failure_threshold | No | Consecutive failures required before an incident opens; default 1 (the first failure). 2-5 absorbs a job's occasional self-resolving failure. Any success resets the count. It gates only the 'fail' cause: silence, overrun, never_started and runaway are time- or rate-based and never delayed by it. A run ending on the model provider's API error (server_error, overloaded, rate_limit) neither counts nor resets it; 3 such runs in a row, or this many when higher, open an 'upstream' incident. Range 1-100. Omitted: unchanged. | |
| probe_expected_body | No | http monitors only: a substring the response body has to contain for the probe to pass, e.g. '"status":"ok"'. A broken app's error page can still return 200 and pass a status-only check; this catches it. Case-sensitive substring, not a regex. Default empty: the body is not inspected. Omitted or an empty string: unchanged; an explicit JSON null stops inspecting the body. | |
| probe_expected_status | No | http monitors only: the exact HTTP status that counts as healthy; default 200, any other code fails the probe. E.g. 204 for a no-content endpoint, or 301 to check that a redirect still exists (with probe_follow_redirects=false; otherwise the probe sees the destination's status). Omitted: unchanged. | |
| probe_follow_redirects | No | http monitors only: whether the probe follows 3xx redirects; default false. When false, the redirect itself is compared with probe_expected_status, so a site that starts redirecting to a login wall or a parking page fails the probe instead of passing on the destination's 200. Omitted: unchanged; false turns following back off. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial behavior beyond the annotations: write-scope requirement, merge-patch survival of omitted fields, whole-set replacement semantics for tags/assertions/guards (the destructive behavior destructiveHint flags), which causes the sets catch, and that slug and ci_provider are immutable. This is exactly the context an agent needs before mutating a monitor.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single dense paragraph that front-loads the scope requirement and the merge-patch rule before the details. Every sentence carries weight; the only cost is density that could be broken into list form for scanning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 29-param mutation tool with no output schema, the description covers the dangerous cross-cutting semantics well while the fully-populated schema handles per-field detail. It does not restate return behavior, which is acceptable given no output schema, but a note on what a successful update returns would round it out.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds cross-parameter semantics the schema cannot: omitted-vs-present-vs-null handling, merge-patch interaction, and the immutability boundary of slug/ci_provider. It meaningfully reduces misuse risk for a 29-parameter tool.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Updates a monitor by UUID') and names the exact semantics (merge-patch). An agent can distinguish this from create_monitor, delete_monitor, pause_monitor, and snooze_monitor without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the precondition ('Requires the write scope or higher') and the operational context: supplied fields change, omitted fields keep their stored value, and get_monitor returns the current sets for tags/assertions/guards. It stops short of explicitly naming when to prefer pause_monitor/snooze_monitor over a field update, so it is clear but not a full when/when-not routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_status_pageUpdate status pageADestructiveIdempotentInspect
Requires the write scope or higher. Updates a status page's title, slug, visibility or monitor set; arguments not supplied keep their value (the tool reads the page and merges, so an omitted check_ids never blanks it). A supplied check_ids replaces the whole monitor set; list_status_pages returns the current ids. A new slug changes the public URL and breaks links already shared.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Status page UUID, from list_status_pages. | |
| slug | No | New URL slug. Omitted: unchanged. A change breaks every link already handed out. Same format and global uniqueness as on create; a taken slug returns 409. | |
| title | No | New page title. Omitted: unchanged. | |
| check_ids | No | Comma-separated monitor UUIDs to show on the page, in no particular order, from list_monitors. Every id has to belong to this project: an unknown or cross-project id returns 400 and nothing is saved. An empty value is legal and produces a page with no monitors. Replaces the page's whole monitor set. Omitted: unchanged. | |
| visibility | No | 'private' (default) or 'public'. A public page is served at an unguessable but unauthenticated URL: anyone with the link sees the title, every monitor's name (often internal, such as 'billing-reconciler') and its up/down history. The free tier allows one public page per project; a second returns 403. Omitted: unchanged. Switching to 'public' publishes every monitor name already on the page. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and idempotentHint=true; the description goes well beyond them by disclosing merge semantics (a read-and-merge, so omitted fields are never blanked), the whole-set replacement of check_ids, the irreversible link breakage a slug change causes, and the fact that going 'public' publishes every monitor name. Those are exactly the side effects an agent must weigh before a destructive call.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three front-loaded sentences: the permission requirement first, then the mutation semantics, then the two highest-risk caveats (whole-set replacement, URL breakage). Every clause carries distinct information with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive update tool with no output schema, the description covers permissions, merge behavior, validation failure modes and the user-visible consequences of public/slug changes. Combined with the annotations' safety profile, an agent has everything needed to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the per-field semantics (omitted = unchanged, 409 on taken slug, 400 on cross-project ids, 403 on second public page) are already documented in the schema. The description's 'reads the page and merges' framing adds a useful holistic view but largely restates what the schema provides, so the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Updates a status page') and enumerates the mutable fields (title, slug, visibility, monitor set), which cleanly separates it from create_status_page, delete_status_page and list_status_pages. An agent can identify the tool's job without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit prerequisite ('Requires the write scope or higher') and routes the agent to sibling tools for inputs: list_status_pages for the check_ids, list_monitors implicitly for monitor UUIDs. It does not spell out when to choose this over create/delete_status_page, but the context is clear enough that no exclusion rules are needed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
29 tool updates
v0.1.17- Changed
add_incident_note2 fields changed- changed
Input schema / properties / body / descriptionPrevious value: -"The diagnosis, in plain words and one or two sentences: what actually failed, whether it is the same failure as before (compare failure_signature.occurrences from list_open_incidents), and what you did about it. Must not be empty or whitespace-only, and must be at most 8192 bytes. An oversized body is REJECTED, never truncated — a truncated diagnosis reads as a complete one that trails off, and the reader cannot tell that the sentence naming the cause was the one cut — so shorten it and call again. A pasted stack trace is a note nobody reads: the full failure output already lives on the run that produced it."New value: +"The diagnosis in plain words: what failed, whether it matches earlier failures (failure_signature.occurrences from list_open_incidents) and what was done, e.g. 'failed because the upstream API returned 503; same as the last three nights; retried twice'. Non-empty, not whitespace-only, at most 8192 bytes; an oversized body is rejected, never truncated. The full failure output already lives on the run." - changed
Input schema / properties / incident_id / descriptionPrevious value: -"The incident's numeric id, taken straight from an entry's incident_id in list_open_incidents. An integer, not a UUID."New value: +"The incident's numeric id, an entry's incident_id in list_open_incidents. An integer, not a UUID."
- Changed
adopt_discovered_agent1 field changed- changed
Input schema / properties / agent_id / descriptionPrevious value: -"Optional agent UUID (from list_agents) to merge the source into. Omit to create a new agent."New value: +"Optional agent UUID (from list_agents) to merge the source into. Omitted: a new agent is created."
- Changed
create_api_key3 fields changed- changed
Input schema / properties / check_id / descriptionPrevious value: -"Only with scope \"ingest\": binds the key to this one monitor (UUID from list_monitors), so it can send telemetry for that monitor and nothing else. Required for an exporter that cannot name its monitor, such as Codex."New value: +"Only with scope \"ingest\": binds the key to this one monitor (UUID from list_monitors), so it sends telemetry for that monitor alone. An exporter that cannot name its monitor, such as Codex, needs it." - changed
Input schema / properties / expires_at / descriptionPrevious value: -"Optional RFC 3339 expiry, e.g. \"2026-12-31T00:00:00Z\". Omit for a 90-day key, capped at the creating key's own expiry. A key can never be given a longer life than the key that creates it."New value: +"Optional RFC 3339 expiry, e.g. \"2026-12-31T00:00:00Z\". Omitted: 90 days. Either way it is capped at the creating key's own expiry." - changed
Input schema / properties / scope / descriptionPrevious value: -"What the new key may do. \"read\" is every GET; \"write\" is everything except managing API keys; \"admin\" is everything, key management included. Omit for \"write\", which is the right tier for a credential handed to a job or an agent: it can do the work and cannot mint itself a replacement. A key can never be given a HIGHER scope than the key that creates it; asking for one is refused and the refusal names the ceiling. \"ingest\" can only send pings and telemetry (traces, metrics, logs) and cannot call the REST API at all: use it for a key that lives in a dotfile or an exporter's config. This tool needs an admin key; with a write key, use create_ingest_key, which mints a tracing key bound to one monitor."New value: +"What the new key may do. \"read\" is every GET; \"write\" (the default) is everything except managing API keys, so a key at that tier cannot mint itself a replacement; \"admin\" is everything. A scope above the creating key's is refused, and the refusal names the ceiling. \"ingest\" only sends pings and telemetry (traces, metrics, logs) and cannot call the REST API, for a key kept in a dotfile or an exporter's config."
- Changed
create_destination1 field changed- changed
Input schema / properties / kind / descriptionPrevious value: -"One of: webhook, telegram, discord, slack, ntfy, pushover, msteams, googlechat, email. Every destination URL must be https. A BRANDED kind must point at its vendor's host: discord at discord.com or discordapp.com, slack at hooks.slack.com, msteams at webhook.office.com or outlook.office.com or logic.azure.com or logic.azure.us or environment.api.powerplatform.com, googlechat at chat.googleapis.com. For any other endpoint use kind \"webhook\", which accepts any https host; ntfy is unpinned too, so a self-hosted ntfy server is fine. A pin narrows the destination to the vendor's own platform; it does NOT prove the endpoint belongs to the person or project that created it, because every pinned domain is multi-tenant and open to anyone who signs up. Do not report a pinned destination as verified or as owned by anyone on the strength of its host."New value: +"One of: webhook, telegram, discord, slack, ntfy, pushover, msteams, googlechat, email. Every destination URL has to be https, and a branded kind has to point at its vendor's host: discord at discord.com or discordapp.com, slack at hooks.slack.com, msteams at webhook.office.com or outlook.office.com or logic.azure.com or logic.azure.us or environment.api.powerplatform.com, googlechat at chat.googleapis.com. Any other endpoint fits kind \"webhook\", which accepts any https host; ntfy is unpinned too, so a self-hosted ntfy server works. A pin narrows the destination to the vendor's platform; it does not prove who owns the endpoint, since every pinned domain is multi-tenant."
- Changed
create_ingest_key1 field changed- changed
Input schema / properties / expires_at / descriptionPrevious value: -"Optional RFC 3339 expiry, e.g. \"2026-12-31T00:00:00Z\". Omit for a 90-day key, capped at the creating key's own expiry."New value: +"Optional RFC 3339 expiry, e.g. \"2026-12-31T00:00:00Z\". Omitted: 90 days. Either way it is capped at the creating key's own expiry."
- Changed
create_monitor22 fields changed- changed
Input schema / properties / agent_id / descriptionPrevious value: -"Attach this monitor to an agent from the registry, by the agent's id OR its slug (both are returned by register_agent). Omit for a monitor with no owning agent. Naming an agent that does not exist is an error — 400 UNKNOWN_AGENT — it is NEVER created implicitly; call register_agent first to get a valid agent_id. On an upsert (existing slug), omitting this leaves the monitor's current attachment (or lack of one) unchanged; supplying it re-applies the attachment, so an agent re-running its own registration converges to 'attached' every time rather than silently no-opping after the first call."New value: +"Attaches the monitor to a registered agent, by the agent's id or slug (register_agent returns both). An agent that does not exist is an error (400 UNKNOWN_AGENT); no agent is created implicitly. Omitted on a create: no owning agent. On an upsert (existing slug), omitting it leaves the current attachment unchanged, and supplying it re-applies the attachment, so a repeated registration converges to 'attached'." - changed
Input schema / properties / blocked_timeout_s / descriptionPrevious value: -"Maximum seconds a run may sit in the 'blocked' state (an agent reported it is waiting on a human) before a 'blocked' incident opens. UNSET DOES NOT MEAN WAIT FOREVER: omitting this does not disable the timeout, it falls back to the default, which is 24 HOURS — an agent still blocked 24 hours after reporting so, with this field never set, gets a 'blocked' incident regardless. Lower it to be paged sooner when a stuck approval is urgent; raise it for work that legitimately waits on a human for longer than a day. This is distinct from the non-incident 'blocked' notification a route on the 'blocked' event type delivers (see set_route), which is held 10 minutes and sent only if the run is still blocked then, at most once per blocked stretch of a run; this field governs the separate incident that opens only if the wait outlives the timeout. Accepted on every monitor_type: unlike max_runtime_s/step_timeout_s it has no run-scoped precondition an http monitor could fail, so there is nothing to reject. On an upsert (existing slug), omitting this clears the monitor's blocked_timeout_s and falls back to the 24h default — pass the current value to keep it."New value: +"Seconds a run may stay 'blocked' (an agent reported it is waiting on a human) before a 'blocked' incident opens. Unset means the 24-hour default, not no limit. Separate from the 'blocked' notification a route delivers (held 10 minutes, sent at most once per blocked stretch of a run). Accepted on every monitor_type. On an upsert (existing slug), omitting it clears the value back to the 24h default." - changed
Input schema / properties / ci_branch / descriptionPrevious value: -"CI filter: only count runs on this branch, e.g. 'main'. REQUIRES ci_provider, and the API enforces it: without a CI binding the request is refused with 400 FIELD_NOT_IN_SHAPE rather than accepted and discarded. Subject to the SAME upsert exception as ci_workflow — create_monitor on an existing slug never writes this filter; use update_monitor. WITHOUT IT a run on ANY branch — a feature branch, a fork's pull request — reports to this monitor, so somebody else's broken branch marks your monitor down. Set it to the branch whose health you actually care about, which is almost always the default branch."New value: +"CI filter: only runs on this branch count, e.g. 'main'. Needs ci_provider (400 FIELD_NOT_IN_SHAPE without a CI binding). Same upsert exception as ci_workflow: create_monitor on an existing slug never writes it; update_monitor does. Unset, a run on any branch, a fork's pull request included, reports to the monitor." - changed
Input schema / properties / ci_provider / descriptionPrevious value: -"Bind this monitor to a CI system, so the CI system itself reports every run by webhook and the job needs NO ping code at all. One of: 'github', 'gitlab', 'jenkins'. SET-ONCE: ci_provider can only be chosen when the monitor is created — update_monitor cannot change or remove it, so a monitor bound to the wrong provider must be deleted and recreated. Setting it generates a webhook secret that is returned exactly ONCE, in THIS call's response, together with the webhook URL. It is never retrievable afterwards — no MCP tool and no API read returns it again — so copy both out of the response and configure the CI webhook before doing anything else. Omit for a monitor that pings for itself. Also set ci_workflow and ci_branch unless the repository really has exactly one workflow on one branch. NOT ACCEPTED on monitor_type='http': an http probe is never bound to CI, and the API returns 400 FIELD_NOT_IN_SHAPE. It used to accept the provider, create no binding, and report success."New value: +"Binds the monitor to a CI system ('github', 'gitlab' or 'jenkins'), whose webhook then reports every run with no ping code in the job. Fixed at creation: update_monitor cannot change or remove it. The webhook secret and URL appear only in this call's result; no tool or API read returns the secret again. Not accepted on monitor_type='http' (400 FIELD_NOT_IN_SHAPE). ci_workflow and ci_branch narrow which runs count." - changed
Input schema / properties / ci_workflow / descriptionPrevious value: -"CI filter: only count runs of the workflow / pipeline / job with this exact name. REQUIRES ci_provider, and the API enforces it: without a CI binding this filter has nowhere to be stored, so the request is refused with 400 FIELD_NOT_IN_SHAPE rather than accepted and discarded. Note that monitor_type='ci' does NOT bind anything on its own — ci_provider does. ONE EXCEPTION, and it is on the path agents use most, so do not rely on the enforcement here: create_monitor on a slug that ALREADY EXISTS is an upsert, and the upsert never writes this filter. With ci_provider in the same call the request is accepted and the filter is silently discarded; without it the request is refused, and doing what the error advises — adding ci_provider — reaches the discarding case instead. Set this filter with update_monitor, which does persist it. WITHOUT IT, EVERY workflow in the repository reports to this monitor — so one unrelated failing workflow opens an incident against a job that is perfectly healthy, and a green run of a different workflow clears an incident the real job never recovered from. Set it whenever the repository has more than one workflow."New value: +"CI filter: only runs of the workflow, pipeline or job with this exact name count. Needs ci_provider: without a CI binding it is refused with 400 FIELD_NOT_IN_SHAPE (monitor_type='ci' alone binds nothing). Exception: create_monitor on an existing slug (an upsert) never writes it, and with ci_provider in the same call it is accepted and discarded; update_monitor persists it. Unset, every workflow in the repository reports to the monitor, so an unrelated workflow's failure opens an incident and its success clears one." - changed
Input schema / properties / expect_every_s / descriptionPrevious value: -"SILENCE FLOOR in seconds: open a 'silence' incident if NO ping of any kind — success, start, fail, step — has arrived within this window, regardless of the schedule. It is anchored on the monitor's last activity, not on a cadence, which is what makes it the ONLY absence rule an 'on_demand' monitor can have: that schedule_kind arms nothing between runs, so without this field an on_demand monitor reads 'up' forever no matter how long the agent stays dark. Set it on any on_demand agent monitor you would be alarmed to find silent — that is what it is for. It does NOT fire mid-run: while a run is in flight (a start ping is outstanding) the floor stands down entirely and the run clock owns detection (max_runtime_s, step_timeout_s), so a legitimate 4-hour run that reports nothing is still not an incident. A 'blocked' ping also pauses it, bounded by blocked_timeout_s. On 'simple'/'cron' monitors it is a backstop rather than the main rule: it joins the existing deadline as whichever is SOONER, so it can tighten detection under a long cadence (a daily cron has a ~25-hour blind window) but can never loosen it. Default: unset, which means no floor and is exactly how every monitor behaved before this field existed. Range 60-31536000. Accepted on every monitor_type and every schedule_kind. On an upsert (existing slug), omitting this clears the monitor's expect_every_s and turns the silence floor back off — pass the current value to keep it."New value: +"Silence floor in seconds: a 'silence' incident opens when no ping of any kind (success, start, fail, step) arrives within this window, timed from the monitor's last activity. It is the only absence rule an 'on_demand' monitor has. It stands down while a run is in flight (the run clock owns that), and a 'blocked' ping pauses it up to blocked_timeout_s. On 'simple'/'cron' monitors it joins the schedule deadline as whichever is sooner, so it can only tighten detection. Unset (default): no floor. Range 60-31536000. Accepted on every monitor_type and schedule_kind. On an upsert (existing slug), omitting it clears the value and turns the silence floor off." - changed
Input schema / properties / failure_threshold / descriptionPrevious value: -"Number of consecutive failures required before an incident opens. Default 1 (open on the very first failure). This is how you stop a single transient blip from paging someone: set 2-5 on a job that fails occasionally for reasons that resolve themselves, and no incident opens until that many runs in a row have failed. Any success resets the count to zero. It gates the 'fail' cause ONLY — silence (a missed ping), overrun, never_started and runaway are time- or rate-based, so a consecutive count means nothing for them and they are never delayed by it. A run that ends on the model provider's API error (server_error, overloaded, rate_limit) neither counts toward it nor resets it: those open an 'upstream' incident once 3 runs in a row end that way, or this many when it is higher. Range 1-100. On an upsert (existing slug), omitting this resets the monitor's threshold to 1 — pass the current value to keep it."New value: +"Consecutive failures required before an incident opens; default 1 (the first failure). 2-5 absorbs a job's occasional self-resolving failure. Any success resets the count. It gates only the 'fail' cause: silence, overrun, never_started and runaway are time- or rate-based and never delayed by it. A run ending on the model provider's API error (server_error, overloaded, rate_limit) neither counts nor resets it; 3 such runs in a row, or this many when higher, open an 'upstream' incident. Range 1-100. On an upsert (existing slug), omitting it resets the threshold to 1." - changed
Input schema / properties / grace_s / descriptionPrevious value: -"Grace period in seconds after a ping is due before alerting. Omit on an on_demand monitor and LastPing uses 300 seconds; on_demand has no cadence, so grace only sets the first-run deadline and the overrun fallback. On an upsert (existing slug), omitting it on an on_demand monitor sets 300: pass the current value to keep it."New value: +"Grace period in seconds after a ping is due before alerting. Omitted on an on_demand monitor, LastPing uses 300 seconds; on_demand has no cadence, so grace only sets the first-run deadline and the overrun fallback. On an upsert (existing slug), omitting it on an on_demand monitor sets 300." - changed
Input schema / properties / max_runtime_s / descriptionPrevious value: -"Maximum seconds a single run may take before it is reported overdue (the 'overrun' rule), measured from the run's start ping. Omit to fall back to grace_s. This is how a long job avoids being flagged overdue while still being detected quickly if it goes silent: e.g. grace_s=600 with max_runtime_s=14400 alerts 10 minutes after a missed ping but tolerates a 4-hour run. It replaces grace_s for the overrun deadline ONLY — the silence rule and the first-run deadline still use grace_s. Range 60-31536000. Not supported on http monitors: a probe has no start/success pair, so the overrun rule can never fire and the API returns 400 MAX_RUNTIME_NOT_SUPPORTED (use probe_timeout_s to bound a single probe). On an upsert (existing slug), omitting this clears the monitor's max_runtime_s — pass the current value to keep it."New value: +"Maximum seconds one run may take, from its start ping, before it is reported overdue (the 'overrun' rule). Unset falls back to grace_s. Example: grace_s=600 with max_runtime_s=14400 alerts 10 minutes after a missed ping but tolerates a 4-hour run. It replaces grace_s for the overrun deadline only; the silence rule and the first-run deadline still use grace_s. Range 60-31536000. Not supported on http monitors (400 MAX_RUNTIME_NOT_SUPPORTED); probe_timeout_s bounds a probe. On an upsert (existing slug), omitting it clears the value." - changed
Input schema / properties / monitor_from / descriptionPrevious value: -"DORMANT UNTIL: an RFC 3339 timestamp before which no deadline is computed and no incident can open — the monitor is fully configured but not yet armed. Use it when you provision ahead of the work: a monitor for a job that does not start running until next Monday is otherwise 'late' from the moment you create it, which is a false alert on day one. The first-run deadline is seeded as monitor_from + grace_s. Default: unset, meaning deadlines start immediately. Example: '2026-01-01T00:00:00Z'. On an upsert (existing slug), omitting this clears the monitor's monitor_from and arms it immediately — pass the current value to keep it."New value: +"Dormant until: an RFC 3339 timestamp before which no deadline is computed and no incident opens, for a monitor provisioned ahead of its job. The first-run deadline is monitor_from + grace_s. Unset (default): deadlines start immediately. Example: '2026-01-01T00:00:00Z'. On an upsert (existing slug), omitting it clears the value and arms the monitor immediately." - changed
Input schema / properties / monitor_type / descriptionPrevious value: -"'heartbeat' (default), 'ci', or 'http'. Any other value is refused with 400 UNKNOWN_MONITOR_TYPE. 'ci' is a label, not a binding: a CI monitor is a heartbeat monitor with ci_provider set, so passing monitor_type='ci' WITHOUT ci_provider creates an ordinary heartbeat and its ci_workflow/ci_branch filters are refused."New value: +"'heartbeat' (default), 'ci' or 'http'; any other value is refused with 400 UNKNOWN_MONITOR_TYPE. 'ci' is a label, not a binding: without ci_provider it creates an ordinary heartbeat, and ci_workflow/ci_branch are refused." - changed
Input schema / properties / notify_min_run_s / descriptionPrevious value: -"NOTIFICATION DURATION FLOOR in seconds: a run SHORTER than this does not produce an INFO-CLASS notification (success, started, every-run, note). This exists for exactly one problem: on an agent monitor, one run is one task you asked for, so asking the agent 'what's 2+2' produces a start and a success notification exactly like a 56-minute deploy does. If you have routed success/started/every-run/note to a destination, you WILL be paged for trivial runs unless you set this. IT NEVER SUPPRESSES A FAILURE. down, fail, recovery and blocked are alert-class and are never affected by this field, however short the run — a run that failed in two seconds is exactly what you need to hear about, and this field cannot silence that, structurally, no matter how it is set. It also never suppresses 'started': a run's duration does not exist yet the moment it begins, so started is always reported regardless of this floor. And it never suppresses an event whose duration could not be measured at all (e.g. a bare success with no preceding start ping) — an unknown duration always means 'notify', never 'suppress'. Default: unset, which means no floor and is exactly how every monitor behaved before this field existed. Range 60-31536000. Not supported on http monitors: an http probe has no start/success pair, so its run duration is never measured and the floor could never apply (the API returns 400 NOTIFY_MIN_RUN_NOT_SUPPORTED). On an upsert (existing slug), omitting this clears the monitor's notify_min_run_s and turns the notification duration floor back off — pass the current value to keep it."New value: +"Notification duration floor in seconds: a run shorter than this sends no info-class notification (success, every-run, note), so a trivial agent run does not notify a destination those events are routed to. It never suppresses a failure: down, fail, recovery, blocked and started always notify, as does an event whose duration was not measured (such as a success with no start ping). Unset (default): no floor. Range 60-31536000. Not supported on http monitors (400 NOTIFY_MIN_RUN_NOT_SUPPORTED). On an upsert (existing slug), omitting it clears the value and turns the floor off." - changed
Input schema / properties / probe_expected_body / descriptionPrevious value: -"http monitors only: a substring that MUST appear in the response body for the probe to count as healthy. THIS IS THE DIFFERENCE BETWEEN 'the server answered' AND 'the app works': a broken app that renders an error page still returns 200, passes a status-only check, and leaves the monitor green. Match on something only a healthy response contains, e.g. '\"status\":\"ok\"'. Substring match, not a regex, and case-sensitive. Default: empty, meaning the body is not inspected at all."New value: +"http monitors only: a substring the response body has to contain for the probe to pass, e.g. '\"status\":\"ok\"'. A broken app's error page can still return 200 and pass a status-only check; this catches it. Case-sensitive substring, not a regex. Default empty: the body is not inspected." - changed
Input schema / properties / probe_expected_status / descriptionPrevious value: -"http monitors only: the EXACT HTTP status code that counts as healthy. Default 200; any other code fails the probe. Set it when the healthy answer is not 200 — 204 for a no-content health endpoint, or 301 when what you are checking is that a redirect still exists (pair that with probe_follow_redirects=false, or the probe will follow it and see the destination's status instead)."New value: +"http monitors only: the exact HTTP status that counts as healthy; default 200, any other code fails the probe. E.g. 204 for a no-content endpoint, or 301 to check that a redirect still exists (with probe_follow_redirects=false; otherwise the probe sees the destination's status)." - changed
Input schema / properties / probe_follow_redirects / descriptionPrevious value: -"http monitors only: whether the probe follows 3xx redirects. Default false. Leaving it false is usually what you want: the redirect itself is then compared against probe_expected_status like any other response, so a site that starts redirecting to a login wall, a parking page or an outage notice is CAUGHT rather than silently followed to a healthy-looking 200. Set true only when the URL you are checking is legitimately a redirect to the thing you actually care about."New value: +"http monitors only: whether the probe follows 3xx redirects; default false. When false, the redirect itself is compared with probe_expected_status, so a site that starts redirecting to a login wall or a parking page fails the probe instead of passing on the destination's 200." - changed
Input schema / properties / probe_method / descriptionPrevious value: -"http monitors only: the HTTP method the probe sends. One of 'GET', 'HEAD', 'POST'. Default 'GET'. Use 'HEAD' for a cheap liveness check when the body does not matter — but note it returns no body, so probe_expected_body cannot match anything."New value: +"http monitors only: the HTTP method the probe sends: 'GET' (default), 'HEAD' or 'POST'. 'HEAD' returns no body, so probe_expected_body cannot match with it." - changed
Input schema / properties / probe_timeout_s / descriptionPrevious value: -"http monitors only: how many seconds a single probe may take before it counts as a failure. Range 1-30, default 10. This is the http equivalent of max_runtime_s, which http monitors reject: it is the only way to say 'answering, but far too slowly to be healthy'."New value: +"http monitors only: seconds one probe may take before it counts as a failure. Range 1-30, default 10. The http counterpart of max_runtime_s, which http monitors reject." - changed
Input schema / properties / runaway_ceiling / descriptionPrevious value: -"PING-RATE CEILING: the maximum number of pings this monitor may receive in a rolling one-hour window. Exceeding it opens a 'runaway' incident. This is the rule that catches a job or agent stuck in a LOOP — the failure every other rule misses, because a looping agent is pinging enthusiastically and therefore reads 'up' the whole time it is burning tokens or money. Set it a little above the monitor's real cadence: a job that runs every 15 minutes sends about 4 pings/hour, so 20 absorbs retries and still catches a loop. It is RATE-based, so failure_threshold does not gate it and neither does any run budget. Default: unset, which disables the runaway rule entirely. On an upsert (existing slug), omitting this clears the monitor's ceiling and turns the runaway rule back off — pass the current value to keep it."New value: +"Ping-rate ceiling: the most pings this monitor may receive in a rolling hour; exceeding it opens a 'runaway' incident. It catches a job or agent stuck in a loop, which keeps pinging and otherwise reads 'up'. A job every 15 minutes sends about 4 pings an hour, so 20 leaves room for retries. Rate-based: failure_threshold and run budgets do not gate it. Unset (default): the rule is off. On an upsert (existing slug), omitting it clears the ceiling and turns the runaway rule off." - changed
Input schema / properties / schedule_kind / descriptionPrevious value: -"'simple' (requires period_s), 'cron' (requires cron_expr), or 'on_demand' (requires neither). Required for heartbeat/ci monitors. NOT ACCEPTED on monitor_type='http', together with period_s, cron_expr and tz: an http monitor's schedule is derived from probe_interval_s, so the API refuses all four with 400 FIELD_NOT_IN_SHAPE instead of accepting and ignoring them. 'on_demand' means no cadence at all: no period_s, no cron_expr — the API returns 400 if either is supplied — and, by default, NO ABSENCE DEADLINES ARE ARMED BETWEEN RUNS. What this trades away: nothing tells you if the agent is never invoked again; silence between runs is invisible unless you opt in to expect_every_s. What it buys: a healthy agent that nobody happens to invoke for a week never generates a false 'late' or 'down' for simply not having been asked to run. Only run-scoped detection still applies once a run starts — max_runtime_s (overrun), step_timeout_s (stall), blocked_timeout_s (stuck on a human) — because those are anchored to a run's own start ping, not to a cadence. IMPORTANT: if you would be alarmed to find this agent silent for hours, set expect_every_s as well — it is the silence floor, and it is the only thing that makes an on_demand monitor detect absence at all. Choose 'simple'/'cron' when the agent is supposed to run on a cadence; choose 'on_demand' when invocation is inherently irregular and a quiet stretch between runs is expected, not a symptom."New value: +"'simple' (with period_s), 'cron' (with cron_expr) or 'on_demand' (neither). Required for heartbeat and ci monitors. Not accepted on an http monitor, and neither are period_s, cron_expr and tz: its schedule comes from probe_interval_s (400 FIELD_NOT_IN_SHAPE). 'on_demand' has no cadence (period_s or cron_expr with it is a 400) and arms no absence deadline between runs: an agent that is never invoked again raises nothing unless expect_every_s is set, and an idle healthy agent never raises a false 'late'. Once a run starts, max_runtime_s, step_timeout_s and blocked_timeout_s still apply. 'simple'/'cron' fit work on a cadence; 'on_demand' fits irregular invocation." - changed
Input schema / properties / slug / descriptionPrevious value: -"Optional stable ID. If a monitor with this slug exists, it will be updated (upsert). Trimmed and lowercased automatically. Must match ^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$ (3-50 chars, lowercase alphanumeric and hyphens, starting and ending alphanumeric) after normalisation. UUID-shaped slugs are rejected — they would be ambiguous with a monitor id when importing into Terraform. Omit entirely for no slug."New value: +"Optional stable ID; when a monitor with this slug exists it is updated (upsert). Trimmed and lowercased, then it has to match ^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$ (3-50 chars, lowercase alphanumeric and hyphens). UUID-shaped slugs are rejected (ambiguous with a monitor id in a Terraform import). Omitted: no slug." - changed
Input schema / properties / step_timeout_s / descriptionPrevious value: -"Progress budget in seconds: how long an armed run may go without reporting a step before a 'stalled' incident opens (the stall rule). The clock is anchored on the LATER of the run's start ping and its most recent step, so a run that wedges before its first step is caught too. Reach for this when 'still running' and 'still making progress' are different things — a long agent loop, a multi-stage pipeline, a migration. max_runtime_s alone tells you nothing until the whole budget expires; step_timeout_s=300 on a 4-hour budget tells you within five minutes, and names the last step that reported. To use it the run must report steps: call get_ping_instructions and use curl_step (POST <ping_url>/step?rid=<run-id>&step=<name>). A monitor with step_timeout_s set whose job never reports a step will open a stalled incident on EVERY run — set the field and instrument the job in the same change. Stall detection needs your job to call /step: the Claude Code hook and the reporting prompt do not send steps, so leave step_timeout_s unset for them. Default: unset, which disables stall detection entirely; a monitor that sets nothing behaves exactly as it did before this field existed. Range 10-86400. Two constraints. (1) It must be strictly LESS than the effective run budget, COALESCE(max_runtime_s, grace_s), or the API returns 400 STEP_TIMEOUT_EXCEEDS_BUDGET — at or above the budget the run overruns first, so the stall rule could never fire. (2) Not supported on http monitors: a probe never arms a run and has no /step endpoint to call, so the API returns 400 STEP_TIMEOUT_NOT_SUPPORTED. A step resets the stall clock ONLY — it never extends max_runtime_s, so an agent that reports progress forever still overruns. On an upsert (existing slug), omitting this clears the monitor's step_timeout_s and turns stall detection back off — pass the current value to keep it."New value: +"Seconds an armed run may go without a step before a 'stalled' incident opens, timed from the later of its start ping and its latest step. Steps are POST <ping_url>/step?rid=<run-id>&step=<name> (curl_step in get_ping_instructions). When set, a job that sends no steps opens a stalled incident on every run. The Claude Code hook and the reporting prompt send no steps. Unset (default): no stall detection. Range 10-86400, strictly below COALESCE(max_runtime_s, grace_s) (400 STEP_TIMEOUT_EXCEEDS_BUDGET). Not supported on http monitors (400 STEP_TIMEOUT_NOT_SUPPORTED). A step never extends max_runtime_s. On an upsert (existing slug), omitting it clears the value and turns stall detection off." - changed
Input schema / properties / trace_content / descriptionPrevious value: -"What this monitor's traces keep of prompt, command and tool content. 'dropped' (the default) removes it; 'redacted' keeps it, with every secret-shaped value redacted when it arrives. Only a person should choose 'redacted': never set it on your own initiative, only when the person you work for has asked for content to be stored. Omit on a create for dropped; on an upsert (existing slug), omitting it leaves the stored value unchanged."New value: +"What this monitor's traces keep of prompt, command and tool content: 'dropped' (the default) removes it; 'redacted' stores prompt, command and tool content from the traced sessions, with secret-shaped values redacted on arrival. Omitted on a create: dropped; on an upsert (existing slug), omitting it leaves the stored value unchanged."
- Changed
create_status_page3 fields changed- changed
Input schema / properties / check_ids / descriptionPrevious value: -"Comma-separated monitor UUIDs to show on the page, in no particular order. Get them from list_monitors. Every id must belong to this project — an unknown or cross-project id returns 400 and nothing is saved. An empty value is legal and produces a page with no monitors on it."New value: +"Comma-separated monitor UUIDs to show on the page, in no particular order, from list_monitors. Every id has to belong to this project: an unknown or cross-project id returns 400 and nothing is saved. An empty value is legal and produces a page with no monitors." - changed
Input schema / properties / slug / descriptionPrevious value: -"Optional URL slug, which is what appears in the public link (/status/<slug>). Must match ^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$ (3-50 chars, lowercase alphanumeric and hyphens, starting and ending alphanumeric). Slugs are GLOBALLY unique across all projects, not just yours, so a desirable one may be taken — that returns 409. OMIT IT unless the user asked for a specific URL: a random unguessable slug is then generated, which is also the safer default for a public page."New value: +"Optional URL slug, shown in the public link (/status/<slug>). Has to match ^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$ (3-50 chars, lowercase alphanumeric and hyphens). Slugs are unique across all projects, so a taken one returns 409. Omitted: a random unguessable slug, the safer default for a public page." - changed
Input schema / properties / visibility / descriptionPrevious value: -"'private' (default) or 'public'. 'public' means the page is served at a guessable-free but UNAUTHENTICATED URL: anyone with the link sees the title, the name of every monitor on it, and its up/down history. Monitor names are frequently internal ('billing-reconciler', 'acme-corp-nightly-sync'), so treat this as publishing them. Choose 'private' unless the user has actually asked for a page other people can see. The free tier allows exactly ONE public page per project; a second returns 403."New value: +"'private' (default) or 'public'. A public page is served at an unguessable but unauthenticated URL: anyone with the link sees the title, every monitor's name (often internal, such as 'billing-reconciler') and its up/down history. The free tier allows one public page per project; a second returns 403."
- Changed
declare_run_expectations2 fields changed- changed
Input schema / properties / assertions / descriptionPrevious value: -"The run's complete set of expectations, declared ONCE at the start of the run -- criteria the ping BODY of THIS run's eventual success ping must satisfy when the run closes, checked instead of letting the run grade itself. IMMUTABLE: a second call for the same rid is rejected with a conflict error and the first declaration stands unchanged -- there is no way to edit, add to, or replace it once made, so decide the whole set before you start work. Declaring nothing is allowed and always has been: simply never call this tool for a run, and the monitor's own check-level assertions (if any) stay in force unchanged. INCLUDE AT LEAST ONE POSITIVE CRITERION -- a 'contains', 'matches' or 'json_path' entry -- in every declaration. A declaration made ENTIRELY of 'not_contains' entries is self-satisfying on empty output: a run that produces nothing at all still passes, because there is nothing for the pattern to find. That is precisely the evasion this feature exists to close, so a purely negative declaration defeats its own purpose. A 'matches' entry only counts as positive if its pattern REJECTS an empty body: '.*', '(?s).*' and '^$' all accept one and are validated as perfectly legal patterns, so a declaration resting on one of those is no better than a purely negative declaration. Supply a JSON ARRAY as a string, e.g. '[{\"kind\":\"json_path\",\"path\":\"result.rows_processed\",\"op\":\"gt\",\"value\":\"0\"}]'. Fields per entry: kind (required), value, path, op -- no name; a run's declared criteria have none, unlike a monitor's own output assertions. kind is one of 'contains' (body contains value as a substring), 'not_contains' (body does not contain it), 'matches' (body matches value as a Go RE2 regexp, max 1000 bytes), or 'json_path' (parse the body as JSON, read the value at path, compare it against value with op). contains/not_contains/matches require value; json_path requires path and op. path is a DOTTED path only ('a.b.c') -- the query syntax of a real JSONPath library ('[', '*', '$') is rejected. op is one of 'eq', 'ne', 'gt', 'gte', 'lt', 'lte'. At most 20 assertions per run. A malformed entry (uncompilable regexp, a path carrying query syntax, an unknown kind or op) is rejected before anything is written, and nothing is stored if any entry fails."New value: +"The run's complete criteria, as a JSON array string, e.g. '[{\"kind\":\"json_path\",\"path\":\"result.rows_processed\",\"op\":\"gt\",\"value\":\"0\"}]'. Fields: kind (required), value, path, op; no name. kind: contains, not_contains, matches (RE2, max 1000 bytes) or json_path (the value at a dotted path, e.g. 'a.b.c', compared with op: eq, ne, gt, gte, lt, lte). Only not_contains entries, or a matches pattern that accepts an empty body ('.*', '^$'), pass on empty output; a contains, json_path or empty-rejecting matches entry catches a run that produced nothing. At most 20; one malformed entry rejects the whole declaration. Runs with no declaration keep the monitor's own assertions." - changed
Input schema / properties / rid / descriptionPrevious value: -"The run id exactly as sent on this run's /start ping — the same rid used on every step and the terminal ping."New value: +"The run id exactly as sent on this run's /start ping, the same rid used on every step and the terminal ping."
- Changed
delete_destination1 field changed- changed
Input schema / properties / id / descriptionPrevious value: -"Destination (channel) UUID. Get it from list_destinations."New value: +"Destination (channel) UUID, from list_destinations."
- Changed
discover_monitors_reconcile1 field changed- changed
Input schema / properties / sources / descriptionPrevious value: -"The complete scan result: a JSON ARRAY supplied as a string, one entry per scheduled job, e.g. '[{\"source_kind\":\"crontab\",\"source_ref\":\"/etc/cron.d/backup:/usr/local/bin/backup.sh\",\"name\":\"nightly backup\",\"schedule_cron\":\"0 3 * * *\",\"tz\":\"Europe/Berlin\"}]'. Fields per entry: source_kind and source_ref (both REQUIRED — an entry missing either cannot be matched against an existing monitor and would be re-created on every scan), name (optional display name; falls back to source_ref), schedule_cron (optional 5-field cron expression, sent only when you actually read one), tz (the IANA zone that cron fires in — REQUIRED for a crontab or systemd-timer entry carrying a schedule_cron, read from the host, never guessed), and suggested_expect_every_s (optional; state the silence floor outright when you know the real cadence better than the cron expression does — it WINS over the value derived from the cron). Send the WHOLE scan in one call: this is a diff, so a source you leave out is reported as orphaned rather than ignored. Send '[]' to report that the scan found nothing — every discovered monitor is then listed as orphaned, and none of them is deleted. At most 1000 entries per call, each source_kind/source_ref pair at most once (a duplicate is rejected outright, not merged), and the project's 100-monitor cap is applied to the whole batch at once — if the batch would exceed it, NOTHING is created. Nothing is written unless every entry validates: one bad entry rejects the entire payload and leaves no monitors behind."New value: +"The full scan as a JSON array string, e.g. '[{\"source_kind\":\"crontab\",\"source_ref\":\"/etc/cron.d/backup:/usr/local/bin/backup.sh\",\"schedule_cron\":\"0 3 * * *\",\"tz\":\"Europe/Berlin\"}]'. Fields: source_kind, source_ref (required), name (default source_ref), schedule_cron (5-field, when one was read), tz (IANA zone the cron fires in; required on a crontab or systemd-timer entry with schedule_cron), suggested_expect_every_s (overrides the silence floor). An omitted source is reported orphaned; '[]' orphans every discovered monitor, deleting none. At most 1000 entries; a repeated source_kind/source_ref pair is rejected. The 100-monitor cap covers the whole batch; one invalid entry rejects it all."
- Changed
export_terraform1 field changed- changed
Input schema / properties / include / descriptionPrevious value: -"Optional comma-separated subset of monitors,destinations,routes,templates,status_pages. Omit to export everything."New value: +"Optional comma-separated subset of monitors,destinations,routes,templates,status_pages. Omitted: everything."
- Changed
get_agent_usage1 field changed- changed
Input schema / properties / id / descriptionPrevious value: -"Agent UUID or slug (from list_agents). Omit for every agent in the project."New value: +"Agent UUID or slug (from list_agents). Omitted: every agent in the project."
- Changed
get_ping_instructions1 field changed- changed
Input schema / properties / tool / descriptionPrevious value: -"Which tool's install `hook_install` carries: claude-code (the default), codex or antigravity. Everything else in the result is the same."New value: +"Which tool's install `hook_install` carries: claude-code, codex or antigravity. `hook_install` is returned only when this is set. Everything else in the result is the same."
- Changed
get_run1 field changed- changed
Input schema / properties / rid / descriptionPrevious value: -"Run id as sent on the ping."New value: +"The run id as sent on the ping."
- Changed
get_trace_setup1 field changed- changed
Input schema / properties / tool / descriptionPrevious value: -"Which tool will send the traces: claude-code, codex, gemini, antigravity, cursor, python, node, otel-sdk or collector. Omit to get every block."New value: +"Which tool sends the traces: claude-code, codex, gemini, antigravity, cursor, python, node, otel-sdk or collector. Omitted: every block."
- Changed
list_dependencies1 field changed- changed
Input schema / properties / kind / descriptionPrevious value: -"Only one kind of dependency: model, tool, http, database, queue, rpc or agent. Omit for all."New value: +"Only one kind of dependency: model, tool, http, database, queue, rpc or agent. Omitted: all."
- Changed
list_monitors1 field changed- changed
Input schema / properties / tag / descriptionPrevious value: -"Optional tag to filter by, e.g. 'agent:claude'. Returns only monitors that have this tag."New value: +"Optional tag to filter by, e.g. 'agent:claude'. Only monitors with this tag are returned."
- Changed
list_runs1 field changed- changed
Input schema / properties / traced / descriptionPrevious value: -"true: only runs that hold spans. Omit or false for every run."New value: +"true: only runs that hold spans. Omitted or false: every run."
- Changed
regenerate_api_key1 field changed- changed
Input schema / properties / api_key_id / descriptionPrevious value: -"UUID of the key to regenerate. Get it from list_api_keys."New value: +"UUID of the key to regenerate, from list_api_keys."
- Changed
register_agent1 field changed- changed
Input schema / properties / description / descriptionPrevious value: -"Optional free-text description of what this agent does. Omit for none."New value: +"Optional free-text description of what this agent does. Omitted: none."
- Changed
revoke_api_key1 field changed- changed
Input schema / properties / api_key_id / descriptionPrevious value: -"UUID of the key to revoke. Get it from list_api_keys."New value: +"UUID of the key to revoke, from list_api_keys."
- Changed
set_alert_template2 fields changed- changed
Input schema / properties / cause / descriptionPrevious value: -"Optional cause for a per-cause override (e.g. 'silence', 'overrun', 'never_started', 'stalled', 'runaway', 'upstream'). Omit or leave empty for an event-type-wide template."New value: +"Optional cause for a per-cause override (e.g. 'silence', 'overrun', 'never_started', 'stalled', 'runaway', 'upstream'). Omitted or empty: an event-type-wide template." - changed
Input schema / properties / template / descriptionPrevious value: -"Template text with {variable} placeholders. Empty string resets to the built-in default."New value: +"Template text with {variable} placeholders; an empty string resets to the built-in default. Variables: {check_name}, {event}, {status}, {cause}, {last_ping}, {schedule}, {incident_url}, {run_url}, {branch}, {commit}, {actor}, {failing_stage}, {duration}, {latency}, {status_code}, {url}, {last_step}, {step_count}, {run_duration}, {body}, {detail}, {title}. {failing_stage}: CI only; GitLab, GitHub when the webhook subscribes to workflow_job, not Jenkins. {body} is the triggering ping's text, which carries a 'blocked' or 'note' reason. {title} is the run's title (its /start body or /title), filled for 'fail', 'stalled' and 'overrun' when the run is identified; else empty."
- Changed
set_route2 fields changed- changed
Input schema / properties / channel_ids / descriptionPrevious value: -"Comma-separated destination (channel) UUIDs to notify. Empty string clears the route."New value: +"Comma-separated destination (channel) UUIDs to notify. An empty string clears the route." - changed
Input schema / properties / event_type / descriptionPrevious value: -"One of eight: down (alert opened), recovery (alert cleared), fail (explicit failure ping), every-run (one notification per completed run, success or failure), success (fires only when a run completes successfully), started (fires when a run begins), blocked (an agent reported it is waiting on a human; held 10 minutes and sent only if that run is still blocked then, at most once per blocked stretch of a run: a note, step, success, fail or cancel for the same run inside the 10 minutes cancels it, a title does not; a blocked ping sent without a run id belongs to no run, so any non-blocked ping on the monitor ends its stretch: a start, log, note, success, fail or cancel of any run, or a step of the monitor's current run (any step when no run is current); this is separate from the 'blocked' INCIDENT that opens later only if the wait outlives blocked_timeout_s, see create_monitor/update_monitor), note (a free-form annotation ping — never itself opens or clears an incident). Prefer down/recovery/fail: they fire only on a state change. every-run, success, started, and note are not state changes and are bounded only by how often the monitor runs (or how often the agent chooses to send them), so they can be very chatty, and none of them is flap-damped. started is the chattiest of the bunch for CI-fed monitors: GitHub maps both the workflow_run 'requested' and 'in_progress' webhook events to a start signal, so a single CI run can emit more than one started event — this was observed in production, where a real run logged two starts seconds apart. every-run, success, started, and note share one separate per-channel rate cap (60/hour by default), so together they can no longer use up the budget that down/fail/recovery/blocked need — but a chatty route on any one of the four can silently suppress its own notifications, and its sibling informational types' notifications, once it exceeds that shared cap. blocked is deliberately NOT in that shared group even though it is agent-reported rather than system-derived: a blocked agent needs a human, so it draws on the protected down/fail/recovery budget instead, precisely so it cannot be starved by chatty every-run/success/started/note traffic. Route informational types to a low-stakes destination, not to the one that pages someone."New value: +"down (incident opened), recovery (incident cleared), fail (failure ping), every-run (each completed run), success, started (GitHub's requested and in_progress each send one, so one CI run can notify twice), blocked (an agent awaits a human: held 10 minutes, cancelled by a ping or step of the same run in that time; sent once per blocked stretch; not the 'blocked' incident of blocked_timeout_s), note (an annotation). down, recovery and fail fire only on a state change. every-run, success, started and note share a separate per-channel rate cap (60/hour default) and are not flap-damped, so one chatty route can suppress the group; blocked draws on the protected down/fail/recovery budget."
- Changed
snooze_monitor3 fields changed- changed
Input schema / properties / clear / descriptionPrevious value: -"Set true to remove the active maintenance window."New value: +"true removes the active maintenance window." - changed
Input schema / properties / duration / descriptionPrevious value: -"Go duration string, e.g. '1h' or '24h'. Use this OR until OR clear."New value: +"Go duration string, e.g. '1h' or '24h'. One of duration, until or clear." - changed
Input schema / properties / until / descriptionPrevious value: -"RFC 3339 end timestamp. Use this OR duration OR clear."New value: +"RFC 3339 end timestamp. One of duration, until or clear."
- Changed
test_destination2 fields changed- changed
Input schema / properties / id / descriptionPrevious value: -"Destination (channel) UUID. Get it from list_destinations or create_destination."New value: +"Destination (channel) UUID, from list_destinations or create_destination." - changed
Input schema / properties / resend_verification / descriptionPrevious value: -"Set true to re-send the email confirmation link INSTEAD of a test alert. Email destinations only — any other kind returns 400. Safe to repeat, and idempotent: on an already-verified destination it reports verified and sends nothing rather than mailing the user again."New value: +"true re-sends the email confirmation link in place of a test alert. Email destinations only (any other kind returns 400). Idempotent: an already-verified destination reports verified and nothing is sent."
- Changed
update_agent2 fields changed- changed
Input schema / properties / description / descriptionPrevious value: -"Free-text description of what this agent does. Omit to leave the agent's current description unchanged — THIS IS THE DEFAULT AND SAFE CHOICE for a name-only rename. Pass an explicit empty string to clear an existing description back to none."New value: +"Free-text description of what this agent does. Omitted: unchanged. An explicit empty string clears it." - changed
Input schema / properties / slug / descriptionPrevious value: -"New slug for the agent, e.g. 'reddit-bot': 3-50 characters, lowercase letters, digits and hyphens. Omit to keep the current slug, which is the default: pass it only when the person asks to change the slug. Saved links, Terraform references and trace sources that name the old slug stop matching this agent, unless they also equal its name (case-insensitive), past traced runs included; a slug equal to a source another agent receives by name or adoption takes that source's traces."New value: +"New slug for the agent, e.g. 'reddit-bot': 3-50 characters, lowercase letters, digits and hyphens. Omitted: unchanged. After a change, references to the old slug (links, Terraform, trace sources and their past runs) stop matching this agent unless they equal its name (case-insensitive)."
- Changed
update_destination3 fields changed- changed
Input schema / properties / config / descriptionPrevious value: -"Replacement config for the destination's existing kind — one of webhook, telegram, discord, slack, ntfy, pushover, msteams, googlechat, email. Shape must match the kind: {\"url\":…,\"secret\":…} for webhook, {\"bot_token\":…,\"chat_id\":…} for telegram, {\"webhook_url\":…} for slack/discord/msteams/googlechat, {\"topic_url\":…} for ntfy, {\"token\":…,\"user_key\":…} for pushover, {\"address\":…} for email. Omit to leave unchanged. A URL you supply is re-checked against the kind's allowed hosts and must be https; a destination created before that rule keeps working until you send a new config for it. The config must name only the fields listed for its kind, each exactly once. The host rule narrows a branded destination to the vendor's own platform; it does NOT prove the endpoint belongs to the person or project that owns the destination."New value: +"Replacement config for the destination's existing kind (webhook, telegram, discord, slack, ntfy, pushover, msteams, googlechat, email), naming only that kind's fields, each once: {\"url\":…,\"secret\":…} for webhook, {\"bot_token\":…,\"chat_id\":…} for telegram, {\"webhook_url\":…} for slack/discord/msteams/googlechat, {\"topic_url\":…} for ntfy, {\"token\":…,\"user_key\":…} for pushover, {\"address\":…} for email. Omitted: unchanged. A supplied URL is re-checked against the kind's allowed hosts and has to be https; a destination created before that rule keeps working until its config is replaced. The host rule does not prove who owns the endpoint." - changed
Input schema / properties / destination_id / descriptionPrevious value: -"UUID of the destination to update. Get it from list_destinations."New value: +"UUID of the destination to update, from list_destinations." - changed
Input schema / properties / name / descriptionPrevious value: -"New human-readable label. Omit to leave unchanged."New value: +"New human-readable label. Omitted: unchanged."
- Changed
update_monitor22 fields changed- changed
Input schema / properties / agent_id / descriptionPrevious value: -"Attach this monitor to an agent from the registry, by the agent's id OR its slug (both are returned by register_agent). Omit for a monitor with no owning agent. Naming an agent that does not exist is an error — 400 UNKNOWN_AGENT — it is NEVER created implicitly; call register_agent first to get a valid agent_id. Omit to leave the monitor's current attachment (or lack of one) unchanged."New value: +"Attaches the monitor to a registered agent, by the agent's id or slug (register_agent returns both). An agent that does not exist is an error (400 UNKNOWN_AGENT); no agent is created implicitly. Omitted: the current attachment (or lack of one) is unchanged." - changed
Input schema / properties / assertions / descriptionPrevious value: -"Output assertions: conditions the ping BODY of a successful run must satisfy, checked on every success ping. This is how you catch the job that exits zero having done nothing — a backup that wrote no rows, an export that produced an empty file. When an assertion fails, the success ping opens an incident with cause 'assertion' naming the assertion that did not hold, exactly as a real failure would. Supply a JSON ARRAY as a string, e.g. '[{\"name\":\"rows written\",\"kind\":\"json_path\",\"path\":\"result.rows_processed\",\"op\":\"gt\",\"value\":\"0\"}]'. REPLACE-THE-SET: the array you send becomes the monitor's complete assertion set — it is NOT merged with what is already there. Omit the argument entirely to leave the current assertions untouched; pass '[]' to remove all of them. Fields per entry: name (required, appears in the alert), kind (required), value, path, op. kind is one of 'contains' (body contains value as a substring), 'not_contains' (body does not contain it), 'matches' (body matches value as a Go RE2 regexp, max 1000 bytes), or 'json_path' (parse the body as JSON, read the value at path, compare it against value with op). contains/not_contains/matches require value; json_path requires path and op and ignores them otherwise. path is a DOTTED path only ('a.b.c') — the query syntax of a real JSONPath library ('[', '*', '$') is rejected. op is one of 'eq', 'ne', 'gt', 'gte', 'lt', 'lte'. Comparison rule for json_path: when BOTH the value read from the body and the value you supplied parse as numbers the comparison is numeric, otherwise both sides are compared as strings — so with op 'gt', value '3' beats '12.5' lexically but loses numerically, and 'rows_processed gt 0' means what it looks like it means. At most 20 assertions per monitor. A malformed entry (uncompilable regexp, a path carrying query syntax, an unknown kind or op) is rejected before anything is written and names the offending assertion."New value: +"Output assertions: conditions a successful run's ping body has to satisfy; one that fails opens an incident with cause 'assertion' naming it. A JSON array as a string, e.g. '[{\"name\":\"rows written\",\"kind\":\"json_path\",\"path\":\"result.rows_processed\",\"op\":\"gt\",\"value\":\"0\"}]'. The array replaces the whole set; '[]' removes all, omitted leaves it. Fields: name, kind (both required), value, path, op. kind: contains, not_contains, matches (RE2, max 1000 bytes) or json_path (compares the value at a dotted path, e.g. 'a.b.c', with op: eq, ne, gt, gte, lt, lte; numeric when both sides are numbers, otherwise compared as strings). At most 20; a malformed entry is rejected by name; the set stays as is." - changed
Input schema / properties / blocked_timeout_s / descriptionPrevious value: -"Maximum seconds a run may sit in the 'blocked' state (an agent reported it is waiting on a human) before a 'blocked' incident opens. UNSET DOES NOT MEAN WAIT FOREVER: omitting this does not disable the timeout, it falls back to the default, which is 24 HOURS — an agent still blocked 24 hours after reporting so, with this field never set, gets a 'blocked' incident regardless. Lower it to be paged sooner when a stuck approval is urgent; raise it for work that legitimately waits on a human for longer than a day. This is distinct from the non-incident 'blocked' notification a route on the 'blocked' event type delivers (see set_route), which is held 10 minutes and sent only if the run is still blocked then, at most once per blocked stretch of a run; this field governs the separate incident that opens only if the wait outlives the timeout. Accepted on every monitor_type: unlike max_runtime_s/step_timeout_s it has no run-scoped precondition an http monitor could fail, so there is nothing to reject. Omit to leave the monitor's current value unchanged; pass 0 to clear it and fall back to the 24h default."New value: +"Seconds a run may stay 'blocked' (an agent reported it is waiting on a human) before a 'blocked' incident opens. Unset means the 24-hour default, not no limit. Separate from the 'blocked' notification a route delivers (held 10 minutes, sent at most once per blocked stretch of a run). Accepted on every monitor_type. Omitted: unchanged; 0 clears it (the 24h default applies)." - changed
Input schema / properties / ci_branch / descriptionPrevious value: -"CI filter: only count runs on this branch, e.g. 'main'. REQUIRES ci_provider, and the API enforces it: without a CI binding the request is refused with 400 FIELD_NOT_IN_SHAPE rather than accepted and discarded. Subject to the SAME upsert exception as ci_workflow — create_monitor on an existing slug never writes this filter; use update_monitor. WITHOUT IT a run on ANY branch — a feature branch, a fork's pull request — reports to this monitor, so somebody else's broken branch marks your monitor down. Set it to the branch whose health you actually care about, which is almost always the default branch. Omit to leave the current filter unchanged; pass an explicit JSON null to remove it. An EMPTY STRING also leaves it unchanged — that is a deliberate API compatibility rule, not a bug, so an empty string cannot be used to clear the filter."New value: +"CI filter: only runs on this branch count, e.g. 'main'. Needs ci_provider (400 FIELD_NOT_IN_SHAPE without a CI binding). Same upsert exception as ci_workflow: create_monitor on an existing slug never writes it; update_monitor does. Unset, a run on any branch, a fork's pull request included, reports to the monitor. Omitted or an empty string (an API compatibility rule): unchanged; an explicit JSON null removes the filter." - changed
Input schema / properties / ci_workflow / descriptionPrevious value: -"CI filter: only count runs of the workflow / pipeline / job with this exact name. REQUIRES ci_provider, and the API enforces it: without a CI binding this filter has nowhere to be stored, so the request is refused with 400 FIELD_NOT_IN_SHAPE rather than accepted and discarded. Note that monitor_type='ci' does NOT bind anything on its own — ci_provider does. ONE EXCEPTION, and it is on the path agents use most, so do not rely on the enforcement here: create_monitor on a slug that ALREADY EXISTS is an upsert, and the upsert never writes this filter. With ci_provider in the same call the request is accepted and the filter is silently discarded; without it the request is refused, and doing what the error advises — adding ci_provider — reaches the discarding case instead. Set this filter with update_monitor, which does persist it. WITHOUT IT, EVERY workflow in the repository reports to this monitor — so one unrelated failing workflow opens an incident against a job that is perfectly healthy, and a green run of a different workflow clears an incident the real job never recovered from. Set it whenever the repository has more than one workflow. Omit to leave the current filter unchanged; pass an explicit JSON null to remove it. An EMPTY STRING also leaves it unchanged — that is a deliberate API compatibility rule, not a bug, so an empty string cannot be used to clear the filter."New value: +"CI filter: only runs of the workflow, pipeline or job with this exact name count. Needs ci_provider: without a CI binding it is refused with 400 FIELD_NOT_IN_SHAPE (monitor_type='ci' alone binds nothing). Exception: create_monitor on an existing slug (an upsert) never writes it, and with ci_provider in the same call it is accepted and discarded; update_monitor persists it. Unset, every workflow in the repository reports to the monitor, so an unrelated workflow's failure opens an incident and its success clears one. Omitted or an empty string (an API compatibility rule): unchanged; an explicit JSON null removes the filter." - changed
Input schema / properties / expect_every_s / descriptionPrevious value: -"SILENCE FLOOR in seconds: open a 'silence' incident if NO ping of any kind — success, start, fail, step — has arrived within this window, regardless of the schedule. It is anchored on the monitor's last activity, not on a cadence, which is what makes it the ONLY absence rule an 'on_demand' monitor can have: that schedule_kind arms nothing between runs, so without this field an on_demand monitor reads 'up' forever no matter how long the agent stays dark. Set it on any on_demand agent monitor you would be alarmed to find silent — that is what it is for. It does NOT fire mid-run: while a run is in flight (a start ping is outstanding) the floor stands down entirely and the run clock owns detection (max_runtime_s, step_timeout_s), so a legitimate 4-hour run that reports nothing is still not an incident. A 'blocked' ping also pauses it, bounded by blocked_timeout_s. On 'simple'/'cron' monitors it is a backstop rather than the main rule: it joins the existing deadline as whichever is SOONER, so it can tighten detection under a long cadence (a daily cron has a ~25-hour blind window) but can never loosen it. Default: unset, which means no floor and is exactly how every monitor behaved before this field existed. Range 60-31536000. Accepted on every monitor_type and every schedule_kind. Omit to leave the monitor's current value unchanged; pass 0 to clear it and turn the silence floor off."New value: +"Silence floor in seconds: a 'silence' incident opens when no ping of any kind (success, start, fail, step) arrives within this window, timed from the monitor's last activity. It is the only absence rule an 'on_demand' monitor has. It stands down while a run is in flight (the run clock owns that), and a 'blocked' ping pauses it up to blocked_timeout_s. On 'simple'/'cron' monitors it joins the schedule deadline as whichever is sooner, so it can only tighten detection. Unset (default): no floor. Range 60-31536000. Accepted on every monitor_type and schedule_kind. Omitted: unchanged; 0 clears it and turns the silence floor off." - changed
Input schema / properties / failure_threshold / descriptionPrevious value: -"Number of consecutive failures required before an incident opens. Default 1 (open on the very first failure). This is how you stop a single transient blip from paging someone: set 2-5 on a job that fails occasionally for reasons that resolve themselves, and no incident opens until that many runs in a row have failed. Any success resets the count to zero. It gates the 'fail' cause ONLY — silence (a missed ping), overrun, never_started and runaway are time- or rate-based, so a consecutive count means nothing for them and they are never delayed by it. A run that ends on the model provider's API error (server_error, overloaded, rate_limit) neither counts toward it nor resets it: those open an 'upstream' incident once 3 runs in a row end that way, or this many when it is higher. Range 1-100. Omit to leave the monitor's current threshold unchanged."New value: +"Consecutive failures required before an incident opens; default 1 (the first failure). 2-5 absorbs a job's occasional self-resolving failure. Any success resets the count. It gates only the 'fail' cause: silence, overrun, never_started and runaway are time- or rate-based and never delayed by it. A run ending on the model provider's API error (server_error, overloaded, rate_limit) neither counts nor resets it; 3 such runs in a row, or this many when higher, open an 'upstream' incident. Range 1-100. Omitted: unchanged." - changed
Input schema / properties / guards / descriptionPrevious value: -"Metric guards: CEILINGS on a number the job reports about itself, checked on every ping. An assertion catches a run that did nothing; a guard catches the opposite — an agent that loops, retries and burns money. Each guard reads one number out of the ping body at a dotted path, rolls it up across a trailing window, and opens an incident with cause 'runaway' when the total EXCEEDS the ceiling (equal does not trip). Supply a JSON ARRAY as a string, e.g. '[{\"name\":\"daily spend\",\"path\":\"cost.usd\",\"window_s\":86400,\"ceiling\":50,\"aggregation\":\"sum\"}]'. REPLACE-THE-SET: the array you send becomes the monitor's complete guard set — it is NOT merged with what is already there. Omit the argument entirely to leave the current guards untouched; pass '[]' to remove all of them. Fields per entry, all required: name (appears on the incident, and is the only thing that tells a tripped guard apart from the fixed pings-per-hour runaway ceiling), path (DOTTED path into the ping body parsed as JSON — 'cost.usd'; the query syntax of a real JSONPath library ('[', '*', '$') is rejected, exactly as for an assertion's path), window_s (trailing window in seconds), ceiling (number), aggregation (one of 'sum', 'max', 'avg'). Pings whose body is missing, is not JSON, or carries nothing numeric at that path are SKIPPED, not counted as zero — so a `start` ping never drags an average down. At most 5 guards per monitor, and window_s at most 604800 seconds (7 days). Both caps are cost, not policy: a guard re-aggregates every ping body in its window on every ping, so the per-ping work is linear in BOTH the window and the number of guards (measured: 4.2 ms/ping at a 1-hour window, 390 ms/ping at 30 days). A window longer than the 90-day ping retention would also aggregate over already-pruned rows and quietly under-report. A malformed entry is rejected before anything is written and names the offending guard."New value: +"Metric guards: ceilings on a number the job reports, checked on every ping; a total above the ceiling (equal does not trip) opens a 'runaway' incident. A JSON array as a string, e.g. '[{\"name\":\"daily spend\",\"path\":\"cost.usd\",\"window_s\":86400,\"ceiling\":50,\"aggregation\":\"sum\"}]'. The array replaces the whole set; '[]' removes all, omitted leaves it. Every entry needs name, path (dotted), window_s (trailing seconds), ceiling and aggregation ('sum', 'max' or 'avg'). Pings with no number at the path are skipped, not counted as zero. At most 5 guards, window_s at most 604800 (7 days); a malformed entry is rejected by name; the set stays as is." - changed
Input schema / properties / max_runtime_s / descriptionPrevious value: -"Maximum seconds a single run may take before it is reported overdue (the 'overrun' rule), measured from the run's start ping. Omit to fall back to grace_s. This is how a long job avoids being flagged overdue while still being detected quickly if it goes silent: e.g. grace_s=600 with max_runtime_s=14400 alerts 10 minutes after a missed ping but tolerates a 4-hour run. It replaces grace_s for the overrun deadline ONLY — the silence rule and the first-run deadline still use grace_s. Range 60-31536000. Not supported on http monitors: a probe has no start/success pair, so the overrun rule can never fire and the API returns 400 MAX_RUNTIME_NOT_SUPPORTED (use probe_timeout_s to bound a single probe). Omit to leave the monitor's current value unchanged; pass 0 to clear it and fall back to grace_s."New value: +"Maximum seconds one run may take, from its start ping, before it is reported overdue (the 'overrun' rule). Unset falls back to grace_s. Example: grace_s=600 with max_runtime_s=14400 alerts 10 minutes after a missed ping but tolerates a 4-hour run. It replaces grace_s for the overrun deadline only; the silence rule and the first-run deadline still use grace_s. Range 60-31536000. Not supported on http monitors (400 MAX_RUNTIME_NOT_SUPPORTED); probe_timeout_s bounds a probe. Omitted: unchanged; 0 clears it (falls back to grace_s)." - changed
Input schema / properties / monitor_from / descriptionPrevious value: -"DORMANT UNTIL: an RFC 3339 timestamp before which no deadline is computed and no incident can open — the monitor is fully configured but not yet armed. Use it when you provision ahead of the work: a monitor for a job that does not start running until next Monday is otherwise 'late' from the moment you create it, which is a false alert on day one. The first-run deadline is seeded as monitor_from + grace_s. Default: unset, meaning deadlines start immediately. Example: '2026-01-01T00:00:00Z'. Omit to leave the monitor's current value unchanged."New value: +"Dormant until: an RFC 3339 timestamp before which no deadline is computed and no incident opens, for a monitor provisioned ahead of its job. The first-run deadline is monitor_from + grace_s. Unset (default): deadlines start immediately. Example: '2026-01-01T00:00:00Z'. Omitted: unchanged." - changed
Input schema / properties / notify_min_run_s / descriptionPrevious value: -"NOTIFICATION DURATION FLOOR in seconds: a run SHORTER than this does not produce an INFO-CLASS notification (success, started, every-run, note). This exists for exactly one problem: on an agent monitor, one run is one task you asked for, so asking the agent 'what's 2+2' produces a start and a success notification exactly like a 56-minute deploy does. If you have routed success/started/every-run/note to a destination, you WILL be paged for trivial runs unless you set this. IT NEVER SUPPRESSES A FAILURE. down, fail, recovery and blocked are alert-class and are never affected by this field, however short the run — a run that failed in two seconds is exactly what you need to hear about, and this field cannot silence that, structurally, no matter how it is set. It also never suppresses 'started': a run's duration does not exist yet the moment it begins, so started is always reported regardless of this floor. And it never suppresses an event whose duration could not be measured at all (e.g. a bare success with no preceding start ping) — an unknown duration always means 'notify', never 'suppress'. Default: unset, which means no floor and is exactly how every monitor behaved before this field existed. Range 60-31536000. Not supported on http monitors: an http probe has no start/success pair, so its run duration is never measured and the floor could never apply (the API returns 400 NOTIFY_MIN_RUN_NOT_SUPPORTED). Omit to leave the monitor's current value unchanged; pass 0 to clear it and turn the notification duration floor off."New value: +"Notification duration floor in seconds: a run shorter than this sends no info-class notification (success, every-run, note), so a trivial agent run does not notify a destination those events are routed to. It never suppresses a failure: down, fail, recovery, blocked and started always notify, as does an event whose duration was not measured (such as a success with no start ping). Unset (default): no floor. Range 60-31536000. Not supported on http monitors (400 NOTIFY_MIN_RUN_NOT_SUPPORTED). Omitted: unchanged; 0 clears it and turns the floor off." - changed
Input schema / properties / probe_expected_body / descriptionPrevious value: -"http monitors only: a substring that MUST appear in the response body for the probe to count as healthy. THIS IS THE DIFFERENCE BETWEEN 'the server answered' AND 'the app works': a broken app that renders an error page still returns 200, passes a status-only check, and leaves the monitor green. Match on something only a healthy response contains, e.g. '\"status\":\"ok\"'. Substring match, not a regex, and case-sensitive. Default: empty, meaning the body is not inspected at all. Omit to leave unchanged; pass an explicit JSON null to stop inspecting the body. An empty string leaves it unchanged, so it cannot be cleared that way."New value: +"http monitors only: a substring the response body has to contain for the probe to pass, e.g. '\"status\":\"ok\"'. A broken app's error page can still return 200 and pass a status-only check; this catches it. Case-sensitive substring, not a regex. Default empty: the body is not inspected. Omitted or an empty string: unchanged; an explicit JSON null stops inspecting the body." - changed
Input schema / properties / probe_expected_status / descriptionPrevious value: -"http monitors only: the EXACT HTTP status code that counts as healthy. Default 200; any other code fails the probe. Set it when the healthy answer is not 200 — 204 for a no-content health endpoint, or 301 when what you are checking is that a redirect still exists (pair that with probe_follow_redirects=false, or the probe will follow it and see the destination's status instead). Omit to leave unchanged."New value: +"http monitors only: the exact HTTP status that counts as healthy; default 200, any other code fails the probe. E.g. 204 for a no-content endpoint, or 301 to check that a redirect still exists (with probe_follow_redirects=false; otherwise the probe sees the destination's status). Omitted: unchanged." - changed
Input schema / properties / probe_follow_redirects / descriptionPrevious value: -"http monitors only: whether the probe follows 3xx redirects. Default false. Leaving it false is usually what you want: the redirect itself is then compared against probe_expected_status like any other response, so a site that starts redirecting to a login wall, a parking page or an outage notice is CAUGHT rather than silently followed to a healthy-looking 200. Set true only when the URL you are checking is legitimately a redirect to the thing you actually care about. Omit to leave unchanged; pass false to turn following back off."New value: +"http monitors only: whether the probe follows 3xx redirects; default false. When false, the redirect itself is compared with probe_expected_status, so a site that starts redirecting to a login wall or a parking page fails the probe instead of passing on the destination's 200. Omitted: unchanged; false turns following back off." - changed
Input schema / properties / probe_interval_s / descriptionPrevious value: -"http monitors only: how often to probe, in seconds. Required when monitor_type='http'. Range 30-86400. Omit to leave unchanged."New value: +"http monitors only: how often to probe, in seconds. Required when monitor_type='http'. Range 30-86400. Omitted: unchanged." - changed
Input schema / properties / probe_method / descriptionPrevious value: -"http monitors only: the HTTP method the probe sends. One of 'GET', 'HEAD', 'POST'. Default 'GET'. Use 'HEAD' for a cheap liveness check when the body does not matter — but note it returns no body, so probe_expected_body cannot match anything. Omit to leave unchanged."New value: +"http monitors only: the HTTP method the probe sends: 'GET' (default), 'HEAD' or 'POST'. 'HEAD' returns no body, so probe_expected_body cannot match with it. Omitted: unchanged." - changed
Input schema / properties / probe_timeout_s / descriptionPrevious value: -"http monitors only: how many seconds a single probe may take before it counts as a failure. Range 1-30, default 10. This is the http equivalent of max_runtime_s, which http monitors reject: it is the only way to say 'answering, but far too slowly to be healthy'. Omit to leave unchanged."New value: +"http monitors only: seconds one probe may take before it counts as a failure. Range 1-30, default 10. The http counterpart of max_runtime_s, which http monitors reject. Omitted: unchanged." - changed
Input schema / properties / probe_url / descriptionPrevious value: -"http monitors only: the absolute http/https URL to probe. Required when monitor_type='http'. The host is resolved at write time and rejected if it resolves only to private/link-local addresses. Omit to leave unchanged."New value: +"http monitors only: the absolute http/https URL to probe. Required when monitor_type='http'. The host is resolved at write time and rejected if it resolves only to private/link-local addresses. Omitted: unchanged." - changed
Input schema / properties / runaway_ceiling / descriptionPrevious value: -"PING-RATE CEILING: the maximum number of pings this monitor may receive in a rolling one-hour window. Exceeding it opens a 'runaway' incident. This is the rule that catches a job or agent stuck in a LOOP — the failure every other rule misses, because a looping agent is pinging enthusiastically and therefore reads 'up' the whole time it is burning tokens or money. Set it a little above the monitor's real cadence: a job that runs every 15 minutes sends about 4 pings/hour, so 20 absorbs retries and still catches a loop. It is RATE-based, so failure_threshold does not gate it and neither does any run budget. Default: unset, which disables the runaway rule entirely. Omit to leave the monitor's current value unchanged; pass 0 to clear it and turn the runaway rule off."New value: +"Ping-rate ceiling: the most pings this monitor may receive in a rolling hour; exceeding it opens a 'runaway' incident. It catches a job or agent stuck in a loop, which keeps pinging and otherwise reads 'up'. A job every 15 minutes sends about 4 pings an hour, so 20 leaves room for retries. Rate-based: failure_threshold and run budgets do not gate it. Unset (default): the rule is off. Omitted: unchanged; 0 clears it and turns the runaway rule off." - changed
Input schema / properties / schedule_kind / descriptionPrevious value: -"'simple', 'cron', or 'on_demand'. NOT ACCEPTED on an http monitor, together with period_s, cron_expr and tz: its schedule is derived from probe_interval_s, so the API refuses all four with 400 FIELD_NOT_IN_SHAPE. 'on_demand' means no cadence at all: no period_s, no cron_expr — the API returns 400 if either is supplied — and, by default, NO ABSENCE DEADLINES ARE ARMED BETWEEN RUNS. What this trades away: nothing tells you if the agent is never invoked again; silence between runs is invisible unless you opt in to expect_every_s. What it buys: a healthy agent that nobody happens to invoke for a week never generates a false 'late' or 'down' for simply not having been asked to run. Only run-scoped detection still applies once a run starts — max_runtime_s (overrun), step_timeout_s (stall), blocked_timeout_s (stuck on a human) — because those are anchored to a run's own start ping, not to a cadence. IMPORTANT: if you would be alarmed to find this agent silent for hours, set expect_every_s as well — it is the silence floor, and it is the only thing that makes an on_demand monitor detect absence at all. Choose 'simple'/'cron' when the agent is supposed to run on a cadence; choose 'on_demand' when invocation is inherently irregular and a quiet stretch between runs is expected, not a symptom."New value: +"'simple', 'cron' or 'on_demand'. Not accepted on an http monitor, and neither are period_s, cron_expr and tz: its schedule comes from probe_interval_s (400 FIELD_NOT_IN_SHAPE). 'on_demand' has no cadence (period_s or cron_expr with it is a 400) and arms no absence deadline between runs: an agent that is never invoked again raises nothing unless expect_every_s is set, and an idle healthy agent never raises a false 'late'. Once a run starts, max_runtime_s, step_timeout_s and blocked_timeout_s still apply. 'simple'/'cron' fit work on a cadence; 'on_demand' fits irregular invocation." - changed
Input schema / properties / step_timeout_s / descriptionPrevious value: -"Progress budget in seconds: how long an armed run may go without reporting a step before a 'stalled' incident opens (the stall rule). The clock is anchored on the LATER of the run's start ping and its most recent step, so a run that wedges before its first step is caught too. Reach for this when 'still running' and 'still making progress' are different things — a long agent loop, a multi-stage pipeline, a migration. max_runtime_s alone tells you nothing until the whole budget expires; step_timeout_s=300 on a 4-hour budget tells you within five minutes, and names the last step that reported. To use it the run must report steps: call get_ping_instructions and use curl_step (POST <ping_url>/step?rid=<run-id>&step=<name>). A monitor with step_timeout_s set whose job never reports a step will open a stalled incident on EVERY run — set the field and instrument the job in the same change. Stall detection needs your job to call /step: the Claude Code hook and the reporting prompt do not send steps, so leave step_timeout_s unset for them. Default: unset, which disables stall detection entirely; a monitor that sets nothing behaves exactly as it did before this field existed. Range 10-86400. Two constraints. (1) It must be strictly LESS than the effective run budget, COALESCE(max_runtime_s, grace_s), or the API returns 400 STEP_TIMEOUT_EXCEEDS_BUDGET — at or above the budget the run overruns first, so the stall rule could never fire. (2) Not supported on http monitors: a probe never arms a run and has no /step endpoint to call, so the API returns 400 STEP_TIMEOUT_NOT_SUPPORTED. A step resets the stall clock ONLY — it never extends max_runtime_s, so an agent that reports progress forever still overruns. Omit to leave the monitor's current value unchanged; pass 0 to clear it and disable stall detection."New value: +"Seconds an armed run may go without a step before a 'stalled' incident opens, timed from the later of its start ping and its latest step. Steps are POST <ping_url>/step?rid=<run-id>&step=<name> (curl_step in get_ping_instructions). When set, a job that sends no steps opens a stalled incident on every run. The Claude Code hook and the reporting prompt send no steps. Unset (default): no stall detection. Range 10-86400, strictly below COALESCE(max_runtime_s, grace_s) (400 STEP_TIMEOUT_EXCEEDS_BUDGET). Not supported on http monitors (400 STEP_TIMEOUT_NOT_SUPPORTED). A step never extends max_runtime_s. Omitted: unchanged; 0 clears it and turns stall detection off." - changed
Input schema / properties / trace_content / descriptionPrevious value: -"What this monitor's traces keep of prompt, command and tool content. 'dropped' (the default) removes it; 'redacted' keeps it, with every secret-shaped value redacted when it arrives. Only a person should choose 'redacted': never set it on your own initiative, only when the person you work for has asked for content to be stored. Omit to leave the monitor's current value unchanged."New value: +"What this monitor's traces keep of prompt, command and tool content: 'dropped' (the default) removes it; 'redacted' stores prompt, command and tool content from the traced sessions, with secret-shaped values redacted on arrival. Omitted: unchanged."
- Changed
update_status_page4 fields changed- changed
Input schema / properties / check_ids / descriptionPrevious value: -"Comma-separated monitor UUIDs to show on the page, in no particular order. Get them from list_monitors. Every id must belong to this project — an unknown or cross-project id returns 400 and nothing is saved. An empty value is legal and produces a page with no monitors on it. REPLACES the page's whole monitor set. Omit to leave the current set alone."New value: +"Comma-separated monitor UUIDs to show on the page, in no particular order, from list_monitors. Every id has to belong to this project: an unknown or cross-project id returns 400 and nothing is saved. An empty value is legal and produces a page with no monitors. Replaces the page's whole monitor set. Omitted: unchanged." - changed
Input schema / properties / slug / descriptionPrevious value: -"New URL slug. Omit to leave unchanged — which is almost always right, because changing it breaks every link already handed out. Same format rules and same global uniqueness as on create; a taken slug returns 409."New value: +"New URL slug. Omitted: unchanged. A change breaks every link already handed out. Same format and global uniqueness as on create; a taken slug returns 409." - changed
Input schema / properties / title / descriptionPrevious value: -"New page title. Omit to leave unchanged."New value: +"New page title. Omitted: unchanged." - changed
Input schema / properties / visibility / descriptionPrevious value: -"'private' (default) or 'public'. 'public' means the page is served at a guessable-free but UNAUTHENTICATED URL: anyone with the link sees the title, the name of every monitor on it, and its up/down history. Monitor names are frequently internal ('billing-reconciler', 'acme-corp-nightly-sync'), so treat this as publishing them. Choose 'private' unless the user has actually asked for a page other people can see. The free tier allows exactly ONE public page per project; a second returns 403. Omit to leave unchanged. Switching a page from private to public publishes every monitor name already on it."New value: +"'private' (default) or 'public'. A public page is served at an unguessable but unauthenticated URL: anyone with the link sees the title, every monitor's name (often internal, such as 'billing-reconciler') and its up/down history. The free tier allows one public page per project; a second returns 403. Omitted: unchanged. Switching to 'public' publishes every monitor name already on the page."
2 tool updates
v0.1.16- Changed
get_ping_instructions2 fields changed- changed
Input schema / properties / tool / descriptionPrevious value: -"Which tool's install `hook_install` carries: claude-code (the default) or codex. Everything else in the result is the same."New value: +"Which tool's install `hook_install` carries: claude-code (the default), codex or antigravity. Everything else in the result is the same." - changed
Input schema / properties / tool / enumPrevious value: -[ - "claude-code", - "codex" -]New value: +[ + "claude-code", + "codex", + "antigravity" +]
- Changed
get_trace_setup2 fields changed- changed
Input schema / properties / tool / descriptionPrevious value: -"Which tool will send the traces: claude-code, codex, gemini, cursor, python, node, otel-sdk or collector. Omit to get every block."New value: +"Which tool will send the traces: claude-code, codex, gemini, antigravity, cursor, python, node, otel-sdk or collector. Omit to get every block." - changed
Input schema / properties / tool / enumPrevious value: -[ - "claude-code", - "codex", - "gemini", - "cursor", - "python", - "node", - "otel-sdk", - "collector" -]New value: +[ + "claude-code", + "codex", + "gemini", + "antigravity", + "cursor", + "python", + "node", + "otel-sdk", + "collector" +]
8 tool updates
v0.1.9- Changed
create_monitor3 fields changed- changed
Input schema / properties / blocked_timeout_s / descriptionPrevious value: -"Maximum seconds a run may sit in the 'blocked' state (an agent reported it is waiting on a human) before a 'blocked' incident opens. UNSET DOES NOT MEAN WAIT FOREVER: omitting this does not disable the timeout, it falls back to the default, which is 24 HOURS — an agent still blocked 24 hours after reporting so, with this field never set, gets a 'blocked' incident regardless. Lower it to be paged sooner when a stuck approval is urgent; raise it for work that legitimately waits on a human for longer than a day. This is distinct from the immediate, non-incident 'blocked' notification a route on the 'blocked' event type delivers the moment the agent reports it (see set_route) — that fires right away; this field governs the separate incident that opens only if the wait outlives the timeout. Accepted on every monitor_type: unlike max_runtime_s/step_timeout_s it has no run-scoped precondition an http monitor could fail, so there is nothing to reject. On an upsert (existing slug), omitting this clears the monitor's blocked_timeout_s and falls back to the 24h default — pass the current value to keep it."New value: +"Maximum seconds a run may sit in the 'blocked' state (an agent reported it is waiting on a human) before a 'blocked' incident opens. UNSET DOES NOT MEAN WAIT FOREVER: omitting this does not disable the timeout, it falls back to the default, which is 24 HOURS — an agent still blocked 24 hours after reporting so, with this field never set, gets a 'blocked' incident regardless. Lower it to be paged sooner when a stuck approval is urgent; raise it for work that legitimately waits on a human for longer than a day. This is distinct from the non-incident 'blocked' notification a route on the 'blocked' event type delivers (see set_route), which is held 10 minutes and sent only if the run is still blocked then, at most once per blocked stretch of a run; this field governs the separate incident that opens only if the wait outlives the timeout. Accepted on every monitor_type: unlike max_runtime_s/step_timeout_s it has no run-scoped precondition an http monitor could fail, so there is nothing to reject. On an upsert (existing slug), omitting this clears the monitor's blocked_timeout_s and falls back to the 24h default — pass the current value to keep it." - changed
Input schema / properties / failure_threshold / descriptionPrevious value: -"Number of consecutive failures required before an incident opens. Default 1 (open on the very first failure). This is how you stop a single transient blip from paging someone: set 2-5 on a job that fails occasionally for reasons that resolve themselves, and no incident opens until that many runs in a row have failed. Any success resets the count to zero. It gates the 'fail' cause ONLY — silence (a missed ping), overrun, never_started and runaway are time- or rate-based, so a consecutive count means nothing for them and they are never delayed by it. Range 1-100. On an upsert (existing slug), omitting this resets the monitor's threshold to 1 — pass the current value to keep it."New value: +"Number of consecutive failures required before an incident opens. Default 1 (open on the very first failure). This is how you stop a single transient blip from paging someone: set 2-5 on a job that fails occasionally for reasons that resolve themselves, and no incident opens until that many runs in a row have failed. Any success resets the count to zero. It gates the 'fail' cause ONLY — silence (a missed ping), overrun, never_started and runaway are time- or rate-based, so a consecutive count means nothing for them and they are never delayed by it. A run that ends on the model provider's API error (server_error, overloaded, rate_limit) neither counts toward it nor resets it: those open an 'upstream' incident once 3 runs in a row end that way, or this many when it is higher. Range 1-100. On an upsert (existing slug), omitting this resets the monitor's threshold to 1 — pass the current value to keep it." - changed
Input schema / properties / step_timeout_s / descriptionPrevious value: -"Progress budget in seconds: how long an armed run may go without reporting a step before a 'stalled' incident opens (the stall rule). The clock is anchored on the LATER of the run's start ping and its most recent step, so a run that wedges before its first step is caught too. Reach for this when 'still running' and 'still making progress' are different things — a long agent loop, a multi-stage pipeline, a migration. max_runtime_s alone tells you nothing until the whole budget expires; step_timeout_s=300 on a 4-hour budget tells you within five minutes, and names the last step that reported. To use it the run must report steps: call get_ping_instructions and use curl_step (POST <ping_url>/step?rid=<run-id>&step=<name>). A monitor with step_timeout_s set whose job never reports a step will open a stalled incident on EVERY run — set the field and instrument the job in the same change. Default: unset, which disables stall detection entirely; a monitor that sets nothing behaves exactly as it did before this field existed. Range 10-86400. Two constraints. (1) It must be strictly LESS than the effective run budget, COALESCE(max_runtime_s, grace_s), or the API returns 400 STEP_TIMEOUT_EXCEEDS_BUDGET — at or above the budget the run overruns first, so the stall rule could never fire. (2) Not supported on http monitors: a probe never arms a run and has no /step endpoint to call, so the API returns 400 STEP_TIMEOUT_NOT_SUPPORTED. A step resets the stall clock ONLY — it never extends max_runtime_s, so an agent that reports progress forever still overruns. On an upsert (existing slug), omitting this clears the monitor's step_timeout_s and turns stall detection back off — pass the current value to keep it."New value: +"Progress budget in seconds: how long an armed run may go without reporting a step before a 'stalled' incident opens (the stall rule). The clock is anchored on the LATER of the run's start ping and its most recent step, so a run that wedges before its first step is caught too. Reach for this when 'still running' and 'still making progress' are different things — a long agent loop, a multi-stage pipeline, a migration. max_runtime_s alone tells you nothing until the whole budget expires; step_timeout_s=300 on a 4-hour budget tells you within five minutes, and names the last step that reported. To use it the run must report steps: call get_ping_instructions and use curl_step (POST <ping_url>/step?rid=<run-id>&step=<name>). A monitor with step_timeout_s set whose job never reports a step will open a stalled incident on EVERY run — set the field and instrument the job in the same change. Stall detection needs your job to call /step: the Claude Code hook and the reporting prompt do not send steps, so leave step_timeout_s unset for them. Default: unset, which disables stall detection entirely; a monitor that sets nothing behaves exactly as it did before this field existed. Range 10-86400. Two constraints. (1) It must be strictly LESS than the effective run budget, COALESCE(max_runtime_s, grace_s), or the API returns 400 STEP_TIMEOUT_EXCEEDS_BUDGET — at or above the budget the run overruns first, so the stall rule could never fire. (2) Not supported on http monitors: a probe never arms a run and has no /step endpoint to call, so the API returns 400 STEP_TIMEOUT_NOT_SUPPORTED. A step resets the stall clock ONLY — it never extends max_runtime_s, so an agent that reports progress forever still overruns. On an upsert (existing slug), omitting this clears the monitor's step_timeout_s and turns stall detection back off — pass the current value to keep it."
- Changed
get_agent_usage1 field changed- added
Input schema / properties / projectAdded value: +{ + "description": "Only usage from traced runs of this project; metrics-only usage has no project and is left out. days then hold one row per UTC day with model and provider empty (a run's totals are not split by model); by_agent is not narrowed.", + "type": "string" +}
- Changed
get_ping_instructions1 field changed- added
Input schema / properties / toolAdded value: +{ + "description": "Which tool's install `hook_install` carries: claude-code (the default) or codex. Everything else in the result is the same.", + "enum": [ + "claude-code", + "codex" + ], + "type": "string" +}
- Changed
list_runs2 fields changed- changed
Input schema / properties / min_cost_usd / descriptionPrevious value: -"Only runs whose estimated cost is at least this many US dollars, as a decimal string, e.g. \"0.25\"."New value: +"Only runs whose cost is at least this many US dollars, as a decimal string, e.g. \"0.25\"." - added
Input schema / properties / projectAdded value: +{ + "description": "Only runs whose Claude Code hook start carried this project label: the name of the folder the session worked in.", + "type": "string" +}
- Changed
set_alert_template1 field changed- changed
Input schema / properties / cause / descriptionPrevious value: -"Optional cause for a per-cause override (e.g. 'silence', 'overrun', 'never_started', 'stalled', 'runaway'). Omit or leave empty for an event-type-wide template."New value: +"Optional cause for a per-cause override (e.g. 'silence', 'overrun', 'never_started', 'stalled', 'runaway', 'upstream'). Omit or leave empty for an event-type-wide template."
- Changed
set_route1 field changed- changed
Input schema / properties / event_type / descriptionPrevious value: -"One of eight: down (alert opened), recovery (alert cleared), fail (explicit failure ping), every-run (one notification per completed run, success or failure), success (fires only when a run completes successfully), started (fires when a run begins), blocked (an agent reported it is waiting on a human — fires immediately, the moment the ping arrives; this is separate from the 'blocked' INCIDENT that opens later only if the wait outlives blocked_timeout_s, see create_monitor/update_monitor), note (a free-form annotation ping — never itself opens or clears an incident). Prefer down/recovery/fail: they fire only on a state change. every-run, success, started, and note are not state changes and are bounded only by how often the monitor runs (or how often the agent chooses to send them), so they can be very chatty, and none of them is flap-damped. started is the chattiest of the bunch for CI-fed monitors: GitHub maps both the workflow_run 'requested' and 'in_progress' webhook events to a start signal, so a single CI run can emit more than one started event — this was observed in production, where a real run logged two starts seconds apart. every-run, success, started, and note share one separate per-channel rate cap (60/hour by default), so together they can no longer use up the budget that down/fail/recovery/blocked need — but a chatty route on any one of the four can silently suppress its own notifications, and its sibling informational types' notifications, once it exceeds that shared cap. blocked is deliberately NOT in that shared group even though it is agent-reported rather than system-derived: a blocked agent needs a human, so it draws on the protected down/fail/recovery budget instead, precisely so it cannot be starved by chatty every-run/success/started/note traffic. Route informational types to a low-stakes destination, not to the one that pages someone."New value: +"One of eight: down (alert opened), recovery (alert cleared), fail (explicit failure ping), every-run (one notification per completed run, success or failure), success (fires only when a run completes successfully), started (fires when a run begins), blocked (an agent reported it is waiting on a human; held 10 minutes and sent only if that run is still blocked then, at most once per blocked stretch of a run: a note, step, success, fail or cancel for the same run inside the 10 minutes cancels it, a title does not; a blocked ping sent without a run id belongs to no run, so any non-blocked ping on the monitor ends its stretch: a start, log, note, success, fail or cancel of any run, or a step of the monitor's current run (any step when no run is current); this is separate from the 'blocked' INCIDENT that opens later only if the wait outlives blocked_timeout_s, see create_monitor/update_monitor), note (a free-form annotation ping — never itself opens or clears an incident). Prefer down/recovery/fail: they fire only on a state change. every-run, success, started, and note are not state changes and are bounded only by how often the monitor runs (or how often the agent chooses to send them), so they can be very chatty, and none of them is flap-damped. started is the chattiest of the bunch for CI-fed monitors: GitHub maps both the workflow_run 'requested' and 'in_progress' webhook events to a start signal, so a single CI run can emit more than one started event — this was observed in production, where a real run logged two starts seconds apart. every-run, success, started, and note share one separate per-channel rate cap (60/hour by default), so together they can no longer use up the budget that down/fail/recovery/blocked need — but a chatty route on any one of the four can silently suppress its own notifications, and its sibling informational types' notifications, once it exceeds that shared cap. blocked is deliberately NOT in that shared group even though it is agent-reported rather than system-derived: a blocked agent needs a human, so it draws on the protected down/fail/recovery budget instead, precisely so it cannot be starved by chatty every-run/success/started/note traffic. Route informational types to a low-stakes destination, not to the one that pages someone."
- Changed
update_agent1 field changed- added
Input schema / properties / slugAdded value: +{ + "description": "New slug for the agent, e.g. 'reddit-bot': 3-50 characters, lowercase letters, digits and hyphens. Omit to keep the current slug, which is the default: pass it only when the person asks to change the slug. Saved links, Terraform references and trace sources that name the old slug stop matching this agent, unless they also equal its name (case-insensitive), past traced runs included; a slug equal to a source another agent receives by name or adoption takes that source's traces.", + "type": "string" +}
- Changed
update_monitor3 fields changed- changed
Input schema / properties / blocked_timeout_s / descriptionPrevious value: -"Maximum seconds a run may sit in the 'blocked' state (an agent reported it is waiting on a human) before a 'blocked' incident opens. UNSET DOES NOT MEAN WAIT FOREVER: omitting this does not disable the timeout, it falls back to the default, which is 24 HOURS — an agent still blocked 24 hours after reporting so, with this field never set, gets a 'blocked' incident regardless. Lower it to be paged sooner when a stuck approval is urgent; raise it for work that legitimately waits on a human for longer than a day. This is distinct from the immediate, non-incident 'blocked' notification a route on the 'blocked' event type delivers the moment the agent reports it (see set_route) — that fires right away; this field governs the separate incident that opens only if the wait outlives the timeout. Accepted on every monitor_type: unlike max_runtime_s/step_timeout_s it has no run-scoped precondition an http monitor could fail, so there is nothing to reject. Omit to leave the monitor's current value unchanged; pass 0 to clear it and fall back to the 24h default."New value: +"Maximum seconds a run may sit in the 'blocked' state (an agent reported it is waiting on a human) before a 'blocked' incident opens. UNSET DOES NOT MEAN WAIT FOREVER: omitting this does not disable the timeout, it falls back to the default, which is 24 HOURS — an agent still blocked 24 hours after reporting so, with this field never set, gets a 'blocked' incident regardless. Lower it to be paged sooner when a stuck approval is urgent; raise it for work that legitimately waits on a human for longer than a day. This is distinct from the non-incident 'blocked' notification a route on the 'blocked' event type delivers (see set_route), which is held 10 minutes and sent only if the run is still blocked then, at most once per blocked stretch of a run; this field governs the separate incident that opens only if the wait outlives the timeout. Accepted on every monitor_type: unlike max_runtime_s/step_timeout_s it has no run-scoped precondition an http monitor could fail, so there is nothing to reject. Omit to leave the monitor's current value unchanged; pass 0 to clear it and fall back to the 24h default." - changed
Input schema / properties / failure_threshold / descriptionPrevious value: -"Number of consecutive failures required before an incident opens. Default 1 (open on the very first failure). This is how you stop a single transient blip from paging someone: set 2-5 on a job that fails occasionally for reasons that resolve themselves, and no incident opens until that many runs in a row have failed. Any success resets the count to zero. It gates the 'fail' cause ONLY — silence (a missed ping), overrun, never_started and runaway are time- or rate-based, so a consecutive count means nothing for them and they are never delayed by it. Range 1-100. Omit to leave the monitor's current threshold unchanged."New value: +"Number of consecutive failures required before an incident opens. Default 1 (open on the very first failure). This is how you stop a single transient blip from paging someone: set 2-5 on a job that fails occasionally for reasons that resolve themselves, and no incident opens until that many runs in a row have failed. Any success resets the count to zero. It gates the 'fail' cause ONLY — silence (a missed ping), overrun, never_started and runaway are time- or rate-based, so a consecutive count means nothing for them and they are never delayed by it. A run that ends on the model provider's API error (server_error, overloaded, rate_limit) neither counts toward it nor resets it: those open an 'upstream' incident once 3 runs in a row end that way, or this many when it is higher. Range 1-100. Omit to leave the monitor's current threshold unchanged." - changed
Input schema / properties / step_timeout_s / descriptionPrevious value: -"Progress budget in seconds: how long an armed run may go without reporting a step before a 'stalled' incident opens (the stall rule). The clock is anchored on the LATER of the run's start ping and its most recent step, so a run that wedges before its first step is caught too. Reach for this when 'still running' and 'still making progress' are different things — a long agent loop, a multi-stage pipeline, a migration. max_runtime_s alone tells you nothing until the whole budget expires; step_timeout_s=300 on a 4-hour budget tells you within five minutes, and names the last step that reported. To use it the run must report steps: call get_ping_instructions and use curl_step (POST <ping_url>/step?rid=<run-id>&step=<name>). A monitor with step_timeout_s set whose job never reports a step will open a stalled incident on EVERY run — set the field and instrument the job in the same change. Default: unset, which disables stall detection entirely; a monitor that sets nothing behaves exactly as it did before this field existed. Range 10-86400. Two constraints. (1) It must be strictly LESS than the effective run budget, COALESCE(max_runtime_s, grace_s), or the API returns 400 STEP_TIMEOUT_EXCEEDS_BUDGET — at or above the budget the run overruns first, so the stall rule could never fire. (2) Not supported on http monitors: a probe never arms a run and has no /step endpoint to call, so the API returns 400 STEP_TIMEOUT_NOT_SUPPORTED. A step resets the stall clock ONLY — it never extends max_runtime_s, so an agent that reports progress forever still overruns. Omit to leave the monitor's current value unchanged; pass 0 to clear it and disable stall detection."New value: +"Progress budget in seconds: how long an armed run may go without reporting a step before a 'stalled' incident opens (the stall rule). The clock is anchored on the LATER of the run's start ping and its most recent step, so a run that wedges before its first step is caught too. Reach for this when 'still running' and 'still making progress' are different things — a long agent loop, a multi-stage pipeline, a migration. max_runtime_s alone tells you nothing until the whole budget expires; step_timeout_s=300 on a 4-hour budget tells you within five minutes, and names the last step that reported. To use it the run must report steps: call get_ping_instructions and use curl_step (POST <ping_url>/step?rid=<run-id>&step=<name>). A monitor with step_timeout_s set whose job never reports a step will open a stalled incident on EVERY run — set the field and instrument the job in the same change. Stall detection needs your job to call /step: the Claude Code hook and the reporting prompt do not send steps, so leave step_timeout_s unset for them. Default: unset, which disables stall detection entirely; a monitor that sets nothing behaves exactly as it did before this field existed. Range 10-86400. Two constraints. (1) It must be strictly LESS than the effective run budget, COALESCE(max_runtime_s, grace_s), or the API returns 400 STEP_TIMEOUT_EXCEEDS_BUDGET — at or above the budget the run overruns first, so the stall rule could never fire. (2) Not supported on http monitors: a probe never arms a run and has no /step endpoint to call, so the API returns 400 STEP_TIMEOUT_NOT_SUPPORTED. A step resets the stall clock ONLY — it never extends max_runtime_s, so an agent that reports progress forever still overruns. Omit to leave the monitor's current value unchanged; pass 0 to clear it and disable stall detection."
15 tool updates
v0.1.6- Added
adopt_discovered_agent - Changed
create_api_key4 fields changed- added
Input schema / properties / check_idAdded value: +{ + "description": "Only with scope \"ingest\": binds the key to this one monitor (UUID from list_monitors), so it can send telemetry for that monitor and nothing else. Required for an exporter that cannot name its monitor, such as Codex.", + "type": "string" +} - changed
Input schema / properties / expires_at / descriptionPrevious value: -"Optional RFC 3339 expiry, e.g. \"2026-12-31T00:00:00Z\". Omit for a key that never expires. A key can never be given a longer life than the key that creates it."New value: +"Optional RFC 3339 expiry, e.g. \"2026-12-31T00:00:00Z\". Omit for a 90-day key, capped at the creating key's own expiry. A key can never be given a longer life than the key that creates it." - changed
Input schema / properties / scope / descriptionPrevious value: -"What the new key may do. \"read\" is every GET; \"write\" is everything except managing API keys; \"admin\" is everything, key management included. Omit for \"write\", which is the right tier for a credential handed to a job or an agent: it can do the work and cannot mint itself a replacement. A key can never be given a HIGHER scope than the key that creates it; asking for one is refused and the refusal names the ceiling."New value: +"What the new key may do. \"read\" is every GET; \"write\" is everything except managing API keys; \"admin\" is everything, key management included. Omit for \"write\", which is the right tier for a credential handed to a job or an agent: it can do the work and cannot mint itself a replacement. A key can never be given a HIGHER scope than the key that creates it; asking for one is refused and the refusal names the ceiling. \"ingest\" can only send pings and telemetry (traces, metrics, logs) and cannot call the REST API at all: use it for a key that lives in a dotfile or an exporter's config. This tool needs an admin key; with a write key, use create_ingest_key, which mints a tracing key bound to one monitor." - changed
Input schema / properties / scope / enumPrevious value: -[ - "read", - "write", - "admin" -]New value: +[ + "read", + "write", + "admin", + "ingest" +]
- Changed
create_destination1 field changed- changed
Input schema / properties / kind / descriptionPrevious value: -"One of: webhook, telegram, discord, slack, ntfy, pushover, msteams, googlechat, email. Every destination URL must be https. A BRANDED kind must point at its vendor's host: discord at discord.com or discordapp.com, slack at hooks.slack.com, msteams at webhook.office.com or outlook.office.com or logic.azure.com or logic.azure.us or environment.api.powerplatform.com, googlechat at chat.googleapis.com. For any other endpoint use kind \"webhook\", which accepts any https host; ntfy is unpinned too, so a self-hosted ntfy server is fine. A pin narrows the destination to the vendor's own platform; it does NOT prove the endpoint belongs to the person or project that created it, because every pinned domain is multi-tenant and self-service. Do not report a pinned destination as verified or as owned by anyone on the strength of its host."New value: +"One of: webhook, telegram, discord, slack, ntfy, pushover, msteams, googlechat, email. Every destination URL must be https. A BRANDED kind must point at its vendor's host: discord at discord.com or discordapp.com, slack at hooks.slack.com, msteams at webhook.office.com or outlook.office.com or logic.azure.com or logic.azure.us or environment.api.powerplatform.com, googlechat at chat.googleapis.com. For any other endpoint use kind \"webhook\", which accepts any https host; ntfy is unpinned too, so a self-hosted ntfy server is fine. A pin narrows the destination to the vendor's own platform; it does NOT prove the endpoint belongs to the person or project that created it, because every pinned domain is multi-tenant and open to anyone who signs up. Do not report a pinned destination as verified or as owned by anyone on the strength of its host."
- Added
create_ingest_key - Changed
create_monitor7 fields changed- changed
Input schema / properties / ci_branch / descriptionPrevious value: -"CI filter: only count runs on this branch, e.g. 'main'. Requires ci_provider. WITHOUT IT a run on ANY branch — a feature branch, a fork's pull request — reports to this monitor, so somebody else's broken branch marks your monitor down. Set it to the branch whose health you actually care about, which is almost always the default branch."New value: +"CI filter: only count runs on this branch, e.g. 'main'. REQUIRES ci_provider, and the API enforces it: without a CI binding the request is refused with 400 FIELD_NOT_IN_SHAPE rather than accepted and discarded. Subject to the SAME upsert exception as ci_workflow — create_monitor on an existing slug never writes this filter; use update_monitor. WITHOUT IT a run on ANY branch — a feature branch, a fork's pull request — reports to this monitor, so somebody else's broken branch marks your monitor down. Set it to the branch whose health you actually care about, which is almost always the default branch." - changed
Input schema / properties / ci_provider / descriptionPrevious value: -"Bind this monitor to a CI system, so the CI system itself reports every run by webhook and the job needs NO ping code at all. One of: 'github', 'gitlab', 'jenkins'. SET-ONCE: ci_provider can only be chosen when the monitor is created — update_monitor cannot change or remove it, so a monitor bound to the wrong provider must be deleted and recreated. Setting it generates a webhook secret that is returned exactly ONCE, in THIS call's response, together with the webhook URL. It is never retrievable afterwards — no MCP tool and no API read returns it again — so copy both out of the response and configure the CI webhook before doing anything else. Omit for a monitor that pings for itself. Also set ci_workflow and ci_branch unless the repository really has exactly one workflow on one branch."New value: +"Bind this monitor to a CI system, so the CI system itself reports every run by webhook and the job needs NO ping code at all. One of: 'github', 'gitlab', 'jenkins'. SET-ONCE: ci_provider can only be chosen when the monitor is created — update_monitor cannot change or remove it, so a monitor bound to the wrong provider must be deleted and recreated. Setting it generates a webhook secret that is returned exactly ONCE, in THIS call's response, together with the webhook URL. It is never retrievable afterwards — no MCP tool and no API read returns it again — so copy both out of the response and configure the CI webhook before doing anything else. Omit for a monitor that pings for itself. Also set ci_workflow and ci_branch unless the repository really has exactly one workflow on one branch. NOT ACCEPTED on monitor_type='http': an http probe is never bound to CI, and the API returns 400 FIELD_NOT_IN_SHAPE. It used to accept the provider, create no binding, and report success." - changed
Input schema / properties / ci_workflow / descriptionPrevious value: -"CI filter: only count runs of the workflow / pipeline / job with this exact name. Requires ci_provider. WITHOUT IT, EVERY workflow in the repository reports to this monitor — so one unrelated failing workflow opens an incident against a job that is perfectly healthy, and a green run of a different workflow clears an incident the real job never recovered from. Set it whenever the repository has more than one workflow."New value: +"CI filter: only count runs of the workflow / pipeline / job with this exact name. REQUIRES ci_provider, and the API enforces it: without a CI binding this filter has nowhere to be stored, so the request is refused with 400 FIELD_NOT_IN_SHAPE rather than accepted and discarded. Note that monitor_type='ci' does NOT bind anything on its own — ci_provider does. ONE EXCEPTION, and it is on the path agents use most, so do not rely on the enforcement here: create_monitor on a slug that ALREADY EXISTS is an upsert, and the upsert never writes this filter. With ci_provider in the same call the request is accepted and the filter is silently discarded; without it the request is refused, and doing what the error advises — adding ci_provider — reaches the discarding case instead. Set this filter with update_monitor, which does persist it. WITHOUT IT, EVERY workflow in the repository reports to this monitor — so one unrelated failing workflow opens an incident against a job that is perfectly healthy, and a green run of a different workflow clears an incident the real job never recovered from. Set it whenever the repository has more than one workflow." - changed
Input schema / properties / grace_s / descriptionPrevious value: -"Grace period in seconds after a ping is due before alerting."New value: +"Grace period in seconds after a ping is due before alerting. Omit on an on_demand monitor and LastPing uses 300 seconds; on_demand has no cadence, so grace only sets the first-run deadline and the overrun fallback. On an upsert (existing slug), omitting it on an on_demand monitor sets 300: pass the current value to keep it." - changed
Input schema / properties / monitor_type / descriptionPrevious value: -"'heartbeat' (default), 'ci', or 'http'."New value: +"'heartbeat' (default), 'ci', or 'http'. Any other value is refused with 400 UNKNOWN_MONITOR_TYPE. 'ci' is a label, not a binding: a CI monitor is a heartbeat monitor with ci_provider set, so passing monitor_type='ci' WITHOUT ci_provider creates an ordinary heartbeat and its ci_workflow/ci_branch filters are refused." - changed
Input schema / properties / schedule_kind / descriptionPrevious value: -"'simple' (requires period_s), 'cron' (requires cron_expr), or 'on_demand' (requires neither). Required for heartbeat/ci monitors. 'on_demand' means no cadence at all: no period_s, no cron_expr — the API returns 400 if either is supplied — and, by default, NO ABSENCE DEADLINES ARE ARMED BETWEEN RUNS. What this trades away: nothing tells you if the agent is never invoked again; silence between runs is invisible unless you opt in to expect_every_s. What it buys: a healthy agent that nobody happens to invoke for a week never generates a false 'late' or 'down' for simply not having been asked to run. Only run-scoped detection still applies once a run starts — max_runtime_s (overrun), step_timeout_s (stall), blocked_timeout_s (stuck on a human) — because those are anchored to a run's own start ping, not to a cadence. IMPORTANT: if you would be alarmed to find this agent silent for hours, set expect_every_s as well — it is the silence floor, and it is the only thing that makes an on_demand monitor detect absence at all. Choose 'simple'/'cron' when the agent is supposed to run on a cadence; choose 'on_demand' when invocation is inherently irregular and a quiet stretch between runs is expected, not a symptom."New value: +"'simple' (requires period_s), 'cron' (requires cron_expr), or 'on_demand' (requires neither). Required for heartbeat/ci monitors. NOT ACCEPTED on monitor_type='http', together with period_s, cron_expr and tz: an http monitor's schedule is derived from probe_interval_s, so the API refuses all four with 400 FIELD_NOT_IN_SHAPE instead of accepting and ignoring them. 'on_demand' means no cadence at all: no period_s, no cron_expr — the API returns 400 if either is supplied — and, by default, NO ABSENCE DEADLINES ARE ARMED BETWEEN RUNS. What this trades away: nothing tells you if the agent is never invoked again; silence between runs is invisible unless you opt in to expect_every_s. What it buys: a healthy agent that nobody happens to invoke for a week never generates a false 'late' or 'down' for simply not having been asked to run. Only run-scoped detection still applies once a run starts — max_runtime_s (overrun), step_timeout_s (stall), blocked_timeout_s (stuck on a human) — because those are anchored to a run's own start ping, not to a cadence. IMPORTANT: if you would be alarmed to find this agent silent for hours, set expect_every_s as well — it is the silence floor, and it is the only thing that makes an on_demand monitor detect absence at all. Choose 'simple'/'cron' when the agent is supposed to run on a cadence; choose 'on_demand' when invocation is inherently irregular and a quiet stretch between runs is expected, not a symptom." - added
Input schema / properties / trace_contentAdded value: +{ + "description": "What this monitor's traces keep of prompt, command and tool content. 'dropped' (the default) removes it; 'redacted' keeps it, with every secret-shaped value redacted when it arrives. Only a person should choose 'redacted': never set it on your own initiative, only when the person you work for has asked for content to be stored. Omit on a create for dropped; on an upsert (existing slug), omitting it leaves the stored value unchanged.", + "enum": [ + "dropped", + "redacted" + ], + "type": "string" +}
- Added
delete_route - Added
get_agent_dependencies - Added
get_agent_usage - Added
get_trace_diagnostics - Added
get_trace_setup - Added
list_dependencies - Added
list_discovered_agents - Added
list_runs - Added
regenerate_api_key - Changed
update_monitor4 fields changed- changed
Input schema / properties / ci_branch / descriptionPrevious value: -"CI filter: only count runs on this branch, e.g. 'main'. Requires ci_provider. WITHOUT IT a run on ANY branch — a feature branch, a fork's pull request — reports to this monitor, so somebody else's broken branch marks your monitor down. Set it to the branch whose health you actually care about, which is almost always the default branch. Omit to leave the current filter unchanged; pass an explicit JSON null to remove it. An EMPTY STRING also leaves it unchanged — that is a deliberate API compatibility rule, not a bug, so an empty string cannot be used to clear the filter."New value: +"CI filter: only count runs on this branch, e.g. 'main'. REQUIRES ci_provider, and the API enforces it: without a CI binding the request is refused with 400 FIELD_NOT_IN_SHAPE rather than accepted and discarded. Subject to the SAME upsert exception as ci_workflow — create_monitor on an existing slug never writes this filter; use update_monitor. WITHOUT IT a run on ANY branch — a feature branch, a fork's pull request — reports to this monitor, so somebody else's broken branch marks your monitor down. Set it to the branch whose health you actually care about, which is almost always the default branch. Omit to leave the current filter unchanged; pass an explicit JSON null to remove it. An EMPTY STRING also leaves it unchanged — that is a deliberate API compatibility rule, not a bug, so an empty string cannot be used to clear the filter." - changed
Input schema / properties / ci_workflow / descriptionPrevious value: -"CI filter: only count runs of the workflow / pipeline / job with this exact name. Requires ci_provider. WITHOUT IT, EVERY workflow in the repository reports to this monitor — so one unrelated failing workflow opens an incident against a job that is perfectly healthy, and a green run of a different workflow clears an incident the real job never recovered from. Set it whenever the repository has more than one workflow. Omit to leave the current filter unchanged; pass an explicit JSON null to remove it. An EMPTY STRING also leaves it unchanged — that is a deliberate API compatibility rule, not a bug, so an empty string cannot be used to clear the filter."New value: +"CI filter: only count runs of the workflow / pipeline / job with this exact name. REQUIRES ci_provider, and the API enforces it: without a CI binding this filter has nowhere to be stored, so the request is refused with 400 FIELD_NOT_IN_SHAPE rather than accepted and discarded. Note that monitor_type='ci' does NOT bind anything on its own — ci_provider does. ONE EXCEPTION, and it is on the path agents use most, so do not rely on the enforcement here: create_monitor on a slug that ALREADY EXISTS is an upsert, and the upsert never writes this filter. With ci_provider in the same call the request is accepted and the filter is silently discarded; without it the request is refused, and doing what the error advises — adding ci_provider — reaches the discarding case instead. Set this filter with update_monitor, which does persist it. WITHOUT IT, EVERY workflow in the repository reports to this monitor — so one unrelated failing workflow opens an incident against a job that is perfectly healthy, and a green run of a different workflow clears an incident the real job never recovered from. Set it whenever the repository has more than one workflow. Omit to leave the current filter unchanged; pass an explicit JSON null to remove it. An EMPTY STRING also leaves it unchanged — that is a deliberate API compatibility rule, not a bug, so an empty string cannot be used to clear the filter." - changed
Input schema / properties / schedule_kind / descriptionPrevious value: -"'simple', 'cron', or 'on_demand'. 'on_demand' means no cadence at all: no period_s, no cron_expr — the API returns 400 if either is supplied — and, by default, NO ABSENCE DEADLINES ARE ARMED BETWEEN RUNS. What this trades away: nothing tells you if the agent is never invoked again; silence between runs is invisible unless you opt in to expect_every_s. What it buys: a healthy agent that nobody happens to invoke for a week never generates a false 'late' or 'down' for simply not having been asked to run. Only run-scoped detection still applies once a run starts — max_runtime_s (overrun), step_timeout_s (stall), blocked_timeout_s (stuck on a human) — because those are anchored to a run's own start ping, not to a cadence. IMPORTANT: if you would be alarmed to find this agent silent for hours, set expect_every_s as well — it is the silence floor, and it is the only thing that makes an on_demand monitor detect absence at all. Choose 'simple'/'cron' when the agent is supposed to run on a cadence; choose 'on_demand' when invocation is inherently irregular and a quiet stretch between runs is expected, not a symptom."New value: +"'simple', 'cron', or 'on_demand'. NOT ACCEPTED on an http monitor, together with period_s, cron_expr and tz: its schedule is derived from probe_interval_s, so the API refuses all four with 400 FIELD_NOT_IN_SHAPE. 'on_demand' means no cadence at all: no period_s, no cron_expr — the API returns 400 if either is supplied — and, by default, NO ABSENCE DEADLINES ARE ARMED BETWEEN RUNS. What this trades away: nothing tells you if the agent is never invoked again; silence between runs is invisible unless you opt in to expect_every_s. What it buys: a healthy agent that nobody happens to invoke for a week never generates a false 'late' or 'down' for simply not having been asked to run. Only run-scoped detection still applies once a run starts — max_runtime_s (overrun), step_timeout_s (stall), blocked_timeout_s (stuck on a human) — because those are anchored to a run's own start ping, not to a cadence. IMPORTANT: if you would be alarmed to find this agent silent for hours, set expect_every_s as well — it is the silence floor, and it is the only thing that makes an on_demand monitor detect absence at all. Choose 'simple'/'cron' when the agent is supposed to run on a cadence; choose 'on_demand' when invocation is inherently irregular and a quiet stretch between runs is expected, not a symptom." - added
Input schema / properties / trace_contentAdded value: +{ + "description": "What this monitor's traces keep of prompt, command and tool content. 'dropped' (the default) removes it; 'redacted' keeps it, with every secret-shaped value redacted when it arrives. Only a person should choose 'redacted': never set it on your own initiative, only when the person you work for has asked for content to be stored. Omit to leave the monitor's current value unchanged.", + "enum": [ + "dropped", + "redacted" + ], + "type": "string" +}
2 tool updates
v0.1.5- Added
get_run - Added
list_deliveries
1 tool update
v0.1.4- Added
get_incident
3 tool updates
v0.1.3- Changed
create_api_key2 fields changed- changed
Input schema / properties / expires_at / descriptionPrevious value: -"Optional RFC 3339 expiry, e.g. \"2026-12-31T00:00:00Z\". Omit for a key that never expires."New value: +"Optional RFC 3339 expiry, e.g. \"2026-12-31T00:00:00Z\". Omit for a key that never expires. A key can never be given a longer life than the key that creates it." - added
Input schema / properties / scopeAdded value: +{ + "description": "What the new key may do. \"read\" is every GET; \"write\" is everything except managing API keys; \"admin\" is everything, key management included. Omit for \"write\", which is the right tier for a credential handed to a job or an agent: it can do the work and cannot mint itself a replacement. A key can never be given a HIGHER scope than the key that creates it; asking for one is refused and the refusal names the ceiling.", + "enum": [ + "read", + "write", + "admin" + ], + "type": "string" +}
- Changed
create_destination1 field changed- changed
Input schema / properties / kind / descriptionPrevious value: -"One of: webhook, email, slack, discord, telegram, ntfy, pushover, msteams, googlechat."New value: +"One of: webhook, telegram, discord, slack, ntfy, pushover, msteams, googlechat, email. Every destination URL must be https. A BRANDED kind must point at its vendor's host: discord at discord.com or discordapp.com, slack at hooks.slack.com, msteams at webhook.office.com or outlook.office.com or logic.azure.com or logic.azure.us or environment.api.powerplatform.com, googlechat at chat.googleapis.com. For any other endpoint use kind \"webhook\", which accepts any https host; ntfy is unpinned too, so a self-hosted ntfy server is fine. A pin narrows the destination to the vendor's own platform; it does NOT prove the endpoint belongs to the person or project that created it, because every pinned domain is multi-tenant and self-service. Do not report a pinned destination as verified or as owned by anyone on the strength of its host."
- Changed
update_destination1 field changed- changed
Input schema / properties / config / descriptionPrevious value: -"Replacement config for the destination's existing kind — one of webhook, telegram, discord, slack, ntfy, pushover, msteams, googlechat, email. Shape must match the kind: {\"url\":…,\"secret\":…} for webhook, {\"bot_token\":…,\"chat_id\":…} for telegram, {\"webhook_url\":…} for slack/discord/msteams/googlechat, {\"topic_url\":…} for ntfy, {\"token\":…,\"user_key\":…} for pushover, {\"address\":…} for email. Omit to leave unchanged."New value: +"Replacement config for the destination's existing kind — one of webhook, telegram, discord, slack, ntfy, pushover, msteams, googlechat, email. Shape must match the kind: {\"url\":…,\"secret\":…} for webhook, {\"bot_token\":…,\"chat_id\":…} for telegram, {\"webhook_url\":…} for slack/discord/msteams/googlechat, {\"topic_url\":…} for ntfy, {\"token\":…,\"user_key\":…} for pushover, {\"address\":…} for email. Omit to leave unchanged. A URL you supply is re-checked against the kind's allowed hosts and must be https; a destination created before that rule keeps working until you send a new config for it. The config must name only the fields listed for its kind, each exactly once. The host rule narrows a branded destination to the vendor's own platform; it does NOT prove the endpoint belongs to the person or project that owns the destination."
36 tool updates
- First observed
add_incident_note - First observed
create_api_key - First observed
create_destination - First observed
create_monitor - First observed
create_status_page - First observed
declare_run_expectations - First observed
delete_agent - First observed
delete_destination - First observed
delete_monitor - First observed
delete_status_page - First observed
discover_monitors_reconcile - First observed
export_terraform - First observed
get_agent - First observed
get_alert_templates - First observed
get_monitor - First observed
get_ping_instructions - First observed
get_run_history - First observed
list_agents - First observed
list_api_keys - First observed
list_destinations - First observed
list_incidents - First observed
list_monitors - First observed
list_open_incidents - First observed
list_status_pages - First observed
pause_monitor - First observed
register_agent - First observed
resume_monitor - First observed
revoke_api_key - First observed
set_alert_template - First observed
set_route - First observed
snooze_monitor - First observed
test_destination - First observed
update_agent - First observed
update_destination - First observed
update_monitor - First observed
update_status_page
TDQS
Scored across 50 tools
Most tools target distinct resource-and-action pairs, and the descriptions draw clear lines between monitors, agents, incidents, runs, destinations, and tracing. A few boundaries blur, such as create_monitor's upsert behavior versus update_monitor, list_runs versus get_run_history, and get_trace_setup versus get_ping_instructions, but the detailed descriptions usually resolve them.
Nearly all tools follow a snake_case verb_noun pattern (list_monitors, create_destination, update_agent), grouped consistently by resource. The main outlier is discover_monitors_reconcile, which uses a verb_noun_verb ordering, but it remains readable and the set is not chaotic.
50 tools is well beyond the recommended 3-15 range and likely over-provisions the surface. Although LastPing spans many subdomains, the sheer endpoint count increases selection complexity and risks overwhelming an agent.
Coverage is broad: full CRUD for monitors, agents, destinations, status pages, and API keys, plus incident, routing, run, and tracing operations. Minor gaps remain, such as no single-destination get, no project-wide incident list, and no explicit ingest-key revoke, but core workflows are well covered.
Maintenance
Related MCP Connectors
Know when cron jobs and AI agents stop running: create monitors and check in from your agent.
Synthetic checks, nightly regression replay and model-drift alerts for AI agents
AI agent run monitoring with incident replay and SLA receipts.
Watchdog for unattended AI agents: alerts, evidence checks and a verifiable proof per run.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceData observability for AI agents. Query alerts, monitor freshness, investigate schema drift, and trace lineage across your data warehouse via 53 MCP tools.1MIT
- AlicenseAqualityAmaintenanceRuntime governance for AI-agent fleets that continuously monitors agent health, confidence, and behavior through check-ins, and returns verdicts to enable self-correction before failures occur.135Apache 2.0
- FlicenseNot gradedqualityCmaintenanceProvides real-time monitoring of AI agents, context, usage limits, workflows, files, Git, tests, builds, errors, secrets, and model-economy advice for tools like Claude Code, Codex, and Cursor, with 30 MCP tools for comprehensive observability.1-
- AlicenseNot gradedqualityBmaintenanceLocal-first observability for AI agent stacks. Provides MCP tools for agents to check health, shadow configs, and burnout metrics proactively.1GPL 3.0