diff --git a/CHANGELOG.md b/CHANGELOG.md
index 983ef56..6a8f971 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+## [0.11.1] — 2026-05-07
+
+### Improvements
+
+- README, GitHub Pages site, and architecture doc now lead with
+ AI session management — discover every past Copilot CLI / Claude
+ Code session, resume any of them in one click, close active ones
+ from the sidebar, delete history from disk, and have every session
+ tab auto-restore exactly where you left it the next time you open
+ the app.
+- Demo animation now showcases the headline workflow: opening the
+ Sessions panel, resuming a past session in one click, and chatting
+ with the resumed Copilot session.
+
## [0.11.0] — 2026-05-07
### Features
@@ -342,7 +356,8 @@ AI-assisted development.
- Eight built-in themes (dark and light variants).
- Keyboard shortcuts for tabs, splits, sidebar, and settings.
-[Unreleased]: https://github.com/Ron537/DPlex/compare/v0.11.0...HEAD
+[Unreleased]: https://github.com/Ron537/DPlex/compare/v0.11.1...HEAD
+[0.11.1]: https://github.com/Ron537/DPlex/compare/v0.11.0...v0.11.1
[0.11.0]: https://github.com/Ron537/DPlex/compare/v0.10.0...v0.11.0
[0.10.0]: https://github.com/Ron537/DPlex/compare/v0.9.2...v0.10.0
[0.9.2]: https://github.com/Ron537/DPlex/compare/v0.9.1...v0.9.2
diff --git a/README.md b/README.md
index ffa1967..1f25529 100644
--- a/README.md
+++ b/README.md
@@ -2,9 +2,9 @@
# DPlex
-**A terminal multiplexer built for AI-assisted development.**
+**A desktop workspace for the AI CLI sessions you run every day.**
-DPlex is a desktop terminal app that manages multiple AI CLI tool sessions alongside regular terminals — all in one window. Think of it as a purpose-built workspace for developers who run **Copilot CLI**, **Claude Code**, or other AI coding agents daily across many projects.
+DPlex **discovers** every **Copilot CLI** / **Claude Code** session you've ever started, lets you **resume** any of them in one click, and **auto-restores every open session tab** the next time you open the app — splits, order, working directory, and resume command preserved. On top of that: the multiplexer essentials — split panes, tabs, projects, worktrees, and a built-in VSCode-style Source Control view.
[](https://github.com/Ron537/DPlex/actions/workflows/tests.yml)
[](https://github.com/Ron537/DPlex/actions/workflows/codeql.yml)
@@ -20,7 +20,7 @@ DPlex is a desktop terminal app that manages multiple AI CLI tool sessions along
-
+
> **🚧 Pre-1.0.** DPlex is functional and used daily by its author, but
@@ -32,11 +32,14 @@ DPlex is a desktop terminal app that manages multiple AI CLI tool sessions along
## Why DPlex?
-When working with AI CLI tools across multiple projects, you end up with a mess of terminal windows — a Copilot session here, a Claude session there, plus regular shells scattered everywhere. DPlex gives you one home for all of it:
+When working with AI CLI tools across multiple projects, you end up with a mess of terminal windows — a Copilot session here, a Claude session there, plus regular shells scattered everywhere, and not a single one of them survives a reboot. DPlex gives you one home for all of it, with **AI session management as the headline feature**:
-- **One window** with split panes, tabs, and an activity bar (Projects · Sessions · Source Control).
-- **Automatic session discovery** — sees active and past AI sessions across providers without manual tracking.
-- **Session persistence** — close the app, reopen it, your AI sessions resume where you left off.
+- **🗂️ Discover every past session.** DPlex reads each provider's data directory and surfaces every Copilot CLI / Claude Code session you've ever started — searchable by name, ID, summary, or workspace.
+- **▶️ Resume in one click.** Click any past session and it opens in a new tab with the correct resume command and original CWD. No copy-pasting session IDs from `~/.copilot/...`.
+- **⏹️ Close active sessions from the sidebar.** Stop running AI sessions without hunting for their terminal — closing a tab fully terminates the underlying process.
+- **🗑️ Delete from disk.** Remove a session's stored data when you're done, with confirmation.
+- **♻️ Auto-restore session tabs across restarts.** Quit the app, reopen it tomorrow — every AI session tab snaps back exactly where it was, with the right resume command, CWD, splits, and tab order preserved.
+- **One window** for everything: split panes, tabs, and an activity bar (Projects · Sessions · Source Control).
- **Project-aware workflow** — group sessions by project, start a new AI session in any folder with one click.
- **Worktree-friendly** — first-class Git worktree support so concurrent feature work doesn't pollute your main checkout.
- **Built-in Source Control** — VSCode-style changes view scoped to whichever project (or worktree) you pick.
@@ -134,7 +137,7 @@ CI logs and SBOMs are attached to every release.
- Sessions panel. Every Copilot CLI / Claude Code session you've ever started, searchable.
+ Sessions panel. Every Copilot CLI / Claude Code session you've ever started, searchable. Click to resume, right-click to delete from disk.
@@ -171,6 +174,60 @@ CI logs and SBOMs are attached to every release.
## Features
+### AI session management
+
+> The headline feature. DPlex gives you full lifecycle control over the
+> Copilot CLI / Claude Code sessions you actually work with daily.
+
+- **🗂️ Past-session list.** Every session you've ever started, surfaced
+ in the **Sessions** activity-bar panel — searchable by name, ID,
+ summary, or workspace, grouped by recency or by project.
+- **▶️ One-click resume.** Click any past session to reopen it in a new
+ tab with the correct resume command and original CWD pre-filled. The
+ re-spawned PTY is matched back to its provider session ID so the
+ active-session indicator lights up automatically once the AI tool
+ writes its lock file.
+- **🟢 Live active-session indicators.** Active sessions are detected
+ via provider lock files (`inuse..lock` for Copilot, pidfiles for
+ Claude) with PID liveness checks, so the sidebar always reflects what
+ is actually running.
+- **⏹️ Close active sessions from the sidebar.** Stop a running AI
+ session without finding its terminal — closing the tab fully
+ terminates the underlying process.
+- **🗑️ Delete sessions from disk.** Remove a session's stored history
+ when you're done with it (with confirmation).
+- **🧠 Prompt-history viewer.** Browse and search the prompts you've
+ sent in any past session — useful for re-running, copy-pasting, or
+ remembering what you asked yesterday.
+- **📌 Recent sessions per project.** Each expanded project (and
+ worktree) lists its last few idle sessions inline, so you can resume
+ them without leaving the projects panel.
+- **🧩 Provider-agnostic.** Same start / resume / close / delete flow
+ whether the underlying tool is Copilot CLI, Claude Code, or one you
+ add yourself — see [docs/providers.md](./docs/providers.md).
+
+### Workspace persistence (auto-restore on restart)
+
+> **Close the app today, open it tomorrow — every AI session tab is
+> back exactly where you left it.** This is the feature DPlex was built
+> around.
+
+- **Every AI session tab is restored.** Tabs are serialized to
+ `sessions.json` in the Electron `userData` directory on every natural
+ lifecycle event and synchronously on quit, so a SIGTERM doesn't lose
+ state.
+- **Splits and tab order survive too.** Horizontal/vertical splits, tab
+ order within each pane, the active group, and the active tab are all
+ rebuilt on launch.
+- **Resume command + CWD preserved.** Each restored tab is recreated
+ with its original resume command and working directory. A short retry
+ loop re-resolves the underlying provider session ID once the AI tool
+ writes its lock file, so active-session indicators light up
+ automatically.
+- **History is independent of workspace state.** Even after a hard kill
+ (SIGKILL/OOM) the session *history* is untouched — every previous
+ session is still discoverable and resumable from the Sessions panel.
+
### Activity bar — Projects · Sessions · Source Control
- **VSCode-style activity bar** on the far left. One click jumps between projects, sessions, and git changes.
@@ -189,8 +246,8 @@ CI logs and SBOMs are attached to every release.
- **Split panes** — horizontal and vertical splits with resizable dividers.
- **Tabbed interface** — multiple terminals per pane, drag tabs between panes.
- **Tab reordering** — drag and drop within and across groups.
+- **Drag a tab onto another pane's edge** to create a new split right there — handy for putting a freshly-resumed AI session next to the one you already had open.
- **Shell selector** — pick from auto-detected system shells (bash, zsh, fish, PowerShell, etc.) when opening a new terminal.
-- **Workspace persistence** — AI session tabs are saved and restored across app restarts.
### Project management
@@ -208,16 +265,6 @@ CI logs and SBOMs are attached to every release.
- **Single-click preview** + **double-click promotes to a permanent diff tab** (VSCode behavior).
- **Live updates** via filesystem watchers — changes appear as you save.
-### Sessions
-
-- **Session discovery** — automatically discovers past sessions from each provider's data directory.
-- **Search & filter** — by name, ID, or summary.
-- **Resume** — click to resume any past session in a new terminal tab.
-- **Close active sessions** — stop running AI sessions from the sidebar; closing a tab fully terminates the underlying process.
-- **Delete sessions** — remove session data from disk.
-- **Time and workspace grouping** — group by recency or by workspace.
-- **Prompt history viewer** — browse and search the prompts you've sent in any past session.
-
### Attention inbox
- **Notification bell** — aggregated inbox surfaces sessions that need you, with an unread badge in the title bar.
@@ -262,7 +309,7 @@ There are great tools in adjacent niches. DPlex isn't trying to replace any of t
| **Wave Terminal** | AI-focused terminal | Adjacent vision; broader scope, more opinionated UI. DPlex is narrower and Electron-portable today. |
| **Zed / Cursor** | AI-native editors | They embed the AI in the editor; DPlex orchestrates the AI you already use from the terminal. |
-If your goal is "I want to run a Claude session in repo A, a Copilot session in repo B, and a regular shell in repo C, all visible at once, and yesterday's sessions findable tomorrow" — that's DPlex.
+If your goal is "I want to start a Claude session in repo A today, a Copilot session in repo B tomorrow, find yesterday's sessions whenever I need them, resume any of them in one click, and reopen the app next week with every tab right where I left it" — that's DPlex.
## FAQ / Troubleshooting
diff --git a/docs/architecture.md b/docs/architecture.md
index 89d9c59..558f733 100644
--- a/docs/architecture.md
+++ b/docs/architecture.md
@@ -92,15 +92,25 @@ A few notable consequences:
## Workspace persistence
-AI session tabs are serialized to `sessions.json` in the Electron
-`userData` directory:
-
-- On quit, `saveWorkspaceSync` ensures a synchronous save so a SIGTERM
+Auto-restoring AI session tabs across app restarts is one of DPlex's
+flagship user-facing guarantees. The implementation:
+
+- AI session tabs are serialized to `sessions.json` in the Electron
+ `userData` directory. The recursive split layout, tab order within
+ each pane, the active group, and the active tab id are all part of
+ this snapshot.
+- Saves happen on every natural lifecycle event (tab open/close,
+ resume, split, group activation, app blur). On quit,
+ `saveWorkspaceSync` performs a synchronous write so a SIGTERM
doesn't lose state.
-- On restore, session tabs are recreated with their original command
- and CWD; session IDs are re-resolved from PID after PTY creation
+- On restore, each tab is recreated with its original resume command
+ and CWD; session IDs are then re-resolved from the new PTY's PID
with retry logic (some AI tools take a beat to write their lock
file).
+- Session *history* is independent of workspace state — past sessions
+ are discoverable from the providers' data directories regardless of
+ what the workspace snapshot says, so even a hard kill never loses
+ history.
## Provider system
diff --git a/docs/assets/demo.gif b/docs/assets/demo.gif
index e88e737..23fef0f 100644
Binary files a/docs/assets/demo.gif and b/docs/assets/demo.gif differ
diff --git a/package-lock.json b/package-lock.json
index fdeabf3..41fa3d7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "dplex",
- "version": "0.10.0",
+ "version": "0.11.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "dplex",
- "version": "0.10.0",
+ "version": "0.11.1",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
diff --git a/package.json b/package.json
index 46ee26d..221c178 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "dplex",
- "version": "0.11.0",
+ "version": "0.11.1",
"description": "A terminal multiplexer built for AI-assisted development. Manage multiple AI CLI sessions (Copilot, Claude, and more) alongside regular terminals in one window.",
"main": "./out/main/index.js",
"author": {
diff --git a/scripts/demo-gif.ts b/scripts/demo-gif.ts
index fc206be..ab9b9e9 100644
--- a/scripts/demo-gif.ts
+++ b/scripts/demo-gif.ts
@@ -5,7 +5,9 @@
* 1. Watching a live AI session
* 2. Switching to Source Control via the activity bar
* 3. Picking a different project from the dropdown
- * 4. Splitting the editor and typing into two terminals concurrently
+ * 4. Opening the Sessions panel, resuming a past session in one click
+ * 5. Typing a follow-up prompt into the resumed session and watching
+ * Copilot respond — proof the resumed session is live
*
* Includes an injected SVG "cursor" that smoothly travels between
* targets so the GIF reads as a guided tour rather than random clicks.
@@ -472,37 +474,94 @@ async function main(): Promise {
await sleep(1200)
await captureFrames(window, 18, 'g-api-changes')
- // ── 5. Back to Projects ───────────────────────────────────────────────
- const projBox = await window.getByTestId('activity-bar-projects').boundingBox()
- if (projBox) {
- const tx = projBox.x + projBox.width / 2
- const ty = projBox.y + projBox.height / 2
+ // ── 5. Open the Sessions panel ────────────────────────────────────────
+ // Tells the user "this is where every past AI session lives, even
+ // ones from yesterday." We move the cursor to the activity-bar
+ // Sessions icon and click; the SessionList already has fakeSessions
+ // seeded into it, so the panel populates immediately.
+ const sessionsBox = await window.getByTestId('activity-bar-sessions').boundingBox()
+ if (sessionsBox) {
+ const tx = sessionsBox.x + sessionsBox.width / 2
+ const ty = sessionsBox.y + sessionsBox.height / 2
await moveCursorTo(window, tx, ty, 0)
- await captureFrames(window, 5, 'h-cursor-to-projects')
+ await captureFrames(window, 5, 'h-cursor-to-sessions')
+ await clickRipple(window, tx, ty)
+ await window.getByTestId('activity-bar-sessions').click()
+ }
+ await captureFrames(window, 14, 'i-sessions-panel')
+
+ // ── 6. Hover a past session and "click" to resume ─────────────────────
+ // The fake providers don't ship real resume commands, so a bare click
+ // wouldn't open a tab. We move the cursor to the row (with ripple) for
+ // narrative, then programmatically create the resumed tab via
+ // terminalStore + paint AI-session content into it. This faithfully
+ // mirrors what handleResume does in production.
+ const RESUMED_SUMMARY = 'Wire OAuth flow with PKCE and refresh-token rotation'
+ const sessionRow = window.locator(`text=${RESUMED_SUMMARY}`).first()
+ const rowBox = await sessionRow.boundingBox().catch(() => null)
+ if (rowBox) {
+ const tx = rowBox.x + rowBox.width / 2
+ const ty = rowBox.y + rowBox.height / 2
+ await moveCursorTo(window, tx, ty, 0)
+ await captureFrames(window, 5, 'j-cursor-to-session-row')
await clickRipple(window, tx, ty)
- await window.getByTestId('activity-bar-projects').click()
}
- await captureFrames(window, 8, 'i-projects-back')
- // ── 6. Vertical split — show two terminals side-by-side ───────────────
- await window.evaluate(() => {
+ const resumedTabId = (await window.evaluate((title) => {
// @ts-expect-error injected
const ts = window.__dplex.terminalStore
const id = ts.getState().activeGroupId
- if (id) ts.getState().splitGroup(id, 'vertical')
- })
+ if (!id) return null
+ return ts.getState().createTerminal(id, title, undefined, undefined, undefined, 'copilot-cli')
+ }, `↻ ${RESUMED_SUMMARY}`)) as string | null
await sleep(450)
- await captureFrames(window, 12, 'j-after-split')
- // ── 7. Type a command into the new (right) terminal ───────────────────
+ // Paint a "session resumed" banner into the new tab so viewers
+ // immediately see this is a different session than the one on the left.
+ if (resumedTabId) {
+ await window.evaluate((tabId) => {
+ // @ts-expect-error injected
+ const entry = window.__dplex.terminalRegistry.getTerminalEntry(tabId)
+ if (!entry?.term) return
+ const ESC = '\x1b'
+ const RESET = `${ESC}[0m`
+ const DIM = `${ESC}[2m`
+ const BOLD = `${ESC}[1m`
+ const CYAN = `${ESC}[36m`
+ const GREEN = `${ESC}[32m`
+ const MAGENTA = `${ESC}[35m`
+ entry.term.write(
+ [
+ `${ESC}[3J${ESC}[2J${ESC}[H`,
+ `${DIM}~/code/api-server ${CYAN}main${RESET}`,
+ `${DIM}$${RESET} copilot --resume=4f1e9c`,
+ ``,
+ `${BOLD}${MAGENTA}● ${BOLD}Wire OAuth flow with PKCE${RESET}`,
+ `${DIM} Resumed · 17 messages · 4 tool calls${RESET}`,
+ ``,
+ `${GREEN}${BOLD}● Copilot${RESET}`,
+ ` Session restored. Where were we?`,
+ ``,
+ `${DIM} Last edit: src/handlers/auth.ts (+34 −12)${RESET}`,
+ `${DIM} Pending: rotate refresh tokens on /token endpoint${RESET}`,
+ ``
+ ].join('\r\n')
+ )
+ }, resumedTabId)
+ }
+ await captureFrames(window, 12, 'k-resumed-tab')
+
+ // ── 7. Talk with the resumed session — type a prompt + stream reply ───
+ // Demonstrates the resumed session is alive and interactive, not a
+ // static screenshot. We type into the now-active resumed tab and
+ // stream a short Copilot response.
await typeIntoActiveTerminal(
window,
- 'copilot -p "audit the auth handler for token leaks"\r\n',
- 'k-typing',
- 50
+ 'rotate the refresh token on /token and add a unit test\r\n',
+ 'm-typing',
+ 45
)
- await sleep(120)
- // Stream a fake response.
+ await sleep(140)
await window.evaluate(() => {
// @ts-expect-error injected
const groups = window.__dplex.terminalStore.getState().groups
@@ -518,23 +577,26 @@ async function main(): Promise {
const DIM = `${ESC}[2m`
const BOLD = `${ESC}[1m`
const GREEN = `${ESC}[32m`
- const MAGENTA = `${ESC}[35m`
const YELLOW = `${ESC}[33m`
entry.term.write(
[
- ``,
- `${BOLD}${MAGENTA}● ${BOLD}Audit auth handler for token leaks${RESET}`,
``,
`${GREEN}${BOLD}● Copilot${RESET}`,
- ` Reading the auth handler...`,
+ ` On it — adding rotation + a unit test.`,
+ ``,
+ ` ${YELLOW}▸${RESET} ${DIM}edit${RESET} src/handlers/refresh.ts`,
+ ` ${GREEN}✓${RESET} ${DIM}+22 −4${RESET}`,
+ ``,
+ ` ${YELLOW}▸${RESET} ${DIM}create${RESET} src/handlers/refresh.test.ts`,
+ ` ${GREEN}✓${RESET} ${DIM}38 lines${RESET}`,
``,
- ` ${YELLOW}▸${RESET} ${DIM}readFile${RESET} src/handlers/auth.ts`,
- ` ${GREEN}✓${RESET} ${DIM}204 lines${RESET}`,
+ ` ${YELLOW}▸${RESET} ${DIM}run${RESET} npm test -- refresh`,
+ ` ${GREEN}✓${RESET} ${DIM}5 passed${RESET}`,
``
].join('\r\n')
)
})
- await captureFrames(window, 14, 'l-response')
+ await captureFrames(window, 18, 'n-chat-response')
// ── 8. End frame — let it breathe ─────────────────────────────────────
await captureFrames(window, 10, 'z-end')
diff --git a/site/index.html b/site/index.html
index fa985a8..0b1b290 100644
--- a/site/index.html
+++ b/site/index.html
@@ -3,10 +3,10 @@
-DPlex — Terminal multiplexer for AI-assisted development
-
-
-
+DPlex — One window for every AI coding session you run
+
+
+
@@ -357,7 +357,7 @@
One window for every AI coding session you run.
- DPlex is a desktop terminal multiplexer that manages your Copilot CLI, Claude Code, and regular shells across projects — with session discovery, persistence, and worktrees built in.
+ DPlex discovers every Copilot CLI and Claude Code session you've ever started, lets you resume any of them in one click, and auto-restores every session tab the next time you open the app — splits, order, and resume command preserved.
macOS · Windows · Linux · No telemetry · Built-in Copilot CLI + Claude Code support
-
+
-
Built for developers running many AI sessions at once.
-
Every feature targets the same problem: keeping a dozen AI sessions across many projects under control without losing context.
+
Built around AI session management.
+
DPlex's headline capability is full lifecycle control over your AI coding sessions — discover them, resume them, close them, delete them, and never lose your place across restarts.
-
+
-
Multi-provider
-
Copilot CLI and Claude Code work out of the box. Add a provider with one TypeScript interface — pluggable, open architecture.
+
Discover every past session
+
Auto-reads each provider's data directory and lists every Copilot CLI / Claude Code session you've ever started — searchable by name, ID, summary, or workspace.
-
+
+
+
Resume in one click
+
Click any past session and it opens in a new tab with the right resume command and original CWD pre-filled. No copy-pasting session IDs.
+
+
+
+
+
+
Auto-restore on restart
+
Quit the app, reopen it tomorrow — every AI session tab is back exactly where you left it. Splits, tab order, resume command, and CWD all preserved.
+
+
+
+
+
+
Close & delete from the sidebar
+
Stop a running AI session without finding its terminal — closing the tab terminates the process. Right-click a past session to delete its data from disk.
+
+
+
+
-
Session discovery
-
Auto-discovers active and past sessions across providers. No copy-pasting session IDs, no manual tracking.
+
Multi-provider
+
Copilot CLI and Claude Code work out of the box. Add a provider with one TypeScript interface — pluggable, open architecture.