Skip to main content

File Viewer

The file panel: read one file as source, rendered Markdown or HTML, inline media, or a diff, shown as a dialog, a grid panel, or a dock chip.

Reviewed

What the File Viewer is

The File Viewer is Daintree's file panel kind: a read-only view of one file. It renders source with syntax highlighting, Markdown and HTML as documents, images, video, audio and PDFs inline, and, when the file has local changes, its working-tree diff. Nothing in it edits anything; it exists so you can confirm what an agent claims to have done without switching to an editor.

To walk a whole directory rather than read one file, use the File Browser, which is a separate panel kind.

Opening a file

WhereWhat you get
Click a file path in terminal outputA file viewer dialog, scrolled to the line if the path carried one (src/index.ts:42:7)
Click a changed file in the Review Hub or the worktree sidebarThe file's diff (see Review Hub)
File Browser, Enter or double-click a rowThe file as its own grid panel
The panel launcherAn empty file panel with a search box (see below). Matches on file, md, markdown, readme, docs, spec, document, viewer
An agent or pluginA dialog (ephemeral) or a grid panel (persistent), depending on which action it dispatches
Tip
Command Control Control +click a file path in a terminal opens it in your external editor instead of the viewer. Clicking a directory in terminal output opens the File Browser revealed at that folder.

A file panel opened with no file shows a picker: type into Search files and it searches the project or worktree root, listing up to 50 matches. Pick one and the panel binds to it.

Dialog, grid, dock

Every panel kind in Daintree has three presentations, and the File Viewer is the kind that uses all three hardest.

  • Dialog: what a terminal file link gives you. A dialog is deliberately ephemeral: it never counts toward the panel limit and is never restored on restart. Dialogs stack rather than replace, so opening a diff from a Review Hub dialog leaves the hub underneath.
  • Grid: a persistent panel alongside your terminals, saved with the layout. Any dialog can become one: the topmost dialog carries an Open as panel button in its header that promotes it into the grid.
  • Dock: the compact strip. File panels are dockable, and they keep both scroll position and view mode across the move, so docking a file mid-read and pulling it back does not reset it. A docked single file panel shows the inline Move to grid button in its header.

Closing a file panel, or moving it to the dock, returns focus to whatever you were last reading rather than to the first terminal in the grid: the viewer is a reading surface, and so is what you were doing before it.

Long files scroll inside the panel's own pane rather than growing the app layout, and the dialog scrolls in both Source and Rendered mode.

Source, Rendered, Diff

The toolbar's left segment is a three-way toggle labeled Source, Rendered and Diff. It only appears when there is more than one mode to choose, and the two optional modes are independent capabilities:

  • Rendered exists for Markdown and HTML only. Every other file is source-only.
  • Diff appears only while the file has a local change in a worktree Daintree knows about. If the change is committed or reverted while you are looking, the segment disappears and the panel falls back to Source.

Source mode carries a metadata bar above the content reading line count, byte size and encoding: 142 lines · 4.2 KB · UTF-8. Rendered mode omits it, because the document is the view.

Markdown

Markdown files get the full Source / Rendered pair. Rendered mode lays the document out with Daintree's own prose styling; Source mode shows the raw text with syntax highlighting.

  • Wrap long lines: a toolbar toggle, offered in Markdown source mode. The choice is a preference, so it holds across files and panels.
  • Local images referenced by a rendered document are re-requested when they change on disk. A Markdown file whose embedded diagram was regenerated shows the new diagram without you reopening the panel: the file's own bytes never changed, which is exactly the case a naive freshness check misses.

HTML

HTML files also get a Rendered mode, served into a sandboxed iframe over a nonce'd internal preview URL that the main process mints only when a read explicitly asks for it. A generated report, a coverage summary, a built page: an agent can produce one and you can look at it without giving the file the run of the app.

In Rendered mode the toolbar's last button changes from Open in editor to Open in browser, which hands the file to your real browser when the sandbox is too tight for what the page needs.

Note
The preview frame is served with a matching cross-origin embedder policy header. Without it the frame loaded but painted nothing: a blank Rendered mode, fixed in v0.27.1. If you are on an older build and HTML previews render empty, that is the bug.

Images, video, audio and PDFs

Media does not go through the text read path at all. Images, video, audio and PDFs are served to the renderer over Daintree's own internal file protocols, which is why they are not subject to the 500 KB text limit: an image larger than that displays rather than failing.

KindPlays or rendersRecognized, but refused with a reason
Imagespng, apng, jpg, jpeg, gif, webp, avif, bmp, icoNone
SVGRead as text, sanitized, then inlinedContent the sanitizer rejects
Videomp4, m4v, webm, ogv, played inlinemov, mkv, avi, wmv
Audiomp3, wav, flac, ogg, oga, opus, m4a, aac, played inlinewma, aiff, aif, mid, midi, amr
PDFFramed into Chromium's built-in viewer, with its own page and zoom controlsNone

The refused formats are listed by name on purpose. Chromium cannot demux them even when the codec inside is one it knows, so the viewer says "Can't play this video format" rather than dropping through to the text path and claiming the file is binary or oversized.

Refresh re-requests the media surface, so a video an agent just re-encoded plays the new file. Background refreshes deliberately do not: a change tick from an unrelated write must not restart playback or throw away a PDF reader's page and zoom.

Diffs

When the file has a local change, the Diff segment opens its working-tree diff without leaving the panel: you do not have to go back to the Review Hub to see what moved. If the file changes underneath a loaded diff, an inline banner reads "File changed since this diff loaded" with a Refresh action.

The multi-file review surface (the changed-file sidebar, per-file viewed markers, full-file toggle, image compare) is a separate panel kind. See Diff Workspace.

The toolbar

ControlWhat it does
Source / Rendered / DiffView mode. Shown only when more than one mode applies.
Path pillShows the path relative to the project or worktree root, middle-truncated to fit while keeping the file name. Click it to copy the absolute path.
Wrap long linesMarkdown source mode only.
RefreshRe-reads the file, or re-fetches the diff, depending on which is on screen.
Show in file browserOpens the File Browser revealed at this file. Offered only when a live worktree contains it: the browser is scoped to a folder, so there is nothing to open for a file outside every worktree.
Reveal in Finder / Show in Explorer / Show in folderThe system file manager, named for your platform. Always offered, including for a file the viewer cannot render. That is exactly when it matters most.
Open in editor or Open in browserYour external editor, or your real browser when you are looking at rendered HTML.

When one of the external actions fails, an inline banner names the target that failed ("Couldn't open in editor", "Couldn't reveal in Finder") with a Retry that re-runs only that one.

Keyboard

ShortcutAction
Command-F Control-F Control-F Find in the focused panel. In a file panel showing source, this opens the viewer's own find bar.
Command-L Control-L Control-L Go to line, in source mode.
EscapeCloses the dialog presentation. A grid or docked panel has nothing for Escape to close. Use the panel's own close control.

Command-F Control-F Control-F is one global binding routed to whichever panel has focus, so the same key finds in a terminal's scrollback, in a file, or in a web page depending on where you are.

Staying current with what agents write

Agents rewrite files while you are watching them, and the panel stays focused the whole time, so "refresh on focus" would never fire. The viewer instead re-reads on a live change signal, and where that signal comes from depends on where the file lives:

  • Inside a worktree: the worktree's own filesystem watcher and its git-status poll, whichever moved most recently. Two signals rather than one, because git status never moves for a write into a gitignored folder.
  • Outside every worktree: scratch folders, projects with no repository, unregistered repos. These previously showed whatever was on disk when the panel opened. They now get their own live signal, polled from the main process and only while the view is visible, so a file the panel is showing stays current wherever it sits.
  • Returning to a project: a project view that was cached while you worked elsewhere re-reads its file panels on reveal, because everything that happened while it sat cached is precisely what the panel could not otherwise see.

Background re-reads are silent: no loading skeleton flashes, and a transient failure (catching a file mid-save) keeps the last good content rather than blanking the panel. A file that is genuinely gone (deleted, or permissions revoked) surfaces the error rather than showing stale text forever.

Limits and error states

Text reads are capped at 512 KB. The cap is not configurable, and it applies only to the text path: media served over the internal protocols is unaffected.

StateMessage
BinaryBinary file: cannot display
Too largeFile too large to display as text (> 500 KB)
Git LFS pointerGit LFS pointer: run git lfs pull to download the file contents
MissingFile no longer exists
Outside the rootFile is outside the project root
Invalid pathInvalid file path
PermissionsPermission denied: you don't have access to this file
Unsupported mediaCan't play this video format / Can't play this audio format, naming the formats that do work

Every error state keeps a Retry button, except for an unsupported media format: retrying the same extension can never succeed, so the action would be dead. Reveal and Open in editor stay available in all of them.