grip-live-diff

command module
v1.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 6, 2026 License: MIT Imports: 1 Imported by: 0

README


Logo

grip-live-diff

Preview Markdown with GitHub's look, and see what changed since you last looked.

What it is

grip-live-diff is a single Go binary that renders a Markdown file in your browser the way GitHub would, reloads the page whenever the file changes on disk, and highlights what changed, word by word, inside the rendered document.

It started as a fork of go-grip by Christoph Herb, a Go reimplementation of grip that renders offline instead of calling GitHub's API. The rendering engine is still go-grip's. What this fork adds is everything around reading a document while something else is writing it: an editor, a teammate, or an AI agent rewriting a spec in place. After an auto-reload the page just looks different and you have to re-read it all to find the delta. This tool shows the delta.

Install

go install github.com/babs/grip-live-diff@latest

Prebuilt binaries for Linux, macOS and Windows, amd64 and arm64, plus 386 on Linux and Windows, are on the releases page, as .xz archives (.zip too on Windows) plus a grip-live-diff.sha256sum. A release binary updates itself in place, after checking the published checksum:

grip-live-diff update

Usage

grip-live-diff README.md   # render one file
grip-live-diff             # README.md of the current directory, or a file listing if there is none

The browser opens on http://localhost:6419. The server watches the file's directory, so any .md under it is served as well, at its own path.

Flag Default Effect
-p, --port 6419 Port to listen on
-b, --browser true Open a browser tab on start (-b=false to disable)
--no-reload false Do not push a reload to the browser when the file changes
-H, --host localhost Host used in the printed and opened URL (the server binds all interfaces)
--bounding-box true Draw the GitHub-style box around the document
--version Print version and commit

The page title comes from the file name (my-guide_v2.md becomes My Guide V2). Ctrl-C stops the server.

Seeing what changed

The ± button in the toolbar switches the diff on and off (key d). It carries a dot as soon as the file on disk differs from the version you opened, so a reload tells you something moved even before you look. With the diff on, a second row picks the reference, one click each:

  • since open (?diff=open, key 1), everything that changed since you opened the file;
  • last edit (?diff=last, key 2), only what the most recent save brought;
  • HEAD (?diff=head, key 3), everything not committed yet, against git HEAD. Greyed out when the file is not served from a git work tree; a file that has never been committed says so instead of showing the whole document as new.

Switching the diff back on returns to the reference you used last.

Insertions are green, removals are struck through in red, and the comparison is done on words, not lines, so re-wrapping a paragraph is not a change. Inside a code block indentation still counts. The diff survives the auto-reload, so the highlights refresh on every save.

Mark as read takes the current disk content as the new reference for since open and last edit. It is greyed out against HEAD, which is git's to move, and when there is nothing new. The scroll position is kept.

Minimap

While a diff is on, a minimap of the whole document runs along the right edge, VS Code style: a scaled rendering with every insertion and removal marked in green and red, and a box for the part on screen. Click it to jump, drag the box to scroll. On a long document the minimap slides with the page so the current position stays visible. The button next to Mark as read hides it.

Annotating for an agent

When the thing rewriting the file is an agent, the feedback loop has a gap: you read the preview, spot a sentence to rework, then describe where it is in the chat. Annotations close it. Turn capture on with the pencil button, select text, click Annotate (or press a) and type what should change. The passage is marked Confluence-style, a yellow tint with an orange underline, and the comment is saved next to the file as <name>.annotations.json5:

// grip-live-diff annotations for README.md. JSON5: comments and trailing commas are fine.
// ... how to take part, what not to touch, the entry format ...
{
  "version": 1,
  "file": "README.md",
  "annotations": [
    {
      "id": "k3f9x2",
      "exact": "the quick brown fox",
      "prefix": "e sentence before it ends with ",
      "suffix": " jumps over the lazy dog. Then",
      "lines": [42, 42],
      "comment": "Too informal, rephrase.",
      "created": "2026-09-05T11:52:03+02:00",
      "updated": null,
      "file_hash": "sha256:3b2f…"
    }
  ]
}

Then hand the file to the agent: "handle the comments in README.annotations.json5". The header of the file tells it the rules: take an flock on the file while editing it; once a request is handled, set status: "done" with a short reply, or delete the entry; when it rewrites an annotated passage, put the new wording in exact so the mark follows; id, created, file_hash and comment are the reader's and must not change. lines is a hint into the markdown source, recomputed at every save from the browser, so exact is the truth. A comment with exact: null is about the whole document (the document button, or A).

Marks are drawn whenever the file has annotations, capture on or off. Hovering one shows the comment and the agent's reply; clicking it opens the comment to edit or delete. The row under the toolbar walks through them, n and p do the same: document-level comments first, then in document order, then the ones whose text is gone from the file. Each comment box says which version of the file it was written against and whether the file changed since; a passage that was reworded is re-anchored on its surroundings and drawn with a dashed underline, a passage that disappeared with its surroundings is kept in the file and reachable last. An entry answered by the agent turns grey and shows the reply.

The marks are also listed at the foot of the document, in the same order; hovering an item lights its mark, clicking it opens the comment. Saving writes the sidecar without reloading the page. Marks need the CSS Custom Highlight API (Chrome 105, Firefox 140, Safari 17.2); older browsers keep the file but draw nothing.

Toolbar

Button Does
Page width: normal (GitHub's 896px), wide (1400px), full (no limit)
± Diff on/off, see above
theme Light or dark
pencil Annotation capture on/off, see above

Keys: d toggles the diff, 1 2 3 pick the reference, n p walk the annotations, a annotates the selection, A comments on the whole document, Esc closes a comment box, Ctrl-Enter saves it.

Width, theme, minimap visibility, annotation capture and the last diff reference are kept in localStorage, so they survive restarts. The open/closed state of <details> blocks and the scroll position survive a reload, per tab.

Rendering

Inherited from go-grip, so the output matches GitHub for the things that matter:

  • GitHub Flavored Markdown with tables, task lists and footnotes
  • syntax highlighting with a copy button on every code block
  • GitHub emojis (:+1:) and #hashtags styled like GitHub
  • issue and PR references (grafana/grafana#22) linked to GitHub
  • mermaid diagrams, with zoom
  • math, inline ($...$), block ($$...$$) and in math code fences
  • alerts (> [!NOTE], [!TIP], [!IMPORTANT], [!WARNING], [!CAUTION])
  • YAML frontmatter rendered as a table
  • a print stylesheet

Open this README in the tool to see three of them:

graph LR;
    edit[file changes] --> reload --> diff[diff highlighted]

$$\left( \sum_{k=1}^n a_k b_k \right)^2 \leq \left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right)$$

[!TIP] Set ?diff=head in the URL to review your uncommitted edits to a document before committing.

A spec in diff mode, with the minimap

Development

Tooling is pinned in mise.toml (Go, golangci-lint, prek):

mise run build   # -> bin/grip-live-diff
mise run test
mise run lint

Features start as a spec in specs/ before any code. release.sh builds the release matrix and the checksum file; the Build and release workflow runs it on every v* tag.

Lineage

  • grip by Joe Esposito: the original, Python, rendering through GitHub's API.
  • go-grip by Christoph Herb: the offline Go rewrite this project forks. Rendering, theming, mermaid, math and emoji support are his work.
  • grip-live-diff: the live diff, minimap, inline annotations for an agent, width toggle, git HEAD comparison and self-update.

MIT, see LICENSE.

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
pkg
alert
Package alert provides a Goldmark extension for GitHub-style alerts.
Package alert provides a Goldmark extension for GitHub-style alerts.
details
Package details provides a Goldmark extension for stateful collapsible details elements.
Package details provides a Goldmark extension for stateful collapsible details elements.
frontmatter
Package frontmatter detects and extracts YAML frontmatter from markdown sources and renders it as an HTML table.
Package frontmatter detects and extracts YAML frontmatter from markdown sources and renders it as an HTML table.
ghissue
Package ghissue provides a Goldmark extension for GitHub issue and PR references.
Package ghissue provides a Goldmark extension for GitHub issue and PR references.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL