Revise CLI menu

JSON output

The --json contract: one envelope for every command.

Add --json to any command and revise prints exactly one JSON object on stdout, and nothing else on stdout or stderr. Every command uses the same envelope, so a script or an agent can handle every result the same way.

revise status contract.docx --json
{
  "schema": 1,
  "ok": true,
  "command": "status",
  "meta": { "version": "3.0.0", "build": "3881be46a" },
  "data": {
    "file": "/work/contract.docx",
    "format": "docx",
    "mode": "suggest",
    "blockCount": 68,
    "wordCount": 2174,
    "trackedChangeCount": 0,
    "checkpoint": 0,
    "sourceFidelity": {
      "fidelity": "exact",
      "regeneratedBlockIds": [],
      "changedDomains": [],
      "convertedReason": null
    }
  },
  "warnings": [],
  "error": null
}

The contract is also a JSON Schema, shipped in the package: revise/cli-output.schema.json.

The envelope#

KeyTypeMeaning
schema1The version of this contract.
okbooleantrue exactly when error is null.
commandstring or nullThe command that ran, by its canonical name: status, xml patch, skill install; call for the tool shorthand; help for help and any --help; version for version and --version. null when the command was not recognized.
metaobjectversion (the revise package version) and build (the commit it was built from).
dataobject or nullThe command's result. Present on failure too whenever there is something to report, such as what was saved before the failure. null when there is nothing. Its presence does not mean success.
warningsarrayThings worth knowing that did not stop the command.
errorobject or nullWhy the command failed.

Compatibility#

All seven keys are always present. Within schema 1, fields may be added; existing fields keep their names, types, and meanings. Ignore fields you don't know, and handle error and warning codes you don't know generically. Breaking changes come with a new schema number and a new major version of revise.

Inside data, every documented key is present. A value that does not apply or is unknown is null; an empty list is []; a zero count is 0. Keys are camelCase, except inside a tool's own result (see Tool calls). Counts end in Count. Paths are absolute; package part names (like word/document.xml) are relative to the package.

The output is UTF-8 with one trailing newline. It is indented when stdout is a terminal and on one line otherwise; both parse the same way. Don't rely on key order.

Exit codes#

CodeokMeaning
0trueDone, including when there was nothing to do.
1falseFailed, and nothing was saved: a usage error, a missing file, a refused edit.
2falsePartly done: some of what was asked was saved or written, and some was not. data says what happened; error says what didn't. A redline that was written but failed its check is also 2.
70falseAn internal error, or a save whose outcome is uncertain (save_uncertain, with details.file and details.saved: null). Check the file before going on; the next revise command on it finishes or undoes the save.

A signal, a crash while starting up, or a closed stdout can still prevent a complete envelope.

Errors#

{
  "code": "change_not_found",
  "message": "Not pending: prop_17915. 1 other change was accepted and saved.",
  "hint": "revise changes contract.docx",
  "details": { "notFound": ["prop_17915"], "failed": [] }
}
KeyMeaning
codeStable and snake_case. Branch on this.
messageOne or two sentences for a person or a model. The wording may change.
hintA command to run next, shell-quoted, or null. Advice, not an instruction.
detailsStructured facts about the failure, or null.

Warnings#

Same code, message, and details as errors, without hint. In human output (without --json), warnings go to stderr as warning[code]: message, and errors (partial results too) as error[code]: message followed by a hint: line. A command that fails with exit 1 prints nothing on stdout.

Saving#

Commands that can change the document report:

KeyMeaning
fileThe document.
savedtrue when this command wrote the file and recorded a checkpoint. false when it saved nothing.
checkpointThe checkpoint the file is at now, saved or not. Undo with revise undo <file>.

Commands that write another file report output (its path) and outputWritten. If such a command fails after writing the file (for example new when its page setup fails), it exits 2 with that receipt: outputWritten: true, and null for what it could not determine.

undo and restore move the file back to an earlier checkpoint and discard the later ones: they don't add a checkpoint.

Vocabulary#

TermMeaning
blockOne unit of the document: a paragraph, heading, list item, table, or image. Block ids stay the same across commands until the block is removed. Block indexes start at 0.
tracked changeA Word revision waiting to be accepted or rejected. Each has a change id.
modesuggest (edits become tracked changes) or edit (edits apply directly).
checkpointA saved state in the file's history. 0 is the file as revise first read it.
sectionThe part of the document under one heading. Not a Word page-layout section.

Commands#

Reading#

status: file, format, mode, blockCount, wordCount, trackedChangeCount, checkpoint, and sourceFidelity: for a .docx, how an export now would relate to the file it came from (otherwise null):

  • fidelity: "exact" (reproduces the original file byte for byte), "grafted" (the original file plus your edits; untouched content is byte for byte), or "converted" (written fresh).
  • regeneratedBlockIds: blocks an export would rewrite.
  • changedDomains: other parts it would rewrite ("styles", "numbering", …).
  • convertedReason: why it is "converted", or null.

outline: file, blockCount, wordCount, sectionCount, sections (each: title, level (1–3), startIndex, endIndex (inclusive), startBlockId, endBlockId, blockCount, wordCount), and nextOffset: pass it to --offset for the next sections, null at the end.

grep: file, pattern, regex, ignoreCase, view, matchCount, and blocks in document order (each: blockId, blockIndex, matchCount, text, matches). text is the block in the view; in tracked, changes are inline as [-deleted-]{+inserted+}. matches lists each match (text, change: "deleted", "inserted", or null for text no change touches, and changeId).

read and search are tool calls.

Editing#

replace-all: file, find, replace, matchedBlockIds (blocks that contain find), replacedOccurrences, regions (occurrences per part: body, header, footer, footnote, endnote; parts with none left out), nearMisses (text looser matching would have replaced; each: text, count, reason: case or characters), changeIds (tracked changes created), failures (blocks that could not be edited; each: blockId, code, message), saved, checkpoint. Some failures: exit 2. All failed: exit 1. Run as replace-text, its 3.0 name, the envelope's command is replace-text.

mode: file, mode, changed (whether this command switched it). The mode is revise's setting, not part of the file.

tools: tools (each: name, summary). tools <name>: name, description, inputSchema.

Review#

changes: file, section and blocks (the filters, or null), trackedChangeCount, and changes in document order (each: changeId, type, author, blockId, blockIndex, section, deleted, inserted). deleted and inserted are the full text, never shortened.

accept, reject: file, action, dryRun, resolved (change ids accepted or rejected), wouldResolve (with --dry-run: what would be; otherwise []), notFound (requested ids that are not pending), failed (pending changes that could not be resolved; each: changeId, code, message), saved, checkpoint. If some ids were not found or failed while others were resolved: exit 2. If none were resolved: exit 1.

diff: file, since (the --since checkpoint, or null for the pending tracked changes), changedParagraphCount, text. text is for reading: [-removed-] and {+added+} inline, which can be ambiguous if the document itself contains those markers.

history: file, checkpoint (current), checkpoints (each: checkpoint, at (ISO 8601, UTC), command, summary).

undo, restore: file, checkpoint (now), from (before), discarded (checkpoint numbers removed), saved.

Output#

render: file, output (the image), outputWritten, mimeType, width, height, pages (1-based), totalPages, view, description, placeholderImageCount, failedImageCount.

export: file, output, outputWritten, format, byteCount, final (whether the output shows no tracked changes: only a .docx can hold them, so every other format is true), view (tracked, accepted, or original: what the output shows), trackedChangeCount (tracked changes in the written file, as revise reads it back; Word stores a replacement as a deletion and an insertion, so this can be higher than the source's count; 0 for other formats; null if a .docx could not be read back), docxExport, and summary. For .docx output, docxExport says what the export did: method ("graft": untouched content copied from the original file; "regenerated": written fresh), exact, regeneratedBlockCount, fallbackCode (why it regenerated, or null). summary describes the written .docx (read back from it). Both are null for other formats.

Create and convert#

new: output, outputWritten, format, mode, checkpoint, summary. checkpoint and summary are null when setting up the file failed after it was written (exit 2). Page options are checked before anything is written.

convert: input, inputFormat, output, outputWritten, format, byteCount, final, view (as for export). input is null when the document came from stdin (-); inputFormat is the format read (docx, odt, rtf, html, md, or txt), from --from, from stdin's bytes, or from the input's extension. Writing to stdout (- as the output) can't be combined with --json.

compare: original, revised, output, outputWritten, author, inlineChangeCount, insertedBlockCount, deletedBlockCount, unmarkedBlockCount (changed blocks that can't carry a tracked change), untrackedRegions (parts that differ but can't be tracked, taken from the revised file), and verification: scope ("normalized_text"), acceptAllMatchesRevised, rejectAllMatchesOriginal. The check compares text with whitespace normalized; it does not check formatting or comments. A redline that fails it is still written: exit 2, redline_unverified.

summary (in new and export): pageCount (null when not measured), wordCount, pageSize, orientation, pageInches (width, height), marginsInches (top, right, bottom, left), title, headingCounts ({"H1": 1, "H2": 4}), lists (each: itemCount), tables (each: rowCount, columnCount), imageCount, headersFooters (each: side, slot, text), trackedChangeCount.

Raw package#

xml ls: file, parts (each: path, byteCount). xml cat: file, part, match, fragments (the distinct elements that contain match: several matches in one paragraph show it once), truncated (more than 20 such elements; the first 20 are shown). xml patch: file, part, replacementCount, saved, checkpoint, copiedFrom.

copiedFrom (replace-all, call, accept, reject, xml patch): with --out, the original the copy was made from, and file is the copy the edit was saved to; otherwise null. When the edit fails outright (exit 1), no copy is left behind.

Everything else#

examples: examples, each { description, command }, plus docs (a page to read more) on some.

skill: markdown. skill install (its own command name): output, outputWritten.

help and --help: commands and globalOptions, or command for one command's help (each command: name, usage, summary, options).

version: version, build.

Tool calls#

call, the tool shorthand (revise replace contract.docx '{…}'), read, and search run an editing tool and report:

KeyMeaning
file, saved, checkpointAs for every command that can change a document.
toolThe tool that ran.
messageThe tool's summary, for reading; may span lines. null if none.
changeIdsTracked changes this call created. An edit that extended an existing change creates none, so an empty list does not mean nothing changed: check saved.
htmlThe blocks the call returned, as HTML with block ids, or null.
resultThe tool's own structured result, or null. Its keys are the tool's own and include snake_case ids such as search_result_id, which later calls take as input.
viewread and search only: the view html shows (tracked, accepted, or original).
viewMatchessearch only: blocks the search tool can't see in the view (each: query, blockId, blockIndex, text, changeIds). Tracked: matches inside deleted text. Original: every match in the original text, and html and result are null (no search_result_id).

A search_result_id stays valid across commands until the document changes. revise remembers the 20 most recent searches per file; an older id is refused with unknown_search_result.

When a tool refuses a call, the command exits 1 with error.code tool_error, the tool's own code in error.details.toolCode, and a data receipt showing saved: false.

Error codes#

CodeWhen
usageWrong arguments, a missing argument, or an unknown option.
unknown_command, unknown_toolNo such command or tool.
file_not_foundA file the command needs does not exist: the document, an input, --from, or @file.json.
checkpoint_not_foundNo such checkpoint.
unsupported_formatrevise can't read or write that format.
read_only_formatrevise reads the format but can't save it in place.
import_failed, read_failedThe file did not open or could not be read.
would_overwriteThe output exists; add --force.
same_fileThe output is the input.
file_busyAnother revise command held the file too long.
file_changedAnother program saved the file while revise worked on it. Nothing was written.
write_failed, commit_failedThe file or its history could not be written. The document was left as it was; a file new had already created is reported with outputWritten: true (exit 2).
io_errorThe system refused a read or write (permissions, a full disk). details: errno, syscall.
save_uncertainA save failed and could not be rolled back. Exit 70. The next command on the file finishes or undoes it.
invalid_regexgrep --regex got a pattern that does not compile.
invalid_jsonTool input is not a JSON object.
invalid_selectionaccept/reject got a selection that can't be combined, or a block range written last..first.
section_not_found--section or --except-section matched no heading. The message lists the headings.
section_ambiguousThe --section text is in more than one heading. Name one by its number or full title.
block_not_found--blocks named a block id the document doesn't have.
tool_errorA tool refused the call; see details.toolCode.
unknown_search_result, stale_search_resultThe search result id is unknown, or the document changed since that search.
change_not_foundSome requested change ids are not pending.
change_not_resolvedSome pending changes could not be accepted or rejected.
replace_failedSome blocks could not be edited.
redline_unverifiedThe redline was written but failed its check.
page_setup_failednew wrote the file, but applying the page setup failed.
no_packageThe file is not a .docx, so it has no package XML.
no_such_partNo such part in the package.
malformed_xmlA patch would produce XML that does not parse.
find_not_found, find_ambiguousxml patch --find matched nothing, or more than once without --all.
body_shape_changedxml patch on word/document.xml would add or remove paragraphs; use the tools.
canvas_missingRendering needs the optional @napi-rs/canvas package.
render_failed, page_out_of_range, too_largeRendering failed, the page does not exist, or the image would be too big.
internalA bug. Run again with REVISE_DEBUG=1 for a stack trace on stderr.

Warning codes#

CodeWhen
file_changed_outsideThe file changed since revise last saw it, and revise re-read it. details: keptBlockCount, changedBlockIds, newBlockCount, removedBlockIds. Read changed and new blocks again before editing them.
save_recoveredAn earlier command was interrupted after writing the file; revise finished recording it.
changes_acceptedThe output format can't hold tracked changes (anything but .docx), so it shows them accepted. details: trackedChangeCount.
font_fallbackA PDF used fallback fonts. details: fonts.
untracked_regionscompare: parts that differ but can't carry tracked changes. details: regions.
summary_unavailableexport wrote the file but could not read it back to describe it.
export_note, engine_warningAnything else the export or engine reported.