Skip to content
nova-loopPublic
forked from webanion/termi

About

A terminal for macOS and Linux with saved commands that open several terminals side by side, and auto-start.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

 
 

Latest commit

 

History

248 Commits

Folders and files

Repository files navigation

Termi

CI Release License: MIT

A terminal app for macOS and Linux with a warm dark theme, saved commands that open several terminals side by side, and auto-start. Built with Electron, React, xterm.js and node-pty.

termi.webanion.com has the downloads, the features and the shortcuts on one page.

Termi on macOS, with a saved command running an API server, a web server, the tests in watch mode and the git log in a grid of four terminals

What it does

  • A sidebar with the running terminals at the top and your saved commands below.
  • A settings panel, with ⌘, (Ctrl+, on Linux) or the gear at the top of the sidebar: whether the sidebar shows, the text size, the cursor's shape and whether it blinks, smooth scrolling with a mouse wheel, whether new terminals wrap long lines, and on macOS whether Termi opens at login. A change applies at once, and each setting can go back to its default.
  • A saved command can run up to 4 terminals in one tab, for example an API server, a web server and a plain shell for one project. Add them with "Add terminal" in the saved command dialog. An empty command opens a plain shell. Each terminal can have a title, such as API or Web, which its pane header shows in place of the command. Pick how the terminals are arranged under Layout in the same dialog, or with the layout control that shows on the right of the header when a tab has more than one terminal. Its last choice, Tabs, shows one terminal at a time at full size, with a tab for each above it. A hidden terminal's tab lights up when it has new output, and ⌘] and ⌘[ (Ctrl+Alt+] and Ctrl+Alt+[ on Linux) move between the tabs. Termi remembers the layout and the view for each saved command.
  • When you close one terminal of a saved command, Reopen shows in the header. It lists the closed terminals by their command, with Reopen all, and ⇧⌘T (Ctrl+Shift+R on Linux) reopens all of them. Each one runs the command the saved command has now, in its folder, and goes back to its place in the layout. While some are closed, the saved command's row in the sidebar shows how many are open, such as 2 of 3.
  • Split any tab to add a plain shell to it, up to 4 terminals, with the split button on the right of the header or ⌘D (Ctrl+Shift+D on Linux). The new shell starts in the folder the tab started in. A split is not saved to a saved command, and while a split tab has more terminals than its saved command, Termi does not save its layout or view. In tab view, a split opens as a new tab.
  • Drag the line between two terminals of a tab to resize them, and double-click the line to make them equal again. The sizes last while the tab runs, and go back to equal when the layout or the number of terminals changes.
  • Saved commands can start when Termi opens (the bolt icon).
  • Press ⌘P (Ctrl+Shift+O on Linux) to run a saved command from the keyboard. A panel lists your saved commands. Type part of a name and press Enter: Termi starts the command, or goes to its tab if it is already running.
  • Turn word wrap off in a terminal with ⌥Z (Ctrl+Shift+Z on Linux), or View > Word Wrap. Long lines then stay on one line, which keeps log lines, tables and git log --graph readable, and the terminal scrolls sideways: with a sideways swipe, Shift and the mouse wheel, or the scrollbar below it. While you type, it follows the cursor. The terminal is 300 columns wide, or the pane's width if that is more, so a line longer than that still wraps. A full-screen program such as vim, htop or less gets the pane's width while it runs. The same keys turn wrap back on, and the setting decides how a new terminal starts.
  • Select text in a terminal to copy it. A double-click copies a word, and a triple-click copies a line.
  • Right-click a terminal for Copy, Paste, Select All and Clear Buffer. On a link, the menu can also open the link in your browser or copy its address. While a program takes the mouse, as tmux and vim can, a right-click is the program's, and ⌥ right-click (Shift+right-click on Linux) opens the menu.
  • Drop files or folders from Finder or the file manager on a terminal to type their paths, quoted for the shell, as Terminal.app does. Nothing runs until you press Enter, and in a split tab the paths go to the terminal under the pointer. This is how a tool like Claude Code attaches a dropped image.
  • Shift+Enter adds a new line in Claude Code's prompt, where Enter sends the message. Termi sends Shift+Enter as ESC and Enter, the bytes Claude Code's /terminal-setup sets up in other terminals. In zsh it adds a line to the command, and in bash it only rings the bell.
  • Drop a folder on the sidebar to open a new terminal in it. A dropped file opens one in the folder it is in. One drop opens up to 4 terminals.
  • The sidebar footer shows CPU use, memory use, and download and upload speed. Termi checks them every 1.5 seconds, and stops while the window is minimized.
  • Termi reopens at the same window position and size. If that display is gone, the window moves to the main display.
  • The header holds the system's own window controls: the traffic lights on the left on macOS, and minimize, maximize and close on the right on Linux.
  • Help is built in. A short guide opens on the first launch and from the Help menu, a sheet lists every shortcut, and a command palette finds any action or running terminal by name. Help, Report an Issue opens the bug report form with the Termi version, the system and the shell filled in, for you to read and submit.

Install

Download a release from termi.webanion.com or Releases. Each release has a SHA256SUMS file to check the downloads against.

macOS. Termi-<version>-mac-arm64.dmg for Apple silicon or Termi-<version>-mac-x64.dmg for Intel, or the .zip of either. Open it and drag Termi to Applications. The builds are not signed with an Apple Developer ID or notarized yet, so macOS blocks the first launch and says it could not verify Termi. On macOS 15 and later, open System Settings, Privacy & Security, and choose Open Anyway next to the message about Termi. On earlier versions, right-click Termi and choose Open. On any version, xattr -dr com.apple.quarantine /Applications/Termi.app clears the block. Termi 0.1.1 and earlier shipped with a broken signature, so macOS says Termi "is damaged and can't be opened" instead, and only the xattr command opens those versions.

Linux. On Debian and Ubuntu, install the deb with sudo apt install ./Termi-<version>-linux-amd64.deb. It sets up Chromium's sandbox, including an AppArmor profile on Ubuntu 24.04 and later. Elsewhere, use Termi-<version>-linux-x86_64.AppImage: make it executable with chmod +x and run it. On Ubuntu 23.10 and later an AppImage cannot bring its own AppArmor profile, so use the deb there.

Run from source

Termi needs Node 24 (see .nvmrc) and the tools to build node-pty: the Xcode Command Line Tools on macOS (xcode-select --install), and build-essential and python3 on Linux.

npm ci
npm run dev

npm ci also downloads Electron and rebuilds node-pty for it. npm run dev serves the window's code from a dev server that reloads when you save. npm start builds Termi into out/ and runs that build.

On Ubuntu 23.10 and later, the development copy of Electron needs an AppArmor profile to start its sandbox when you run it from a normal terminal (VS Code's terminal works without one). npm run setup:apparmor checks, and changes nothing: it names the Electron binary and the profile it would write, and says whether the restriction is on. To install the profile, once per checkout:

npm run setup:apparmor -- --execute

It writes /etc/apparmor.d/termi-dev-<hash> with sudo and loads it. On macOS, or where the restriction is off, it says nothing is needed.

Tests and checks

Termi is written in TypeScript, with a React renderer, and built with electron-vite. CI runs all of these on Linux and macOS for every pull request, so run them before you open one:

npm run typecheck
npm run lint
npm run format:check
npm run test:scripts      # the changelog tool and the AppArmor script
npm test                  # unit tests
npm run test:integration  # the MCP server and real shells, after a build
npm run smoke             # the built app, end to end

The tests use a temporary data folder, never your real settings. npm run smoke opens a Termi window for a few seconds. On Linux without a display, run it as xvfb-run -a npm run smoke.

Build the app

npm run dist:mac    # dmg and zip for arm64 and x64, on a Mac
npm run dist:linux  # AppImage and deb for x64, on Linux

Both write to _releases/<version>/. The macOS builds are signed ad hoc, not with an Apple Developer ID, and are not notarized.

The logo is flat: one solid color, with no gradients or shadows. To change it, edit assets/logo.svg and assets/logo-mark.svg, which is the same logo without the outer padding, then run npm run icons. It needs rsvg-convert (brew install librsvg on macOS, sudo apt install librsvg2-bin on Ubuntu). The .icns also needs iconutil, which only macOS has, so elsewhere the script writes the PNGs and leaves the committed icon.icns as it is. The PNGs include the Linux icon set in assets/icons/, one per size from 16 to 512, which the Linux packages install into the system icon theme.

Releases

Releases are made by the Release workflow in GitHub Actions, never by hand. Run it from main and choose the bump. It opens a pull request from release/v<version> with the version bumped and a CHANGELOG.md section written from the commits since the last release. Merging that pull request runs CI on the merge commit, builds the macOS and Linux packages, then tags v<version> and publishes the GitHub Release with the packages, a SHA256SUMS file, and its contributors: everyone whose commits are in it. The changelog groups commits by their Conventional Commits type, so every commit subject has to follow it, and CI checks that on each pull request.

Shortcuts

Action macOS Linux
New terminal ⌘T Ctrl+Shift+T
Split terminal ⌘D Ctrl+Shift+D
Reopen closed terminals ⇧⌘T Ctrl+Shift+R
Close terminal ⌘W Ctrl+Shift+W
New saved command ⇧⌘N Ctrl+Shift+N
Run a saved command ⌘P Ctrl+Shift+O
Go to terminal 1 to 9 ⌘1 to ⌘9 Alt+1 to Alt+9
Previous and next terminal ⇧⌘[ and ⇧⌘] Ctrl+Page Up and Ctrl+Page Down
Previous and next pane in a split tab, or tab in tab view ⌘[ and ⌘] Ctrl+Alt+[ and Ctrl+Alt+]
Clear the terminal ⌘K Ctrl+Shift+K
Show or hide the sidebar ⌘B Ctrl+Shift+B
Word wrap on or off in the focused terminal ⌥Z Ctrl+Shift+Z
Copy and paste ⌘C and ⌘V Ctrl+Shift+C and Ctrl+Shift+V
Full screen ⌃⌘F F11
Text size ⌘=, ⌘- and ⌘0 Ctrl+=, Ctrl+- and Ctrl+0
Settings ⌘, Ctrl+,
Open a link ⌘ click Ctrl+click
Command palette ⇧⌘P Ctrl+Shift+P
Keyboard shortcuts ⌘/ Ctrl+Shift+/

On Linux a plain Ctrl+letter always reaches the shell, so Ctrl+C interrupts, Ctrl+W deletes a word, Ctrl+K deletes to the end of the line and Ctrl+B stays the tmux prefix. Termi's own shortcuts use the keys other Linux terminals use: Ctrl+Shift with a letter, Alt+1 to 9 for tabs, and Ctrl+Page Up and Page Down to move between them.

Double-click a running terminal in the sidebar to rename it, or press F2 while its row has keyboard focus. In a tab with more than one terminal, closing the terminal closes the whole tab. To close one terminal, use the × in its pane header, or type exit. To get a saved command's terminal back, use Reopen in the header.

MCP server

src/mcp/ is an MCP server for the saved commands. An AI assistant such as Claude Code can use it to list, add and edit them. npm run build bundles it into out/main/mcpServer.js, which runs on plain Node over stdio and has no dependencies.

Tool What it does
list_saved_commands Lists every saved command with its id, name, terminal commands, terminal titles, folder, auto-start, layout and view
add_saved_command Adds a saved command with 1 to 4 terminals
edit_saved_command Changes a saved command, found by id or by name. Only the fields you give change, and a terminal keeps its title while its command stays in the same place
get_termi_docs Returns the guide to the server. The same text is the termi://docs resource

The guide is src/mcp/docs.md, and the build puts it inside the server. The server adds a reference to the end of it, built from the code: the layouts, every tool and parameter, and the paths this install uses. So the reference never goes out of date.

It follows the same rules as the saved command dialog. The first terminal needs a command, and a tab has at most 4 terminals. It writes to the same settings.json as the app. A running Termi watches that file, so a change shows in the sidebar right away, and the name of a running tab follows a rename.

To add it to Claude Code for all your projects, build Termi once with npm run build, then:

claude mcp add termi --scope user -- node /path/to/termi/out/main/mcpServer.js

add_saved_command and edit_saved_command change what runs later, including at launch through auto-start, and a command changed behind a button you already trust runs the next time you click it. So keep the assistant's calls to those two tools on manual approval. An assistant that reads untrusted text can be talked into planting a command.

Where data is stored

Termi keeps its data in ~/Library/Application Support/Termi/ on macOS, and in $XDG_CONFIG_HOME/Termi on Linux, which is usually ~/.config/Termi.

  • settings.json: the saved commands, with their terminals, terminal titles, layout and view, the sidebar width, whether the sidebar shows, the text size, the cursor style and whether it blinks, whether a mouse wheel scrolls smoothly, whether a new terminal wraps long lines, and whether the guide has opened. It has a version number, and Termi upgrades an older file when it reads it. If you edit it while Termi runs, Termi applies the change, and a value it cannot use goes back to its default. Open at login is not in this file: macOS keeps it.
  • window-state.json: the window's position and size.

Set TERMI_USER_DATA to point the app and the MCP server at another folder, for example for tests.

Contributing

Bug reports, ideas and pull requests are welcome. CONTRIBUTING covers everything from branch names to what a pull request needs, and AGENTS.md describes the code's layout and the rules that keep the page away from the shell. Issues labelled good first issue are a place to start. Everyone taking part follows the Code of Conduct.

Security

Termi collects nothing and sends nothing: no telemetry, no analytics and no update check. The only network traffic it causes is a link you open and whatever you run in its terminals.

Report a vulnerability privately, never in an issue. SECURITY says how and what counts.

License

MIT

About

A terminal for macOS and Linux with saved commands that open several terminals side by side, and auto-start.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages