extensions/diffs/README.md
Read-only diff viewer plugin for OpenClaw agents.
It gives agents one tool, diffs, that can:
before and after text or a unified patchThe tool can return:
details.viewerUrl: a gateway URL that can be opened in the canvasdetails.filePath: a local rendered artifact path when file rendering is requesteddetails.fileFormat: the rendered file format (png or pdf)details.artifactId and details.expiresAt: artifact identity and TTL metadatadetails.context: available routing metadata such as agentId, sessionId, messageChannel, and agentAccountIdWhen 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:
diffs with mode=view, then pass details.viewerUrl to canvas presentdiffs with mode=file, then send the file through the normal message tool using path or filePathdiffs with mode=both when it wants both outputsBefore and after:
{
"before": "# Hello\n\nOne",
"after": "# Hello\n\nTwo",
"path": "docs/example.md",
"mode": "view"
}
Patch:
{
"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
Deprecated alias: image behaves like file and is still accepted for backward compatibility.layout: unified or splittheme: light or dark (default: dark)fileFormat: png or pdf (default: png)fileQuality: standard, hq, or printfileScale: 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 inputlang: language hint for before/after input; unknown values fall back to plain texttitle: explicit viewer titlettlSeconds: artifact lifetime for viewer and standalone file outputsbaseUrl: override the gateway base URL used in the returned viewer link (origin or origin+base path only; no query/hash)viewerBaseUrl plugin config: persistent fallback used when a tool call omits baseUrlLegacy input aliases still accepted for backward compatibility:
format -> fileFormatimageFormat -> fileFormatimageQuality -> fileQualityimageScale -> fileScaleimageMaxWidth -> fileMaxWidthInput safety limits:
before and after: max 512 KiB eachpatch: max 2 MiBSet plugin-wide defaults in ~/.openclaw/openclaw.json:
{
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 URLsviewerBaseUrl (optional): persistent viewer-link origin/path fallback for shareable URLsExample:
{
plugins: {
entries: {
diffs: {
enabled: true,
config: {
viewerBaseUrl: "https://gateway.example.com/openclaw",
},
},
},
},
}
Open in canvas:
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):
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:
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:
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;
}
/plugins/diffs/....$TMPDIR/openclaw-diffs).127.0.0.1) unless you set plugin viewerBaseUrl, pass baseUrl, or use gateway.bind=custom + gateway.customBindHost.gateway.trustedProxies includes loopback for a same-host proxy (for example Tailscale Serve), raw 127.0.0.1 viewer requests without forwarded client-IP headers fail closed by design.mode=file / mode=both for attachments, or intentionally enable remote viewers and set plugin viewerBaseUrl (or pass a proxy/public baseUrl) when you need a shareable viewer URL.browser.executablePath if auto-detection is not enough.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.