No description
  • TypeScript 99.1%
  • CSS 0.7%
  • HTML 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-03-05 07:18:51 -05:00
.github/workflows bug fixes and improvements 2026-02-26 13:17:53 -05:00
build/icons v0.2.1 - Add Icon 2026-03-04 20:25:53 -05:00
design/logo-final v0.2.1 - Add Icon 2026-03-04 20:25:53 -05:00
electron v0.2.3 - add option to keep or clean uncommitted changes when creating a 2026-03-05 07:18:51 -05:00
src v0.2.3 - add option to keep or clean uncommitted changes when creating a 2026-03-05 07:18:51 -05:00
.gitignore bug fixes and improvements 2026-02-26 13:17:53 -05:00
bun.lock bump v0.1.5 2026-03-04 19:15:54 -05:00
index.html init 2026-02-26 09:15:57 -05:00
index.js init 2026-02-26 09:15:57 -05:00
package.json v0.2.3 - add option to keep or clean uncommitted changes when creating a 2026-03-05 07:18:51 -05:00
README.md v0.2.3 - add option to keep or clean uncommitted changes when creating a 2026-03-05 07:18:51 -05:00
tsconfig.json init 2026-02-26 09:15:57 -05:00
vite.config.ts init 2026-02-26 09:15:57 -05:00

Duplex

Desktop app for working on multiple coding branches with built-in terminals and Git workflows.

CleanShot 2026-03-04 at 20 04 21@2x

Features

  • Multi-branch workspace tabs (create, reopen, switch, close).
  • Per-tab CLI terminal sessions (codex, claude, kimi, or opencode) for branch work.
  • Custom CLI tools can be added and edited (name + command), then used per tab.
  • Custom commands are validated on save, and missing commands show clear launch errors (local/SSH).
  • User-selectable default CLI for newly opened projects and tabs.
  • Bottom shell terminal (always plain terminal), resizable.
  • Git sidebar with:
    • unstaged/staged sections
    • stage/unstage file or all
    • discard file or all unstaged changes
    • commit / amend / push / publish branch
    • diff viewer for staged and unstaged changes
  • Session persistence:
    • last project path
    • open tabs and active tab
    • panel sizes and layout state
    • branch tabs restored on app restart
  • SSH remote project support (ssh://user@host:/absolute/path internally).

Tech Stack

  • Electron + React + Vite
  • Tailwind CSS
  • Zustand
  • xterm + node-pty

Requirements

  • Bun (recommended) or Node-compatible environment for tooling
  • git available in PATH
  • ssh available in PATH (for remote projects)
  • Optional: codex, claude, kimi, and/or opencode installed where you want to run them
    • local tabs: local machine
    • SSH tabs: remote host

Getting Started

bun install
bun run dev

Build production assets:

bun run build

Create distributable app (AppImage on Linux, DMG on macOS config):

bun run dist

Usage

Select a project

  • Use Local to open a local folder.
  • Use SSH and enter:
    • host (example: user@server)
    • absolute remote repo path (example: /home/user/my-repo)

Branch tabs

  • New Branch creates a branch workspace tab.
  • Existing branches can be reopened from Open existing branch....
  • Branch workspaces are copied from the project root and skip node_modules.
  • If the source repo has uncommitted changes, New Branch asks whether to keep or discard them in the copied workspace.
  • New Branch includes an optional Run bun install after branch setup toggle (local and SSH).

Terminals

  • Main tab terminals run the selected CLI (Codex / Claude / Kimi / OpenCode) per tab.
  • Default CLI is configurable under CLI Settings in the sidebar.
  • Custom tools added in CLI Settings appear in all CLI selectors.
  • Bottom terminal is always a shell terminal in the active tab folder.
  • Drag the divider above the bottom terminal to resize split height.

Git panel

  • Stage/unstage files and view diffs.
  • Commit or amend with message.
  • Push or publish (push -u origin <branch>).
  • Discard operations apply to unstaged changes.

SSH Notes

  • Remote project paths are stored as: ssh://user@host:/absolute/path.
  • Git operations for SSH projects execute remotely over SSH.
  • Branch copy/reopen/delete for SSH projects are also done remotely.
  • If CLI commands fail in SSH tabs, verify the CLI exists on the remote host.
  • Clipboard image paste in SSH tabs is forwarded by Duplex: the image is uploaded to /tmp/codex-clipboard-*.png on the remote host and that remote path is pasted into the terminal.

Project Structure

electron/
  main/        Electron main process, IPC handlers, git/project/pty services
  preload/     Renderer bridge API
src/
  components/  UI panels (sidebar, terminal, git)
  stores/      Zustand state
  types/       Shared TS types

Troubleshooting

  • Black window on Linux:
    • Use the latest built app from this repo state.
    • GPU acceleration is disabled for Linux in main process for stability.
  • AppImage fails with chrome-sandbox setuid error or doesn't display:
    • Launch with: ./Duplex-*.AppImage --no-sandbox --ozone-platform=x11
    • Or set environment variable: ELECTRON_OZONE_PLATFORM_HINT=x11 ./Duplex-*.AppImage --no-sandbox
  • SSH connection fails:
    • test directly: ssh user@host
    • verify repo path exists and is a git repo.
  • Push/publish fails:
    • check remote auth and branch upstream configuration.