Current version · v1.1.0

Changelog

All notable changes to Termbay are documented in this file.

1.1.0

Multi-language release plus a round of terminal, viewer and status fixes. Every user-visible string now lives in per-feature translation catalogs (src/shared/i18n/), guarded by a key-parity test across all languages and a lint rule that rejects hard-coded UI text. Test suite: 1925 passing.

Added

  • Eight languages: the whole interface can now be used in English, Spanish, Brazilian Portuguese, French, German, Italian, Japanese and Simplified Chinese. Pick one under Settings > Language; it switches live, and on first run Termbay follows your Windows language.
  • Read-only file viewer: files opened from the Explorer show up in their own pane between the sidebar and your terminals, with tabs, a draggable divider, a maximize mode, and automatic refresh whenever an agent edits the open file.
  • VS Code-style Source Control: the Git panel was redesigned with Staged Changes / Changes groups, colored status letters, a Timeline, and side-by-side or inline diffs that open as viewer tabs.
  • Terminal copy & paste: Ctrl+C copies the selection (as clean, reflowed text) and still interrupts when nothing is selected; Ctrl+Shift+C copies raw text; Ctrl+V pastes; right-click opens a Copy / Copy raw text / Paste menu; Claude Code’s /copy now reaches the clipboard.
  • Shift+Enter inserts a newline in Claude Code and Codex prompts instead of sending them.
  • Drag paths into terminals: dropping files or folders from Windows Explorer — or dragging rows out of Termbay’s own file tree — types their paths into the terminal, quoted when needed.

Changed

  • Automations panel: clearer scheduler status with a single Pause all / Resume all control, a styled Import button instead of the raw file picker, an explanatory empty state, and a cancellable import review.
  • Downloads and updates now live at termbay.com.

Fixed

  • Projects no longer stay stuck on “Running” after an agent finishes, and a subagent finishing late no longer flips a finished project back to running.
  • “Needs you” now only appears when an agent is actually blocked on you (a permission request or a question), not for Claude Code’s idle reminder; background subagents keep the project shown as running.
  • Termbay now detects your Windows language correctly.

1.0.5

Closes out every item under “Remaining issues” in docs/ux-review-1.0.3.md (now marked resolved there with evidence). Verified with fresh dark + light screenshots of every affected screen, including a synthetic single-row 6-column grid at 1100x760. Test suite: 611 passing (605 + 6 new clampNotePosition tests). scripts/e2e-panels.mjs: 36/36 steps passing (step 33 updated for the Voice per-project mute <Toggle> rollout).

Added

  • Responsive column grid: a row’s columns no longer shrink below a 360px floor (--column-min-width); once a row can’t fit every column at that floor, it scrolls horizontally with snap instead of crushing terminal text into illegibility.
  • Sticky-note clamping: a note’s full box now always stays within the grid’s bounds (including on a plain window resize, no drag required) and a column-anchored note can never render on top of that column’s header.
  • Automation status pills: idle/running/queued/paused-globally/ disabled/error each get a distinct color and icon (never color alone), plus a hoverable “status legend” next to the Automations list. error is a new state (most recent run failed/timed out).
  • Context-menu shortcut hints: the column context menu now shows a keyboard-shortcut hint next to any action that actually has one bound, sourced directly from the same shortcut registry ShortcutsOverlay uses.

Changed

  • Toggle rollout completed: every remaining ad-hoc checkbox for a boolean setting (Automation editor, Profiles’ Primary flag, Spawn popover, Search overlay, Voice’s per-project mute list) now uses the shared <Toggle>, matching Sync/Voice’s “Enabled” from 1.0.4. (The per-column “include in broadcast” checkbox in the column header is left as a native checkbox — a multi-select list item, not a settings toggle, and too tight on space for a full switch.)
  • Skeleton rollout completed: Profiles, Endpoints, Custom Providers, Run tab, and Snippets manager now all show a shimmering placeholder instead of a plain “Loading…”/“Detecting run targets…” string.
  • Findings row actions: “Open in session”/“Resume session” is now the app’s primary button style; the sticky findings mini-window’s “Acknowledge” button (previously a bare unstyled <button>) now matches the rest of the app.

1.0.4

UX pass: screenshotted every screen (main grid, all 18 rail panels/modals, shortcuts overlay, context menu, a toast, and the empty-grid state) in dark and light at 1600x1000 plus a narrow 1100x760 window, wrote up findings in docs/ux-review-1.0.3.md, and fixed the high-impact ones. Test suite: 605 passing (unchanged count, all still green). scripts/e2e-panels.mjs: 36/36 steps passing (added step 36, onboarding).

Fixed

  • Empty-row dead end: killing (or moving out) a row’s last column used to leave that row rendering nothing — no message, no way back in short of a keyboard shortcut. Rows that end up with zero columns are now pruned, falling back to the existing “Spawn your first agent” empty state.
  • Profiles panel: a long CLAUDE_CONFIG_DIR=... value with no whitespace overflowed its row and visually overlapped the Edit/Delete buttons; long values now wrap instead.
  • Usage panel: the empty state showed both “No usage data found” and a self-contradictory “0 tokens … roughly the length of 0.0 novels” card; the novels card is now suppressed at zero.

Added

  • First-run onboarding: a skippable 3-step welcome overlay (add a project → pick a provider detected on PATH → spawn the first column), shown once on a genuinely empty, non-demo install and never again after it’s skipped or completed.
  • Loading skeletons: Git, Voice, and Fleet panels now show a shimmering placeholder instead of a plain “Loading…” string while their first fetch is in flight.
  • Shared <Toggle> switch component, replacing three different “enabled?” patterns (checkbox vs. On/Off text button) with one — applied to the Sync and Voice panels.
  • Global keyboard-focus ring: every interactive element (inputs, selects, buttons, links, menu items) now gets the app’s teal focus ring by default, not just the handful of components that opted in before.

Changed

  • Endpoints/Profiles panels’ “Delete” buttons now get the same red destructive treatment Automations already used, instead of looking identical to “Edit”/“Cancel”.
  • Hooks inspector’s “Connect hooks” button is now styled as the app’s primary CTA while disconnected (it’s the only action available in that state).

1.0.3

Security hardening pass, closing all High and Medium findings (except code signing, which requires a paid certificate and is documented as a known trade-off in SECURITY.md) from docs/security-review-1.0.2.md, plus every cheap Low finding. New/refreshed SECURITY.md. Test suite: 510 → 603+ passing. scripts/e2e-panels.mjs: still 35/35 steps passing.

Security

  • git.createWorktree base-directory containment (H1): no longer accepts a caller-supplied baseDir at all — main always derives the worktree base directory from the repo root itself.
  • Windows npm-script cmd.exe injection (H2): a strict script-name charset allowlist (src/shared/run/npm-script-name.ts) is enforced both where RunTargets are parsed and again immediately before spawn.
  • Isolation-clone remote-URL allowlist (H3): sourceUrl must be https:/ssh:/git:/scp-like/file:-inside-an-authorized-root; ext::/fd:: and every other scheme are rejected, both for a manually-entered URL and an imported automation. git clone/fetch now also run with -c protocol.ext.allow=never -c protocol.fd.allow=never.
  • shell.openPath/reveal-in-folder allowlist (H4): switched from a blocklist to a strict allowlist of known-safe extensions; UNC and \\?\ paths are rejected.
  • Every BrowserWindow hardened uniformly (H5): a shared hardenWindow helper wires CSP, setWindowOpenHandler, will-navigate, and will-redirect for main, popout, findings-sticky, and job-watcher windows alike.
  • Per-connection PTY ownership (M1): write/resize/kill only work for the connection that created a given PTY, with an explicit, capability-authorized reattach path for legitimate ownership transfer.
  • PTY WebSocket Origin check (M2) and env blocklist enforced at the pty-host spawn boundary itself (M3), plus expanded env blocklist coverage (M4): BASH_FUNC_*, PERL5OPT, JAVA_TOOL_OPTIONS, _JAVA_OPTIONS, JDK_JAVA_OPTIONS, PYTHONHOME.
  • Electron Fuses (M5): runAsNode/Node-options/CLI-inspect disabled, cookie encryption + asar integrity validation enabled, applied via an electron-builder afterPack hook. The pty-host’s “no system Node” fallback now uses utilityProcess.fork instead of ELECTRON_RUN_AS_NODE.
  • Hook auth token file permissions (M7): ~/.claude/settings.json (and its backups) are chmod 0o600’d after every write on POSIX.
  • Run tab trust boundary (M8): IPC.run.execute re-derives the trusted command from main’s own last-detected-targets cache by id, never from renderer-supplied command/args directly.
  • Timing-safe token comparisons (L1/L2), hook-receiver Origin rejection (L3), attachment-filename trailing-dot/space stripping (L4), allowDowngrade: false (L6), a malformed-hooks-value guard (L7), and a case-insensitive-filesystem containment regression test (L8).
  • New/refreshed SECURITY.md: threat model, architecture, hardening summary, and the code-signing trade-off/plan.

1.0.2

Closes the automation editor P0 gap flagged in docs/qa-report-1.0.1.md (“Automations panel has no ‘create new automation’ UI”) plus a CRUD completeness audit across every entity in the app, a light-theme text- contrast fix, and a refreshed app-automations.png. Test suite: 501 → 510 passing. scripts/e2e-panels.mjs: 27 → 35 steps.

Added

  • Full automation editor modal (AutomationEditor.tsx, spec §11/§24): create/edit/duplicate/delete an automation, agent list add/remove/ reorder/duplicate, per-agent prompt/provider (headless-capable built-ins or a custom provider)/model/effort/endpoint/subscription profile, schedule builder (interval, weekday+time-of-day chips, on-startup, manual, run-after with failure/inherit-output options), session mode, repo isolation toggle, usage gate, max duration, MCP server ids, an encrypted-at-rest database connection (new automation-db-secrets.json store, same safeStorage pattern as endpoints/voice — the plaintext connection string is never returned to the renderer), and a pipeline supervisor section. Live validation (Save disabled with an inline reason until the form is valid), a human-readable schedule summary and next-run preview per agent (describeSchedule/WEEKDAY_FULL_LABELS, new in src/shared/schedule/schedule.ts). Run history now also shows summary/ output excerpt/cost, not just status.
  • Custom providers panel (CustomProvidersPanel.tsx, Settings → “Custom providers”) — create/edit/delete; the backend (providers.listCustom/saveCustom/removeCustom) already supported this, it just had no UI (“in a future update” placeholder removed).
  • Run-tab env profile editor — create/edit/delete EnvProfiles (name + KEY=value lines) directly in the Run panel; previously only a read-only <select> existed.
  • Project/workspace rename — new projects:rename/ projects:renameWorkspace IPC + Sidebar pencil-icon inline rename.
  • Project/workspace delete from the UI — Sidebar trash-icon delete with confirmation (backend already existed); workspace delete is hidden when it’s the project’s only workspace, and removeWorkspace in the store never leaves a project with zero workspaces.
  • Voice per-project mute list UI (VoicePanel.tsx) — the mutedProjectIds field existed and was already read by playback eligibility, but had no checkbox anywhere to set it.
  • Portable customProviderId export/import (import-export.ts): export now maps a custom agent’s customProviderId to the custom provider’s name (never the machine-local id); import re-resolves by name against the importing machine’s own custom providers and returns a clear per-agent warning when no match exists, instead of silently dropping the reference. importAutomation now returns { automation, warnings }.
  • AutomationAgent.effortId — per-provider reasoning-effort selection for an automation agent, threaded through headless-runner.ts’s buildSpawnArgs call.

Fixed

  • Light theme text contrast: --primary-strong/--accent/ --accent-strong/--danger/--success were never overridden for light theme, so several status badges/labels tuned for a dark surface (the .kbd “installed” badge, Delete/danger labels, findings/git-diff accents) fell below WCAG AA’s 4.5:1 body-text minimum on white (measured as low as ~2.0:1). --primary itself is intentionally left alone — it’s only ever a filled-button background with a fixed dark label, already ~7.9:1 regardless of theme.
  • Hooks inspector feed wrapped a long column id across two lines at the panel’s fixed width — now truncated with an ellipsis and a title tooltip showing the full id.
  • Escape didn’t close the automation editor — it’s local component state, invisible to the global close-modal shortcut handler, so Escape would instead blow away the whole Automations panel underneath it (via setActivePanel('none')). Now handled locally on the capture phase, so only the editor closes.

1.0.1

Panel-by-panel end-to-end QA pass (real app, real PTYs, isolated --user-data-dir + a fake home directory — never the real ~/.claude, ~/.codex, or Termbay userData). Fixes 11 real, root-cause bugs found by actually driving the app through every panel; see docs/qa-report-1.0.1.md for the full write-up. Adds scripts/e2e-panels.mjs (27 steps) alongside the existing scripts/e2e-smoke.mjs. Test suite: 480 → 501 passing.

Fixed

  • Every registered keyboard shortcut silently did nothing while a terminal column had focus — the most common state a user is in. xterm.js was never wired with attachCustomKeyEventHandler, so it captured combos like Ctrl+Enter/Ctrl+Shift+W before Termbay’s own global shortcut listener ever saw them. src/renderer/features/grid/Column.tsx.
  • Automations never ran for any real (non-demo) project — the scheduler’s project-root resolver was hardcoded to only work in --demo mode; every real automation silently did nothing or got auto-disabled with a misleading “working directory no longer exists”. src/main/index.ts, src/main/automations/scheduler.ts.
  • Custom-provider automations could never run headlessly — added AutomationAgent.customProviderId and a resolver so a custom agent can run a saved local command headlessly (prompt piped via stdin), the only safe way to exercise Automations/Findings without a real agent CLI or paid API. src/shared/automations/*, src/main/automations/*.
  • A single failed PTY spawn crashed the entire terminal-host sidecar, killing every live column in the app, with no auto-restart. node-pty’s spawn() can throw synchronously (e.g. a bad/missing command); now caught and returned as a normal per-spawn failure instead. src/main/pty-host/pty-manager.ts.
  • Run tab npm scripts never worked on Windows — node-pty has no shell/.cmd resolution, so the bare "npm" command always failed to spawn; resolved to npm.cmd on win32. src/main/run/run-launcher.ts.
  • Opening a brand-new project’s Instructions editor threw an uncaught error (and so did saving any genuinely new file anywhere containment is checked) — the containment check’s realpath resolution always failed closed for a not-yet-existing path. Now walks up to the nearest existing ancestor (still defeats a symlink-swap attack) instead of failing outright. src/shared/fs/path-containment.ts.
  • Snippet \trigger expansion never worked in any real column — a classic stale-closure bug: xterm’s onData listener captured the always-empty initial snippets list before the async fetch resolved, and was never rebound. Fixed with the same ref pattern already used for the Git panel’s commit-staged shortcut. src/renderer/features/grid/Column.tsx.
  • Git stash Pop/Drop were completely broken — %gd combined with --date=iso rendered the stash id as a date string instead of stash@{N} on this git build, always failing validation. The id is now derived from stash-list order instead of trusting that format specifier. src/main/git/git-ops.ts.
  • An untracked file’s Git status row showed “Unstage” instead of “Stage” — index: '?' (untracked) was misclassified as already staged. src/renderer/features/git/GitPanel.tsx, new src/shared/git/status-classify.ts.
  • Custom-provider columns were unreachable from the Spawn popover (and the toolbar’s quick-spawn dropdown) — the provider list backing both only ever included built-in providers. The full Spawn popover now also lists saved custom providers and wires customProviderId through to spawn. src/renderer/features/spawn/SpawnPopover.tsx.
  • Files panel: a failed Save was silently swallowed (unhandled promise rejection, dirty stuck true, no visible error) — missing .catch(). src/renderer/features/explorer/ExplorerPanel.tsx.

1.0.0

First 1.0 release: closes the last recorded parity gap (the agent-initiated “file sent” lifecycle event), passes a full regression sweep, and packages signed-checksum Windows installers plus a rebuilt marketing site that derives its version/filenames from package.json instead of hardcoding them.

Added

  • “File sent” lifecycle event + agent-initiated attachments (spec §14/§19, closes the last item in docs/parity-audit.md). The local hook receiver (src/main/hooks/hook-receiver.ts) now recognizes an agent-initiated file two ways:

    • A Claude Code PostToolUse hook payload for its Write tool — recognized automatically once “Connect hooks” has been used, no extra setup.
    • The documented termbay-send <path> helper command (scripts/termbay-send.mjs) for any other agent/CLI, which POSTs directly to a new /attachment route on the same token-authed receiver.

    Candidate paths get cheap, pure shape validation (src/shared/attachments/sent-file-validation.ts, unit-tested) before ever reaching the filesystem, then real containment (assertContained against the live authorized project roots — the “explicit allow-list of locations actually observed from a real attachment event” the spec requires, never a general scratch directory) in src/main/attachments/attachments-store.ts#registerSentFile. A rejected candidate is logged and dropped, never reaching the renderer. Accepted files show up in the existing per-column attachment tray (tagged “SENT”) without ever being copied — reveal and a new open action (shell.openPath) are both available; removing an agent-sent attachment from the tray only detaches it, it never deletes the agent’s real project file (dropped/pasted attachments still delete their app-owned copy, as before).

  • window.termbay.attachments.open(id) — opens an attachment directly in its OS-default handler, alongside the existing reveal-in-folder.

Changed

  • Version bumped to 1.0.0.
  • README.md’s Download section now points at the live termbay.luismedinaraed.com.ar/download/ installers (Setup, Portable, and a SHA256SUMS.txt) instead of “build from source until then”.
  • The marketing site (site/) no longer hardcodes an app version or installer filenames anywhere — both are derived from the root package.json at build time, so the download page and changelog excerpt can never drift from what’s actually shipped.
  • site/src/assets/screenshots/app-hero.png and app-grid.png regenerated against the 1.0.0 build so the status bar reads the real version.

0.9.2

Git panel completion pass: stash/branches/diff/log, real git worktree isolation, Codex job-watcher multi-directory search, Buoy polish, voice manual controls, and a couple of real bug fixes found along the way.

Added

  • Git panel, full (spec §16): stash (list/push/pop/drop), branch list with current-branch marker + switch + create (from HEAD or an explicit start point), a colored unified diff viewer (per file, staged vs unstaged, and per commit — click a commit in the log to see its diff), and a commit log with hash/author/relative-time/message. A column’s “target branch” hint — set automatically from its worktree’s branch, or best-effort from its bound session’s transcript — switches the tab to a read-only branch-relative view (log/ahead-behind/diff vs. a resolved base branch: main/master if either exists, else whatever’s checked out) and hides every mutating action when it differs from what’s actually checked out in that cwd. The Git detail panel is wider (640px) to give the diff viewer and log real room.
  • Git worktree isolation actually works (spec §5.2): spawning a column with “Git worktree isolation” checked now runs a real git worktree add -b termbay/<slug> <repo>/.termbay/worktrees/<slug> (slug derived from the column title, shell-sanitized and validated), the column’s cwd points at the real new worktree, and its target-branch hint is recorded automatically. Killing such a column offers to remove the worktree too (confirmation; a second, stronger confirmation before force-removing one with uncommitted changes).
  • Codex-class job watcher, multi-directory (spec §23): now searches every candidate state directory — a CODEX_HOME environment override, every Codex-provider subscription profile’s own config directory, a worktree-derived <cwd>/.codex guess, and the default ~/.codex — and attributes background jobs by session id across all of them; ids stay opaque to the renderer throughout. A column’s overflow menu now offers “Background jobs” only once a session is actually confirmed to have some, opening a dedicated read-only popout window.
  • Buoy polish (spec §21): a Settings-level “Buoy companion” on/off switch overriding every column’s own visibility toggle; drag-to- reposition the companion within its column, persisted as a relative fraction of the column’s bounds so it survives resize/reflow; distinct working-state sub-pose CSS animation variants (tilt / wrench-bob / blink, cycling between the working and thinking artwork) instead of one static pose; and a one-shot pulse reacting to a fresh notification (alert) state.
  • Voice manual controls + focus catch-up (spec §20): per-column “Read full” / “Read summary” buttons in the header’s overflow menu, with pause/resume-on-the-same-source and stop-without-resynthesizing-on-a- different-source semantics; a reply that finishes while its column isn’t focused is flagged unspoken and auto-replayed the instant the user focuses that column (also replayable manually at any time). Custom spoken personality is now mirrored to every secondary subscription profile’s own config directory on save, the same read-modify-write-safe pattern as global instructions, with a failure toast on a partial mirror.
  • Start Termbay when you log in setting (Settings → General), backed by app.setLoginItemSettings; the OS’s own registration is the source of truth, never duplicated into settings.json.
  • Findings inbox now groups by the automation’s real display name instead of its internal id, shows relative-time labels instead of an absolute timestamp, and sorts groups newest-activity-first.
  • scripts/e2e-smoke.mjs extended with a keyboard-shortcut step (Ctrl+Shift+E toggles the file explorer) and a context-menu step (move the Shell column to a second seeded workspace); now 10/10 steps passing.

Fixed

  • Real git-argument bug: git checkout -- <ref> (and the equivalent for show/log against a bare revision) forces git to parse ref as a pathspec, not a revision — confirmed empirically (git checkout -- main fails with “pathspec ‘main’ did not match any files” instead of switching branches). This silently broke the pre-existing gitCheckout (so the original “Branches: switch” affordance never actually worked) and would have broken the new commit-diff/branch-relative-log features too. Fixed everywhere a revision — as opposed to a genuine path/URL — is the variable argument, with a regression test against a real temp git repo (src/main/git/git-ops.test.ts).
  • Legacy workspace-upgrade dead code: getWorkspaceLayout’s legacy single-array-format branch guarded on workspaceId in {}, which is always false, so the guard never actually ran — every workspace (not just the project’s real Primary one) silently inherited the pre-upgrade layout instead of starting empty. Extracted into a pure, directly-unit-tested resolveLegacyArrayLayout.

Removed

  • src/shared/search/transcript-search.ts (the earlier whole-document literal/regex transcript matcher), superseded by the streaming src/main/search/transcript-discovery.ts and unused everywhere else. Its still-relevant test coverage (regex-metacharacter escaping, case-insensitive matching) moved into transcript-discovery.test.ts rather than being dropped.

0.9.1

Parity/hardening pass closing the gaps recorded in docs/parity-audit.md.

Added

  • Project roots via native picker only: projects.pickFolder now returns an opaque, single-use grant id instead of a raw path; projects.add consumes the grant server-side and rejects anything else — the renderer can no longer self-authorize an arbitrary filesystem root.
  • Auto-update: electron-updater against a generic publish provider (https://termbay.luismedinaraed.com.ar/download/), checked on startup for packaged/non-demo runs, a status-bar “Update ready — restart” indicator, install-on-quit, and a Settings toggle to disable automatic checks. Not code-signed yet; relies on electron-updater’s built-in latest.yml sha512 verification as the checksum-only interim mitigation.
  • Session/transcript search overlay (Ctrl+Shift+F, moved file-explorer to Ctrl+Shift+E): real streaming line-by-line search across ~/.claude/projects/**.jsonl and ~/.codex/sessions/**, literal or regex, this-project/all-projects scope toggle, a “my prompts” mode over ~/.claude/history.jsonl (and a Codex equivalent if present), and click-to-resume (switches project, spawns a column resuming that session). Added to the command palette.
  • Keyboard shortcuts: single shared registry (src/shared/shortcuts/registry.ts) driving both the shortcuts-reference overlay and the real keydown matcher, so the overlay can’t claim an unwired binding. Kill column, maximize/ restore, add row, jump to column 1–9, prev/next/up/down column navigation, commit staged, zoom in/out/reset (persisted), toggle explorer, and Escape now closes every open modal/panel.
  • Voice session binding wired in: columns acquire-bind to their newest matching transcript session (never stealing a sibling’s), feeding both the per-column context meter and the search/findings resume flow.
  • Column context menu (right-click header): rename, respawn, kill, maximize, duplicate, move to row/workspace (PTY stays alive), open cwd in the OS file explorer, toggle Buoy visibility.
  • Live usage bars, per-column usage since spawn, and threshold notifications (70%/90%, OS notification + in-app toast).
  • Endpoint failover: network-looking PTY exits trigger a resolved fallback preset respawn with an in-column banner.
  • Global-instructions save now mirrors to every secondary subscription profile, with a failure toast; findings inbox now folds answered-decision resolutions into the next automation run’s prompt.

First broadly-shippable release: the full MVP + V2 + Phase 2b feature set, plus a release-engineering pass (packaging, real end-to-end QA, demo screenshot quality) to get the app ready to actually hand to someone.

Added

  • Terminal grid — rows x columns of live agent sessions, drag-resize (ratio-persisted), drag-reorder columns and rows (including moving a column to a different row), maximize-in-row, custom titles, per-column provider color chip, a live context meter, and a 7-state original Buoy companion driven by real Claude Code hooks or a per-provider output heuristic for everyone else.
  • Provider registry — 8 built-in adapters (Claude Code, Codex, Gemini CLI, OpenCode, Aider, Cursor Agent, GitHub Copilot CLI, Amp) plus unlimited user-defined Custom providers, each declaring its own capabilities and spawn-arg shape.
  • Projects & workspaces sidebar, atomic JSON persistence, per-project workspace layouts, popout windows.
  • Spawn popover (provider/model/effort/permission-mode/worktree/ bare/strip-MCP/headless/extra-args + endpoint-preset + subscription- profile picker) and a toolbar quick-spawn dropdown.
  • Broadcast bar and a command palette with a custom fuzzy ranker.
  • Git panel and a file explorer + inline editor, both scoped to the focused column’s working directory and path-guarded.
  • Usage & cost panel — real Claude Code transcript parsing and Codex rollout parsing, a live per-column context meter, Summary/Daily/ Sessions/Cost tabs.
  • Snippets (\trigger -> expansion, {{variable}} placeholders) with live in-terminal expansion.
  • Project & global instructions editor for every provider with a known instructions file.
  • Endpoints & failover — named base-URL/token presets encrypted at rest, automatic failover.
  • Multi-subscription profiles — cascade resolution and global- instructions mirroring.
  • Run tab — detects npm scripts, .vscode/launch.json, launchSettings.json, and Makefile targets; dispatches to a fresh, contained terminal column.
  • Hooks inspector & live activity feed for Claude Code, with a “zero signal” canary.
  • Sticky notes — draggable, resizable, color-coded, anchored to a column or the grid.
  • Attachments — drag-and-drop or paste into a column with a per-column tray.
  • OS notifications for a background column entering waiting/alert.
  • Automations & Pipeline Supervisor — scheduled headless agent runs, a real supervisor decision loop, repo-isolation clone hygiene, run history, portable import/export.
  • Findings inbox — fingerprint-deduped, retention-safe, delivered via an always-on-top sticky window.
  • Voice (TTS) — ElevenLabs-backed reading of a column’s own buffer when it finishes replying, with auto-play eligibility gating.
  • Cross-device sync — picker-selected destination folder, conflict- safe mirror rules.
  • Codex background-job watcher and Fleet Overview (per-project branch/dirty/findings aggregation).
  • Demo mode (--demo, --screenshot, --size, --theme, --demo-open=<target>, --demo-panel=none) against a fully isolated, disposable app-data directory, seeding realistic snippets/endpoints/ profiles/sticky-notes for repeatable marketing screenshots. Each column’s scripted output now writes a large (40-80 line) pre-filled scrollback immediately on spawn instead of trickling in, and --screenshot waits for a real “every column’s viewport is full” signal before capturing.
  • --user-data-dir=<path> flag: redirects the whole app’s userData directory, for isolated real end-to-end QA runs (or any other scripted use) without touching a real user’s app-data.
  • scripts/e2e-smoke.mjs — a real end-to-end smoke test (Playwright’s _electron) against the built app: project load, a real PTY input/output round trip, starting-then-killing real agent CLIs when present on PATH, resize/maximize, and quit+relaunch session restore. See docs/qa-checklist.md.
  • Windows packaging — npm run dist:win produces a working NSIS installer (Termbay-Setup-<version>.exe) and a portable build (Termbay-<version>-portable.exe). dist:mac/dist:linux targets are configured (not buildable/verified on this machine).

Fixed

  • Status bar showed Electron’s own runtime version (“Termbay v33.4.11”) instead of Termbay’s actual version; now reads it from package.json at build time regardless of dev vs. packaged layout.
  • A project restored from a prior session was never re-authorized for path-guarded filesystem operations (git status, file explorer, run detection, …) after a fresh app launch, only ones added fresh that session — every such operation would fail right after a restart. Found via real end-to-end “quit and relaunch” QA.
  • Terminal columns had no DOM/accessibility text representation of their content at all (screenReaderMode was off) — a real accessibility gap, and something that also blocked verifying PTY output programmatically.
  • The packaged app’s terminal host failed to start entirely: its sidecar scripts weren’t unpacked from app.asar (a spawned OS process can’t read inside the archive), and even once unpacked, in-process path construction still pointed at the in-archive location rather than the real unpacked one.
  • electron-builder’s automatic native-module rebuild step failed outright in this environment trying to rebuild node-pty from source; disabled it (npmRebuild: false) since node-pty ships N-API prebuilds that already work under both system Node and ELECTRON_RUN_AS_NODE with zero rebuild (verified directly).
  • Corrected stale comments/log text claiming node-pty needs an Electron-specific rebuild via a postinstall step that never actually existed in this repo.

Changed

  • Version bumped to 0.9.0.
  • Demo screenshots regenerated with the denser scripted output; progress bars and long lines are now word-wrapped to a safe width so nothing wraps mid-word even in the narrowest realistic grid column.
  • Installers will be served from termbay.luismedinaraed.com.ar/download (see README’s new Download section).

Download the latest version →