Install and first launch
infiniterm runs on Apple Silicon Macs with macOS 13 or later. It is free for personal use; paid work, freelance included, needs a commercial licence, $29 per person, one time.
Install
Section titled “Install”curl -fsSL https://infiniterm.app/install.sh | shIt downloads the latest release, checks its checksum, its signature and its notarization the way the app’s own updater does, copies it into /Applications, and puts ift on your PATH. An app already installed is left alone, since it updates itself. Read the script first if you like.
Agent hooks edit the agent’s config, so the script asks before wiring them, and only for the agents it finds (Claude Code, Pi, Codex, OpenCode, Cursor, Antigravity). With nobody at a terminal to answer (an agent running the install, a CI job) it skips them and prints the commands. To decide up front, end the line with | sh -s -- --hooks claude,pi,codex,opencode,cursor,antigravity (any of them) or | sh -s -- --no-hooks.
Homebrew
Section titled “Homebrew”brew install --cask ekinertac/tap/infinitermThe cask links ift onto your PATH too. The app updates itself, so brew upgrade leaves it alone. If you installed the app from the DMG before, add --adopt so Homebrew takes over the copy you have.
Download by hand
Section titled “Download by hand”The app is signed and notarized, so Gatekeeper opens it without a warning, and it updates itself.
-
Download the
.dmgfrom the latest release. -
Open it and drag infiniterm into Applications, then launch it once.
-
In any card, put
ifton your PATH:Terminal window /Applications/infiniterm.app/Contents/MacOS/ift installThis symlinks
iftinto~/.local/binand writes its zsh completion. If either directory is not on yourPATHorfpath, it prints the line to add.
On Windows ift already works inside every card, with no setup: the app puts its own folder first on that card’s PATH when the card starts. Your own PATH and the registry are not changed. To run ift in a terminal outside the app, add the app’s folder to your PATH yourself; ift install prints which folder.
Build from source
Section titled “Build from source”The source is public. You need Rust, the CEF binary distribution and a checkout of cef-rs for its bundler; the README has the steps. Builds are yours to use, not to hand to anyone else.
Agent hooks
Section titled “Agent hooks”Card borders show what an agent in the card is doing. Each agent reports through hooks, installed once from any shell:
ift install-claude-hooks # Claude Code: edits ~/.claude/settings.jsonift install-pi-hooks # Pi: installs an extension into ~/.pi/agentift install-codex-hooks # Codex: edits ~/.codex/hooks.json (or $CODEX_HOME)ift install-opencode-hooks # OpenCode: writes a plugin to ~/.config/opencode/pluginsift install-cursor-hooks # Cursor: ~/.cursor/hooks.json and hooks/infiniterm-cursor-hook.shift install-antigravity-hooks # Antigravity CLI: ~/.gemini/hooks and ~/.gemini/config/hooks.jsonCodex asks you to approve new hooks once: run /hooks inside Codex after installing. ift install-pi-hooks DIR takes a different agent directory, for a wrapper that runs Pi against its own. The Cursor hook is a small script that needs python3 on the Mac; it covers Cursor’s agent CLI and the IDE’s agent, and the card shows violet while a turn runs but never yellow, since Cursor has no hook while an approval dialog is open. It has not been tried on a live Cursor session yet, because the CLI needs a subscription: the hook path, the payload names and the resume command come from Cursor’s documentation. If a Cursor card shows the wrong colour, please open an issue. The first Cursor hook script reported nothing, so if you installed it before this version, run ift install-cursor-hooks again to replace it.
Antigravity CLI (agy) loads hooks when a session starts, so start a new agy session after installing. The card is violet while a turn runs, green when it finishes and red when it ends in an error. Antigravity has no event for a permission prompt, so a turn waiting for your approval shows violet, never yellow. All six accept --dry-run, which prints what would change and changes nothing.
They are safe to run again, after an update or from a dotfiles script: they add nothing the second time. install-claude-hooks merges eight hook entries into your settings.json and leaves everything else in it alone (permissions, env, other hooks), and it refuses to touch a file that does not parse. If settings.json (or the Codex, OpenCode or Pi file) is a symlink into a dotfiles repo, the installer writes the file it points at and keeps the link. Each prints the file it changed.
An agent session that was already running keeps the settings it started with, so start a new session to see its card change colour. To check it works, give the agent a prompt: the card’s border goes violet. If it does not, agent.log in ~/Library/Application Support/dev.ekinertac.infiniterm/ shows whether any hook event arrived.
To remove them: delete the entries whose command runs infiniterm-hook from ~/.claude/settings.json and ~/.codex/hooks.json, delete ~/.pi/agent/extensions/infiniterm.ts and ~/.config/opencode/plugins/infiniterm.js, and remove infiniterm’s entries from ~/.cursor/hooks.json plus ~/.cursor/hooks/infiniterm-cursor-hook.sh.
Other commands need no setup: a zsh or PowerShell started in a card reports each command’s start and exit status to the app. See Card states.
Shell history per card
Section titled “Shell history per card”This is for zsh and PowerShell. PowerShell needs no setup: a card’s pwsh saves to the card’s own file through PSReadLine. Other shells keep their usual history, see Which shell.
Each card gets its own zsh history file, so a new card does not open with every other card’s past, and after a reboot a card that ran Claude has claude --resume <id> as its last history entry. macOS sets HISTFILE before your .zshrc runs, so add one line to .zshrc:
HISTFILE="${INFINITERM_HISTFILE:-$HOME/.zsh_history}"Outside infiniterm the variable is unset and your usual history file is used.
That keeps each card’s history in its own file, and zsh writes it when the shell exits. A card you leave open for days has not written yet, and ~/.zsh_history (or a tool that reads it) never sees what you typed in a card. To copy each command to your main history as you enter it, add this to .zshrc as well:
autoload -Uz add-zsh-hookzmodload zsh/datetime_ift_copy_history() { [[ -n $INFINITERM_HISTFILE ]] || return 0 local nl=$'\n' line=": ${EPOCHSECONDS}:0;${1%$'\n'}" line=${line//$nl/\\$nl} print -r -- $line >> ~/.zsh_history return 0}add-zsh-hook zshaddhistory _ift_copy_historyIt does nothing outside infiniterm, because INFINITERM_HISTFILE is unset there.
mcfly keeps its own database and records commands with its own hook, so the hook above adds nothing for it. If you want mcfly’s Ctrl R to read ~/.zsh_history as well, set export MCFLY_HISTFILE=~/.zsh_history; to do that only inside infiniterm, guard it with [[ -n $INFINITERM_HISTFILE ]].
Registering a licence
Section titled “Registering a licence”Optional. The app never asks for the key and works the same without it; the key in your receipt email is your proof of purchase either way. To have the About window say who the Mac is licensed to:
ift licence you@example.com XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXIt asks Lemon Squeezy once whether the key is an infiniterm licence bought with that email, and saves it in licence.json beside the canvas. Nothing re-checks it later. Bare ift licence says whether this Mac is registered. It exits 3 when the key or email is refused and 4 when Lemon Squeezy cannot be reached.
Updates
Section titled “Updates”The app checks for a new build at launch and every hour. A newer build is downloaded, its signature and notarization are checked, and it is installed the next time the app restarts. The status bar says “update N ready” until then. “Check for Updates…” in the app menu checks now. “About infiniterm” in the app menu (or “App: about infiniterm” in the palette) shows the version and build you are running; Enter, Escape or a click outside closes it.
The check is a plain GET of latest.json with nothing about you in it.
What’s new after an update
Section titled “What’s new after an update”The first time you open a newer version after an update, the changelog appears in a sheet over the canvas, newest release first, without the days not yet released. Escape or the × in its top right corner closes it. The arrows, Page Up, Page Down, Home, End and the wheel scroll it. Any other key, or a click outside, only makes the sheet flash: nothing is typed anywhere. It does not appear on a first install.
“Help: show what’s new” in the palette opens it at any time. To stop it opening by itself, set "ui.showWhatsNew": false. The app keeps the version it last ran in last_version in its data folder.
Your first minute
Section titled “Your first minute”Cmd Topens a terminal card.Cmd Wcloses it.Cmd Shift Pis the command palette: everything the app does is in it.- A first launch opens a “Start here” page and nothing else:
Cmd Tmakes the first terminal beside it, andCmd Alt ←comes back to it. “Help: open the welcome card” opens it again later. Cmd /lists every shortcut, searchable.- “Help: open the docs” in the palette opens these pages inside the app, as a card with the page list beside it.
- “Help: open the changelog” in the palette shows what changed in each release, newest first, as a page card beside the one you are on. It is the same text as the what’s-new sheet, in a card you can keep.
Cmd+ scroll zooms,Cmd+ drag pans. Bare scroll and drag belong to the card under the pointer.Cmd 2fits every card in the window,Cmd 1fits the focused one.