Elyra
Elyra The coding agent eTerm The terminal that knows where each command ends e The native code editor Elyra Grove Native local development environment Askr The real server for Laravel & PHP Elyra Framework Rust + Svelte 5 framework for desktop apps Elyra Conductor Local project conductor Elyra SQL Server MySQL-compatible SQL server in Rust Elyra Félagi Agents as teammates on one board Elyra SQL Client Native desktop SQL workbench Elyra SQL Anywhere Replication-ready SQL engine Elyra Sjá SEO & GEO workspace for macOS Elyra DataGrid Server-driven data grid for Laravel
Release notes
Changelog
Elyra
Configuration

Configuration

Settings live in ~/.config/eterm/settings.toml and are written on every change made in the settings window (cmd-,). The file can also be edited by hand; eterm reads it at startup.

The file is not inside the application, so upgrading never touches it. It also survives being unreadable, which matters more than it sounds: settings are saved on every change, so defaults loaded into memory would otherwise become defaults on disk the moment you touched a toggle.

  • A file that cannot be parsed is moved to settings.toml.broken and the settings window says so along the bottom, with the reason and the line. Nothing is lost; copy back what you want.
  • The previous file is kept as settings.toml.bak before each save.
  • Saving writes a temporary file and renames it over the old one, so a crash or a full disk halfway through cannot leave a half-written file.
  • Anything the file does not mention takes its default, and anything eterm does not recognise is ignored — so a file written by an older or a newer version still loads.

Everything below is optional. An empty file is a valid file.

appearance

[appearance]
palette = "palenight"      # one of the 22 built-in palettes
font_family = ""           # empty picks the best installed monospace font
font_size = 14.0
line_height = 1.4          # multiplier, not pixels
letter_spacing = 0.0       # extra pixels between cells
padding = 18.0             # around the grid
cursor_style = "block"     # block, bar, underline
show_footer = true         # the directory and title strip at the bottom
highlight_input = true     # colour the command line as you type it

highlight_input turns the first word green when it is a command that exists. It needs shell integration, which is what reports where the prompt ends, and it never touches a cell the shell has already coloured — so a prompt framework or zsh-syntax-highlighting keeps its own work.

A word we do not recognise is left alone rather than marked wrong, because it may be an alias or a shell function, and neither of those is visible from here.

The palette list is in the Appearance pane. Eight of them are designed to sit on a shader surface; four of those are light.

font_family is resolved against what is installed. If the named font is missing, eterm falls back through JetBrains Mono, SF Mono, Berkeley Mono, IBM Plex Mono, Fira Code, Menlo and Monaco, and the Appearance pane offers only the ones actually present.

motion

[motion]
cursor_blink = true
blink_interval = 530       # milliseconds per half cycle
smooth_scroll = true
animate_surface = false    # drift the shader surface

animate_surface is off by default because a moving surface means the window never idles: about 5% of a core at 30fps. The surface itself costs 0.10ms a frame when it does move.

shell

[shell]
program = ""               # empty means your login shell
args = []
working_directory = ""     # empty means home
scrollback = 10000

# Directories put in front of the inherited PATH. ~ is expanded.
path = [
    "~/.local/bin",
    "~/.cargo/bin",
    "/opt/homebrew/bin",
    "/opt/homebrew/sbin",
    "/usr/local/bin",
]

# Environment variables for the session. These win over everything eterm sets,
# the shell integration included. A leading ~/ is expanded.
[shell.env]
EDITOR = "hx"

path matters more than it looks. A process launched from the Dock inherits launchd's PATH, which on a stock Mac is four system directories and nothing else, so cargo and brew are missing even though they work in another terminal. The Shell pane shows the result: every directory marked inherited, added or missing, and which of 21 known tools are reachable.

A login shell can still rewrite PATH in its own rc files afterwards. What eterm sets is the starting point, not the last word.

LANG is set for you when nothing else did. An application launched from the Dock inherits no locale — launchd has none to give — and a shell without one works in bytes rather than characters: æøå is three characters and six bytes, and the line editor counts six. Backspace then takes half a letter. eterm sets LANG from the region macOS is set to, falling back to en_US.UTF-8 when that region has no locale installed, and leaves it alone when LANG or LC_ALL already says something.

shell.env is also the way out of the automatic shell integration: eterm points zsh at a ZDOTDIR of its own, and setting ZDOTDIR here is what overrules it.

Secrets on screen

cat .env, and the tokens are on the screen — when somebody is looking over your shoulder, when the screen is shared, and when the screen is about to be handed to a model. With hide_secrets on, anything shaped like a secret is drawn as a bar in the accent colour, and shown only while the pointer is over it. Copying still copies the real text: this is for the shoulder, not for you.

What counts is decided by shape, chosen for precision: GitHub, Anthropic, OpenAI, AWS, Slack, Stripe and Google tokens by their prefixes and lengths, JWTs, the header of a private key, and the value of any SOMETHING_KEY=, _SECRET=, _TOKEN= or _PASSWORD= line of eight characters or more. A commit hash is not a secret and is left alone.

The same shapes are replaced with [redacted] in everything that leaves for a model — the screen sent with a first question, the output of every step after it — and in a block handed to another pane with cmd-shift-s, since what is in that pane is usually a model too. See AI mode.

A tab that wants you

Agents sit and wait in panes you are not looking at. When a program in a session asks for you — with the bell, with iTerm2's OSC 9, urxvt's OSC 777 or kitty's OSC 99, or by saying through OSC 9;4 that it has stopped being busy, which is how Elyra reports progress — the dot on its tab grows to full size and full colour, and the Dock bounces if eterm is not the app in front. The mark clears the moment you type or click in that session.

Claude Code rings the bell by default when it needs an answer; set preferredNotifChannel to iterm2 and it sends OSC 9 instead, which is heard the same way.

keys

[keys]
option_as_meta = false

Off leaves the option key to the system, so dead keys and input methods compose: ⌥U then A is ä. On sends ESC-prefixed keys, which is what readline expects from ⌥B. It cannot be both.

ai

[ai]
enabled = false
provider = "anthropic"     # anthropic or open_ai
model = "claude-opus-5"
context_lines = 40         # lines of screen sent with the question
fetched_models = []        # filled in by Refresh in the settings pane

The API key is deliberately not here. See AI mode.

input

[input]
suggestions = true         # the rest of a command you have run before, in grey
completions = true         # a list of commands, options or paths while typing

Both need shell integration. See Suggestions for what they read and what they leave alone.

review

[review]
enabled = true             # cmd-r opens a pull request for reading

Off means the command does not exist and the window cannot be opened. The token is not here — it is in the login keychain, for the same reason the model key is. See Review.

renderer

[renderer]
vsync = true
max_fps = 120

updates

[updates]
check = true               # ask elyracode.com once a day whether there is a newer eterm

Nothing but the request goes out, and nothing is fetched or installed until you press the button. See Updates.

other

[other]
notify_after = 20          # bounce the Dock icon for commands this slow; 0 is off
confirm_on_quit = false
copy_on_select = false     # copy a selection as soon as it is made
bell = true               # a program ringing the bell is asking for you
hide_secrets = true       # tokens and keys drawn as a bar, and kept from models

notify_after only applies when eterm is not the application in front — you are already looking at it otherwise. A command that succeeded bounces the Dock icon once; one that failed keeps bouncing until you come back.

Session state

~/.config/eterm/session.toml is written by eterm and holds the window size, the tabs, how each was split, the ratios and the directory each pane was in. Deleting it gives you a plain window. Only the window a run starts with restores and records it; a window opened with cmd-n is a new window.