Modern terminal emulator built with Electron. Lightweight, fast, and feature-rich.
- Multiple tabs with independent zsh sessions
- WebGL-accelerated rendering (canvas fallback)
- Kitty keyboard protocol β Shift+Enter, Ctrl+Enter, Ctrl+Shift+Enter sequences
- Full Unicode support β Cyrillic, accented characters, emoji
- Shell directory tracking via OSC 7 β file tree syncs automatically
- Command busy indicator via OSC 133 β navigation buttons reflect shell state
- Tab drag-and-drop β reorder tabs by dragging the grip handle
- Configurable new tab placement β choose whether new tabs open adjacent to the active tab or at the end; hold Cmd/Ctrl while clicking "+" to toggle the behavior (configurable in Settings)
- Auto-open tab for busy terminal β triggering a run-script or cd from the file tree while the active tab is occupied by an agent automatically opens a new tab for the command
- 2,500 lines scrollback buffer (performance-optimized)
- Scroll-to-bottom button β floating button appears when you scroll up into history; click to jump back to the latest output
- Shared global history (5,000 lines) across all tabs
- Per-tab history files β each tab gets its own
HISTFILE - Smart merging β new commands merge back to global on tab close
- Session restore β history survives app restarts
- Automatic cleanup of orphaned history files
- Lazy-loaded directory tree with expand/collapse
- Hidden files toggle
- Quick navigation β
cd ..andcd ~buttons - Live sync β filesystem watcher with 500ms debounce
- Context menus β new file/folder, rename, delete, copy, paste, open external, copy relative path
- Hover overlay β quick-action buttons appear on hover: cd into directory, copy path, and run script (βΆ) to execute the file in the active terminal
- Multi-select β Ctrl/Cmd+Click, Shift+Click range, Ctrl+A select all
- Bulk operations β copy (
Ctrl+C/Cmd+C), paste (Ctrl+V/Cmd+V), and delete (Delete) on the current selection - Drag-and-drop β move files/folders within the tree
- Undo β Ctrl+Z to undo last move operation
- Binary file handling β images, videos, executables (.dmg, .exe, etc.) open with the OS default application instead of the code editor
- Resizable sidebar (150β600px)
- Path traversal protection β all paths validated against CWD
- CodeMirror 6 with syntax highlighting for 20+ languages: JavaScript/TypeScript, Python, Go, Rust, HTML, CSS/SCSS, JSON, YAML, Markdown, Vue, C#
- Send to terminal β select code and send it to the active shell (Cmd+Enter)
- Unsaved changes indicator
- Auto-features β bracket closing, fold gutter, active line highlight, search
- Resizable editor panel
- Status bar showing
Β± +N -Ndiff stats, updated every 5 seconds- Click on stats to toggle Git panel
- Branch management β switch, create, delete branches
- Inline diff viewer with colored additions/deletions
- Commit, push, discard β all from the GUI
- Per-file stats β additions and deletions count for each changed file
- File tree indicators β new files (green), modified (blue), deleted (red + strikethrough)
- Folder dot markers β nested changes bubble up to parent directories (deleted > modified > new)
- Editor gutter bars β 3px color strips left of line numbers for added (green) and modified (blue) lines
- Auto-refresh β polling every 5 seconds + immediate update on file save (
Cmd+S) - Repository-aware β only active when the working directory is inside a git repo
- Modal search dialog β
Cmd+F(macOS) /Ctrl+F(Windows/Linux), or double-tapShift - File names + contents β searches both simultaneously; file-name matches shown first
- Search options β case sensitive, whole word, regex toggles; include/exclude glob patterns
- Live preview β click a result to preview file contents with highlighted matches
- Quick open β double-click or
Enteropens the file in the editor and closes the dialog - Cancellable β long searches abort automatically when the query changes
- Status-bar launcher β one-click launch of detected CLI agents
- Auto-detection β Claude, Codex, Copilot, Cursor Agent, OpenCode, Qwen, Agento
- Busy lock β agent buttons disabled while terminal is busy
- Active agent highlight β launched agent button glows while running
- Force-disable β toggle agents on/off in Settings
- Proxy support β configure HTTP proxy for all agent commands
- Customizable quick replies β define agent-specific quick commands (e.g.,
/clear,Ok,ΠΡΠΎΠ΄ΠΎΠ»ΠΆΠ°ΠΉ) via Settings; drag-and-drop to reorder - Double-click to select active agent β when the terminal is busy but the active agent wasn't auto-detected (e.g., launched manually or via another app), double-click any agent button in the status bar to manually assign it as active. This enables that agent's quick-reply buttons.
- Per-agent Shift+Enter mode β configure how Shift+Enter behaves for each AI agent (Kitty protocol, newline, or Ctrl+J). Qwen and Agento default to Ctrl+J mode; others default to Kitty protocol.
- 7 built-in themes: Catppuccin Mocha (default), Monokai, Dracula, One Dark, Nord, Solarized Dark, Gruvbox Dark
- Focus indicator β glow, border, top-line, or none
- File tree behavior β collapse children on close, single/double-click to open
- Prompt style β default (from
~/.zshrc), short, minimal, arrow (for new tabs) - Status bar size β compact, standard, or large; adjustable in Settings β Appearance
- New tab placement β
modifierAdjacent(Cmd/Ctrl opens next to active tab) ormodifierEnd(Cmd/Ctrl appends to end); configurable in Settings β Terminal - AI agent quick replies β CRUD editor with per-agent toggles; drag-and-drop reordering
- Auto-persisted to disk with debounced saves
- Tab state saved on quit, restored on next launch (with confirmation dialog)
- Per-tab tree state β expanded directories and scroll position remembered when switching tabs
- Menu option to manually restore tabs
| Shortcut | Action |
|---|---|
Cmd+F / Ctrl+F |
Open project search dialog |
Cmd+E / Ctrl+E |
Toggle editor panel |
Cmd+S / Ctrl+S |
Save file in editor |
Cmd+Enter |
Send selection from editor to terminal |
Shift+Enter |
Kitty protocol: \x1b[13;2u |
Ctrl+Enter |
Kitty protocol: \x1b[13;5u |
Ctrl+Shift+Enter |
Kitty protocol: \x1b[13;6u |
Cmd+ArrowLeft (macOS) |
Home β \x1b[H |
Cmd+ArrowRight (macOS) |
End β \x1b[F |
| Component | Technology |
|---|---|
| Desktop shell | Electron 33 |
| Build tooling | electron-vite (Vite-based) |
| Terminal UI | xterm.js 5.5 + WebGL, Fit, WebLinks, Search addons |
| PTY backend | node-pty 1.0 (native module) |
| Code editor | CodeMirror 6 with 13 language packages (JS/TS, Python, Go, Rust, HTML, CSS, JSON, YAML, Markdown, Vue, C#) |
| Git operations | simple-git |
| UI font | Roboto (global application font) |
| Packaging | electron-builder |
| Logging | electron-log |
| Auto-update | electron-updater (stub) |
- Node.js 18+
- macOS: Xcode Command Line Tools β
xcode-select --install
npm install npm run dev
# 1. Compile with electron-vite npm run build # 2. Package distributable npm run dist # macOS .dmg (arm64 + x64) npm run dist:win # Windows NSIS installer npm run dist:linux # Linux AppImage + .deb
Output goes to dist/.
Without certificates the app is signed ad-hoc β fine for local testing. For a signed and notarized release:
export CSC_LINK=/path/to/certificate.p12 export CSC_KEY_PASSWORD=... export APPLE_ID=you@example.com export APPLE_APP_SPECIFIC_PASSWORD=xxxx-xxxx-xxxx-xxxx export APPLE_TEAM_ID=XXXXXXXXXX npm run build && npm run dist
codesign -dv --verbose=4 dist/mac-arm64/eTty.app spctl -a -vvv -t install dist/mac-arm64/eTty.app
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Main Process β
β ββββββββββββ ββββββββββββ ββββββββββββββββββββββββββββ β
β βPtyManagerβ βFileManagerβ β HistoryManager β β
β β node-pty β β fs ops β β global + per-tab β β
β ββββββββββββ ββββββββββββ ββββββββββββββββββββββββββββ β
β ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββββ β
β βGitServiceβ β TabState β βSettingsStoreβ βAgentServiceβ β
β β countDiffβ β persist β β JSON config β β detect CLI β β
β ββββββββββββ ββββββββββββ ββββββββββββββββ ββββββββββββββ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β AppService β window, menu, auto-updater, state save on quit β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β βββββββββββ βββββββββββ βββββββββββ βββββββββββ βββββββββββ β
β βpty-handlβ βfs-handl β βgit-handlβ βtabs-handβ βsettings β ... β
β β ers β β ers β β ers β β ers β β-handlersβ β
β βββββββββββ βββββββββββ βββββββββββ βββββββββββ βββββββββββ β
ββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββ
β IPC (~50 channels, constants in shared/)
ββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββββββββββββββ
β Preload (contextBridge) β
β ~50 methods on window.electronAPI β
ββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββββββββββββββ
β Renderer Process β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Core Infrastructure β β
β β EventBus β StateStore β DI Container β ElectronApiAdapter β β
β β GitStatusService (polling) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β ββββββββββ ββββββββββ ββββββββββββ ββββββββββββ ββββββββββββββββ β
β βTerminalβ βFileTreeβ βEditorPanelβ β GitPanel β βSettingsPage β β
β βxterm.jsβ β lazy β βCodeMirror β β diff β β overlay β β
β β tabs β β DnD β β 20+ langs β β branches β β themes β β
β ββββββββββ ββββββββββ ββββββββββββ ββββββββββββ ββββββββββββββββ β
β ββββββββββ ββββββββββββββββββ βββββββββββββββββββββββββββββββββββ β
β β TabBar β β ProjectSearch β β StatusBar β β
β βreorder β β dialog β β git Β± β cwd β AI agents β β
β ββββββββββ ββββββββββββββββββ βββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
The codebase follows a layered architecture after a 4-block refactoring:
- DI Container (
renderer/core/container.js) β components receive dependencies via constructor injection, not global variables - EventBus (
renderer/core/event-bus.js) β pub/sub communication between decoupled components - StateStore (
renderer/core/state-store.js) β centralized reactive state with subscriptions (ui.theme,ui.sidebarVisible, etc.) - IPC_CHANNEL constants (
shared/ipc-channels.js) β single source of truth for all IPC channel names, no string literals - IPC handler modules (
main/ipc-handlers/*.js) β each domain group in its own file withregister*Handlers(ipcMain, deps)signature - AppService (
main/services/app-service.js) β application lifecycle in main process (window, menu, updater, state save)
All user data is stored in ~/.config/eTty/ (Electron userData):
| File | Purpose |
|---|---|
settings.json |
App settings (theme, focus indicator, file tree behavior, prompt style, agent proxy, force-disabled agents, quick replies) |
tabs-state.json |
Saved tab state for session restore |
history/global.zsh_history |
Shared command history (5000 lines) |
history/tabs/<id>.zsh_history |
Per-tab command history |
node-ptyis a native module. electron-builder rebuilds it automatically vianpmRebuild: true.build/entitlements.mac.plistcontains macOS entitlements required for node-pty under hardened runtime (JIT, unsigned memory, library validation).- Auto-update is stubbed β logs only, no update server configured yet.
- Settings overlay blocks tab switching to prevent focus leaking to hidden terminals.
Private