File Browser
A read-only file tree beside your agents: browse a worktree, scratch or plain folder, read files inline, and send an @file reference straight into an agent's input.
What the File Browser is
The File Browser is a read-only panel with two columns: a collapsible, resizable tree on the left and a viewer on the right that shows whatever the tree points at. It arrived in v0.29 and grew through v0.31 into the panel you reach for when the question is "what is in here, and what did the agent just touch".
It is a separate panel kind from the File Viewer. The File Viewer shows one file; the File Browser is the tree you navigate, with a viewer attached. Neither of them edits anything.
Unlike a terminal or a file panel, the browser does not dock: a two-column browser has no meaningful compact chip form. As a dialog it is pinned at 85% of the window height so an expanding tree does not resize the frame under your cursor.
Opening one
There are six ways in, and as of v0.31 every global one opens the browser as a persistent grid panel rather than a modal dialog. A second launch does not open a second browser: it focuses the one already open for the same folder.
| Entry point | Notes |
|---|---|
| Option-Command-F Control-Alt-F Control-Alt-F | Opens the browser for the focused worktree, or for the project or scratch folder when no worktree is selected. |
| The toolbar Browse files button | Ships visible on the toolbar as of v0.31. The web browser and dev preview moved into a panel tray in the same change; no saved layout was altered. |
| Right-click a file path in a terminal → Open in file browser | Opens the tree revealed at that path. Clicking a directory link in terminal output does the same thing directly. |
| The File Viewer toolbar → Show in file browser | The route back to the tree the file came from. Offered only for a file inside a live worktree. |
| The empty-grid launcher → Browse files | The chip row you see in a workspace with no panels open yet. |
| A worktree card's menu → Browse Files | Selects that worktree first, then opens its browser: a person who names a worktree means to go there. |
The panel launcher also carries it, matching on files, browse, explorer, tree, folder, finder and assets.
The two columns
Each column can be collapsed, and each column's toggle lives in the other column's header, which is what makes "both collapsed" unreachable.
- Toggle file viewer sits in the tree's header. Collapsing the viewer gives the tree the whole panel.
- Toggle file tree sits in the viewer's toolbar. Collapsing the tree leaves a single reading column.
The divider between them is a drag handle: the tree column runs from 200px to 600px, defaults to 288px, and remembers its width per panel. It is keyboard-operable: focus it and use the arrow keys, with Shift for a coarser step. A remembered width is stored even while the viewer is collapsed, so reopening the viewer restores the split you had.
Tree header
Back to worktree root · the root path · Up one level · Hide dotfiles · Refresh · Toggle file viewer. Refresh moves to the viewer's toolbar whenever a file is open there, so the panel never shows two buttons named Refresh.
Viewer toolbar
Toggle file tree · a Source/Rendered toggle for Markdown · the file's path (click to copy) · the sort menu or Refresh · reveal in the system file manager · Open in editor.
Navigating the tree
The tree distinguishes moving through a folder from asking to see it, because those are different intentions and conflating them kept hijacking the viewer.
| Gesture | On a file | On a folder |
|---|---|---|
| Click, or arrow onto it | Opens it in the viewer column | Expands it. The viewer stays on whatever you were reading. |
| Enter or double-click | Opens the file as its own File Viewer panel in the grid | Renders its contents as a listing in the viewer column |
| → | None | Expands, or steps into the first child if already expanded |
| ← | Jumps to the parent folder | Collapses, or jumps to the parent |
| Home / End | First / last visible row | |
| Shift-F10 Shift-F10 Shift-F10 or the Context Menu key | Opens the row's context menu without the mouse | |
Opening a file as its own panel reuses a panel already showing that file rather than piling up duplicates. If the browser was a dialog when you pressed Enter, the dialog closes: otherwise the panel you just asked for would be sitting behind it.
The tree scrolls to keep the cursor visible only when the cursor actually moves or first appears. Expanding a folder re-splices every row below it, and treating that as movement used to drag the view off the folder you had just opened; since v0.31 the tree stays put.
Two rows can be highlighted at once, and they mean different things: the cursor is where the tree is, and the open row is what the viewer column is showing. They diverge whenever you arrow past a folder, which is the whole point of the split. Neither uses the accent color. Collapsing a branch that holds the cursor rehomes the cursor onto the branch itself, so the keys that read it never go dead.
The tree is single-select, and there is no search box in it. To find a file by name, open it from somewhere that already knows the path (a terminal link, the changed-files summary, or the File Viewer's own file picker), and the tree expands to it.
A restored browser paints its last-known tree structure instantly while the live refresh runs behind it. The snapshot stores names and paths only (never contents, sizes or timestamps), which is why a just-restored row shows a placeholder dash for Size and Modified until the refresh lands.
What the right-hand column shows
Three states, in priority order:
- A file is selected: the file is read inline, with a Source/Rendered toggle for Markdown.
- A folder is selected: a listing with Name, Size and Modified columns and an item count. A single click in the listing re-points it at a subfolder or opens a file; there is no double-click counterpart, because either way the listing's contents change.
- Nothing is selected shows the Changed files summary: every uncommitted change in the worktree, with its status marker, path, and
+/-line counts. Clicking one reads the file (its diff belongs to the Review Hub), and expands its ancestors in the tree so the row stays findable afterwards. Deleted files stay listed (the change set would be lying without them) but are not openable. On a clean worktree the pane reads Worktree is clean.
The idle summary is the reason the browser exists in the shape it does: you open it to answer "what did the agent just change in here", so on a dirty worktree that answer is the pane's primary content rather than a placeholder apologizing for the absence of one.
Sorting
The sort menu in the viewer toolbar has two groups: Sort by (Name, Modified, Size, Type) and Order (Ascending or Descending). One value orders both the tree and the listing, so the two columns can never disagree about the same directory. It is the single home for sort: the listing's column headers are deliberately not clickable, because a header that looks sortable in one column with no counterpart in the tree would misdescribe what the setting governs. The menu is hidden while a file is open (a single document has no order), and the slot goes to Refresh instead.
Git status on rows
Tree rows carry a status marker for every uncommitted change, and a folder carries the worst status found anywhere beneath it, so a collapsed folder can say "something in here changed" without its children ever having been listed. Worst-first:
conflicted → deleted → modified → added → renamed → copied → untracked → ignored
That order is specific to this badge. A conflict blocks the branch outright, so it outranks everything; a deletion means the content is gone rather than merely edited; gitignored noise comes last. The index is built from the changed-file set alone (dozens to hundreds of entries), never from the tree's own listings, which run to tens of thousands of nodes on a real repository.
Rows also carry file-type icons, so a directory of mixed assets is scannable without reading every extension.
Sending a file to an agent
Two gestures put a file reference into an agent's input:
- Drag a row onto an agent's terminal.
- Press Command-I Control-I Control-I while the tree has focus and the cursor is on a row.
Nothing gates either gesture on the row being a file: a folder reference works the same way, which is often what you want when the instruction is "look at everything under here". Both append an @file token to the agent's draft, in the same cwd-relative form autocomplete already produces. The cwd used is the destination agent's, not the browser's: that is what keeps a reference into the agent's own worktree short while a cross-worktree one falls back to an absolute path. Duplicates are preserved: referencing the same file twice is something people do on purpose.
The destination is the agent you were last typing to; failing that, the sole eligible agent in the view. If neither resolves, the gesture refuses with "No agent is available for a file reference". It also stands down while two or more agents are armed for a fleet broadcast, so one reference cannot fan out to a whole fleet by accident.
Neither gesture moves focus. You are mid-flow in the tree and likely to reference several files; a locator pill names the destination instead.
Hidden files: two layers
Two independent rules decide whether a row appears, and they are not the same rule twice.
| Always-hidden patterns | Hide dotfiles | |
|---|---|---|
| Scope | App-global: every file browser panel | Per panel |
| Where | Settings → Worktree → Always-hidden files | The tree header's Hide dotfiles toggle |
| Default | .DS_Store, Thumbs.db, desktop.ini, ._*, .git | Off: dotfiles are visible by default |
| Matching | Basename only, with * as a wildcard. Slashes are rejected: this is a junk list, not an ignore file. | Any entry whose name starts with a dot |
The always-hidden list is checked first and unconditionally: a name it matches stays hidden whatever the dotfile toggle says. That is why .git lives there rather than relying on the dotfile rule: turning dotfiles on to see .env should not also unfold a repository's object store into the tree. The list is editable, resettable, and capped at 100 patterns of 200 characters each; clearing it entirely is a valid "hide nothing" choice.
When the dotfile toggle empties a folder, the tree says so rather than claiming the folder is empty: "Dotfiles are hidden here", with a Show dotfiles action. A selection the toggle has just hidden gets a reveal strip below the tree instead of silently vanishing.
Re-rooting the tree
A monorepo's worktree root is rarely where you are working. Any folder row's menu offers Set as root, which reframes the tree at that folder. From there the header gives you Up one level and Back to worktree root.
While the tree is re-rooted, the header's root path becomes a button: click it to copy the absolute path, the same thing a row's Copy path does. Its tooltip carries the untruncated path.
Beyond git worktrees
Since v0.30 the browser opens scratch workspaces and project folders with no repository, not only git worktrees, the same "a git repo is no longer required" shift that runs through projects and worktrees. When no worktree is selected, the browser resolves the workspace folder behind the view and roots itself there.
Some worktree-scoped items are absent for a workspace root for the same reason: Copy context is worktree-scoped, so it does not appear on rows in a workspace-rooted tree rather than sitting there dead.
Staying current
A worktree-rooted browser refreshes on the worktree's own change signal, which is already coalesced upstream by an adaptive burst debounce: an npm install or a generated asset batch arrives as one tick rather than hundreds, so the tree needs no debounce of its own. File browsers also re-read when you return to a project view that was sitting cached while you worked elsewhere.
If a refresh fails while a tree is already on screen, the last-known files stay usable under an error banner with a Retry ("Couldn't refresh this worktree. Showing the last known files.") rather than the tree being replaced by an error.
The row menu
Right-click any row. Since v0.32 the same file menu appears on all four surfaces that list files (the worktree card, this browser, the Review Hub and the diff sidebar) instead of the browser's rows inheriting a menu aimed at the whole worktree.
| Item | Applies to |
|---|---|
| Show contents · Set as root | Folders |
| Open diff | Files with local changes |
| Open file · Open in editor | Files that still exist on disk |
| Insert file reference (Command-I Control-I Control-I ) | Any row. Disabled, not hidden, when no agent resolves. |
| Copy context | Any row in a worktree (see CopyTree) |
| Copy path · Copy relative path · Copy file name | Any row |
| Reveal in Finder / Show in Explorer / Show in folder | Any row |
Plugins reach file rows through one section at the end of this menu, with the clicked file's path passed as the item's argument, so a plugin item is contributed once and appears on every file surface, this browser included.