# Revise CLI

Read, edit, and redline Word documents. Available as CLI and TypeScript library.

```bash
npx revise
```

## For Agents

The `revise` CLI makes AI agents faster and cheaper.

Claude Code and Codex finish the same document tasks about 1.5-2× faster and using 30-70% less usage compared to their default `docx` toolset. See our [benchmarks on GitHub](https://github.com/reviseio/revise/deployments/benchmark).


```text
Read https://revise.io/skills/cli.md and follow it.
```

## Install

```bash
npm i -g revise
```




Global options:

- `--json`: one machine-readable object per command; see [JSON output](https://revise.io/developer/docs/revise/json).
- `--author <name>` (or `REVISE_AUTHOR`): sign tracked changes.
- `--no-color`: plain text. Output is colored only on a terminal, and never
  with `--json`. `NO_COLOR=1`, `TERM=dumb`, and `FORCE_COLOR=0` turn it off;
  `FORCE_COLOR=1` turns it on even in a pipe.
- `--help`: help for a command, e.g. `revise render --help`.

Results go to stdout. Warnings and errors go to stderr as
`warning[code]: …` and `error[code]: …`, often with a `hint:` command to run
next.

Exit codes: `0` done (including nothing to do), `1` failed and nothing was
saved, `2` partly done (some of it was saved; the error says what wasn't),
`70` internal error or a save whose outcome is uncertain.

## Reading

| Command | What it does |
| --- | --- |
| `status <file>` | Size, mode, pending changes, checkpoint, and how faithfully it round-trips to Word |
| `outline <file>` | Headings with block ranges, as `first..last` block ids, and paragraphs that look like headings but are body text |
| `read <file> [index] [--count n]` | Blocks as HTML with block ids, from `index` on (`n` of them) |
| `read <file> --section s` | A section, subsections included: `"8"`, `"8.1"`, its title, or several: `"4,7,9"` |
| `read <file> --blocks a,b` | Specific blocks, or a range `first..last` |
| `grep <file> "text" ["text" ...] [--regex] [--ignore-case]` | Blocks matching any of the phrases, with ids: a long block shows the passage around each match, and after 40 blocks it stops (`--json` has every block, whole) |
| `search <file> "text" ["text" ...]` | Matching blocks as HTML |

`read`, `grep`, and `search` show pending tracked changes: `read` marks them
`<del data-change-id="…" data-author="Jane Smith">100</del><ins …>120</ins>`,
and `grep` writes them `[-100-]{+120+}` and finds text on either side, saying
which matches are in deleted or inserted text. `search` adds the blocks whose
deleted text matches. `--view accepted` reads the text as if every change were
accepted (what the editing tools edit), `--view original` as if every one were
rejected. Tracked HTML pasted back into a tool edits the accepted text: `<ins>`
reads as its text and `<del>` is left out.

## Editing

Edits save the file. To keep it as it is, add `--out new.docx` to
`replace-all`, `call`, `accept`, `reject`, or `xml patch`: the result is saved
as the new file (same format; `--force` replaces an existing one), and block
ids read from the original work on it. The copy has its own history, starting
from the original, so `undo` steps back to it.

| Command | What it does |
| --- | --- |
| `replace-all <file> "find" "replace"` | Replace every occurrence: body, headers, footers, footnotes. `--ignore-case`; `--exact` makes quotes and spaces count; `--blocks a,b` limits it |
| `batch <file> '[{"tool":…}, …]'` | Several edits in one save: editing tools, plus `{"tool":"replace_all","find","replace"}`. If one step fails, nothing is saved |
| `replace-text …` | The 3.0 name of `replace-all`; still works |
| `call <file> <tool> '<json>'` | Run an editing tool. JSON can also come from stdin (`-`) or a file (`@file`). `--direct` applies it without tracking. |
| `<tool> <file> '<json>'` | The same, shorter: `revise replace f.docx '{...}'`. `revise <tool> --help` shows its input schema. |
| `tools [name]` | List the editing tools, or show one's schema |
| `mode <file> [suggest\|edit]` | Track changes, or apply directly |

The tools are the ones the Revise agent uses: `replace`, `insert_block`,
`replace_block`, `remove_blocks`, `style_blocks`, `leave_comment`,
`insert_footnote`, table row, column, and cell tools, `set_header_footer`,
`set_page_layout`, and the read and search tools. `revise tools <name>` prints
a tool's JSON schema.

```bash
revise call contract.docx replace - <<'JSON'
{"id": "p-12", "replacements": [{"find": "thirty", "replace": "sixty"}]}
JSON
```

## Review

| Command | What it does |
| --- | --- |
| `changes <file> [--section s] [--blocks b] [--details]` | Pending tracked changes: where they are and what text they change |
| `diff <file> [--since n]` | Word-level diff of the pending changes, or since checkpoint `n` |
| `accept <file> <id...>` | Accept changes by id |
| `reject <file> <id...>` | Reject changes by id |
| `accept <file> --all` | Every pending change (`reject` too) |
| `accept <file> --section s` | Changes under one heading, subsections included: `"8"`, `"8.1"`, or its title |
| `accept <file> --blocks b` | Changes in these blocks: `id,id` or a range `first..last` |
| `accept <file> --except-section s` | Every change outside a section |
| `history <file>` | Checkpoints |
| `undo <file> [steps]` | Undo the last edits |
| `restore <file> <n>` | Go back to checkpoint `n` |

`--dry-run` on `accept` and `reject` lists what would be settled.

A section is a heading and everything under it until the next heading at its
level or above. Numbers work whether they're typed or Word's automatic
numbering, as `outline` shows them. A title matches when typed in full, or by
any part of it that's in only one heading; text in several headings is an
error, never a guess. `--section`, `--except-section`, and `--blocks` combine.
`read` and `replace-all` take block ids only (`--ids` is the older name).

## Output

| Command | What it does |
| --- | --- |
| `export <file> <out>` | Write a copy as `.docx`, `.pdf`, `.md`, `.html`, or `.txt`. `--view accepted` accepts pending changes in the copy, `--view original` rejects them; only a `.docx` keeps them tracked. |
| `render <file> [--page n] [--pages a-b]` | Pages as an image. `--view tracked`, `accepted`, or `original`; `--layout` overlays layout boxes. Needs a canvas package: `npm i @napi-rs/canvas` (or `canvas`). |

## Create and convert

| Command | What it does |
| --- | --- |
| `new <out.docx> --content draft.md` | A new document from Markdown or HTML. `--page-size letter` or `a4`, `--orientation`, `--margins 1in`, `--header text`, `--footer "Page {PAGE} of {PAGES}"` |
| `compare <original> <revised> [--out redline.docx]` | A redline: the revised document with every difference as a tracked change |
| `convert <in> <out>` | Convert between formats; `--view accepted` or `original` as for `export`. Either side can be `-` for a pipe (below). |

### Pipes

`-` as the input reads the document from stdin, and `-` as the output writes
it to stdout:

```bash
cat notes.md | revise convert - notes.docx           # format recognized from the bytes
curl -s https://example.com/page | revise convert - page.docx
revise convert contract.docx - | grep -i liability   # stdout is Markdown by default
revise convert contract.docx - --to html > contract.html
revise convert contract.docx - --to docx | ssh host 'cat > copy.docx'
```

On stdin, revise recognizes .docx and .odt from their zip entries, and RTF
and HTML from how they start (after any leading whitespace or comments). Any
other text reads as Markdown, which plain text already is. Text that opens
with `<!doctype html>`, `<html>`, `<head>`, or `<body>` is HTML. Text that
opens with any other tag is HTML too, unless the rest of it writes Markdown
(`#` headings, code fences, links, `*emphasis*`), like a README under its
banner; lists count as Markdown only when no HTML block is closed. Text may
be UTF-8, UTF-16, or Windows-1252, recognized or named. When a guess would be
wrong, `--from` settles it.
`--from md|txt|html|rtf|odt|docx` names the format instead, for example
`--from txt` to keep a line starting with `#` as text. `--to md|html|txt|docx|pdf`
picks stdout's format. A .docx or PDF won't print to a terminal, and `--json`
can't be combined with `-` as the output, because both would need stdout.

## Names from 3.0

These still work, so scripts written for 3.0 keep running:

| 3.0 | Now |
| --- | --- |
| `replace-text` | `replace-all` (output keeps `"command": "replace-text"` when run under the old name) |
| `read --ids`, `replace-text --ids` | `--blocks` |
| `new --from <file>` | `new --content <file>` |
| `new --page <size>` | `new --page-size <size>` |
| `search --page <n>` | `search --results-page <n>` |

## Raw package

For what the tools don't cover: style definitions, numbering, settings,
document properties.

| Command | What it does |
| --- | --- |
| `xml ls <file>` | The parts in the `.docx` package |
| `xml cat <file> <part> [--match text]` | A part's XML, or the elements matching `text` |
| `xml patch <file> <part> --find '<xml>' --replace '<xml>' [--all]` | Replace XML that matches once (or every match) |
| `xml patch <file> <part> --file new.xml` | Replace a whole part |

Patches apply directly to the file, and `undo` reverts them.

## Agents

| Command | What it does |
| --- | --- |
| `examples` | Example commands for the most common jobs |
| `skill` | Print the agent skill (SKILL.md) |
| `skill install [--dir d]` | Install it as `revise-cli/` where the agent reads skills: `.claude/skills` from Claude Code or in a project with a `.claude` folder, else `.agents/skills` (Codex, Cursor, Copilot, and others). Replaces a `revise/` folder an earlier version installed |

See [agents](https://revise.io/developer/docs/revise/agents).
