# How to Use Wigolo’s Diff and Watch Tools to Track Website Changes

> Learn how to use wigolo diff and watch tools to effectively track website changes. Discover how these MCP tools compare page versions and monitor sites for real time updates.

- Repository: [Towhid Khan/wigolo](https://github.com/KnockOutEZ/wigolo)
- Tags: how-to-guide
- Published: 2026-07-29

---

**Wigolo provides two MCP tools—`diff` for comparing page versions and `watch` for monitoring sites—that work together to detect changes through cached content and configurable polling intervals.**

The [KnockOutEZ/wigolo](https://github.com/KnockOutEZ/wigolo) repository ships a lightweight, cache-aware website monitoring system built on the Model Context Protocol (MCP). By combining the **diff** tool’s multi-granularity comparison engine with the **watch** tool’s job scheduling, you can track website changes without running background daemons.

## Understanding the Diff Tool

The `diff` tool, implemented in [[`src/tools/diff.ts`](https://github.com/KnockOutEZ/wigolo/blob/main/src/tools/diff.ts)](https://github.com/KnockOutEZ/wigolo/blob/main/src/tools/diff.ts), compares two page sources and returns structured change reports. It supports three output shapes and three comparison granularities to match your specific use case.

### Input Resolution and Validation

The tool requires an object containing `old` and `new` fields. Each side accepts either a raw Markdown string (`markdown`) or a URL (`url`). When URLs are provided, the tool calls `resolveSide` (lines 23-64) to check the cache via `getCachedContent`. If the old URL is not cached, it returns a `cache_miss` envelope. Invalid URLs trigger an `invalid_input` envelope immediately.

### Output Shapes and Granularity

Valid **output shapes** are `unified`, `hunks`, or `summary`. Valid **granularities** are `line`, `word`, or `section`. The tool validates these enums (lines 71-89) before invoking the computation engine. Unified output produces standard patches, hunks return arrays of change blocks, and summary provides a concise boolean result.

### The Diff Engine

Actual computation happens in [[`src/cache/diff-engine.js`](https://github.com/KnockOutEZ/wigolo/blob/main/src/cache/diff-engine.js)](https://github.com/KnockOutEZ/wigolo/blob/main/src/cache/diff-engine.js) via `computeDiffEnvelope`. The engine performs LCS (Longest Common Subsequence) comparison at the line, word, or Markdown section level. Results are wrapped in a `StageResult<DiffOutput>` containing a `changed` flag and the diff content.

### Truncation Safety

When pages exceed internal LCS table limits (line count or token count), the engine automatically marks results with `truncated: true` and falls back to summary shape. This prevents process crashes on extremely large pages (see tests in [[`tests/unit/tools/diff.test.ts`](https://github.com/KnockOutEZ/wigolo/blob/main/tests/unit/tools/diff.test.ts)](https://github.com/KnockOutEZ/wigolo/blob/main/tests/unit/tools/diff.test.ts) lines 23-68).

## Understanding the Watch Tool

The `watch` tool in [[`src/tools/watch.ts`](https://github.com/KnockOutEZ/wigolo/blob/main/src/tools/watch.ts)](https://github.com/KnockOutEZ/wigolo/blob/main/src/tools/watch.ts) manages persistent monitoring jobs stored in SQLite. Unlike traditional monitoring systems, wigolo uses a **lazy execution** model with no background daemon.

### Creating Watch Jobs

Use `action: create` to register URLs for monitoring. You must provide `interval_seconds` (minimum 60) and can optionally specify a CSS `selector` and `notification` mode (`inline` or webhook URL). The tool passes URLs through `guardUrl` for SSRF protection before persisting via `createJob` in [[`src/watch/store.ts`](https://github.com/KnockOutEZ/wigolo/blob/main/src/watch/store.ts)](https://github.com/KnockOutEZ/wigolo/blob/main/src/watch/store.ts). Batch creation supports up to 1,000 URLs (lines 29-34).

### Listing and Managing Jobs

- **List**: `action: list` returns all jobs from `listJobs()` with status, URL, and interval data.
- **Pause/Resume**: `action: pause` or `action: resume` updates job status via `setJobStatus`.
- **Delete**: `action: delete` removes the job row entirely.

All management actions validate `job_id` presence and return `invalid_input` if the job is missing.

### Running Checks

Manual checks use `action: check` with a `job_id`. The scheduler retrieves the job, fetches current content using the same pipeline as `diff`, runs the comparison, updates the `content_hash`, and returns a `ChangeReport`. The response includes the updated job record and a `changes_since_last` array showing what changed.

### Lazy Execution Model

Wigolo does **not** run a background daemon. Jobs execute only when you explicitly call `watch { action: 'check' }` or when the server auto-dispatches `scheduleOverdueCheck(router)` (see [[`src/watch/scheduler.ts`](https://github.com/KnockOutEZ/wigolo/blob/main/src/watch/scheduler.ts)](https://github.com/KnockOutEZ/wigolo/blob/main/src/watch/scheduler.ts) lines 45-57) upon detecting overdue jobs during regular operation.

## Practical Code Examples

### One-Shot Diff Between Two URLs

Compare a cached version against a live version using unified line-level diff:

```typescript
import { client } from 'wigolo';

await client.callTool({
  name: 'diff',
  arguments: {
    old: { url: 'https://example.com/old-page' },
    new: { url: 'https://example.com/new-page' },
    output: 'unified',
    granularity: 'line',
  },
});

```

**Result:** Returns `{ ok: true, data: { changed: true, unified_diff: '--- a\n+++ b\n@@ …' } }`.

### Register a Watch Job

Poll a news site every 5 minutes with inline notifications:

```typescript
await client.callTool({
  name: 'watch',
  arguments: {
    action: 'create',
    url: 'https://news.example.com',
    interval_seconds: 300,
    notification: 'inline',
  },
});

```

### List Active Jobs

Retrieve all monitoring jobs and their current status:

```typescript
await client.callTool({
  name: 'watch',
  arguments: { action: 'list' }
});

```

### Manually Trigger a Check

Force an immediate comparison for a specific job:

```typescript
await client.callTool({
  name: 'watch',
  arguments: {
    action: 'check',
    job_id: 'job-1',
  },
});

```

### Pause or Delete a Job

Temporarily stop monitoring without removing the job:

```typescript
await client.callTool({
  name: 'watch',
  arguments: {
    action: 'pause',
    job_id: 'job-1',
  },
});

```

Permanently remove the job:

```typescript
await client.callTool({
  name: 'watch',
  arguments: {
    action: 'delete',
    job_id: 'job-1',
  },
});

```

## Summary

- **Diff Tool**: Located in [`src/tools/diff.ts`](https://github.com/KnockOutEZ/wigolo/blob/main/src/tools/diff.ts), supports `unified`/`hunks`/`summary` outputs with `line`/`word`/`section` granularity, and safely handles large pages via truncation.
- **Watch Tool**: Located in [`src/tools/watch.ts`](https://github.com/KnockOutEZ/wigolo/blob/main/src/tools/watch.ts), provides CRUD operations for monitoring jobs with 60-second minimum intervals and batch limits of 1,000 URLs.
- **Execution Model**: Uses lazy scheduling via `scheduleOverdueCheck` in [`src/watch/scheduler.ts`](https://github.com/KnockOutEZ/wigolo/blob/main/src/watch/scheduler.ts)—no persistent background process required.
- **Storage**: Jobs persist in SQLite through [`src/watch/store.ts`](https://github.com/KnockOutEZ/wigolo/blob/main/src/watch/store.ts), while [`src/cache/store.js`](https://github.com/KnockOutEZ/wigolo/blob/main/src/cache/store.js) manages content caching for both tools.
- **Safety**: SSRF protection via `guardUrl` and input validation with consistent error envelopes (`invalid_input`, `cache_miss`, `diff_failed`).

## Frequently Asked Questions

### What input formats does wigolo diff support?

The `diff` tool accepts two input types for each side of the comparison: a `markdown` string containing raw content, or a `url` string pointing to a web resource. When using URLs, the old version must already exist in the cache (fetched previously), while the new version is fetched live. Invalid URLs or uncached old URLs return structured error envelopes.

### How does wigolo handle large pages during diffing?

The diff engine in [`src/cache/diff-engine.js`](https://github.com/KnockOutEZ/wigolo/blob/main/src/cache/diff-engine.js) implements truncation guards. When content exceeds LCS table capacity in terms of line count or token count, it automatically sets `truncated: true` in the result and falls back to summary output. This ensures the process remains stable even when comparing massive web pages.

### Is there a background process running for watch jobs?

No. Wigolo uses a lazy execution model where watches only run when explicitly triggered via `action: 'check'` or when the server detects an overdue job and calls `scheduleOverdueCheck`. There is no daemon or cron process; the scheduler in [`src/watch/scheduler.ts`](https://github.com/KnockOutEZ/wigolo/blob/main/src/watch/scheduler.ts) coordinates checks on-demand.

### What notification modes are available for watch jobs?

When creating a job with `action: 'create'`, you can set `notification` to either `inline` (returns diff results directly in the MCP response) or provide a webhook URL to receive HTTP callbacks when changes are detected. The notification mode is stored with the job and used when generating `ChangeReport` results during check cycles.