GitHub - hoangperry/herminal: Local-first native macOS terminal with Vietnamese IME support and coding-agent observability · GitHub
Skip to content
hoangperryPublic

About

Local-first native macOS terminal with Vietnamese IME support and coding-agent observability

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

186 stars

Watchers

2 watching

Forks

Repository files navigation

herminal

AI-native macOS terminal for developers who run Claude Code and agent CLIs all day — built Vietnamese-first, IME-correct for every input method.

Website: https://hoang.tech/herminal/ · Download: latest release · Source: this repo

CI Release Downloads License: MIT macOS 14+ Swift 6 Homebrew Engine

Status: v1.0.0 is publicly available as a signed, notarized DMG; main carries post-v1 fixes. See CHANGELOG. Platform: macOS 14+ Apple Silicon.

🇻🇳 Phiên bản tiếng Việt: README.vi.md

The herminal workspace — agent dashboard in the left slot, split terminal panes in the center, per-session notes on the right, status bar along the bottom

Live agents and worktrees on the left, splits in the middle, per-session notes on the right. The left slot is one slot: the agent dashboard and the SSH manager take turns in it.

The real app: split panes with the agent dashboard open — a detected Claude Code process with its status badge and pane chip

SSH host manager panel Per-session notes panel with the local-SQLite footer

Real screenshots, captured from the CI-built app by the screenshots workflow — re-run it after any chrome change and they regenerate.


What is herminal

A local-first macOS terminal built around two daily realities the existing 2026 terminals each miss part of:

  1. You run Claude Code / Codex / Aider all day and need a glanceable view of which agents are alive, idle, or done — without an open-a-second-window detour.
  2. You type a language an English keyboard can't reach — Vietnamese Telex / VNI, Korean 2-Set Hangul, Japanese romaji, Chinese Pinyin — and need the composition to land correctly the first time, in tmux, in vim, every time.

herminal pairs the libghostty engine (Zig, mature, native performance) with a Swift / AppKit shell that owns the IME and the chrome. Storage is SQLite for both per-session notes and saved SSH hosts. No cloud, no telemetry, no account.

One NSTextInputClient bridge serving Vietnamese Telex, Korean 2-Set Hangul, Japanese romaji-to-kanji and Chinese Pinyin, plus the Tab-while-preedit case they all share

The composition APIs live on the terminal surface itself, not in a wrapper text field — so one bridge serves every input method macOS offers. Vietnamese is the release gate because it's the PRD's headline persona, not because it's special-cased in code.

Why a new terminal

In 2026 nothing on the market hits all five at once:

Need iTerm2 Warp Wave Ghostty herminal
Native macOS speed ✓ partial partial ✓ ✓
Vietnamese IME + in-preedit shell completion ✓ × × partial automated¹
tmux + multi-session ✓ partial × ✓ ✓
Built-in agent dashboard × partial × × ✓
Local-only persistent notes per session × × × × ✓

The IME row is scored on Vietnamese because that's the rubric's persona. The bridge underneath is generic — Korean, Japanese and Chinese get their own smoke matrix in docs/QA/cjk-ime-checklist.md.

See docs/research/ for the full comparison and scoring rubric the table is derived from.

v1 scope

Shipped in v1.0.0; main continues with post-release fixes:

  • Native terminal core via libghostty (Metal renderer, p95 keystroke <5ms)
  • Vietnamese IME bridge with automated Tab/preedit regressions; live Telex/VNI release gate pending¹
  • Multi-session workspace: tmux-style recursive splits, drag-to-resize dividers, directional pane focus, pane zoom
  • Agent dashboard: running / idle / starting / needs-input badges, npx/python wrapper detection, per-pane attribution, accessible filtering
  • Agent worktree cockpit — ⌘⌥W spawns an agent in an isolated git worktree
  • Session continuity: restore-on-launch, named workspaces, filterable Claude session browser (⌘⇧C → claude --resume)
  • Per-session notes (SQLite WAL) with Markdown round-trip
  • SSH Connection Manager with one-click spawn, ~/.ssh/config import, and host filtering
  • Dark + light chrome with follow-system (Raycast/Linear style)
  • tmux compatibility verified against vim, less, htop, fzf, lazygit, btop, starship
  • Telemetry-free local crash diary with redacted export
  • Developer-ID codesign + notarize pipeline

¹ The implementation and state-transition regressions are green, and a dated live run cleared the core Telex and VNI one-Tab commit-and-complete paths (docs/QA/results/vietnamese-ime-live-2026-08-15.md). The full T1–T7 visual matrix still wants an owner pass — see issue #2.

Still deferred — see docs/ROADMAP.md for the feedback gates: groups / folders and per-host keypair UI in the SSH manager, Sparkle auto-update (today the app's manual Check for Updates… action opens the official GitHub releases page; automatic Sparkle checks are still stub-only), App Store distribution (sandbox-incompatible by design), Linux / Windows.

Install

Homebrew (recommended)

brew install --cask hoangperry/herminal/herminal

brew upgrade --cask herminal keeps it current. Public artifacts must be Developer-ID signed, notarized, and stapled so Gatekeeper can validate them; macOS may still show its standard first-open confirmation.

Direct download

  1. Grab herminal-vX.Y.Z.dmg from the Releases page.
  2. Open the DMG → drag herminal.app into /Applications.
  3. Launch. Verify the publisher in the standard macOS first-open confirmation.

From source

git clone --recurse-submodules https://github.com/hoangperry/herminal
cd herminal
Scripts/bootstrap.sh           # builds libghostty xcframework (~5-15 min cold)
Scripts/make-app-bundle.sh     # assembles .app with ad-hoc signature
open .build/herminal.app

Prereqs: Xcode 26+, Swift 6.2+, Zig 0.15.2+ (for libghostty), clang for the kernel-probe binaries used by the integration scripts.

First-run quick tour

  • ⌘T / ⌘W — new tab / close current pane (closes tab when last)
  • ⌘D / ⌘⇧D — split vertical / horizontal
  • ⌘⇧] / ⌘⇧[ — next / previous tab
  • ⌘⌥A — new Claude pane (split)
  • ⌘⌥W — new isolated agent worktree
  • ⌘⇧A — toggle agent dashboard (live agents + worktrees)
  • ⌘1…⌘9 — jump to tab N / last tab
  • ⌘⇧S — toggle SSH host manager (mutex with the agent dashboard in the left slot)
  • ⌘⇧N — toggle the per-session notes panel on the right
  • ⌘⇧C — Claude session browser: pick a past session, it reopens with claude --resume in the right cwd
  • ⌘⇧L — toggle light / dark theme
  • ⌥⌘← → ↑ ↓ / ⌘⇧↩ — directional pane focus / zoom the focused pane

Full map in docs/KEYBOARD-SHORTCUTS.md.

Agent worktrees: working on two fixes at once? ⌘⌥W creates an isolated checkout under ../<repo>.worktrees/<branch> via git worktree add and opens it in a new tab running the agent you pick (claude / codex / aider) or a plain shell. The dashboard lists every worktree with open / remove — remove always confirms and never passes --force.

Agents are detected by walking herminal's process subtree — start claude, codex, or aider in any tab and they'll appear in the dashboard within ~2 seconds with a running / idle / starting badge tracked via CPU sampling.

The five stages of one agent poll: timer, sysctl process snapshot, classify by name or argv, annotate with CPU delta and tab hint, render

No agent has to cooperate and no API key is involved — the signal is derived entirely from the process tree. argv is read only to recognise node / python / bun / deno wrappers, and is dropped immediately after. See docs/CONTRIBUTOR-TOUR-AGENT-SIGNAL.md to follow one signal end to end.

Tech stack

Layer Tech Why
Terminal engine libghostty 1.3.1 (C ABI via Zig) Mature, native, no Electron
App Swift 6 + AppKit + SwiftUI chrome Real NSTextInputClient, real Metal layer
Surface NSView hosting libghostty's Metal layer Pixel-precise IME
Storage SQLite WAL (notes + SSH hosts) Local-only, atomic, indexable
Distribution Developer-ID signed + notarized DMG/zip and Homebrew cask App Store sandbox is incompatible
The five dependency layers: HerminalApp, HerminalAgent, HerminalDB, HerminalCore, GhosttyKit.xcframework

libghostty is consumed as an upstream release through its published C ABI — not vendored as a fork. Full write-up in docs/ARCHITECTURE.md.

Repo layout

herminal/
├── Sources/
│   ├── HerminalCore/         # libghostty C ABI bridge + BellRegistry
│   ├── HerminalDB/           # NotesStore + SSHHostsStore + SSHConfigImporter
│   ├── HerminalAgent/        # process-subtree detection + status + pane mapping
│   └── HerminalApp/          # NSApp, WorkspaceView, panels, worktree cockpit, Diary
├── App/                       # Info.plist + entitlements
├── Tests/                     # Swift Testing unit and integration suites
├── Scripts/                   # bootstrap, bundle, verify-*, dogfood, sign, release, capture-screenshots
├── Vendor/libghostty/         # git submodule (Ghostty v1.3.1)
└── docs/
    ├── assets/               # README diagrams + app screenshots
    ├── research/             # market scan + scoring
    ├── define/herminal.prd.md # source-of-truth PRD
    ├── backlog/              # monthly task lists + retrospectives
    ├── QA/                   # IME checklists (VI + CJK), dogfood checklist + journal
    └── launch/               # press kit + tweet/LinkedIn drafts

Contributing

Read CONTRIBUTING.md first — the project is opinionated about what's in scope. Bug reports go through the bug template which prompts for the diary excerpt; security issues go to SECURITY.md. From the app, Help > Report a Security Issue… opens the private reporting path without sending anything automatically.

Documentation

Doc Purpose
CHANGELOG.md Per-version release notes
CONTRIBUTING.md How to propose changes
SECURITY.md How to report vulnerabilities
docs/FAQ.md Install, first-run, and "is this for me" answers
docs/TROUBLESHOOTING.md Crashes, IME double-typing, empty agent dashboard
docs/KEYBOARD-SHORTCUTS.md The full shortcut map, including conflicts
docs/ROADMAP.md Shipped / next / won't-ship-by-design
docs/ARCHITECTURE.md One-page system overview — read before the first PR
docs/AGENT-INTEGRATIONS.md The lifecycle-only agent signal contract
docs/THREAT-MODEL.md What herminal defends against — and what it deliberately doesn't
docs/MAINTAINER-AI-POLICY.md Human boundaries for AI-assisted maintenance
docs/BETA.md Privacy-safe beta protocol and evidence ledger
docs/RELEASE.md Cutting a signed + notarized release
docs/define/herminal.prd.md The PRD that frames every decision
docs/QA/dogfood-checklist.md What to watch for during daily-driver use
docs/QA/vietnamese-ime-checklist.md 20-phrase Telex/VNI smoke matrix
docs/QA/cjk-ime-checklist.md Korean / Japanese / Chinese IME smoke matrices
docs/backlog/ Monthly task lists + retrospectives M1 → M12

If Herminal is useful in your daily workflow, a GitHub star helps more macOS and Vietnamese developers discover the project.

Made with 🐈 by Yuuhou Meow team in Việt Nam.

About

Local-first native macOS terminal with Vietnamese IME support and coding-agent observability

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

186 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages