All notable changes to AgentDeck will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Full UI redesign with a new top tab bar, 8 first-class tabs, three new dark palettes, and a hardened IPC + state layer. Every engine (PTY, workflow scheduler, cost tracker, git worktree manager, 7-agent registry) is preserved untouched — ship state verified by a 3-round multi-agent pre-merge review.
Screens and navigation
TopTabBarprimary nav — Home · Sessions · Projects · Agents · Workflows · History · Alerts · Settings.Alt+1..Alt+8jump shortcuts. Alerts tab carries a live count from the notifications slice.SessionsScreen,ProjectsScreen,AgentsScreen,WorkflowsScreen,HistoryScreen,AlertsScreen,AppSettingsScreen— one screen per tab with consistentScreenShell+FilterChipchrome.NewSessionScreencomposer — agent picker, prompt, branch mode (existing / new / worktree), cost cap, run mode, approval map. The prompt is piped into the agent's stdin 2 s after PTY spawn;existing/newmode prepend the correctgit checkoutbefore startup commands.DiffReviewScreen— per-session Keep / Discard / Request-changes flow; comment text is sent to the agent's stdin with ack-based success/error toasts.SessionHero— step rail + bottom metrics strip wrapping the session view. Metrics show tokens, elapsed (derived fromsession.startedAt), writes, cost (with optional/ CAP $X.XXmarker and ⚠ once crossed).Mascot(Pixel the cat) — optional pose that reflects running-session count, errors, local hour. On by default;localStorage['mascot.enabled'] === '0'disables.
Home primitives
ScopeVizconcentric-ring session scope with per-agent blips.Panelchrome (corner ticks) +KpiTilestat tile.AgentChipB1,ProjectCardB1,CostReadoutB1,SessionTimelineB1Home tiles.
Right Panel
- Four new inspector tabs alongside the legacy three: Diff, Files, Cost, Config (7 total).
Titlebar brand row
- Search pill that opens the Command Palette, LIVE dot bound to real session state, clock, READY / ATTENTION / WSL-DOWN status word, WSL distro + app version chip.
Themes and typography
- Three palettes:
tungsten(default, sodium amber on warm charcoal),phosphor(retro CRT green on ink),dusk(violet + coral on plum-black). Space Grotesk display font via@fontsource/space-grotesk. - Per-agent accent tokens (
--agent-claude,--agent-codex, …) for consistent agent-color treatment across themes. - One-shot migration of retired v5.x palette names (amber / cyan / violet / ice → dusk or phosphor; parchment / fog / lavender / stone → tungsten) with an info toast on first boot. Idempotent via
appPrefs.themeMigrated.
IPC and data model
pty:writeconverted from fire-and-forgetipcMain.ontoipcMain.handlereturning{ ok: boolean; error?: string }.PtyManagergainshasSession(id)so the handler explicitly reports unknown-session writes instead of silently dropping.src/renderer/utils/pty-write.tsexportssafeWrite— chains.then+.catcharound every fire-and-forget call site so a non-ok ack logs a warning and an IPC rejection can't escape asunhandledRejection.Sessionextends a newSessionLaunchConfig:initialPrompt,branchMode,initialBranch,costCap,runMode,approve.addSessionaccepts the full config.- UI slice:
tabParams+setTab(view, params?).setTabdoes NOT push toviewStack— the stack is reserved for sub-view modals. - Notifications slice:
silencedToastIdssplit fromnotifications. Toast auto-silences after 5 s; Alerts tab still shows the record until explicit dismiss. theme:popMigrationIPC channel returns the legacy→successor pair exactly once.appPrefs.themeMigratedflag added toAppPrefs.
Tests
- 20 new renderer tests pinning load-bearing contracts:
setTabnav primitive,silenceToastsplit,ScopeVizselector shape (guards against regression to the pre-8e401f7form that crashed with React #185),agent-uihelper fallbacks. Total: 781 passing (was 761).
- Home screen reorganized around a hero row (scope viz + KPI strip + session timeline), followed by live sessions, agents, projects + cost.
- Sidebar becomes contextual — surfaces only inside Sessions and Projects tabs.
ProjectCardB1reads the real branch fromgitStatuses[project.id]?.branchinstead of a literalmainstring.CostReadoutB1per-agent breakdown no longer double-counts today (history contains today;perAgentTodaywas being added on top). Both memos share onetodayIsoderived fromuseMidnightso they can't disagree across midnight.NotificationToastauto-silence effect simplified to close over a local timer constant so bursts within the 5 s window can no longer cancel without rescheduling.DiffReviewScreenworktree-inspect uses a cancelled flag; switching active session mid-inspect no longer commits stale summary / loading state.MascotrAF throttled to ~20 Hz (was 60 Hz);role="button"gainstabIndex={0}+ Enter/Space keyboard activation.SessionsScreenmigrated fromrole="table"/"row"/"cell"/"columnheader"torole="list"with<button>rows — a button cannot legally contain cells.AgentsScreen.handleUpdatewrites the new version intoagentVersionson success — the display refreshes and the Update button disables on its own instead of waiting for an explicit re-check.- Launch button in
NewSessionScreenis disabled when the prompt trims to empty. XTERM_THEME_OVERRIDESextended with tungsten / phosphor / dusk.ViewTypeextended with redesign tab ids:sessions,projects,project-detail,agents,workflows,history,alerts,app-settings,new-session,diff.
- Theme data-loss on upgrade — the IPC allowlist previously narrowed silently and coerced every legacy name to
''. DiffReviewScreen"Request changes" andContextTabtemplate click both showed success toasts regardless of whether the bytes reached the agent — now branch on the new ack.- 7+ keystroke / paste / file-drop / onData sites routed through
safeWriteso an IPC transport rejection can't escape asunhandledRejection. safeWrite's own fallback logger chains.catch(() => {})on its innerlog.sendcalls so a logger-IPC failure can't itself produce the very failure modesafeWriteexists to prevent.App.tsxtheme.popMigration().then(...)gained a terminal.catch— a rejection would previously have skipped the migration toast silently.ipc-window.theme:setlogs a warn when an unknown theme id is coerced (was silent).AppSettingsScreen.handleResetZoom,DiffTab,ContextTabpreviously swallowed IPC errors silently; each now logs throughagentDeck.log.sendor raises a notification.
- All 7 agents in
src/shared/agents.ts— registry, icons, version + update commands,SAFE_FLAGS_RE,KNOWN_AGENT_IDS,AGENT_BINARY_MAP,AGENT_DISPLAY. pty-manager.ts,workflow-engine.ts,edge-scheduler.ts,cost-tracker.ts,cost-history.ts,worktree-manager.ts,git-port.ts,project-store.ts,variable-substitution.ts,workflow-run-store.ts,log-adapters.ts,agent-updater.ts— diff-empty vsmainapart fromhasSessionadded toPtyManagerandthemeMigratedadded toAppPrefs.- Full xterm stack with WebGL + search + unicode11 addons.
- Per-session git worktree isolation and Keep / Discard review flow.
- Every Zustand slice shape (sessions, ui, projects, workflows, templates, notifications, home) plus existing hooks.
- Typecheck + ESLint
--max-warnings=0clean on every commit; 781 tests passing.
- The 8 legacy themes (
amber,cyan,violet,ice,parchment,fog,lavender,stone) are no longer selectable. Users on those palettes are migrated to the nearest successor on first boot.
- Home Screen Command Center — 13 new components (DailyDigest, QuickActions, LiveSessionCard, LiveSessionGrid, ProjectCardV2, SuggestionsPanel, ReviewQueue, RecentWorkflows, SessionTimeline, CostDashboard, AgentStrip, CollapsibleSection, GitStatusRow)
- 8 hooks (useGitStatus, useSuggestions, useSessionTimeline, useDailyDigest, useCostHistory, useRecentWorkflowRuns, useElapsedTime, useMidnight)
- 3 backend modules (git-status, review-tracker, cost-history) with 6 IPC channels
- Home Zustand slice for git statuses, review queue, cost history, collapse state
- 12 theme-adaptive surface tokens (--surface-tint, --surface-border, --surface-hover, --overlay-scrim, --dialog-shadow, --context-shadow, etc.)
--edge-highlighttoken for light/dark theme edge gradientssrc/shared/constants.ts— 12 named constants (MAX_PANE_COUNT, ACTIVITY_FEED_CAP, etc.)useMidnighthook — shared midnight rollover (was duplicated in 3 hooks)- BrowserWindow backgroundColor reads persisted theme at startup
- Editorial design system replaces Fusion FX across all views — system sans-serif font, edge-lit surfaces, no decorative FX
- Titlebar rewritten: 42px, flat tabs, gradient active state, pulsing status dots
- Command Palette: PanelBox/HexGrid removed, Editorial surface styling
- All dialogs (About, Shortcuts, Confirm) use
var(--bg1)+var(--border)(theme-adaptive) - SplitView: PanelBox removed, clean border focus state, divider grip removed
- Right Panel: PanelBox removed, system font tabs,
aria-labelledbyon tabpanel - StatusBar: HexDot replaced with CSS dot, system font for buttons
- Workflow Editor: system font for UI buttons/tabs/selects
- NotificationToast: system font
- Sidebar:
var(--bg0)background (was hardcoded #0a0b0e), system font for UI buttons - StackBadgeSelector: CSS data-badge approach replaces inline hex colors
removeSessionpreserves sessions asexitedinstead of deleting — cost/timeline/digest survive tab close- Activity parser broadened: Claude Code tool indicators (⏺●◆▶), file-path fallback, \r overwrite semantics
- Session Timeline uses per-session time span (not full day) with min 0.5% segment width
- Cost tracking refreshes every 30s, agent resolved from project config
- Recent Workflows re-fetches when workflow execution statuses change
getSessionForProjectfilters out exited sessionscloseWorkflowfallback only considers live sessions- ~73 hardcoded rgba values replaced with surface tokens across 23 CSS files
- God-class decomposition: Sidebar 703→183 lines (ProjectSection + WorkflowSection), CommandPalette 779→500 lines (paletteItems + themeUtils), TerminalPane context menu extracted
- HexGrid, EnergyVein, AmbientGlow, HexDot, CornerAccent, PanelBox components + CSS + tests (16 files)
- All Fusion Design System tokens from tokens.css (all 8 themes)
- Dead keyframes from global.css (hex-pulse, logo-breathe, vein-drift, edge-glow-pulse, energy-underline-in)
useAmbientStatehook (zero call sites after Fusion removal)- Dead
active-sessionCSS class andsessionStatusesselector from SplitView
- Deep review Round 1: 17 issues (1 CRITICAL, 8 HIGH, 8 MEDIUM) — onActivity subscription, rAF cleanup, cancelled guards, starting status CSS, dialog backgrounds, WorkflowNode flash, sidebar labels, a11y
- Deep review Round 2: 5 issues (2 HIGH, 3 MEDIUM) — ::after positioning, reduced-motion selectors, opacity flash, dead code
- Codex review: 6 issues (2 HIGH, 4 MEDIUM) — dead session reuse, workflow routing, error state, hardcoded colors, non-semantic click targets, bare \r ghost activity
- Home screen data no longer resets on session tab close
- Session Timeline shows visible segments (was filtering out sub-0.1% widths)
- Tab close properly removes tab while preserving session data
- Cost tracking shows correct agent name (was "unknown")
- Light themes render correctly (was white-on-white invisible borders/hover states)
- Error pattern in activity parser is case-sensitive (was matching "No recent activity" as error)
- Dialog overlays use
var(--overlay-scrim)token (lighter on light themes) - Context menu shadows use
var(--context-shadow)token
- Cost tracking silently broken for all sessions —
$HOMEinside single quotes prevented bash expansion; discovery always timed out (R4-01) - Workflow deadlock reported as false success — engine now detects unreachable nodes after upstream failure and reports error (R2-01)
- Startup commands joined with
&&silently prevented agent launch on any setup failure — changed to;(BUG-1) - Implicit PTY exit force-discarded isolated worktrees — now uses
keepto prevent data loss (CDX-4) - Project deletion with active sessions orphaned worktrees — now kills sessions first (BUG-4)
- Loop counter reset affected sibling loop edges from the same condition node (BUG-5/CDX-5)
- Agent updater
repairNpmBinLinkhardcoded.jssuffix — now derives entry from package.json (BUG-2) - Post-kill PTY data emission on ptyBus — added sessions.has guard (BUG-6)
restartSessionleakedsessionUsageentries in Zustand store (LEAK-13)- Copy flash setTimeout not cancelled on terminal unmount (LEAK-10)
- Timer TOCTOU race in CostTracker on unbind during async callback (R2-02)
- Orphan worktree pruning leaked registry entries for manually-deleted directories (R2-25)
- SplitView pulse timers not reset on pane layout change (BUG-8)
- Workflow rename non-atomic — now reverts optimistic update on IPC failure (BUG-9)
- IPC validation: SAFE_ID_RE applied consistently across all 53 IPC channels (was duplicated in 4 files, 12 handlers missing checks)
- Shell injection:
shellQuotefor agent updater node -e script (SEC-31) andisBinaryOnPath(R2-03) - Path traversal: backslash normalization in
projects:readFileguard (SEC-34) - Renderer log data bounded to 4KB to prevent log exhaustion (SEC-33)
agentFlagstype/length validation inpty:spawn(R2-21)cost:bindvalidatesspawnAtas finite number (R2-23)- Missing
--separator in wsl.exe calls fixed in cost-tracker and index.ts (R2-20, R5-02)
- Titlebar uses narrow serialized session selector (prevents re-renders at PTY data rate)
listWorkflowsreads files concurrently via Promise.all (was sequential)pruneRunssorts by filename timestamp instead of calling stat() on each file- Worktree registry I/O converted from synchronous to async (unblocks main process)
- Edge-scheduler
isDone()is O(1) via activeCount tracking (was O(n) scan) - HomeScreen uses Map for O(1) agent metadata lookup (was O(n) find per chip)
- Cached accent RGB in themeObserver to avoid getComputedStyle per terminal on theme change
- Static AmbientGlow position arrays hoisted to module scope (prevents new refs on render)
- Shared
validation.tsmodule — single source of truth for SAFE_ID_RE paneSessionscapped at 3 entries to prevent unbounded growth- Silent
.catch(() => {})oncost.unbindreplaced with debug logging .some()test assertions replaced withtoContainEqualfor actionable failures- Vite HMR cleanup for version info IPC listener (dev-only leak fix)
- Cache invalidation no longer deletes in-flight scan promises (prevents stale overwrite race)
- Empty workflows rejected with error event instead of persisting 0ms run records
- 611 tests (all passing), 0 lint warnings
- Cost/token tracking for Claude Code and Codex CLI sessions (PR #20)
- Log adapters parse JSONL session logs with per-model pricing maps
- CostTracker discovers log files via WSL, tails on 3s poll, pushes usage over IPC
- Cost badge in PaneTopbar: Zap icon + USD cost + total processed tokens (accent-colored)
- Tooltip shows per-type breakdown (input, output, cache read, cache write)
- Claude pricing: opus/sonnet/haiku tiers with cache write 1.25x and cache read 0.1x rates
- Codex pricing: per-model map (gpt-4o, o3, o4-mini, gpt-5.3/5.4, codex-mini)
- Git worktree isolation for per-session branches (PR #19)
- GitPort abstraction + WslGitPort implementation
- WorktreeManager: acquire/inspect/discard/keep/releasePrimary/pruneOrphans
- Branch badge in PaneTopbar, worktree indicator in StatusBar
- Close flow with inspect + ConfirmDialog (Keep/Discard/Cancel)
- Claude adapter: skip streaming partials (stop_reason: null) to prevent double-counting
- Claude adapter: compute cost from model pricing (JSONL has no costUSD field)
- Codex adapter: normalize input_tokens by subtracting cached_input_tokens (was showing inflated 12k for simple prompts)
- Codex adapter: parse real JSONL format (payload.info.total_token_usage, not payload directly)
- Cost badge: show total processed tokens consistent with cost (no mismatch between $0.18 and "87 tokens")
- Windows paths converted to WSL format before log file discovery
- Session agent override shown in PaneTopbar (was showing project default)
- 614 tests (up from 511)
- Keyboard tab cycling: Ctrl+Tab / Ctrl+Shift+Tab
- ConfirmDialog component for destructive actions (project/workflow deletion)
- IPC error-to-notification middleware with user-friendly messages (12 new tests)
- Workflow state hydration — renderer recovers running workflow status after reload
- WSL health status banner — red warning when WSL is not detected
- PTY spawn failure now shows error message in terminal instead of blank screen
- Suspense spinner fallback for lazy-loaded screens
- Agent install guidance tooltips for missing agents
- Empty sidebar section hints (pinned, templates, workflows)
- Sidebar path tooltips on hover
- Workflow load failure error state
- Resource limits: max 20 PTY sessions, max 3 concurrent workflow runs
- Default 30-minute absolute timeout on agent nodes
- safeStorage unavailability warning toast
- Process cleanup handlers (uncaughtException, unhandledRejection)
- CSP enforced via onHeadersReceived header (in addition to meta tag)
- Smart Settings command palette action (resolves active project, disabled state)
- Accessibility: prefers-reduced-motion support (targeted, preserves ambient effects)
- Accessibility: keyboard support on all interactive div elements (role, tabIndex, onKeyDown)
- Accessibility: ARIA landmark/widget roles across sidebar, tab bars, status bar, toasts
- Accessibility: visible focus indicators (:focus-visible)
- Accessibility: WCAG AA color contrast on all 4 light themes (--text3 darkened)
- Security: shellQuote for project paths in pty-manager (was double-quote interpolation)
- Security: sessionId validation in pty:spawn handler
- Security: block all navigation in will-navigate (was only blocking file://)
- Reliability: async WSL check (was blocking main process up to 10s)
- Reliability: electron-store write lock prevents concurrent save races
- Reliability: workflowEngine.stopAll() on renderer crash and window close
- Reliability: WSL distro fallback warning log
- UX: tab bar horizontal scroll on overflow
- UX: quick-open bar opens command palette instead of wizard
- UX: replaced window.confirm with custom ConfirmDialog
- 511 tests (up from 499)
- License switched from MIT to Elastic License 2.0
- Electron 40 → 41, lucide-react 0.577 → 1.7, jsdom 28 → 29, addon-fit 0.10 → 0.11
- Bumped lint-staged, @types/node, typescript-eslint, zustand, @xyflow/react, @vitest/coverage-v8
- GitHub Actions CI workflow (lint, typecheck, format, test)
- Dependabot for weekly npm and GitHub Actions updates
- GitHub issue templates (bug report, feature request)
- Community files: CHANGELOG, CODE_OF_CONDUCT, CONTRIBUTING, SECURITY
- Branch protection on main (require PR + CI pass)
- Private vulnerability reporting enabled
- brace-expansion moderate vulnerability (npm audit fix)
- SECURITY.md: replaced unreachable noreply email with GitHub private vulnerability reporting
- Sidebar CSS: templates section crushed when all sections expanded
- Codex skill discovery — scans projects for SKILL.md files with YAML frontmatter, TTL-cached
- Project metadata refresh on IPC
- Agent updater safety: binary verification, npm bin symlink auto-repair, rollback on failure
- Stale package names in agent updater
- UX audit: 26/27 issues resolved (welcome card, terminal context menu, a11y, focus traps, toasts, skeleton loaders, validation, breadcrumbs, node duplication, empty states)
- 499 tests (up from 436)
- Conditional branching —
conditionnode type with exit code and output match modes - Loop/retry — loop-back edges with max iterations, per-node retry with configurable delay
- Workflow variables —
{{VAR}}substitution with typed pre-run dialog - Import/export —
.agentdeck-workflow.jsonbundles with role remapping - Workflow clone — deep copy with new UUID
- Execution history — per-run summaries with node timing, error tails, History tab
- 5 new seed workflows (12 total): Test Coverage, Dependency Update, Documentation Pass, Performance Audit, Release Prep
- Engine rewrite: tier-based scheduler replaced with edge-activation scheduler (ready queue, pending edge counts, skip propagation, loop subgraph reset)
- God-class refactor:
appStore.tssplit into 6 Zustand slices; workflow engine split into 3 files; workflow editor split into 3 files - ESLint tightened:
eqeqeq,no-console,no-eval,react-hooks/exhaustive-depspromoted to error,--max-warnings=0 - TypeScript: added
noImplicitOverride - 436 tests (up from 348)
- 5 npm dependency vulnerabilities
- Codex
-Cflag and--skip-git-repo-checksupport - WF-1 through WF-15 (signal exit codes, truncated output buffer, scheduler double-complete, loop subgraph reset bug)
- Test coverage expansion: 293 to 348 tests across 32 files
- IPC split into 6 modules
terminal-utils.tsextraction (pure functions)- Portability fixes P1-P6
- TERM-12 through TERM-20 (post-refactor terminal issues)
- Terminal scroll and formatting fixes (5 tasks)
- TERM-1 through TERM-11 across 3 review rounds (4-way review, 11 issues found, 9 fixed)
- Architecture splits:
workflow-seeds.ts,store-seeds.ts,agent-detector.ts,workflow-utils.ts,ThemeSubmenu.tsx,AgentsSubmenu.tsx
- 59 code review fixes across 2 rounds (security, memory, performance, bugs, error handling)
- 7 seed workflows (Codex-focused)
- 293 tests
- Fusion UI redesign
- Migrated all icons to Lucide React (tree-shakeable SVGs)
- Full code review: 38 fixes
- Hardened security:
sandbox: trueon BrowserWindow
- 286 tests
- Workflow engine with visual node-graph editor
- Polymorphic tabs (sessions + workflows)
- Command palette with fuzzy search
- Terminal performance optimizations
- WSL resilience (retry, cold-boot handling)
- Bare terminal sessions
- 250 tests
- 8 themes (4 dark + 4 light) with view transitions
- 16 seed prompt templates
- Initial release
- Multi-agent terminal management (7 agents)
- Project management with WSL path support
- Split terminal views (1/2/3 panes)
- Terminal caching and state preservation
- Prompt template system
- electron-store persistence