Fresh
Fresh is a command-line tool designed to automatically refresh and reload applications during development by monitoring file system changes. It watches specified directories and files for modifications, then executes predefined commands or restarts processes when changes are detected, eliminating the need for manual intervention. The tool supports customizable file patterns, ignore rules, and delay settings to optimize the development workflow. Fresh is particularly valuable for web developers, scripters, and software engineers working with interpreted languages or build systems that require frequent recompilation. Its lightweight architecture and simple configuration make it ideal for integration into existing development environments, CI/CD pipelines, and automated testing workflows, significantly reducing development cycle time.
Latest Releases
All releasesFor live updates on Fresh, [follow me on X](https://x.com/TheNoamLewis).
Fresh is now licensed GPL-3.0-or-later, up from GPL-2.0-only (#3328).
> Most config options below can be changed in the Settings UI - run Open Settings from the command palette (
Ctrl+P).Features
- Orchestrator mode - a bare
fresh, with no file or flags, reopens the workspace you were last in, dock and all, running as a background daemon. On by default, toggle it in Settings (#3306) - New CLI commands -
workspace list, andagent list/get/explain/wait/start, for scripting Orchestrator workspaces and agents without reading the dock - Confirmations are a modal dialog now, not a line on the bottom row - a centred card with each outcome spelled out as its own button, answering to arrows, Tab, Enter, Esc, the mouse and the letter underlined in the label; an outcome that loses work is in the error colour and never opens armed (#3320)
- Orchestrator: a Repositories registry tracks one main clone per project per machine - the New Workspace / Run Agent dialog resolves paths from it, warns when a machine has none, and confirms before cloning; its fields now fold behind one-line summaries instead of staying open all at once (#3360)
- Orchestrator: workspaces run on a saved machine, chosen from one consistent list - the dock's
⋯is a labeledMenunow, and the Machines dialog matches the look of the Projects dialog (#3361) Ctrl+Qin a daemon session asks Detach / Quit / Cancel instead of always stopping the daemon and every terminal and agent it hosts; Detach is the default, Quit and Stop All continue into the normal quit path- Tokyo Night and Gruvbox ship as built-in themes, which the homepage already promised (#3107, reported by @sgon00)
- Alt+Shift+N / Alt+Shift+P cycle the keyboard through the sidebar, so a plugin panel like the Markdown outline is reachable without the palette (#3326)
- Search folds case by default everywhere - Find/Replace, Live Grep, the Search & Replace panel and Git Grep all match
todoagainstTODOnow; each keeps its own toggle, andeditor.searchseeds the default for a workspace that hasn't set its own (#3349, requested by @Korkman) - Settings reorganized - new Keybindings and Syntax & Languages pages, plugin settings nested under Plugins, a more compact category tree, and shorter descriptions (#3357)
- Interrupted saves are recoverable - if a save stops partway (disk full, I/O error, crash), a full copy is kept and an Interrupted Save dialog offers Restore / Show Diff / Discard on the next start, or any time via Review Interrupted Saves (#3383)
- Much faster JavaScript/TypeScript highlighting, and a quieter idle daemon - JS/TS moved off a parser that re-read the whole file on every keystroke, large files parse only as far as the view, and idle CPU drops to a few percent (#3418)
- Live Grep dialog redesigned - an aligned form with underlined shortcut letters and a Provider dropdown listing only the providers that can run; the Ignored toggle moves to Alt+I (#3367)
- Dialog pickers behave like standard controls - suggestion lists act as combo boxes, and the Browse… file picker floats over the form, closes when focus leaves, and supports double-click, Home/End and type-to-jump (#3367)
fresh --cmd init pluginsets up a typed plugin project - TypeScript config, API types and the language server, with a new setup guide; Load Plugin from Buffer on a saved file now loads it from disk, so relative imports work, and reloads it in place (#3422)
Bug Fixes
echo 123 | freshopens the pipe instead of hanging - piping intofreshwith no file and no-brought up an editor that took no input at all, spun on a full CPU core, and could not even be quit with Ctrl+Q. Stdin with nothing else to open now meansfresh -; with a file to open it is left unread, but the keyboard works either way. Any redirect counts, not just a pipe -fresh < fileandfresh < /dev/nullhung the same way (#3252)- Orchestrator dock polish - the welcome screen and dock could fail to appear in a daemon session, a context menu could close itself too fast, and a workspace just created from the dock could end up not taking keyboard input (#3306, #3275)
- The workspace dock is there from the first frame - the editor used to come up full width and the dock shoved it aside a moment later, once the plugins had loaded. The column is now laid out before any plugin runs. The dock also remembers whether you left it open and how wide you dragged it across launches;
autoOpenDock: falsekeeps it closed until you open it, and a barefreshalways opens it (#3321) - A nested
freshin the editor's own terminal no longer shreds the pane - and a terminal in a daemon session advertisesFRESH_SESSIONagain, sofresh FILEthere hands the file to the editor you are already in (#3318) - Sidebar panels stay with the window and file they belong to - a Markdown outline mounted in one window showed in every other, and a restored panel no plugin claimed sat reading "Panel unavailable" forever (#3326)
- The Markdown outline follows the reader while the file tree has the keyboard, and its toggle reveals the panel instead of reporting ON for something off screen (#3326)
- The explorer says why a reveal could not move the tree - an unnamed buffer, or a file outside the project - and its scrollbar can be grabbed and dragged (#3326)
- SSH workspaces - creating one didn't always honor your
~/.ssh/config, and hung with a plain error on an unrecognized host key instead of asking to trust it; deleting one could occasionally crash the app (#3301, #3299, #3300) - A remote host that connects and then says nothing gives up instead of leaving the workspace on "scanning" forever
- Attaching to a machine keeps the window you are in - its buffers, splits, layout and terminals - instead of restarting the editor
- Markdown compose: a heading no longer flickers while you type in it, and backspacing a list item no longer throws the caret two rows down (#3318)
- The occurrence highlight keeps up with the cursor - it used to wait for your next keystroke to repaint, and in a daemon session every other time-driven repaint was stranded with it (#3318)
- Code tour: clicking the prose takes the keyboard, and its caret stays visible past the end of a line (#3318)
- A tab after CJK text no longer eats the character before it - the tab marker was placed by visual column against an index counted in characters, so a double-width glyph put it one character early and the
→took that glyph's place:你好⇥worlddrew as你→ world. The file was never touched (#3218, reported by @sgon00) - Highlighted lines (diff view, code tour) no longer hide inlay hints at the end of the line (#3314)
wrapcolumncounts text columns -wrapcolumn: 80now fits 80 characters per row; the line-number gutter used to eat into it (#3405)- With
wrap_columnset, arrowing down no longer leaves the cursor below the visible lines (#3294, reported by @gibboni) editor.scroll_offsetfixed for files under 5000 lines with line wrap off (#3248)- Markdown code block borders no longer break while you type inside them (#3247)
- LSP now finds the right project folder on Windows (#3067, reported by @Bearmancer; fixed by @56steve)
- Keybinding fixes - multi-byte bindings like German
Ctrl+ünow load from config (#3036, by @georglauterbach); a panel's Shift+Tab and Review Diff's fold shortcuts now fire (#3253); a rare case with certain Unicode letters no longer got a phantom Shift (#3302) - Emacs chords work in a plugin-mode buffer again -
C-x C-c,C-x C-fandC-x C-sin a Markdown buffer ran the second key's own action instead of completing the chord (#3060, by @dbactual) - Split resize shortcuts reach the editor from a terminal pane instead of being typed into the shell (#3245, by @kimprap)
- Vi mode: many Vim-parity fixes -
Y,J,G,x/X, visual mode, text objects, dot-repeat, and more, checked against real Vim (#2447) - Vi
.no longer drops the insert it replays when typed quickly after Esc - Fixed stale LSP diagnostics after vi-mode edits, and Save All sending the wrong file's content to language servers (#3258)
- Vi mode holds in every window -
autoStartturns it on at startup again, and dialogs, window switches and newly opened workspaces no longer drop it (#3305, reported by @thedadams; #3395) - The homepage's demo player paints again on Chrome/Linux instead of showing a black box (#3106, reported by @sgon00)
- A language server can no longer delete your files. A server-initiated
workspace/applyEditarrived with no confirmation and was applied as-is, including its "delete this file (recursively)" operation — permanently, bypassing the system trash the file explorer deletes through. Fresh now reports the request and ignores it - Uninstalling a package, replacing one on upgrade, and deleting a theme all go to the system trash, instead of being unlinked outright. A mis-click is recoverable now
- Deleting a folder that contains a symlink no longer empties what the link points at. The recursive delete treated a link to a directory as a directory and descended into it, so deleting a folder holding a link to, say,
~/Documentsdeleted the contents of~/Documents— then reported a failure, after the fact. Links are unlinked now, never followed (reachable from the file explorer when cutting and pasting between filesystems) - A language server can no longer overwrite a file either.
CreateandRenameresource operations honoured anoverwriteflag from the server, truncating or clobbering an existing file with no confirmation. Both are now reported and ignored - The install script refuses to replace a directory that is not a Fresh install.
FRESHINSTALLDIRis removed wholesale during an install, and the only guards were against"",/and$HOME— soFRESHINSTALLDIR=$HOME/.localwiped it without a prompt. An existing directory now has to be empty or hold a Fresh binary, receipt or file manifest - Rust highlighting is on a current grammar now - an unspaced
<before a string, as inensure!(limit<=MAX_OUTPUT,"..."), used to be read as the start of a generic argument list; recovering from it ate the string's opening quote, so the string body rendered as code and every line after it was painted as a string literal until the next quote. The Rust grammar bundled inside syntect was years out of date, so Fresh now ships its own copy of the current upstream one - which also brings better type, constant and macro colouring across Rust files (#3325, reported by @asukaminato0721) - File Explorer: the scrollbar no longer steals a row's hit targets - hovering the bar could pop the tooltip of the file hidden behind it, and the selection caret covered its own row so that row's status marker answered nothing (#2859, by @asukaminato0721)
- Search, replace and goto-line history persists across restarts again - it silently stopped saving, and a plain
fresh file.rs(which skips workspace restore by default) could even overwrite what was already stored - A block (column) selection no longer stays active after you move the cursor without selecting - Alt+Shift+Arrow then a plain arrow left a stale rectangle painted, and the next keystroke fanned out into one cursor per rectangle line
- Terminal id mix-ups across windows fixed - an exit in a background window's terminal could mark or kill the active window's same-numbered terminal instead; ids are now unique across the whole editor
- LSP: semantic-token highlighting refreshes when a language server asks for it, instead of staying stale until you next edit the buffer
- Custom LSP notifications (e.g. clangd's file-status) reach plugins again, instead of being logged and dropped
- Settings dialog keybindings fire again - a custom binding scoped to the settings context was silently dropped instead of reaching the dialog
- File Explorer resize divider tracks the pointer accurately, and its grip sits on the correct wall when the explorer is docked on the right
- Plugin API: killing a background process now actually kills it and reports whether it's still running, instead of leaving it orphaned with its promise never settling
- Settings: adding an entry to a nested map (an LSP server's
envorlanguageidoverrides) saves into the field it belongs to, instead of being misfiled as a new top-level item on the settings page - The status bar underlines a hovered element again - the underline was silently dropped in the move to the current renderer, and every hovered element's colour, plus the separator, stopped following the theme
- The horizontal scrollbar can reach the end of the widest line - a press at the far end of the track, or a drag of the thumb to it, used to stop short by the gutter's width
- Clicking a split pane hits the pane you clicked - in a layout without a visible separator, every pane past the first could be off by one column, and a click on the separator or past the last pane landed in the first pane instead
- Saving keeps the file's identity and touches nothing else - saving
foo.txtcould delete an unrelatedfoo.tmp, and saving (including undersudo) changed the file's group and broke hard links and xattrs; very long file names now save too (#3377, #3348 reported by @qs5779, #3409) - A file changed on disk is never silently overwritten - Save All, Save and Quit, auto-save and closing a tab with Save skip it and say why, and auto-save on exit waits until you confirm the quit (#3346, reported by @mommysgoodpuppy)
- "Changed on disk" is reported once, and only for real changes - clock skew on NFS or SMB, or a save's own failed write, no longer counts (#3380, #3403)
- Quitting - the prompt lists each unsaved buffer and why, cancelling says "Quit cancelled", Save on a tab that needs
sudokeeps it open until the save succeeds, restoring a recoverable quit adds no extra[No Name], and counts read "Saved 1 file" (#3400, #3404, #3385, #3401, #3399) - Integrated terminal keys reach the program - a terminal-context binding like
noopon Ctrl+Q passes the key through (#3270, reported by @brunnerh), Ctrl+J arrives as Ctrl+J rather than Enter (#3169, reported by @liugh-dev), and Shift+Enter and other modified keys reach kitty-protocol TUIs like OpenCode (#3323, reported by @sdecima; #3408) - Integrated terminal output - CJK text in scrollback no longer gains extra spaces (#3235, reported by @leonchen2012), a program's last output survives its exit (#3379), and a mouse-tracking program gets each wheel notch once with smooth scroll on
- Clicks and paging keep the view still - clicking the top or bottom row no longer scrolls, PageUp/PageDown keep the caret's column and screen row, and drag-selecting past the end of the top line no longer scrolls and selects from the wrong place (#3407, #3398, #3329 reported by @asukaminato0721)
- Clicking past the end of a one-character line puts the caret after it (#3351, reported by @asukaminato0721)
- The welcome page's cursor sits in the focused text field (#3234, reported by @asukaminato0721)
- The status bar shows the right line after opening a file that's already open in another window (#3397)
- TOML: an apostrophe in a comment no longer turns the rest of the file into a string (#3358, reported by @rsramkis)
- Live Diff shows no false diff for Shift-JIS and other non-UTF-8 files (#3246, reported by @asukaminato0721)
- Rainbow brackets: the matching pair under the cursor is highlighted on every page (#3084, reported by @Korkman)
- C++ headers highlight as C++ - a
.hin a C++ project, including over SSH, used to highlight and report as C (#3009, reported by @asukaminato0721) - Large files with long multi-byte lines no longer panic or save invalid UTF-8 - invalid bytes now show as
<XX>(#3285, reported by @CnsMaple) - Windows: formatters and shell commands run through
cmd /c- they used to fail, or replace the buffer with cmd's banner (#3279, by @CnsMaple) - A transient LSP crash no longer pops "Language Server Not Found" or opens log tabs while a restart is pending (#3282, by @CnsMaple)
- A client whose daemon dies at startup says so and names the daemon's log, instead of spinning at full CPU (#3418)
Internals
- Minor performance and dependency updates, including a security fix for a TLS library (RUSTSEC-2026-0285)
- Less allocation churn on the render path - a new memory-profiling harness found two hot spots copying and regrowing tens of MB over a two-minute editing session, and a large batch of explorer decorations no longer re-resolves the project root once per path (#3266, #3103)
- Scrollbars are one shared implementation, so they behave the same on every surface
- Plugins can no longer delete, move, or overwrite a path they name.
removePath,renamePathandcopyPathare gone from the plugin API.removePathchecked that its target sat under the temp or config directory, but only the top-level argument — a symlink inside the target walked its recursive delete back out of the fence — andrenamePathhad no fence at all and fell back to copy-then-delete, so anythingremovePathrefused could be moved somewhere it allowed and deleted from there. What replaced them names a *thing* rather than a path:scratchCreate/scratchPath/scratchDiscardfor staging directories the editor issues and takes back,scratchFromDirectory/installScratch/uninstallPackagefor packages by kind and name, andstateSet/stateGet/stateKeys/stateDeletefor namespaced storage whose layout the editor owns. Third-party plugins using the old calls will need updating writeFilerefuses to overwrite an existing file, as it always claimed to. The docs said it "fails if the file already exists to prevent plugins from accidentally overwriting user data"; the implementation wrote a temp file and renamed it over whatever was there, so a plugin trusting the documentation destroyed the file. Replacing one is nowreplaceFile, asked for by nameeditor.setInputMode(name | null)sets an editor-wide input mode for modal-editing plugins like vi, besidesetEditorMode, which is now documented as window-scoped. Keys resolve against a focused panel's mode, then the buffer's, the window's editor mode, the input mode, and the base keymap.getInputMode()reads it andinputmodechangedannounces changes (#3395)- The orchestrator's saved machines moved into the editor-owned state store and are imported from the old directory on first load. The old files are left in place — a plugin can no longer delete a path it names — and are inert
For live updates on Fresh, [follow me on X](https://x.com/TheNoamLewis).
> Most config options below can be changed in the Settings UI - run Open Settings from the command palette (
Ctrl+P).Bug Fixes
- Startup crash on an empty buffer with unsaved changes - hit crash-recovery restores where the deletion itself was the unsaved change, panicking on every launch (#3236, reported by @CC-Hsu)
- A closed Welcome tab's panel no longer keeps trying to repaint itself on every resize
- Git gutter survives an external revert of the open file instead of going stale until the buffer is reopened
For live updates on Fresh, [follow me on X](https://x.com/TheNoamLewis).
A massive refactoring is included in this release, hopefully without any regression in usability. Please open issues on GitHub if you encounter any breakage. The refactoring paves the way to new features like the new Markdown Table of Contents in the side-panel.
> Most config options below can be changed in the Settings UI - run Open Settings from the command palette (
Ctrl+P).Features
- Interactive Welcome screen on startup, in a background tab (#3147). The content is still in the works, suggestions welcome!
- Search previews now open the real file as a preview tab - full syntax colours, gutter, folds and scrolling (#3196, #3200; #836, requested by @66RED99)
- Review Diff opens large diffs almost instantly - a 500+ file review now opens in ~2s instead of ~16s (#3056)
- Sidebar sections - the explorer sidebar can hold multiple collapsible sections, starting with a Markdown Table of Contents (#3045, requested by @mruff-aeq)
- Markdown types brackets and quotes literally instead of auto-pairing them. Typing backticks or quote marks is not annoying now!
- Markdown Compose reflows hard-wrapped text - a paragraph, list item or quote written over several source lines lays out as one block against the page measure, instead of one row per source line. Also, many bugs fixed in markdown compose mode (see below)
- Syntax-highlighting in Review Diff and Git Log modes (#3104, reported by @tinchoz49; #2871)
- Shaded pane edges - text fades out at the top/bottom instead of cutting mid-line (
editor.viewportedgefade) - Smooth wheel scrolling, a line at a time instead of jumpy notches (
editor.smooth_scroll, #3091) - Git Blame readability - better contrast, and blame keeps your place on
b/q(#3088)
Bug Fixes
- Review Diff & Git Log
Review Diff: / Git Log: palette prefixes (#3098) * Works with an external difftool instead of showing an empty diff (#3066, by @asukaminato0721) * D on a fully staged file discards it (#2318) * Follows the working tree, and re-running no longer stacks a duplicate panel (#3126, reported by @asukaminato0721) * The files sidebar scrolls on large reviews, shows full filenames, and a click moves highlight and focus together (#3063, #3188) * git's output parses under more configs - quoted paths, blank context lines, diff.relative, submodules, signed commits (#3199) * A file over 1 MiB is listed and marked instead of expanded into a multi-million-line patch, and binary files show up in a range review instead of vanishing- Orchestrator
Ctrl+Q from a clean workspace no longer skips the unsaved-work prompt for another workspace, or deletes that workspace's recovery files on the way out (#3189, reported by @sdecima; #3221) * The dock paints its own background, instead of showing the terminal's through the gaps * "Move to Folder…" keeps the keyboard, so Down no longer dismisses it and switches the live workspace (#3163, #3137) * A deep repo path plus a long workspace name no longer overruns the terminal directory's name * Archiving names the worktree after the workspace, not its display label, and a repeat archive takes the next free suffix * A workspace whose window is still being created no longer freezes the picker- Multi-cursor editing
- Integrated terminal
- Large single-line files (minified JSON and friends)
Down has nowhere to go - turn soft wrap on to read it vertically * Plugin decorations (blame, live diff, compose reflow) are bounded to the visible text, so a plugin can no longer make a frame read the whole line- Markdown Compose (#3206)
- Language servers
LSP (stuck) (#2197) * Diagnostics no longer get stuck reporting errors you already fixed (#3038, reported by @thedadams) * A server too slow to drain its input no longer loses an edit and then reports errors against text you never wrote (#3100) * Inlay hints no longer jump to the next line while you type at their anchor (#722) * deno.json no longer disables TypeScript on a project without Deno (#2981, reported and fixed by @atk)- Editing
autosurround works with autoclose off, so the per-language override is usable * Enter on a blank last line keeps the cursor's column instead of indenting to the block above (#3165) * The block-selection highlight is exactly what a block copy takes - it used to paint a column it did not select (#3150, reported by @Korkman) * Conceals spanning a line break no longer crash the editor (#3139) * Down moves off the first line under a Git Blame header (#3088)- Keys, mouse and scrolling
asterisk/kp_multiply bindings (#1128, reported by @michelpado) * Shift+wheel scrolls sideways everywhere (#1580) * Dragging the scrollbar leaves the text cursor where it is, like the wheel already did (#3192, reported by @akarinotomoshibi) * Dragging a divider keeps up with the pointer (#3140)- Rendering
- Dialogs and settings
Delete works again in the Settings dialog's Edit Item text field (#2875, reported by @asukaminato0721, fixed by @56steve) * A single-line field scrolls to the start of a long value instead of pinning its tail, so a long name or path can be seen and edited- Starting, quitting and updating
Ctrl+C/kill end the editor promptly instead of occasionally deadlocking or crashing * Quitting no longer panics while plugin work is still in flight * ... | fresh - no longer leaves a temp file behind in /tmp (#3134, reported by @Korkman) * The daemon's locale follows config.json instead of the environment (#3149, reported by @kirinriki7777-sys) * SSH remote sessions no longer hang when the target is Windows (#3145, by @mommysgoodpuppy) * curl | install.sh no longer fails behind a shared IP or silently on error (#3070) * fresh --cmd update no longer fails on GitHub's shared API rate limit, and honours GITHUB_TOKEN (#3198)- The Welcome screen reads like a document - text selects with
Shift+movement or the mouse and copies withCtrl+C, and focus follows the caret rather than the whole row - Search & Replace results scroll horizontally to reveal a long match, accept a pasted query, and no longer move a hidden buffer cursor on
Ctrl+arrow (#3154, #3184; #1960, reported by @mandolyte; #1580, #3186) - New file/folder names with slashes create their missing parent directories (#2640, requested by @akarinotomoshibi, by @asukaminato0721)
- Wave screensaver ends when you return to the window, not just on the next keypress (#3204)
- The file explorer does less filesystem work on a large project, so a repo with thousands of changed files no longer stalls the editor (#3103, reported by @asukaminato0721; #3127, by @atirna)
Internals
- Twelve fewer crates in the build, from replacing
rust-i18nwith an in-tree library (#3102). - Plugin dialogs and panels handle focus and typing correctly - fifteen widget-runtime fixes, and three new options a plugin can ask for: a focused text field wins printable keys over the mode's own bindings, a panel can keep "nothing focused" as a real state, and a scroll command can reveal a widget rather than jump it to the top.
- A large rewrite moves the editor's chrome onto a retained-mode layout tree; continued flaky-test stabilization.
For live updates on Fresh, [follow me on X](https://x.com/TheNoamLewis).
> Most options below can be changed in the Settings UI - run Open Settings from the command palette (
Ctrl+P).Features
- Prettier Markdown Compose / Preview - headings, block quotes, and horizontal rules get nice styling and conceal the literal
#/>/---, lists get bullets and spacing, fenced code blocks are framed with side rails, and the default preview width is a readable centered measure instead of the full pane (#2967, requested by @mommysgoodpuppy). - Review Diff - improved UX - no soft wrap, side panels (file list, comments) can be toggled (use F and C keys), and the sidebar nests files by directory like the File Explorer instead of repeating the full path on every row.
fresh --skill- prints the guide to driving a running editor from an embedded terminal: the script verbs, the calling convention, and worked examples. Coding agents running from within Fresh should have an easier time controlling the Fresh UI at your request.- Selection Highlighting - empty lines are now visibly highlighted within selections, and whitespace indicators are shown (
·/→) even when the indicators are otherwise off - this new behavior is configurable from settings (whitespaceinselection, on by default) (#2797, reported by @akarinotomoshibi). - Linux musl installs register a desktop entry and icons, so Fresh shows up in your app launcher - continuing 0.4.9's move to a single self-updating musl binary.
- Selection now reaches the buffer edges - Shift+Up on the first line and Shift+Down on the last line extend the selection to the buffer start/end, and dragging the mouse past the top or bottom edge keeps selecting and auto-scrolls instead of stopping dead (#3006, #3017, reported by @akarinotomoshibi).
- A selection is readable again - while text is selected, the word-under-cursor highlight steps aside and the other occurrences of the *selected* text are highlighted instead (as in VSCode/Zed), so the extent of the selection is unambiguous. The builtin themes also got occurrence-highlight colours that stay clearly visible against both the editor background and the selection - including on 256-color terminals, where
high-contrastandsolarized-darkpreviously quantized onto their own background and showed nothing at all - and text that would be unreadable on the highlight is nudged to a legible shade while it is marked. Code tours get their ownui.tourstepbgkey so their step band keeps its previous colour (#3011, reported by @akarinotomoshibi). - Folding
... - seen as a KDL file's debug { vanishing (#3031, reported by @rsramkis). * A collapsed fold's header row stays legible when the folded line itself is empty. * Deleting the line a fold was folded on now expands the fold instead of leaving a dangling marker.- Search & Replace no longer opens with every input field missing when invoked a second time while the panel is still opening (#3019).
- Git Log: diff colours in the commit detail panel no longer drift off their rows for commits containing non-ASCII text (#3014).
- Diff files: a hunk header's coloured bar now covers the whole row - the enclosing-section name
git diffappends after the closing@@no longer sits in an uncoloured gap (#3021). - Markdown
**/` ` until you click elsewhere (#2968, reported by @mommysgoodpuppy). * Comments inside fenced code blocks are no longer misdetected as Markdown syntax, and scrolling a large file in Compose mode is smooth on the first pass instead of only after it's been scrolled through once.- Rendering: the 256-color contrast pass no longer stalls large terminal windows or the Settings dialog, and a dimmed dialog no longer paints a fixed dark gray instead of following the active theme (#2982).
- Terminals: a focused terminal keeps
Ctrl+B/Ctrl+E for the shell instead of them toggling/focusing the File Explorer, and File Explorer keys (like Enter) no longer leak into a terminal's PTY sitting behind it.File Explorer: the sidebar caret no longer blinks through modal dialogs. With fileexplorer.followactive_buffer on, the tree now also follows the first file a session opens — previously a code tour's opening step (or any first open into the empty [No Name] buffer) left the explorer parked at the root — and a follow request no longer gets thrown away when it arrives while the tree is still expanding for the previous one (#2988).Review Diff: PageDown/PageUp no longer stalls with the cursor off-screen while paging over a collapsed file (#3029); a panel like the git-log commit view now word-wraps correctly no matter which split shows it.Editing near a fold, concealed span, or virtual line no longer corrupts the rendered layout (wrong hidden text, row count, or scrollbar position) after certain edit sequences, or leaves it stuck stale after a file reload or undo past a bulk edit. Whitespace indicators * Indicators inside a selection are drawn in a subdued colour of their own (whitespaceindicatorselected_fg, derived from the selection background when a theme doesn't set it) instead of taking the selected text's full-contrast foreground, where they were louder than the code around them. * Toggle Whitespace Indicators (Current Buffer) now marks every space when switched on, so it does something visible in a space-indented file — with the default settings (spaces off, tabs on) both halves of the toggle looked identical. Tab and line-ending indicators still follow the configuration.- Line numbers
* A per-buffer line-number toggle survives a tab switch in Page View instead of reappearing for one frame and then vanishing on the next keypress (#2931, reported by @mygirleatsmayo). * Toggle Line Numbers in a Compose/Page View buffer no longer writes a setting the user never chose, leaving no way to turn numbers off while composing. * Vi's :set number / :set nonumber are honoured again on a buffer carrying a per-buffer pin, where they had become a silent no-op that still reported success.- Rulers: the column guide is drawn on the column it names rather than one cell to its right, and it stays visible where it crosses full-width characters instead of leaving a hole in the bar (#2928, reported by @dhanoosu).
- Daemon mode: resizing a terminal attached with
fresh -a no longer smears the last-painted colour across the blank cells - seen as a purple/theme-coloured screen fill when dragging a Windows Terminal window between monitors over SSH (#2723, reported by @amirhosseindavoody).Starting a coding agent ("Teach Fresh CLI" in Run Agent / New Workspace) * Choosing codex or opencode no longer writes an AGENTS.md into your repository. The instructions ride the agent's launch prompt instead, so nothing lands in your checkout and an AGENTS.md you wrote yourself is left alone. * codex's Auto mode can now actually drive the editor. It used to launch with approvals turned off entirely, which left it no way out of its own sandbox to reach the editor's control socket - so an agent that had been taught the CLI could describe it perfectly and never once use it. Auto mode now escalates on request and has those escalations reviewed automatically, the same posture the checkbox already meant for claude. * What the agent is told is now a short pointer to fresh --skill rather than a transcript of the API. The old copy duplicated a declaration file thousands of lines long, drifted out of date as the API moved, and sent agents paging through those declarations instead of searching them.
fresh --cmd ... from a sandboxed process now says so. A caller that is denied access to a running editor's control socket - a sandboxed coding agent, or anything in a PID namespace - is told the socket could not be reached and to retry outside the sandbox, instead of being told no editor is running. Relatedly, an inconclusive liveness check can no longer delete a live editor's socket files, which had made it possible for a sandboxed process to knock out the editor you were working in.
- Packages browser
* Package: Install from URL on an already-installed package now upgrades it instead of refusing. The replacement is downloaded and validated before the installed copy is touched, so a bad source leaves the working version intact, and the new code is live in the session rather than only on disk. * Update is offered for every package with a known source and actually works for packages installed from a monorepo subpath, a local directory, or a direct file - not just plain git clones. The ↑ update marker now appears only when the registry is genuinely ahead of what you have. * Closing the browser by the tab's ×, Close Buffer, or a vanishing split no longer makes Package: Packages dead for the rest of the session, and re-running the command while it is open focuses it instead of doing nothing. * The first Down/Up press moves the selection by one package, including when the browser is opened before the registry has finished loading; an open browser now shows "Loading..." rather than "No packages found" while that is in flight. * A package installed from a URL is a package like any other: it appears in the open browser the moment it is installed, its detail pane names its kind, and language packs and bundles are covered by Update, Remove, Update All, Show Outdated and the lockfile alongside plugins and themes. * Install, update and uninstall failures are shown in the browser's own detail panel instead of a status message that anything else overwrites.- Emacs keymap now covers the whole editor. It previously replaced the default bindings outright, leaving 139 actions with no key at all - no way to accept a completion, escape a terminal, select all, redo, comment, or use any LSP command. It now inherits the default map and keeps only its own overrides, adds the commands an Emacs user reaches for first (
C-x u/h/b/s/d, C-x C-w, C-r, M-;, M-/, M-./M-,, M-{/M-}, M-TAB, C-n/C-p in the minibuffer, popups, menus and the file explorer), fixes M-<, M-> and M-%, which never matched a key a terminal sends, and makes C-k kill to end of line rather than delete the whole line.The minibuffer and the menu honour their keybindings. The prompt and menu sections of a keymap were decorative - Emacs C-b/C-f/C-d/C-n/C-p/C-g in a prompt, and C-n/C-g in an open menu, did nothing however they were bound.Keybinding editor * Deleting or editing a chord binding (such as Emacs C-x C-s) no longer destroys it: delete now disables the chord it names, edit keeps the sequence instead of saving an unparseable binding, and removing one custom chord no longer drops the others sharing its action. * A rebound key is listed once, showing what it does under the active keymap, instead of also advertising the inherited binding it replaced. * The context dropdown covers every context (searchPrompt, dock, settings, compositeBuffer, fileExplorer), so bindings for those can be authored at all - and editing a fileExplorer binding no longer silently reassigns it to prompt on save. The keymap dropdown lists macos-gui.- macOS binaries start on a Mac without Homebrew. The published
aarch64-apple-darwin build failed at launch with Library not loaded: /opt/homebrew/opt/xz/lib/liblzma.5.dylib`; liblzma is now compiled into the binary on every target, and the Linux gnu builds shed the same external dependency.Internals
- A large rewrite unifies mouse, wheel, and keyboard dispatch across the editor's chrome and panels behind one registration/dispatch model, and lays groundwork with a new backend-independent widget library crate; overlay indexing, plugin-state-snapshot, and Markdown-decoration performance work; flaky-test stabilization across settings, mouse, review-diff, and markdown suites.
For live updates on Fresh, [follow me on X](https://x.com/TheNoamLewis).
> Most options below can be changed in the Settings UI - run Open Settings from the command palette (
Ctrl+P).Features
- Installing and updating Fresh - the preferred install method for Linux is now a single self-contained, self-updating, statically linked (musl) binary - one install that works everywhere, instead of a dozen fragile packaging channels.
- LSP completions can offer auto-imports - servers like rust-analyzer now suggest unimported symbols, and accepting one inserts the
use/import line (#2603). - The scripting API can manage the whole Orchestrator dock - create, rename, move, archive, delete and list workspaces, including over SSH, not just create them.
- A new workspace opens the moment you ask for it - a progress page shows while
git worktree addstill runs, the workspace can be renamed, moved or deleted mid-build, and the build finishing no longer steals focus. The dock also got tidier: compact by default, uniform full-width menu rows. - The mouse wheel pans the tab strip - tabs scroll into view under the pointer without changing the active tab.
fresh +50 file.txtopens the file at that line, vim-style (#1926, requested by @asukaminato0721).F3/Shift+F3step through search matches without closing the search bar first (#2111).- Choose which files are too ephemeral to remember - a configurable pattern list keeps cursor positions from being saved for build output, generated sources and the like; git's own scratch files are excluded by default.
- Bulgarian locale (by @ci4ic4).
- Unparseable keybinding config entries are now logged instead of silently dropped (#1128, reported by @michelpado).
Bug Fixes
Ctrl+/(toggle-comment) works on every terminal, not just kitty - including non-US layouts where/needs Shift (#2933).- Hover popups no longer render on top of modal dialogs (#2912, reported by @maxco1d).
- Long text in the search/open-file/palette input scrolls so the cursor stays visible (#2876, reported by @asukaminato0721).
- Vi dot-repeat (
.) aftero/O/a/Ano longer corrupts the buffer (#2443). - Mouse wheel scrolls the view, not the selection
- A wheel over the menu, tab or status bar no longer scrolls the focused pane - chrome wheel events used to land on whatever had focus, dropping a focused terminal into scrollback (#2969).
- Plugin dock panels get their geometry right - opening one (like a code tour) now resizes terminals above it so shell output doesn't vanish off-screen, panels reflow when the file explorer toggles instead of spilling at their old width, and dock hover/selection highlights span the whole row (#2969).
- A code tour opens every step into the same pane - stepping through one while clicking between splits used to scatter its files across all of them (#2969).
- Auto-indent
else:, except: or a custom dedent keyword re-indents the line on the spot, like } always did (#2582). * Braceless if/for/while bodies indent correctly in TypeScript/JavaScript (#2492). * Enter on a blank line between an indented block and an unindented line below no longer inherits the deeper indent (a #1425 corner case).- Format-on-save keeps the cursor on the text it was on - a formatter deleting lines above no longer drops it into an unrelated word (#2777, #2706, reported by @720720).
- Workspaces
--no-restore truly writes no session state (#2735). * The Search & Replace panel and dock terminals open as a split again after the last editor split is closed - a stale dock tag used to stick, even across restarts (#2415, reported by @mandolyte). * Git's COMMITEDITMSG/MERGEMSG/etc. no longer restore a stale cursor position into freshly regenerated content (#2761, reported by @skostojohn).- Keybindings
Alt+]/Alt+[ correctly again (#2930, reported by @FreekyFrank).- Malformed
ssh://URLs fail loudly instead of silently opening a same-named local file (#2221). - Review Diff: stage/unstage/discard confirmations no longer vanish - they used to be overwritten within the same frame by the status refresh they triggered.
- The bundled help manual no longer shows literal
<0D>characters on Windows (by @ci4ic4). - Four small fixes:
bun.lockhighlights as JSONC (#2921); generated tsconfigs usemoduleResolution: bundlerfor TypeScript 7 (#2872); docs no longer claim Ctrl+H opens Find & Replace (#2109); the Rust LSP mode-switching doc references the real palette command name.
Internals
- Input handling split into a pure decision core plus an imperative shell, GitHub Actions workflows now lint in CI, and a round of flaky-e2e-test stabilization across the settings, vi-mode, LSP, review-diff and orchestrator-scripting suites.
Installation
npm install -g @fresh-editor/fresh-editor
brew install sinelaw/fresh/fresh-editor
cargo install fresh-editor