Releases: praxis-labs-io/zen-term
Release list
ZenTerm 1.2.0
This release is about tabs: a tab can carry a name of your own, and sit where you put it.
New
Rename a tab. Double-click it, or run Rename Tab from the command palette. A card opens with the current title in it: Enter or a click away commits, Esc cancels. Empty the field and the name is cleared, so the tab goes back to following the folder it is in, which is what the placeholder shows you. Rename Tab ships with no default chord; bind one with keybind = rename_tab=<chord>.
Move a tab along the bar. ⌘⌃[ and ⌘⌃] shift the active tab one slot left or right. The brackets are already what steps through tabs, so the control tier moves what ⌘ steps through. Tab numbers, tooltips and the ⌘1 through ⌘9 shortcuts follow the new order, and the tab you moved is scrolled back into view. Ghostty leaves moving a tab unbound, so these two are ours; rebind them with move_tab_left and move_tab_right.
Fixed
A tab switch with scroll mode or Find open stranded a hollow cursor. Both of those render the focused pane unfocused while they hold the keyboard. Ending one after you had already changed tabs lifted that from the wrong tab, so the tab you left kept drawing a still, hollow cursor over a live pane, and nothing but opening and closing another mode on it cleared the display.
Updates now download the exact build the feed named. The appcast pointed at a moving link rather than the release it was written for. Anything that moved that link between the app reading the feed and fetching the download handed over a file the signature did not cover, and the update failed with nothing on screen to say why.
Install
ZenTerm updates itself. On v0.2.0 or later, the update card appears in the app. For a first install, open the DMG and drag ZenTerm to Applications. macOS 14 or later, Apple Silicon.
Reporting a bug
From inside the app: Help → Report an Issue prefills the version and your environment. You can still open an issue directly.
ZenTerm 1.1.0
This release is about themes: forty-eight more of them, a chrome that holds its contrast in every one, and Neovim recoloring alongside the terminal.
New
Forty-eight more themes. Settings → Appearance lists 65 now, up from 17, and 20 of them are light where three were before. Monokai Pro's seven, the six Nightfox siblings, five GitHub themes, Flexoki, Gruvbox Material, Iceberg, Jellybeans, Kanso, Melange, Moonfly, Oxocarbon, Vesper, Kanagawa Dragon and Lotus, and the Bones family. Each palette is copied from its source, and Acknowledgements credits every project it came from.
Neovim recolors with the terminal. ZenTerm writes the active theme to ~/Library/Application Support/ZenTerm/theme.json at launch and on every theme change. Install zen-theme.nvim and switching theme in Settings switches your editor's colorscheme to match, live. Bundled themes name their Neovim colorscheme already; your own theme files join in with one nvim-colorscheme line, which is documented in the theme file itself. It changes no color, so a theme file carrying it is still a valid ghostty theme.
Type to filter any dropdown. Every dropdown in Settings is a combo box now: the list is sorted, and typing narrows it instead of jumping to the first letter. Picking a theme out of 65 is the case it was built for.
Changed
The default accent is blue. It was magenta, which came from the hand-picked iris in Rosé Pine Zen; blue is the slot most themes treat as their primary. The accent paints focus rings, the active tab's underline, primary buttons, and the focused pane's glow. If you set accent-color yourself, nothing moves. To keep magenta, put accent-color = magenta in ~/.config/zen-term/config.
The chrome holds its contrast on every theme. Text and icons ran on twenty-one hand-tuned transparencies that were picked against one dark theme, so a caption that receded there could go unreadable on a light theme and a divider could vanish. They resolve from four weights now, lifted on light themes where dark ink reads fainter, and fills are scaled per theme so a border is equally visible in all of them. In practice: inactive tab titles and footer icons are legible where a translucent shell used to lose them, disabled labels sit below the text next to them, and a keycap reads as a control rather than a caption.
backdrop-alpha says what it costs. Below 1 you are looking at your desktop through the shell, and the chrome on top of it reads against your wallpaper. The reference config now says so where you set it.
Fixed
A notice wore the accent instead of its own color. The badge on a warning or an error painted from the chrome accent rather than the notice's own tone, so all four kinds looked alike. Each takes its own again.
A notice open across a theme change kept the old theme. Its icon recolored while Dismiss and Switch stayed in the previous theme's accent.
A focused button gave no feedback but the ring. Three of six button kinds could show accent text and the rest showed none, so tabbing to one was easy to miss. Focus tints the label now, except on a destructive button, which keeps its warning color.
A dropdown left open through a theme change stayed in the old theme. ⌘⇧, reloads your config, which left a dark list hanging under a light Settings card until you typed.
Closing a dropdown could take the keyboard with it. Clicking an open list reopened it, tabbing away dropped focus until you clicked, and resizing the window left the button as a search box holding a query typing could not change.
Install
ZenTerm updates itself. On v0.2.0 or later, the update card appears in the app. For a first install, open the DMG and drag ZenTerm to Applications. macOS 14 or later, Apple Silicon.
Reporting a bug
From inside the app: Help → Report an Issue prefills the version and your environment. You can still open an issue directly.
ZenTerm 1.0.0
ZenTerm is open source. The code is public under MIT, the built-in diff viewer is replaced by zen-review, a standalone tool you can run anywhere, and everything now lives in one repository.
Changed
ZenTerm is open source. The whole app is at praxis-labs-io/zen-term under the MIT license. You can read how any of it works, build it yourself, and open a pull request. LICENSE ships inside the app beside the third-party notices, and About shows who holds the copyright.
Downloads, issues and updates come from that one repository. They used to live in a separate zen-term-releases repo, which existed only because a private repository's Releases cannot be downloaded. That reason is gone. Help → Report an Issue files against the new tracker. Your copy will find this update on its old feed and follow the new one from here on, so there is nothing to do.
The diff viewer is replaced by zen-review. Reviewing a diff is a job worth doing well, and doing it well means a tool that is not tied to one terminal. So it became its own: zen-review is open source and available now, it does more than the viewer ever did, and it runs in any terminal rather than only this one.
It tracks which changes you have inspected and whether they are still the ones you inspected, so an agent rewriting your branch does not cost you the whole review. Comments anchor to lines and survive a refresh. Install it and give it the chord the viewer used to hold:
float = title:Review command:"zen-review" key:cmd+g git:true persist:dir icon:checklist
⌘G then floats it over the repo you are working in, keeping a session per repo. If you bound diff_viewer or diff-layout yourself, those keys no longer do anything and the log says what to write instead. Nothing else about your config changes.
Four Rosé Pines, each carrying its own values. The default shipped as Rosé Pine Moon but was Moon's palette on Main's darker base, and Moon itself was not selectable. Now rose-pine is Main untouched, rose-pine-moon is Moon's own base, rose-pine-dawn is the light one, and rose-pine-zen is ours and is the default. It is byte-identical to what shipped before, so no colors move. The default is a real name now, so theme = rose-pine-zen works in a config file rather than only in the picker.
Every bundled theme is credited. Seventeen themes ship in Settings → Appearance and none of them had an entry in Acknowledgements. All nine upstream projects are named there now, with their licenses reproduced from source. Two tests keep it that way, so a theme cannot ship unattributed again.
Install
ZenTerm updates itself. On v0.2.0 or later, the update card appears in the app. For a first install, open the DMG and drag ZenTerm to Applications. macOS 14 or later, Apple Silicon.
Reporting a bug
From inside the app: Help → Report an Issue prefills the version and your environment. You can still open an issue directly.
ZenTerm 0.10.0
This release is about reading back through what a command printed. Scroll mode grew the rest of vim's motions, it works over a tool float now, and a selection stays with its text instead of dying the moment anything moves.
New
Scroll mode reads like vim. Every motion takes a count, so 12j moves twelve rows and 3yy copies three. ^ goes to the first thing on the row that is not whitespace. W B E are the whitespace-delimited WORD motions, so foo.bar is one where w sees three. H M L name a row by where it sits on screen. f F t T find a character on the row and ; , do that find again or back. * opens the find bar on the word you are sitting on.
⌃d and ⌃u page through the buffer. They used to move the view and leave the cursor at its screen row, which made the first press and the last press both wrong: from the top the band did not move, and against either end nothing happened. The cursor now walks half a screen down the buffer and the view takes as much of that as it can, so the band parks mid-screen while the text runs past it. Where the view cannot take it all the cursor makes the rest of the trip, which is the only way to reach the last half page by paging.
⌘⇧S and ⌘F read a tool float. With a card open, scroll mode and the find bar work on the float's buffer instead of the pane behind it, and the card wears the header while they are up. Prompt jumps, clear screen and the three screen-to-file verbs reach a float now too. All of them were being swallowed.
Clear notices from the keyboard. ⌘⇧N takes the oldest, so presses walk down the stack, and ⌘⌥⇧N takes the lot. A card answers Return and Esc directly rather than needing the mouse. Two new config keys say whether a notice waits to be answered or clears itself: attention-toast and completion-toast, both sticky by default. toast-duration sets how long anything that clears itself stays up.
Selected text gets its own color. Every character used to keep the color it already had, so a dark one went unreadable on the selection fill. A theme file can name selection-foreground; leave it out and it comes from the theme's own foreground.
Eight more tool float icons, and brand marks for real TUIs. The picker is 48 now: docker for lazydocker, kubernetes for k9s, postgres for pgcli, Slack for wee-slack. The glyphs that said the same thing twice came out to make room. A float already pinned to one of those keeps its glyph and its label.
Fixed
Dragging a window edge narrow and back destroyed scrollback. Output that was in history was gone afterwards, and widening back did not bring it home. Every intermediate frame Auto Layout walked the pane through was reaching the terminal and rewrapping the whole buffer, and a frame a few pixels wide rewraps scrollback into a column or two. The grid the layout settled on is what gets pushed now. Live reflow is unchanged: the terminal still rewraps as you drag.
Selecting a wide character copied short. echo "你好 world" then 0v$y copied 你好 worl, and the band drew a cell left of true for every wide character earlier in the row. A column is a character offset and everything downstream was reading it as a cell. A selection stopping on one half of a wide character now covers the whole of it.
A selection died whenever anything moved. Scroll and it was gone, resize the pane and it was gone. It follows its text now: a scroll grows it by the rows that arrive, and a resize re-finds it where the rewrap put it. It goes when the row you started on leaves the screen, which is as far as the terminal core can read.
Focus Mode ended scroll mode. ⌘⇧⏎ over an open reader took you out of it, and the find bar was left behind with a dead caret.
Output at the live end scrolled your line away. A tail -f under an open scroll mode pushed the row you were reading off the top. The screen holds still now, and leaving hands the live end back.
A resize left the band on its old row while the line it was reading rewrapped out from under it. The line is re-found where the rewrap put it.
L skipped the prompt and $ would not move on it. Entering the mode reflows the pane, and a shell blanks its prompt before redrawing it, so the rows read during that window were cached as empty. The read is scoped to one keystroke now.
The find bar outlived scroll mode. Leaving the mode any way except Esc left the bar over a live prompt, where n and N were eaten as search steps and never reached the shell. q, i and ⌘⇧S take the bar down with the mode. Two more in the same place: the cursor sat a step behind the highlight on every downward step, and the count read newest-first, so the first match a search landed on read 1 / 3 at the bottom of three. It reads in the order you see now, match 1 nearest the top.
Ctrl-Return and Ctrl-/ never reached the program. AppKit's key-equivalent dispatch took them before the keystroke ran: Ctrl-Return hit the default context-menu equivalent and Ctrl-/ beeped.
Scratch was one shell per window. It is one per tab now, the way drawers are. Closing a tab closes the shell in it, a busy one confirms first, and a hidden Scratch asking for input opens the tab that owns it rather than whichever was up.
A Settings dropdown was left stranded by a window resize. Its card is placed once, at open, so resizing left it where the button used to be. It closes on a resize now, the way a menu does.
Changed
find_next and find_previous are search_next and search_previous. Every label you read says Find and every token you type says search; those two were the odd pair out. Both still ship unbound, and the old spellings still parse, so an existing config keeps its binding.
Attribution for two things that ship in the app. The 463 bundled color schemes and the vendored bash-preexec.sh had no entry in the notices. Both have one now, along with the check that would have caught them.
Install
ZenTerm updates itself. On v0.2.0 or later, the update card appears in the app. For a first install, open the DMG and drag ZenTerm to Applications. macOS 14 or later, Apple Silicon.
Reporting a bug
From inside the app: Help → Report an Issue prefills the version and your environment. You can still open an issue directly.
ZenTerm 0.9.0
Scratch is a blank shell one chord away, over whatever you are working on. Two defaults also come back to stock, and both change what you see the moment you update.
New
Scratch, on ⌘;. A blank login shell in a card over your work. Press ⌘; again and it goes away with the shell still running, so the next press puts you back where you were, scrollback and all. Type exit and it dies; the press after that gets a fresh one.
One per window, and its toolbar button carries the dot that means a shell is alive behind it. It is the only tool float that ships built in: it has no float = line and no Settings → Tools row, so a clean install still writes nothing to disk. Rebind it in Settings → Shortcuts like any other action, or hide its button with hide-toolbar-buttons = scratch.
New Tool Float, in the command palette. Building a tool float used to mean opening Settings first. ⌘⇧P now reaches the same form. It ships with no chord, and takes one as new_tool_float.
Changed
Both of these are visible the first time you launch v0.9.0.
Terminal text is thinner. Every glyph was being fake-bolded, and nothing said so. The setting is font-thicken now, off by default, which is what stock Ghostty does. If you liked the heavier text, Settings → Terminal → Font has a Thicken row, or put font-thicken = true in your config.
New tabs and windows start at your home directory. ⌘T and ⌘N were inheriting the focused pane's directory, which is the right answer for a pane and the wrong one for a tab. Panes, drawers, tool floats and ⌘P workspace tabs still inherit. To put it back, set the Start directory row in Settings → Terminal → Shell to Current pane, or tab-inherit-cwd = true.
Fixed
Settings and the palettes jumped around under a held arrow. The row you were moving toward could sit against the top edge with its group caption cut off above it, and holding a key threw the selection back and forth. Both lists now keep the caption with its row and hold the row at a steady place in the pane.
A tab's tooltip blinked while you read it. The tab bar rebuilt every chip whenever any title changed, which took the tooltip out from under your pointer roughly once a second.
The find bar went grey over a transparent background. Below full opacity a pane has no fill of its own, so the bar's tint composited onto the desktop instead. It paints on the pane's own color now. The band above it was a separate hole in the padding, left the wrong size when a strip opened, and it is repainted too.
A toast could cover an open card. Cards take the keyboard and dim what is behind them, so a notice landing on top read as broken. Cards now sit above the toast stack.
Text fields had a pink caret. Every field left its insertion point to macOS, which paints it in the system accent color rather than your theme's. The caret follows the theme now, matching the text areas it sits above.
Two Settings descriptions were cut in half, and the Report an Issue box started its text on a different line than the field above it.
Install
ZenTerm updates itself. On v0.2.0 or later, the update card appears in the app. For a first install, open the DMG and drag ZenTerm to Applications. macOS 14 or later, Apple Silicon.
Reporting a bug
From inside the app: Help → Report an Issue prefills the version and your environment. You can still open an issue directly.
ZenTerm 0.8.0
Come from Ghostty and ZenTerm should feel like home from the first keystroke. The defaults are Ghostty's chords now, apart from a few we hold an opinion about. Most shortcuts moved, so read the table before you update.
Changed
The default keymap is Ghostty's. Open ZenTerm after Ghostty and the chords are the ones your hands already know. Two we keep our own answer to, below the table.
| Action | Was | Is |
|---|---|---|
| Split side by side | ⌘⇧\ |
⌘D |
| Split top and bottom | ⌘⇧- |
⌘⇧D |
| Move between panes | ⌘H ⌘J ⌘K ⌘L |
⌘⌥← ⌘⌥↓ ⌘⌥↑ ⌘⌥→ |
| Resize the pane | ⌘⇧H ⌘⇧J ⌘⇧K ⌘⇧L |
⌘⌃← ⌘⌃↓ ⌘⌃↑ ⌘⌃→ |
| Find in the scrollback | ⌘/ |
⌘F |
| Focus Mode | ⌘F |
⌘⇧⏎ |
| Fill Screen | ⌘⇧F |
⌘⏎ |
| Command palette | ⌘P |
⌘⇧P |
| Workspace picker | ⌘⇧P |
⌘P |
| Diff viewer | ⌘D |
⌘G |
| Reload config | ⌘⌥R |
⌘⇧, |
Tabs are the one place ZenTerm keeps its own answer. ⌘[ and ⌘] step tabs here, the way they do in Safari and the rest of the Mac, where Ghostty spends them on panes. That inverts the whole bracket family: panes take the shifted pair below.
⌃⌘F stays unbound. Ghostty spells fullscreen that way as well as ⌘⏎, but it is macOS's own native-fullscreen chord and Fill Screen is a maximize, so answering it would promise a space switch it does not make.
Want your old chords back? Every one is a line in the config, and the reference file lists them together under "Chords ZenTerm does not ship". keybind = nav_left=cmd+h and its three siblings restore ⌘HJKL. Settings → Shortcuts does the same without the file.
Nothing ships twice. Each action holds exactly one shortcut, so there is one place to look when you want to change something, and rebinding moves the whole action.
Stepping a search is n and N. Press Return in the find bar and the keys go back to the pane, where n and N walk the matches. find_next and find_previous ship with no chord as a result, which is what leaves ⌘G for the diff viewer. Bind them if you want to step from anywhere.
⌘A comes from Edit → Select All. A menu shortcut reaches a text field and a pane both, which a keybind cannot. Two things follow: any keybind or float key: landing on ⌘A is refused with a notice, and select_all=none cannot hand the chord back to the program in your pane. Bind select_all to another chord and it works over a pane like any other action.
New
Step through panes. ⌘⇧[ and ⌘⇧] walk the panes in order and wrap at both ends. Open drawers are in the ring, so focus never cycles out of one and fails to come back.
Seven chords the terminal held became actions you can rebind. They do what they always did, so pressing one feels the same. What changed is that each now has a row in Settings, a name in the config file, and a chord you can move.
| Clear the screen, and the scrollback with it | ⌘K |
| Select the whole buffer | ⌘A |
| Scroll back to the selection | ⌘J |
| Jump between prompt marks | ⌘⇧↑ ⌘⇧↓ |
| Paste what you have selected | ⌘⇧V |
| Write the screen to a file | ⌘⇧J |
⌘⇧J writes the file and types its path at your prompt, so the next command has something to point at. ⌘⇧⌃J copies the path instead and ⌘⇧⌥J opens the file. The write happens either way, so the three differ only in where the path goes.
⌘⇧V used to paste exactly what ⌘V pastes. It pastes your selection now, whether you made it with the mouse or with v in scroll mode.
The prompt jumps take Ghostty's shifted spelling and not its bare ⌘↑ and ⌘↓. macOS claims that pair on most Macs, so the keypress never arrives, and a default nobody can press is worse than none. Bind them if yours are free.
Cut, Undo and Redo. ⌘X, ⌘Z and ⌘⇧Z join the Edit menu, which is the only route a text field has to them.
Fixed
⌘A did nothing in any text field. Not the find bar, not the palette filter, not Settings, not the Report an Issue box. AppKit serves Select All from an Edit menu item and there was no such item, while the keymap held the chord and resolves before a field ever sees a key. The Edit menu carries it now, along with Copy, Paste, Cut, Undo and Redo, and a focused field takes it first.
⌘C in the find bar copied the buffer behind you. Copy and Paste were routed by a private selector no text field implements, so they walked past the caret and reached the terminal instead. Both are AppKit's own now, so they follow your focus.
Install
ZenTerm updates itself. On v0.2.0 or later, the update card appears in the app. For a first install, open the DMG and drag ZenTerm to Applications. macOS 14 or later, Apple Silicon.
Reporting a bug
From inside the app: Help → Report an Issue prefills the version and your environment. You can still open an issue directly.
ZenTerm 0.7.0
Read back through a pane without the trackpad. ⌘⇧S moves the scrollback with vim keys, ⌘/ searches all of it, and the chords libghostty was quietly eating come back to you.
New
Scroll mode. ⌘⇧S puts the focused pane into a mode where the keys are vim's. j and k move a cursor line a row at a time, and the buffer only moves once the cursor reaches an edge. ⌃d and ⌃u take half a page, ⌃f and ⌃b a full one, { and } move by paragraph, which in a terminal is the blank line between one command's output and the next. gg and G reach the ends. The pane header says SCROLL and counts how far below you the buffer runs. Esc, q or i gives the keys back.
The keys that should do this are j, k, ⌃d and ⌃u, and every one of them belongs to the shell. That is why it is a mode rather than four more shortcuts.
Select and yank inside it. v starts a selection at the cursor and V takes whole rows. Motions grow it: h and l by a column, w, b and e by a word, 0 and $ to the ends of the row. y copies it, drops back out of selection, and pulses the span it took, so a copy that did not take never looks like one that did. A selection lives on the screen you can see, so scroll to the block you want first, then select it.
Find in the scrollback. ⌘/ opens a find bar along the bottom of the focused pane and searches its whole buffer, not just what is on screen. Every match highlights as you type and the bar counts them. If what you typed is only in history, the pane scrolls to it while you type. The bar opens on whatever you have selected, so a word you can see is never retyped. Press Return and the keys go back to the pane in scroll mode, sitting on the match, with n and N stepping.
⌘G and ⌘⇧G step matches from anywhere, and ⌘E searches the selection.
Seven chords became actions you can rebind. ⌘Home, ⌘End, ⌘Page Up and ⌘Page Down move the viewport for when you want a look rather than a read. Those four plus ⌘G, ⌘⇧G and ⌘E were the terminal core's and are ZenTerm's now, with a row in Settings and a name in the config file.
Take a shortcut away. keybind = find_next=none drops an action's shortcut and puts nothing back, so the chord reaches the program in your pane. In Settings, Delete on a shortcut does the same thing.
Hide toolbar buttons. Settings → Appearance picks which of the footer buttons show, or hide-toolbar-buttons in your config names them. A tool float takes toolbar:false to drop its button and keep its shortcut and palette entry.
A link preview on ⌘-hover. Holding ⌘ over a link already underlined it. It now shows where the link goes, so a ⌘-click is never blind.
A background tab says when a long command finished. Start something slow, switch tabs, and the tab tells you when it is done.
VoiceOver reads a pane. The terminal answers as a text area with its contents, selection and lines.
The diff viewer reads any branch. A Branch: picker sits above Base:. A branch with a worktree stays fully live; one without is read as commits only and says so. Each tab keeps its own viewer session, so two tabs on two repos no longer share one place, base and cache. The diff also refreshes itself when the files change under it.
Fixed
⌘⌥ and ⌘⌃ arrows reach your program. The terminal core's keymap runs underneath ZenTerm's, and 51 of its chords either duplicated something ZenTerm already does or swallowed the key for nothing. Those arrows were the worst of them: eaten, dead, and now arriving as ordinary arrow sequences.
Hide works again. ⌘⇧H opened nothing because a resize shortcut sat on the same chord and won. Menu shortcuts are protected from the keymap now, and a config line that lands on one is refused with a notice naming the menu item.
A held chord stops firing at the repeat rate. Holding ⌘N opened windows for as long as you held it. Only the actions that accumulate toward something repeat now: pane nav, resize, font size, page scroll.
Modifiers and middle click reach the program. A program reading keys through the kitty protocol, like Helix or nvim, saw no modifiers at all, and a program with mouse reporting on, like tmux, vim or htop, never saw a middle click. Key releases also pair with their presses now, so a program is never told a key came up that it never saw go down.
Programs get your real color scheme. Every pane reported "light" to a program asking through the newer detection path, however dark your theme was. nvim, delta and bat were fine, because they ask the older way.
Font size steps every pane. ⌘=, ⌘- and ⌘0 changed the focused pane and left its siblings, the other tabs, every tool float and every other window where they were.
Files with no extension get highlighted. A bin/ script or a config file always rendered plain in the diff viewer. Their shebang and modeline name a language, and that is read now. A long file highlights again too: the cap is on bytes rather than line count, which was firing on ordinary source.
A pane in a background window reports hover. Mouse reporting stayed suppressed until the pointer physically moved, so a window made key with the pointer already over a pane went unnoticed. Coming back to the app from another one had the same hole.
A shell session gets swept when it exits. Sessions were cleaned up within a guessed window rather than when their leader actually exited, which left processes behind.
Changed
⌘G, ⌘⇧G and ⌘E are ZenTerm's. They did the same jobs before, in the terminal core, so pressing one feels the same. What changed is that a tool float or a keybind line of yours on any of the three now collides with a shipped default. When that happens the app raises a card at launch naming both actions, with Accept to record the loss and Revert to put both back on their defaults. Closing it changes nothing and it returns next launch.
Delete removes a shortcut instead of restoring its default. On a row whose default is a chord something else already holds, restoring read as doing nothing. Reset moved to an icon beside the input in the capture popover.
Install
ZenTerm updates itself. On v0.2.0 or later, the update card appears in the app. For a first install, open the DMG and drag ZenTerm to Applications. macOS 14 or later, Apple Silicon.
Reporting a bug
From inside the app: Help → Report an Issue prefills the version and your environment. You can still open an issue directly.
ZenTerm 0.6.0
A diff viewer, built in. ⌘D opens the changes in your repo with a file tree, syntax highlighting, and vim keys, and hands an agent the exact lines you mean.
New
A diff viewer. ⌘D opens the changes in the focused pane's repository: a file tree on the left, the diff on the right, and a base you can point at any branch. It reads side by side, or inline as one column, and a narrow pane folds to inline on its own, because two columns stop reading as code. diff-layout in your config picks which one it opens with.
It is syntax highlighted, in more than thirty languages, by the same tree-sitter parsers an editor uses. The colors come from your theme, so it matches the terminal beside it and follows any theme you switch to.
It has its own keys while it is open, and they are vim's. j and k move, h folds and l opens a file, { and } jump between changes, V selects lines, \ swaps the layout, and q closes it. Press ? for the full sheet. Nothing here reserves a shortcut outside the viewer.
Selecting lines is what the rest is for. y yanks the code. Y yanks a path:42-44 reference instead, and ⏎ opens a comment on those lines and sends it to a terminal in the tab. That is the short path from reading a diff to telling an agent which lines you mean.
Your place is kept. Folds, the selected file, the cursor, and the base survive a reload and a reopen, so a viewer you come back to is where you left it.
Pick the chrome's accent color. accent-color in your config takes any hue from your theme's palette, and the whole chrome follows: the focused pane's glow and border, focus rings, the active tab's underline, a tool's activity dot, primary buttons, the progress bar. Settings → Appearance shows each slot's swatch and hex. The terminal is untouched, so a program printing in that color is unaffected.
Fixed
Full-screen TUIs survive a drawer slide. Opening or closing a drawer resized the terminal on every frame of the animation, pushing the grid through about thirty widths in a third of a second. Ordinary output survives being rewrapped that many times. A full-screen TUI does not, because it places its rows with cursor moves rather than wraps, so every step narrower than the frame hard-wrapped rows that were never wraps, and the damage stayed in the scrollback after the pane widened back. The terminal now reflows once per animation instead of once per frame.
A pane matches a background the program repainted. A program that sets its own background color repainted the terminal grid but not the padding the pane draws around it, so it sat inside a ring of the old color. The two agree now. The rest of the chrome still follows your theme: a program can recolor its own pane and nothing beyond it.
Ctrl-navigation reaches a tool inside a float. With a tool float open, Ctrl plus a direction moved pane focus behind the card instead of reaching the program in it, so a tool with its own splits could not be navigated.
A tab's canvas transition plays where you can see it. Switching tabs ran the incoming canvas's transition before the tab was on screen, so the motion happened somewhere you were not looking and the tab appeared already settled.
Settings no longer describes a slider that was never there. The terminal section explained how to drag a control the app has never had.
Changed
⌘I is no longer a shortcut. Toggling the diff layout used to reserve ⌘I across the whole app, including inside the terminal, for something only the diff viewer could act on. The viewer owns its keys now, so the layout toggle is a bare \ while it is open and ⌘I is yours again. If you rebound toggle_diff_layout in your config, that line no longer resolves and can come out.
Install
ZenTerm updates itself. On v0.2.0 or later, the update card appears in the app. For a first install, open the DMG and drag ZenTerm to Applications. macOS 14 or later, Apple Silicon.
Reporting a bug
From inside the app: Help → Report an Issue prefills the version and your environment. You can still open an issue directly.
ZenTerm 0.5.0
Terminal backgrounds can go translucent, workspaces reorder from Settings, and closing a pane no longer leaves its background jobs running.
New
A translucent terminal. background-alpha sits in Settings → Terminal, and applies as you type it. 1 is solid, 0 puts your text over the window blur with your desktop behind it. The padding around a terminal follows the same value, in a pane and in a tool float, so each reads as one surface. A float frosts the panes it covers, the way a pane frosts the desktop. Toasts, Settings, and the palette stay solid. backdrop-alpha still dials the window shell, and the two are independent.
Reorder workspaces from Settings. The ⌘⇧P picker lists workspaces in the order their sections appear in the workspaces file. Settings → Workspaces now moves them for you: focus a row, hold ⌥, and press ↑ or ↓. Settings → Tools has worked this way for a while. Moving a section by hand does the same thing, and a comment sitting on a header travels with it.
Fixed
Closing a pane takes its processes with it. ZenTerm signalled the pane's shell and nothing else, so jobs the shell had parked elsewhere outlived the pane: background jobs, children in their own process group (what npm, turbo, and concurrently do), nohup, and disown. Quitting was worse. It freed no pane at all, so every shell in the app was orphaned and only each terminal's foreground job was hung up. ZenTerm now sweeps the shell's whole session when a pane goes away, and waits for those sweeps before it exits. Closing twenty panes costs the same 150ms as closing one.
A workspace picker on a network home no longer stalls the window. ⌘⇧P read the workspaces file on the main thread. That is a few milliseconds on a local disk and a beachball on a network-backed or cloud-synced home. The read is off the main thread now. The picker also used to appear and then resize as its list arrived, so the open read as two movements; it opens at its full size.
A config warning goes away when you fix the config. The notice naming a problem in your config file stated what was wrong at that moment, and nothing ever took it down. Fixing the file and reloading left the warning on screen contradicting a file that was already clean.
The command palette follows a rebind. With ⌘P open, changing a shortcut in Settings left the old chord drawn beside its action until you closed the palette and opened it again.
Pane gap and window gutter reach a window that is already open. Changing either left an already-split canvas, and the toast stack's position, on the old value until the next launch.
Changed
A live setting costs less to apply. Every config write re-applied the whole window: relayout each tab, recolor each surface, rebuild the dock, re-theme the open card. Settings live-apply is debounced at 180ms, so editing one number paid all of it five times a second, and rebinding a shortcut paid for work nothing keyboard-related reads. Each change now re-applies only what moved. Measured through a four-tab window with both drawers open: 3.4ms before, 0.8ms for a rebind, 0.42ms for a gutter drag, 1.23ms for a theme swap. ⌘⌥R still re-applies everything, since that is what it is for.
Typing in ⌘P and ⌘⇧P is cheaper. Each character tore down every row and built it again, resolving shortcut glyphs per row and reading the Git mark off disk. Rows are reused now, those two assets resolve once, and the Git badges in the workspace picker load off the main thread, so a folder that becomes a Git repository picks up its badge without a relaunch.
A focused tool float wears the accent ring. A surface float takes the active tab's focus from the pane behind it, and its edge said nothing about that: it wore the same neutral hairline as a picker that takes no focus. It now shows the accent ring a focused pane wears.
Install
ZenTerm updates itself. On v0.2.0 or later, the update card appears in the app. For a first install, open the DMG and drag ZenTerm to Applications. macOS 14 or later, Apple Silicon.
Reporting a bug
From inside the app: Help → Report an Issue prefills the version and your environment. You can still open an issue directly.
ZenTerm 0.4.1
Cursor shaders stop drawing when you are not looking at them, an update card that could freeze now can't, and two floating lists no longer outlive the tab they belong to.
Fixed
A cursor shader costs nothing in the background. With a shader on, a pane kept redrawing the whole terminal surface at full rate after you switched to another app, and kept going while its window sat fully covered. On a 5K display that measured as most of the GPU, spent on frames nobody could see. ZenTerm now tells the terminal when it isn't frontmost and when its window is covered or minimized, and the drawing stops. Switching panes with a shader on also no longer touches the disk, which is what it used to do three times per switch.
A theme change reaches every pane. With a shader on, swapping the theme left the unfocused panes on the old one until you clicked into each of them.
The update card can't get stuck. If a save panel or another app was in front while the update finished downloading, the card stayed on the previous step: its buttons did nothing, and it couldn't be dismissed. The card now moves through its steps whatever window is in front. What the updater did along the way is also in the diagnostics bundle now, so Help → Report an Issue carries it.
Floating lists close with their tab. Opening the theme dropdown or the workspace icon picker and then switching tabs left the open list drawn over every tab until you restarted.
Changed
Cursor Tail draws a cleaner trail. The cursor's hole in the trail is smoothed to match the trail's own edge, which clears the faint dots that were left at two of its corners. Both shaders now fade the trail along its length. Cursor Tail never had a fade at all, and Cursor Warp shipped with its own switched off.
The config file says what a shader costs. Neither the cursor-shader reference nor its Settings row mentioned that a shader redraws the whole surface every frame. Both say so now.
Install
ZenTerm updates itself. On v0.2.0 or later, the update card appears in the app. For a first install, open the DMG and drag ZenTerm to Applications. macOS 14 or later, Apple Silicon.
Reporting a bug
From inside the app: Help → Report an Issue prefills the version and your environment. You can still open an issue directly.