# herdr file viewer: the right pane decides what to show you

> herdr-file-viewer is a read-only Rust TUI pane for herdr that picks the view for you: a changed file opens as a diff, a README renders as markdown, code gets highlighted. It never writes, it hands off to your editor when you press one key, and its annotations travel back to an agent as copied text.

**smarzban/herdr-file-viewer** — A git-aware, read-only file viewer for herdr. Mouse friendly,  keyboard-driven TUI: tree + content pane with diffs, rendered markdown, and syntax highlighting.

- Repository: https://github.com/smarzban/herdr-file-viewer
- Stars: 624 · Forks: 50
- Language: Rust
- License: MIT
- Published: 2026-09-17 · Updated: 2026-09-17 · Language: en
- Canonical page: https://hysenlabs.com/projects/smarzban-herdr-file-viewer

## The right pane decides what to show, not you

The tree is on the left and the content is on the right, but the interesting part is that you do not pick what appears there. A file that git reports as changed opens as a diff. A README opens rendered, with headings, inline code and tables drawn in your terminal's theme. Code opens with syntax highlighting. There is no cat, no mode switch, and no commands to learn before you read.

You override it when you want to, and only then. `v` cycles the view between the three, so the automatic choice has an escape hatch without becoming the interface.

The whole thing is read-only. It never writes to your files, which is the property that makes it safe to point at a fresh clone or at a worktree an agent is actively editing, where a viewer that could save would be a liability rather than a convenience. The related project herdr-tsk takes the complementary half, keeping your work and your agents' work on one board, as a TUI for you and a CLI for them.

## Git lives in the tree rather than a second window

Every row in the tree carries a status character: `M` for modified, `A` for added, `D` for deleted and `?` for untracked. The README is explicit that this is not a separate git client; the status is part of the file list, which is what removes the round trip between looking at a tree and looking at a diff summary.

Filtering and jumping follow from that. `c` narrows the tree to changed files only, and `]` and `[` jump to the next and previous changed file without opening anything. `b` flips the diff baseline between your branch's merge base and `HEAD`, which is the difference between seeing what your branch did and seeing what the last commit did.

`f` fuzzy-finds any file in the tree, so when you know the name but not the path, one key is enough. The combination is what makes a large working tree navigable: filter to changed, jump, read the diff, flip the baseline if the picture does not add up.

## Pin freezes the right pane while the tree keeps moving

`p` pins the current file, which freezes it on the right while the tree stays browsable. The layout then shows three things: the tree, whatever file you are on, and the frozen pinned file with its baseline, for instance `Pinned: [main]`.

The interesting use is comparison across checkouts. `W` switches to another git worktree in place, so you can pin a file from one checkout and then walk the same file in another. The alternative is pinning the old version and reading the new one, which is the same operation aimed at history rather than at a second working copy.

`Z` takes the current file full screen when the split is too narrow for a diff, and `L` copies a `path:line` reference, or the selected lines, which is the piece that makes anything you point at quotable in an issue or a message.

## Annotations leave as text, not as a feature request

The agent loop is the reason the plugin exists, and it runs in both directions. Outbound, you teach an agent the bundled skill at `skills/herdr-file-viewer/SKILL.md`, after which an instruction like opening `src/app.rs:42` in Files drops you at that line rather than at the top of a file.

Inbound, you mark things yourself. `a` annotates the current file or the selected range, `A` then `y` copies the notes out, and you paste them into the chat. The notes are text in your clipboard, not a structured attachment, which is the point: nothing has to be interpreted or exported for another tool to read them.

Handing off in the other direction is three keys. `e` opens the file in neovim, vim, micro, or whatever you configured as `editor`, falling back to `$EDITOR`. `O` opens it in the operating system default application, and `R` reveals it in the file manager.

## The viewer never writes, and e waits for you to quit

The editor hand-off is the one place where the read-only rule is interesting. `e` suspends the viewer and starts your editor on the file. You edit there, and when you quit, the viewer returns. The viewer itself never writes the file at any point, which means an agent cannot be interrupted by the viewer saving over something.

That restriction is treated as a feature rather than a limitation, and it is backed by a stated threat model: SECURITY.md covers the threat model for opening untrusted content and how to report a vulnerability. The claim is that the viewer is hardened for an agent's worktree or a fresh clone, contexts where the file contents are not necessarily yours.

Documentation is split to match. ARCHITECTURE.md covers the in-process TUI that owns both columns, the component map and the load-bearing decisions, while docs/usage.md and docs/keys.md hold the feature tour and the complete key and mouse reference.

## Styling is delegated, and the fallback is plain text

Rendering is not implemented in the viewer. It delegates to glow for markdown, git-delta for diffs and bat for code, which is why the install step asks for all three:

```bash
# 1. Install the plugin (downloads a prebuilt binary for released versions; otherwise builds from source):
herdr plugin install smarzban/herdr-file-viewer

# 2. (recommended) install the renderers, so markdown / diffs / code are styled, not plain text:
brew install glow git-delta bat     # macOS, or use your package manager
#   Linux / cross-platform: run scripts/install-renderers.sh from the plugin dir (`herdr plugin list`)
```

On macOS that is a brew line. Elsewhere you run `scripts/install-renderers.sh` from the plugin directory, which is the path `herdr plugin list` prints.

The consequence of skipping step two is worth stating plainly: the views still work, they just arrive as unstyled text, and docs/renderers.md documents the plain-text fallback along with each integration. Whether a missing binary degrades or breaks depends on that fallback, so install them before you judge the output.

## The plugin registers its own actions, so config is two key bindings

Installing the plugin is one command. After that the only configuration is a key binding in your herdr config at `~/.config/herdr/config.toml`, and there are two of them, one for a split and one for a tab:

```toml
[[keys.command]]
key = "prefix+f"
type = "plugin_action"
command = "herdr-file-viewer.open-file-viewer"
description = "open file viewer in split"

[[keys.command]]
key = "prefix+shift+f"
type = "plugin_action"
command = "herdr-file-viewer.open-file-viewer-tab"
description = "open file viewer in tab"
```

Run `herdr server reload-config` and the keys work. The open actions themselves ship inside the plugin and register on install, which is why nothing else needs writing.

Optional settings are a read-only TOML file that can override the editor, the renderer and opener commands, startup toggles, the tree layout and the keybindings. A commented `config.example.toml` ships in the plugin folder; copy it to `config.toml` in the directory `herdr plugin config-dir herdr-file-viewer` prints. The `?` overlay has a Settings section that shows what is actually in effect.

## Rust 2024 with a perf lane that is off by default

The Cargo manifest pins a modern toolchain: edition 2024 with rust-version 1.96, library `herdr_file_viewer` in `src/lib.rs` and binary `herdr-file-viewer` in `src/main.rs`. The runtime dependencies are small and each one is a deliberate choice: ratatui and crossterm for the terminal, ansi-to-tui to render the output of external tools, ignore for the file walk, and serde with serde_json and toml for configuration.

The single feature flag is `perf`, and the comment above it is unusually informative. It enables the absolute stopwatch budget tests, namely render_perf, tree_perf and the reroot budget, and is off the default pull request lane, run instead with `cargo test --features perf`. The relative-scaling tests, search_perf and index_perf, run on the default lane.

Testing leans on insta for snapshots and expectrl for driving a pseudo terminal, which is what makes an in-process TUI testable at all. Version 1.17.0 in the manifest matches the newest release tag, dated 2026-09-16, the same day as the last push to main.

## Conclusion

Use it if you read a lot of code that an agent is touching, and the thing slowing you down is having to remember whether to cat, diff or read. Skip it if you want a viewer that can write, since that is a deliberate non goal and SECURITY.md covers the threat model for untrusted content. Before you rely on the pretty output, install glow, delta and bat, because without them the same views fall back to plain text, and on Windows accept that native support is still a preview while WSL is the settled path.

## FAQ

### What does the herdr file viewer actually show?

A tree on the left and a content pane on the right that opens a changed file as a diff, a README as rendered markdown and code with syntax highlighting. Press v to cycle between the three views when you want something other than the automatic choice.

### Does herdr-file-viewer ever modify my files?

No. It is read-only and never writes, which is why it is described as safe on an agent's worktree or a fresh clone. Press e to suspend the viewer and edit the file in neovim, vim, micro or your configured editor, and the viewer returns when you quit.

### How do I install herdr-file-viewer and its renderers?

Run herdr plugin install smarzban/herdr-file-viewer, which downloads a prebuilt binary for released versions and otherwise builds from source. Then install glow, git-delta and bat, with brew on macOS or by running scripts/install-renderers.sh from the plugin directory elsewhere.

### How do I pass notes from the viewer back to an AI agent?

Mark the file or the selected range with a, copy the notes with A then y, and paste them into the chat. In the other direction, teach the agent the bundled skill so an instruction to open a path and line lands you there.

### Is the herdr file viewer supported on Windows?

Native Windows is supported as a preview, with the same install and open actions using -windows action ids and herdr's preview channel. WSL works today with no extra setup. See docs/windows.md for the specifics.

## Sources

- [Issues](https://github.com/smarzban/herdr-file-viewer/issues)
- [License: MIT](https://github.com/smarzban/herdr-file-viewer/blob/main/LICENSE)
- [README](https://github.com/smarzban/herdr-file-viewer/blob/main/README.md)
- [Releases](https://github.com/smarzban/herdr-file-viewer/releases)
- [smarzban/herdr-file-viewer on GitHub](https://github.com/smarzban/herdr-file-viewer)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/smarzban-herdr-file-viewer
