Elyra
Elyra The coding agent 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
Elyra integration
Elyra agent
Release notes
Changelog
Elyra
Terminals & panes

Terminals & panes

Every terminal in Conductor is a real PTY: one portable-pty session per pane in Rust, rendered with xterm.js in the webview. Your login shell runs with TERM=xterm-256color, rooted at the pane's working directory.

Tabs

Each tab is an open session — either a terminal (with its own split layout) or an Elyra agent panel. Open a new terminal tab with the button, ⌘KNew terminal tab, or by selecting a project.

  • Drag to reorder tabs — grab a tab and drag it sideways; a blue insertion marker shows where it will land. (Reordering uses pointer events, so it works reliably inside the webview.)
  • Jump to a tab with ⌘1⌘9 (its position in the bar, left to right). The shortcuts follow whatever order you've dragged the tabs into.
  • Close a tab with its , or close the focused pane with ⌘W (closing the last pane closes the tab).
  • A tab is labelled by its project name, so you can always tell which project it belongs to. When a foreground command is running (e.g. ⌘R / npm run dev), a pulsing marker and a small process chip (vite, php, …) appear next to the name.

Split panes

Split any pane to run multiple processes side by side:

Action Shortcut
Split right (vertical divider) ⌘D
Split down (horizontal divider) ⇧⌘D
Close active pane ⌘W

Splits nest freely, and you can drag the dividers to resize. Each pane also has hover controls in its top-right corner (split right / split down / close).

Move between panes with ⌘⌥ + the arrow keys, and zoom the active pane to fill the tab with ⌘⌥Z (press again to restore) — tmux-style. Switching tabs, splitting, or navigating unzooms automatically.

Global scrollback search

Press ⇧⌘F (or the command palette → Search all terminals) to search the buffer of every open terminal at once — not just the focused one. Matches are grouped by pane with a count and a sample line; pick one to jump straight to that tab/pane with the match highlighted. Great for “which of my six running services logged that error?”

Why splitting never loses your session

Terminals live in a flat, absolutely-positioned layer keyed by terminal id. A pure layout module (layout.js) computes each pane's geometry from a split tree. Because the DOM node for a terminal is never remounted when the tree changes, the PTY session and scrollback survive every split and divider drag. (Rendering the tree recursively would have killed and respawned shells on every relayout.)

See Architecture & boundaries for the full data flow.

Notification rings

Background tabs pulse green when their terminal produces new output, and the indicator clears when you switch to the tab. All tabs stay alive in the background, so nothing is lost when you switch away from a long-running process.

A tab whose last command failed pulses red instead, and its border turns red — a failure outranks “there is new output”. Unlike the green ring it does not clear when you look at the tab, because noticing it is the whole point. It clears when you either:

  • click the red dot, which hands the command, exit code, output tail and git branch to an Elyra agent for diagnosis (the same context as the Fix it toast, but available long after the toast has gone), or
  • run something that succeeds in the same tab, which supersedes the old failure.

Requires shell integration for exit codes. Interrupts and signals you caused yourself (Ctrl-C, SIGPIPE, SIGTERM, job control) never raise it. Without the Elyra CLI installed the dot is still shown, and clicking it opens the tab.

Finished-command notifications

When a long-running command in a background tab returns to the shell — a build, test run, or deploy completing while you're in another app — Conductor fires a native notification (e.g. “✓ cargo finished · my-project · ran 54s”). It watches the foreground-process titles it already polls, so there's nothing to configure per command:

  • Only fires for commands that ran at least ~8 seconds (no noise from quick commands).
  • Never fires for the tab you're actively watching (focused window + active tab).
  • Toggle it from the command palette — Notify when a background command finishes / Disable finished-command notifications. The choice persists across restarts.

First use asks for macOS notification permission; you can also manage it later under System Settings → Notifications → Elyra Conductor.

Shell integration (zsh)

On by default, shell integration makes new terminals capture the real command line and exit code of each command you run, via OSC 133/633 sequences. Toggle it from the command palette (⌘KEnable/Disable shell integration); your choice is remembered. It powers the command timeline, the persisted history, and "Fix it".

It's safe with your existing setup: Conductor points ZDOTDIR at a small shim that sources your own .zshenv / .zprofile / .zshrc (so your prompt — powerlevel10k, instant prompt, aliases — is untouched) and then adds precmd/preexec hooks.

With it on:

  • The command timeline (🕘) shows the full command and a ✓ / ✗ exit-code badge, and every command is saved to a searchable history — see Command history & insights.
  • The sidebar shows a per-project ✓ / ✗ test badge from the last test run (pest, phpunit, vitest, jest, pytest, cargo/go test, …).

Only zsh is supported for now; other shells keep the lighter, process-name-based timeline.

In-terminal search

Press ⌘F while a terminal is focused to open a find bar. Use / ⇧↵ to step through matches and Esc to close. Powered by the xterm search addon.

Clickable links

URLs in terminal output are underlined on hover and open in your system browser when clicked (e.g. a dev server printing ➜ Local: http://localhost:1420). Links open via the OS, not inside the app window.

Font size

⌘+ and ⌘− grow and shrink the terminal font across all panes at once; ⌘0 resets it to the default (13px). The chosen size persists across restarts (it's part of the saved layout). Emoji and wide CJK glyphs are measured at their correct width (Unicode 11), so box-drawing in TUIs stays aligned.

Ask about this terminal (⌘↵)

Press ⌘↵ in any terminal pane to open an inline ask bar; Esc dismisses it. Type a question and Elyra answers in place.

It works wherever the shell is — a local zsh, an SSH session, docker exec, a REPL — for one reason: the context that matters is the scrollback, and Conductor holds that locally regardless of where the shell actually runs.

What gets sent

  • the pane's working directory, and the git branch if there is one
  • the last 5 commands in that pane with their exit codes (needs shell integration)
  • the last 120 lines of output, with credential-shaped text masked by the same redaction used for persisted scrollback

Redaction is not optional here. Terminal output routinely contains tokens, and unlike saved scrollback — which stays on your disk — this text leaves the machine for a model provider.

It answers; it does not act

Tools are disabled, so the bar cannot edit files or run commands. Where the answer contains a shell command, you get an Insert button that places it on the prompt line without pressing Enter, so you read it and run it yourself. An LLM suggestion is not consent.

Only fenced bash/sh/zsh blocks are offered — a command mentioned in prose is deliberately ignored. When you want an agent that can actually change things, Open in Elyra ▸ escalates to a full agent tab where there is a transcript to review.

No keys in Conductor

There is no provider or API-key setting for this, in Settings or anywhere else. Conductor pipes your question to elyra --print, which already owns providers, models, and credentials. Configure them with elyra config. See Architecture.

Newline vs. submit (⇧↵)

Many TUIs use ⇧↵ to insert a newline while submits. Plain xterm.js can't send a distinct sequence for modified Enter — it collapses ⇧↵, ⌥↵, and ⌃↵ to a bare carriage return. Conductor fixes this by emitting the Kitty keyboard-protocol CSI u sequence for modified Enter, so apps like the Elyra CLI receive ⇧↵ as a real newline instead of submitting. No configuration is needed.

Broadcast input (synchronize panes)

Toggle ⌁ Sync in the top actions (or ⌘KBroadcast input to all panes) to mirror your keystrokes to every pane in the active tab — tmux synchronize-panes-style. Useful for running the same command across several services in a monorepo. Toggle it off to return to typing in just the focused pane.

Scrollback across restarts

Each pane's recent output is persisted and replayed as read-only history the next time Conductor launches, with a fresh shell started beneath it. A live PTY cannot be revived once the app closes, so this restores context, not a live process. Details and limits are in State & persistence.

Secrets in saved scrollback

Saved scrollback is stored in localStorage as plain text, and terminal output regularly contains credentials — a cat .env, an exported token, a connection string printed by a migration. Conductor masks the common shapes before writing: *_TOKEN / *_PASSWORD assignments, Bearer tokens, GitHub / AWS / Stripe / Slack / OpenAI keys, JWTs, PEM private-key blocks, and credentials inside URLs all become •••REDACTED•••.

That is a mitigation, not a guarantee — a secret in an unusual format can still slip through. If you would rather nothing were written at all, ⌘KStop saving terminal scrollback to disk turns it off and deletes whatever is already stored.

Running a command on open

Tabs opened for a task (or a file run) start a shell and then run the chosen command once. This is the same mechanism behind Run: … in the command palette.

Rendering & performance

Terminals are tuned to stay smooth even with several repaint-heavy TUIs (e.g. multiple Elyra agents) streaming at once:

  • GPU rendering — xterm renders via WebGL, offloading the work from the main thread. If a GPU context is unavailable (or lost when many are live), the affected pane falls back to the DOM renderer automatically.
  • Batched output — PTY output is coalesced into one write per animation frame, so a fast stream of small chunks doesn't multiply parse/render work.
  • Binary streaming — PTY bytes reach the webview over a binary channel (an ArrayBuffer), not a JSON event, avoiding a ~3.6× size hit and a JSON.parse per frame.
  • Hidden panes keep their size — an inactive (hidden) pane is never measured at 0×0, so switching or closing tabs doesn't shrink or garble the terminal you land on.