| # @openclaw/diffs |
|
|
| Read-only diff viewer plugin for **OpenClaw** agents. |
|
|
| It gives agents one tool, `diffs`, that can: |
|
|
| - render a gateway-hosted diff viewer for canvas use |
| - render the same diff to a file (PNG or PDF) |
| - accept either arbitrary `before` and `after` text or a unified patch |
|
|
| ## What Agents Get |
|
|
| The tool can return: |
|
|
| - `details.viewerUrl`: a gateway URL that can be opened in the canvas |
| - `details.filePath`: a local rendered artifact path when file rendering is requested |
| - `details.fileFormat`: the rendered file format (`png` or `pdf`) |
|
|
| When the plugin is enabled, it also ships a companion skill from `skills/` and prepends stable tool-usage guidance into system-prompt space via `before_prompt_build`. The hook uses `prependSystemContext`, so the guidance stays out of user-prompt space while still being available every turn. |
|
|
| This means an agent can: |
|
|
| - call `diffs` with `mode=view`, then pass `details.viewerUrl` to `canvas present` |
| - call `diffs` with `mode=file`, then send the file through the normal `message` tool using `path` or `filePath` |
| - call `diffs` with `mode=both` when it wants both outputs |
|
|
| ## Tool Inputs |
|
|
| Before and after: |
|
|
| ```json |
| { |
| "before": "# Hello\n\nOne", |
| "after": "# Hello\n\nTwo", |
| "path": "docs/example.md", |
| "mode": "view" |
| } |
| ``` |
|
|
| Patch: |
|
|
| ```json |
| { |
| "patch": "diff --git a/src/example.ts b/src/example.ts\n--- a/src/example.ts\n+++ b/src/example.ts\n@@ -1 +1 @@\n-const x = 1;\n+const x = 2;\n", |
| "mode": "both" |
| } |
| ``` |
|
|
| Useful options: |
|
|
| - `mode`: `view`, `file`, or `both` |
| - `layout`: `unified` or `split` |
| - `theme`: `light` or `dark` (default: `dark`) |
| - `fileFormat`: `png` or `pdf` (default: `png`) |
| - `fileQuality`: `standard`, `hq`, or `print` |
| - `fileScale`: device scale override (`1`-`4`) |
| - `fileMaxWidth`: max width override in CSS pixels (`640`-`2400`) |
| - `expandUnchanged`: expand unchanged sections (per-call option only, not a plugin default key) |
| - `path`: display name for before and after input |
| - `title`: explicit viewer title |
| - `ttlSeconds`: artifact lifetime |
| - `baseUrl`: override the gateway base URL used in the returned viewer link (origin or origin+base path only; no query/hash) |
|
|
| Input safety limits: |
|
|
| - `before` and `after`: max 512 KiB each |
| - `patch`: max 2 MiB |
| - patch rendering cap: max 128 files / 120,000 lines |
|
|
| ## Plugin Defaults |
|
|
| Set plugin-wide defaults in `~/.openclaw/openclaw.json`: |
|
|
| ```json5 |
| { |
| plugins: { |
| entries: { |
| diffs: { |
| enabled: true, |
| config: { |
| defaults: { |
| fontFamily: "Fira Code", |
| fontSize: 15, |
| lineSpacing: 1.6, |
| layout: "unified", |
| showLineNumbers: true, |
| diffIndicators: "bars", |
| wordWrap: true, |
| background: true, |
| theme: "dark", |
| fileFormat: "png", |
| fileQuality: "standard", |
| fileScale: 2, |
| fileMaxWidth: 960, |
| mode: "both", |
| }, |
| }, |
| }, |
| }, |
| }, |
| } |
| ``` |
|
|
| Explicit tool parameters still win over these defaults. |
|
|
| Security options: |
|
|
| - `security.allowRemoteViewer` (default `false`): allows non-loopback access to `/plugins/diffs/view/...` token URLs |
|
|
| ## Example Agent Prompts |
|
|
| Open in canvas: |
|
|
| ```text |
| Use the `diffs` tool in `view` mode for this before and after content, then open the returned viewer URL in the canvas. |
| |
| Path: docs/example.md |
| |
| Before: |
| # Hello |
| |
| This is version one. |
| |
| After: |
| # Hello |
| |
| This is version two. |
| ``` |
|
|
| Render a file (PNG or PDF): |
|
|
| ```text |
| Use the `diffs` tool in `file` mode for this before and after input. After it returns `details.filePath`, use the `message` tool with `path` or `filePath` to send me the rendered diff file. |
| |
| Path: README.md |
| |
| Before: |
| OpenClaw supports plugins. |
| |
| After: |
| OpenClaw supports plugins and hosted diff views. |
| ``` |
|
|
| Do both: |
|
|
| ```text |
| Use the `diffs` tool in `both` mode for this diff. Open the viewer in the canvas and then send the rendered file by passing `details.filePath` to the `message` tool. |
| |
| Path: src/demo.ts |
| |
| Before: |
| const status = "old"; |
| |
| After: |
| const status = "new"; |
| ``` |
|
|
| Patch input: |
|
|
| ```text |
| Use the `diffs` tool with this unified patch in `view` mode. After it returns the viewer URL, present it in the canvas. |
| |
| diff --git a/src/example.ts b/src/example.ts |
| --- a/src/example.ts |
| +++ b/src/example.ts |
| @@ -1,3 +1,3 @@ |
| export function add(a: number, b: number) { |
| - return a + b; |
| + return a + b + 1; |
| } |
| ``` |
|
|
| ## Notes |
|
|
| - The viewer is hosted locally through the gateway under `/plugins/diffs/...`. |
| - Artifacts are ephemeral and stored in the plugin temp subfolder (`$TMPDIR/openclaw-diffs`). |
| - Default viewer URLs use loopback (`127.0.0.1`) unless you set `baseUrl` (or use `gateway.bind=custom` + `gateway.customBindHost`). |
| - Remote viewer misses are throttled to reduce token-guess abuse. |
| - PNG or PDF rendering requires a Chromium-compatible browser. Set `browser.executablePath` if auto-detection is not enough. |
| - If your delivery channel compresses images heavily (for example Telegram or WhatsApp), prefer `fileFormat: "pdf"` to preserve readability. |
| - `N unmodified lines` rows may not always include expand controls for patch input, because many patch hunks do not carry full expandable context data. |
| - Diff rendering is powered by [Diffs](https://diffs.com). |
|
|