Releases: hoangperry/herminal
Release list
herminal v0.4.2 — named workspaces
Closes the v0.4 Sessions milestone: Claude session browser → session restore → named workspaces.
Named workspaces
Save a tab + split layout under a name, reopen it any time. Like iTerm2's window arrangements.
- Window → Save Workspace As… (⌃⌘S, or the ⌘⇧P palette) — name the current layout.
- Window → Open Workspace ▸ — pick any saved layout to restore it. The submenu rebuilds each time it opens, so new saves show up immediately. Hold Option on an entry to delete it.
- Same safe policy as session restore: layout + each pane's directory come back as plain shells; commands (ssh / claude) are not replayed.
The Sessions milestone, complete
| Version | Feature |
|---|---|
| v0.4.0 | Claude session browser (⌘⇧C) — resume past conversations |
| v0.4.1 | Session restore — reopen last layout on launch |
| v0.4.2 | Named workspaces — save & reopen layouts on demand |
All built on OSC 7 working-directory tracking.
Install
curl -LO https://github.com/hoangperry/herminal/releases/download/v0.4.2/herminal-v0.4.2.dmg
open herminal-v0.4.2.dmgSigned + notarized + stapled. 79/79 tests pass.
herminal v0.4.1 — session restore
v0.4 milestone slice 2. Quit with a layout, get it back on launch.
Session restore
herminal now remembers your tab + split layout and reopens it next launch — each pane a plain shell in its last working directory. No more rebuilding your workspace every morning.
- Persists to
~/Library/Application Support/herminal/workspace.jsonon quit + on every structural change (add/close/split tab). - Settings → "Restore tabs & panes on launch" (default on). Off → fresh single tab, snapshot cleared.
What it restores (and what it doesn't)
- ✅ Tab count, split axis, pane ratios, focus, each pane's cwd.
- ❌ Commands. ssh / claude / arbitrary commands are NOT re-run — those are side-effectful (network connections, LLM resumes) and surprising to fire on every launch. A former ssh pane comes back as a clean local shell.
- Every restored cwd is validated against the local filesystem; a stale or remote path falls back to home rather than failing.
Pairs with v0.4.0's Claude session browser (⌘⇧C): restore brings back your layout, and the browser one-click-resumes the actual Claude conversations.
Install
curl -LO https://github.com/hoangperry/herminal/releases/download/v0.4.1/herminal-v0.4.1.dmg
open herminal-v0.4.1.dmgSigned + notarized + stapled. 79/79 tests pass.
herminal v0.4.0 — Claude session browser
The feature the "terminal for devs living in Claude Code" tagline always promised: reopen any past Claude conversation in one click.
⌘⇧C — Claude session browser
A new left sidebar reads Claude Code's own transcript store (~/.claude/projects/) and lists every project you've run claude in — sorted by last-active, with the real working directory and git branch.
- Resume opens a tab running
claude --resume <id>in the project's cwd — reattaches the exact conversation. - Open Shell Here drops a plain shell in that directory.
Read-only — herminal never writes into ~/.claude. Reads only the first 16 KB of each transcript, so even a multi-hundred-MB session file costs two syscalls, not a parse. Paths with hyphens (e.g. andromeda-next) resolve correctly — the cwd is parsed from the transcript body, not the lossy directory slug.
Foundation (reused by future session-restore)
- OSC 7 cwd tracking — every pane now knows its live working directory.
working_directoryspawn — tabs can open in a specific dir.
What's next (v0.4 milestone)
This is slice 1. Session restore (snapshot every tab/pane on quit, restore on launch) and named workspaces build on this same foundation.
Install
curl -LO https://github.com/hoangperry/herminal/releases/download/v0.4.0/herminal-v0.4.0.dmg
open herminal-v0.4.0.dmgSigned + notarized + stapled. 79/79 tests pass.
herminal v0.3.3 — drag-resize splits
Final slice of the v0.3 polish wave.
Drag-resize splits
Split panes were locked to an even share. Now a draggable handle sits on the gap between panes — hover it (cursor turns into the resize arrows), drag to rebalance. Closing a pane redistributes the freed space; survivors never shrink below a grabbable sliver.
The v0.3 polish wave, complete
| Slice | Version | What |
|---|---|---|
| 1 | v0.3.0 | Vibrancy + content padding + spring animations + right-click menu |
| 2 | v0.3.1 | Command palette (⌘⇧P) + global hotkey (⌥Space) |
| 3 | v0.3.2 | Scrollback search (⌘F) |
| 4 | v0.3.3 | Drag-resize splits |
These four shipped against the brutal-honest audit in docs/research/09-polish-audit.md that diagnosed the "không đã" (doesn't feel as good as other terminals) feedback. Root cause: Ferrari engine (libghostty Metal), plastic chassis (default AppKit chrome). Fixed.
Deferred (documented, not forgotten)
Caret blink phase-reset needs a libghostty upstream patch — no host-side cursor API exists. Image rendering, semantic double-click, and a font-picker UI are feature work for a later milestone, not polish.
Install
curl -LO https://github.com/hoangperry/herminal/releases/download/v0.3.3/herminal-v0.3.3.dmg
open herminal-v0.3.3.dmgSigned + notarized + stapled. 79/79 tests pass.
herminal v0.3.2 — scrollback search (⌘F)
Polish-wave slice 3. The headline feature.
⌘F — Find in terminal
Floating search bar appears top-right of the active pane. Type to filter, Enter / ⌘G for next match, ⌘⇧G for previous, Esc to dismiss. Live results — libghostty re-scans on every keystroke and reports match count + selected index.
libghostty does ALL the heavy lifting (scan + highlight in the Metal render); herminal just owns the AppKit overlay.
Closes the headline audit finding
"Terminal mà không search được output để debug là đồ chơi, không phải công cụ." — docs/research/09-polish-audit.md §2 row 1.
Available via
- ⌘F keyboard shortcut
- Edit menu → Find in Terminal…
- ⌘⇧P command palette → "Find"
Install
curl -LO https://github.com/hoangperry/herminal/releases/download/v0.3.2/herminal-v0.3.2.dmg
open herminal-v0.3.2.dmgSigned + notarized + stapled. 79/79 tests pass.
herminal v0.3.1 — command palette + ⌥Space
Polish-wave slice 2. Two "magic feature" items.
⌘⇧P — Command palette
Fuzzy launcher over the workspace. 15 actions indexed (tabs, splits, sidebars, theme, Settings, hotkey window). Search field at top, ↑↓ to navigate, Enter to fire, Esc to dismiss. Adding new menu items only needs a one-liner entry; dispatch travels the responder chain.
⌥Space — Global hotkey
Brings herminal forward from anywhere on macOS, or hides it if already key. Carbon RegisterEventHotKey (no accessibility permission required). If the combo is grabbed by another app, the menu fallback (Window → Show Hotkey Window) still works.
Slice 3 next
Scrollback search ⌘F, drag-resize splits, caret blink reset — each needs a libghostty integration spike first.
Install
curl -LO https://github.com/hoangperry/herminal/releases/download/v0.3.1/herminal-v0.3.1.dmg
open herminal-v0.3.1.dmgSigned + notarized + stapled.
herminal v0.3.0 — polish wave (slice 1: vibrancy + padding)
First slice of the v0.3 polish wave. Addresses the owner's "không đã" feedback (full diagnosis at docs/research/09-polish-audit.md).
This release ships visible chrome only — scrollback search, command palette, and hotkey window land in later slices.
What changed
- Vibrancy. Workspace wrapped in NSVisualEffectView (.underWindowBackground, .behindWindow). The window now blends with whatever sits behind it instead of reading as a flat hex rectangle.
- Content padding. 6 px inset between the libghostty Metal surface and the pane chrome. No more text-flush-against-edge cheap feel.
- Tab inactive opacity. Non-active, non-hovered tabs fade to 62%. Active tab reads as the focus point.
- Right-click context menu on the terminal — Copy / Paste / Select All. Only fires when libghostty isn't claiming the click (vim mouse mode still wins).
- Spring tab transitions replacing the old linear .easeOut.
Install
curl -LO https://github.com/hoangperry/herminal/releases/download/v0.3.0/herminal-v0.3.0.dmg
open herminal-v0.3.0.dmgSigned + notarized + stapled.
Coming in v0.3.x
- Scrollback search (⌘F)
- Command palette (⌘⇧P)
- Drag-resize splits
- Hotkey/Quake window (⌥Space)
- Smooth caret + selection alpha
herminal v0.2.5 — I-beam cursor + clickable URLs
Fifth audit-pass slice. Two more action_cb cases land:
MOUSE_SHAPE
- HerminalSurfaceView now defaults to `.iBeam` — a terminal IS a text surface, the default arrow always felt wrong.
- vim mouse mode → pointing-hand, URL hover → pointing-hand, crosshair / resize / grab / not-allowed mapped (12 shapes total).
OPEN_URL
- Cmd-click on a URL libghostty detected in terminal output now opens the user's default browser via NSWorkspace.
- Defensive scheme allow-list: `http`, `https`, `mailto`. `file://` and custom schemes rejected so a hostile shell can't pop Finder on `file:///etc/passwd`.
Five-day audit summary
| Version | Stub fix |
|---|---|
| v0.2.1 | `read/write_clipboard_cb` |
| v0.2.2 | mouse events → libghostty |
| v0.2.3 | `close_surface_cb` |
| v0.2.4 | SET_TITLE / SET_TAB_TITLE |
| v0.2.5 | MOUSE_SHAPE + OPEN_URL (this release) |
Each survived 12+ months. The audit pattern (`grep '_ in }|return false$' Sources/HerminalCore/*.swift`) is now baked into the dogfood-checklist pre-release routine.
Install
```bash
curl -LO https://github.com/hoangperry/herminal/releases/download/v0.2.5/herminal-v0.2.5.dmg
open herminal-v0.2.5.dmg
```
Signed + notarized + stapled.
Requirements
- macOS 14.0 (Sonoma) or later
- Apple Silicon (arm64)
herminal v0.2.4 — shell-set tab titles
Fourth stub-from-spike fix in the v0.2.0 → v0.2.4 audit window. `GhosttyApp.handleAction` was a one-case switch (only handled `RING_BELL`); SET_TITLE / SET_TAB_TITLE returned false, so OSC 0/2 escapes from vim/htop/starship-style prompts were silently dropped — the tab strip stayed on "herminal" no matter what the shell wrote.
Fix
- `GhosttyApp.handleAction` routes SET_TITLE + SET_TAB_TITLE through `ghostty_surface_userdata` → `ClipboardOwner` protocol → `surfaceTitleDidChangeNotification`.
- `WorkspaceView` observes, finds the matching pane by identity, updates `TerminalSession.title`, rebuilds the tab strip.
- Empty payload falls back to "herminal" (OSC 0 with empty string conventionally clears the title).
Try it
```bash
printf '\033]0;mytab\007'
```
The tab label switches to `mytab`.
Four-day audit pass
| Version | Stub fix |
|---|---|
| v0.2.1 | `read/write_clipboard_cb` (clipboard moves bytes) |
| v0.2.2 | mouse events → libghostty (drag-select works) |
| v0.2.3 | `close_surface_cb` (`exit` closes the pane) |
| v0.2.4 | SET_TITLE / SET_TAB_TITLE actions (this release) |
Each one survived 12+ months because the dogfood checklist never explicitly verified the round-trip end-to-end. The `verify-clipboard.sh` (v0.2.2) and `verify-title.sh` (v0.2.4) regression-guards now catch any future regression on day one.
Install
```bash
curl -LO https://github.com/hoangperry/herminal/releases/download/v0.2.4/herminal-v0.2.4.dmg
open herminal-v0.2.4.dmg
```
Signed + notarized + stapled.
Requirements
- macOS 14.0 (Sonoma) or later
- Apple Silicon (arm64)
herminal v0.2.3 — exit closes the pane
Third stub-from-spike fix in the v0.2.0 → v0.2.3 audit window. `close_surface_cb` was an empty closure, so when the shell PTY child exited (`exit`, crash, PTY disconnect) the pane locked onto "Process exited" until the user manually ⌘W'd.
Fix
- `GhosttyApp.closeSurface` posts `surfaceDidCloseNotification` with the surfaceOwner.
- `WorkspaceView` listens, walks tabs/panes by identity, removes the matching pane.
- If the closed pane was the last in its tab, the tab is collapsed automatically.
- Skip the note-confirm prompt — the process exited on its own.
Three-day audit pass
- v0.2.1 — wired `read_clipboard_cb` + `write_clipboard_cb` to NSPasteboard
- v0.2.2 — forwarded mouse events to libghostty (selection)
- v0.2.3 — wired `close_surface_cb` (this release)
Plus the M11 `Scripts/verify-clipboard.sh` regression-guard runs the clipboard round-trip end-to-end every day so the v0.2.0 mistake stays caught.
Install
```bash
curl -LO https://github.com/hoangperry/herminal/releases/download/v0.2.3/herminal-v0.2.3.dmg
open herminal-v0.2.3.dmg
```
Signed + notarized + stapled.
Requirements
- macOS 14.0 (Sonoma) or later
- Apple Silicon (arm64)