CLIApr 20, 20267 min read

Parsing GetWebP JSON Output in Agent Workflows

Image optimization is easy to automate badly. A script can convert files, print a cheerful message, and still leave the next step guessing which images changed, which inputs failed, and whether the job should block a release. That ambiguity becomes more expensive when an AI agent is driving the work, because the agent needs structured evidence instead of terminal prose.

GetWebP CLI supports machine-readable output through --json. The JSON output reference documents that this mode emits newline-delimited JSON, with one event envelope per line. Used carefully, that output gives agents and CI jobs a stable way to inspect conversion results without scraping human logs. The goal is not to make the agent "smart" about images. The goal is to give it clear facts: inputs, outputs, status, errors, and enough context to decide what to do next.

"Parse the output" is not a reliable instruction for agents unless the article names the real stream shape, event types, exit codes, per-file fields, and the decisions an agent is not allowed to make from conversion data alone.

Treat Structured Output as the Contract#

Human-friendly terminal logs are useful while debugging, but they are not a contract. Wording can change. Progress bars can move. A warning may wrap differently in a narrow terminal. Structured output exists so automation does not depend on those details.

For a small one-off conversion, a plain command may be enough:

getwebp ./public/images

For an agent workflow, prefer structured output:

getwebp ./public/images --json

The exact fields should be read from the command output your installed version emits, not guessed from examples in old scripts. In practice, a parser should look for the pieces documented in the GetWebP JSON schema: whether the run produced convert.completed, which results have status: "success", which have status: "error", and which outputPath values were written.

This is also where the current exit-code model matters. If the process exits with 0, the conversion completed successfully. If it exits with 3, the run had partial failures. Exit code 2 is reserved for usage errors such as invalid arguments. An agent should not flatten those cases into "done." Partial success usually deserves a short report and a decision about whether the failed inputs should be retried, skipped, or reviewed manually.

Parse NDJSON Deliberately#

Regular JSON is convenient when the whole result can be read at once, but GetWebP's --json stream is NDJSON, not one JSON array or one summary object. The JSON Lines format describes the core convention: UTF-8 text, one valid JSON value per line, and a line terminator after each value. That shape is simple enough for shell tools, Node.js, Python, and CI log processors to consume without holding a whole run in memory.

The important implementation detail is simple: parse each non-empty line, then select the event types your workflow understands. For conversion runs, that usually means keeping the version preamble for provenance, reading convert.completed for successful or partially successful runs, and handling convert.failed when the command could not start.

The main mistake is mixing modes mentally. A regular JSON parser expects one complete document. An NDJSON parser expects independent lines. If a workflow wraps GetWebP output into a regular JSON artifact later, make that a separate normalization step instead of feeding raw NDJSON to JSON.parse(stdout).

Useful references:

Keep the Parser Small#

A good parser for image conversion output should be boring. It should validate the process status, parse records, collect successful output paths, collect failures, and stop there.

For example, a Node.js wrapper might follow this sequence:

import { spawn } from "node:child_process";

const child = spawn("getwebp", ["./public/images", "--json"], {
  stdio: ["ignore", "pipe", "pipe"],
});

let stdout = "";
let stderr = "";

child.stdout.on("data", (chunk) => {
  stdout += chunk;
});

child.stderr.on("data", (chunk) => {
  stderr += chunk;
});

child.on("close", (code) => {
  const events = stdout
    .trim()
    .split(/\r?\n/)
    .filter(Boolean)
    .map((line) => JSON.parse(line));

  const summary = events.find(
    (event) =>
      event.type === "convert.completed" || event.type === "convert.truncated",
  );
  const results = summary?.data?.results ?? [];
  const outputs = results
    .filter((result) => result.status === "success")
    .map((result) => result.outputPath);
  const failures = results.filter((result) => result.status === "error");

  if (code === 0) {
    console.log("Conversion completed", { outputs });
    return;
  }

  if (code === 3) {
    console.warn("Conversion partially failed", { outputs, failures });
    return;
  }

  const errorEvent = events.find((event) => event["@level"] === "error");
  const message = errorEvent?.["@message"] ?? stderr.trim();
  throw new Error(`getwebp failed with exit code ${code}: ${message}`);
});

That is intentionally modest. The wrapper treats stdout as event records, not a single JSON document. It does not infer quality from file size alone. It does not delete originals. It does not rewrite application code. It gives the surrounding agent a reliable facts object and lets the next step make a scoped decision.

Make Agent Decisions Explicit#

An agent should not silently decide that every converted image is ready for production. Structured output can tell the agent that a file was written. It cannot prove that the image is visually acceptable, that the chosen quality setting matches brand requirements, or that a CMS template now references the new file correctly.

A safer decision tree is:

  1. If the command fails with an authentication or network-related exit code, stop and report the operational issue.
  2. If the command exits with partial failure, report the failed inputs and avoid claiming the folder is fully optimized.
  3. If all files succeed, compare the output list with the expected input list.
  4. If the conversion changed important hero, product, or UI images, request or run visual review before publishing.
  5. If the job is part of CI, publish a concise artifact that contains the conversion summary.

This kind of decision tree is more valuable than a long prompt. It limits what the agent is allowed to conclude from the data.

If the workflow uses the GetWebP MCP server instead of spawning the CLI directly, keep the same boundary: the agent may call structured tools such as scan_images and convert_images, but the tool result is still conversion evidence, not visual approval.

Avoid Fragile File Matching#

Image folders often contain repeated names: hero.jpg, hero.png, cover.jpg, and cover@2x.png appear in many projects. A parser should preserve full paths, not just basenames. It should also avoid assuming that output files sit beside inputs unless the command was run that way.

GetWebP can write outputs next to originals or into an output directory, depending on the flags used. If the wrapper passes an output directory, downstream code should read output paths from the structured result rather than reconstructing them with string replacement.

This matters for docs sites and static site generators. A careless script that replaces every .jpg with .webp in Markdown may break remote images, code examples, frontmatter values, or files that were intentionally left unchanged. The conversion result should inform the next step, but it should not be treated as permission for broad text rewrites.

Preserve Review Evidence#

High-quality automation leaves behind enough evidence for a human to understand what happened. For image conversion, that usually means storing the command, version, input directory, output directory, exit code, and structured result. A CI artifact, build log attachment, or pull request comment can all work.

One compact record is enough for most agent runs:

Command: getwebp ./public/images --output ./public/images-webp --recursive --json
Parser contract: /docs/cli/json-output, event type convert.completed
Exit code: 3, partial failure
Converted outputs: 42
Failed inputs: ./public/images/legacy/corrupt-logo.png
Agent action allowed: open a report and suggest retry/manual review
Agent action not allowed: rewrite all image references automatically

That evidence is especially useful when an image gets larger after conversion. WebP is often smaller than JPEG or PNG, but not always. Screenshots, already-compressed images, and tiny assets can produce surprising results. A parser should record outcomes honestly instead of hiding files that did not improve.

If an agent opens a pull request, the summary should say what changed in plain terms: how many files were converted, how many failed, which settings were used, and what still needs review. That is a stronger workflow than presenting image optimization as a black box.

A Practical Standard#

For agent-driven image optimization, the standard should be simple: parse structured output, respect exit codes, keep originals untouched, and avoid broad claims. The agent can help with repetitive work, but the workflow still needs clear boundaries.

GetWebP's JSON output is most useful when it is treated as operational evidence. It tells the next step what the converter did. It should not be stretched into proof of visual quality, SEO improvement, or production readiness. When the parser stays narrow, the automation becomes easier to review and much less likely to surprise the team maintaining the site.

Jack avatar

Jack

GetWebP Editor

Jack writes GetWebP guides about local-first image conversion, WebP workflows, browser compatibility, and practical performance checks for teams that publish images on the web.