Signal Diff CLI for coding agents

This post is about the signaldiff CLI: how to install it, run a local sitemap crawl, and hand that to Cursor, Copilot, or Claude Code so the agent can spot SEO and crawl issues without opening a dashboard.

Signal Diff is the product behind that command. It fetches the URLs in a sitemap, checks on-page SEO and crawl health (titles, meta descriptions, redirects, slow responses, and more), and can compare a run with a baseline—often the previous deploy—so you see what changed. I already use it on this blog after each Static Web Apps release via funkysi1701/signal-diff-action . That Action is the unattended gate. The CLI is the same crawl, from a shell. (There is also a customer-hosted crawler; this post stays on the coding-agent path.)

A CLI is a good fit here because coding agents already have a terminal. They can install one binary, run a crawl, and read an HTML report. You do not need a browser session, and you do not need an MCP server. Local crawls need no account. Cloud commands are optional once an API key is already in the environment. The rest of this post walks through install, a capped crawl of this site, the prompt I give an agent, and the cloud commands worth using when a key is set.

CLI behaviour agents need

Once a key exists, the subcommands sites, runs, diff, findings, and scan call the Agent API . Full command reference: signaldiff.dev/docs/cli .

A few behaviours matter once an agent is the one typing:

  • signaldiff with no arguments prints help and exits. It does not start a crawl.
  • --json belongs on cloud subcommands. Success JSON goes to stdout. A failure is one JSON object on stderr, with a status code and, on a rate limit, how many seconds to wait. Progress logs stay on stderr, so a pipe keeps the result.
  • A local --sitemap crawl refuses --json and still writes HTML.

Install, then crawl this blog

The installers are self-contained. You do not need the .NET SDK, and you do not need a clone of the repo. They verify SHA256 before putting signaldiff on your PATH. Prefer that path, or download a versioned zip from the CLI downloads page and check the published .sha256 sidecar yourself. On Windows:

irm 'https://signaldiff.dev/install/cli.ps1' -OutFile "$env:TEMP\signaldiff-install-cli.ps1"
& "$env:TEMP\signaldiff-install-cli.ps1"

On Linux or macOS:

curl -fsSL 'https://signaldiff.dev/install/cli.sh' | bash

Open a new terminal so PATH picks up the binary (~/.local/bin on Linux and macOS). Then crawl a real sitemap, with a page cap so the first run stays small:

signaldiff --sitemap https://www.funkysi1701.com/sitemap.xml --max-pages 20 --output seo-report.html --quiet

--output creates missing folders before the crawl starts. --quiet keeps the summary short. The report path is on stdout. I point this at my own sitemap because that is the site I already monitor. Swap in yours.

signaldiff update replaces the install with the latest published build and checks the SHA256. signaldiff update --check tells you whether one is waiting, and leaves the current binary alone.

What I tell the agent

The API key stays in the environment. It stays out of the chat. Here is the prompt I give Cursor, Copilot, or Claude Code:

Install the Signal Diff CLI from https://signaldiff.dev/docs/cli . Then, in a new terminal, run signaldiff --sitemap https://www.funkysi1701.com/sitemap.xml --max-pages 20 --output seo-report.html --quiet. Read seo-report.html and list the SEO and crawl issues worth fixing, with the URL for each and a concrete change. Use cloud commands only if SIGNALDIFF_API_KEY is already set. Leave the key out of the chat.

That is the loop. The agent installs if it must, runs a capped crawl, and works from the HTML. I still read the suggestions. A title that is two characters over the limit is a real fix. A rewrite of a post I care about is a suggestion until I agree with it.

On a recent crawl of this sitemap the report had no errors and a few hundred warnings. Even with --max-pages, a site-wide CSS finding still fans out across every page the crawl touched. The agent did not invent a title rewrite for every post. It collapsed them into one finding: Font Awesome’s CSS sits at the 100 KB file-size limit, repeated across pages. That is the shape of answer I want—site-wide root cause, not hundreds of identical notes.

This sits next to the split I described in how I use AI on side projects . ChatGPT when the question needs no repo. Cursor when the answer is in the files. The CLI when the question is about the live sitemap.

When a key is already set

Cloud commands need a paid key from the Signal Diff dashboard (Developers → API keys). Set it in the environment. Prefer that to --api-key, which shows up in the process list.

$env:SIGNALDIFF_API_KEY = "sck_…"
$env:SIGNALDIFF_API_BASE_URL = "https://signaldiff.dev/api"

The base URL includes /api. That is the easy one to get wrong. The GitHub Action uses a different variable, and the site origin with no /api suffix. Same secret value. Different names, different URL shape.

CallerVariableBase URL
CLI and the Agent APISIGNALDIFF_API_KEYhttps://signaldiff.dev/api
GitHub ActionSIGNALDIFF_CI_API_KEYhttps://signaldiff.dev

These are the commands I want an agent to run once that is set:

You wantCommand
Sites you already monitorsignaldiff sites list
Recent runs for one sitesignaldiff runs list --site example.com
A short brief for one runsignaldiff runs summary <runId>
Only the deploy diffsignaldiff diff get <runId>
Errors from that runsignaldiff findings list <runId> --severity Error --limit 50
Machine-readable outputadd --json

runs list is how you get a runId. runs summary is the one I point agents at after that. It is a capped brief: headline counts, top regressions, top improvements, and fix hints. It leaves out the full page payload. diff get is there when the only question is what changed against the baseline.

Starting a cloud scan is a separate decision. signaldiff scan start queues work on the service, and signaldiff scan wait <scanId> --json polls until it finishes. I leave that out of the default prompt. A local HTML report answers “what is wrong on this sitemap right now”. A cloud scan spends quota and shows up in the dashboard, so I ask for it on purpose.

The Action still runs after deploy

The pipeline check stays. On this blog the Action still crawls after a Static Web Apps deploy, with the API key in GitHub secrets and a pinned signal-diff-action version. The Action answers “did this deploy stay healthy?” when I am not looking. The CLI answers the same SEO questions while an agent and I are still in the change. A local --sitemap crawl is not a drop-in for that CI step: it does not attach a commit SHA, collect a code diff, or comment on a pull request.

Try it on a sitemap you care about

Install the CLI, cap a crawl with --max-pages, and have the agent read the HTML before it edits templates. If you already have a key, ask for runs summary on the latest run and see whether the brief is enough to act on.

I am curious how you give an agent this kind of check. A CLI it can run, an MCP server, or a dashboard you still open by hand? Tell me in the comments. Command reference, updates, and checksums are on the CLI docs .

Read next

Support this site

Comments