All notable changes to Agent Deck will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- Expose custom tools in the Settings panel default-tool picker so configured tools can be selected without editing
config.tomlby hand.
- Add
preview.show_notessupport so the notes section can be hidden from the preview pane while keeping the main session view intact. - Add Gemini hook management commands and hook-based Gemini session/status sync, including install, uninstall, and status flows.
- Add remote-session lifecycle actions in the TUI so remote sessions can be restarted, closed, or deleted directly from the session list.
- Add richer Slack bridge context so forwarded messages include stable sender/channel enrichment.
- Preserve hook-derived session identity across empty hook payloads by persisting a read-time session-id anchor fallback.
- Improve Telegram bot mention stripping and username handling so bridge messages route more reliably in group chats.
- Avoid repeated regexp compilation in hot paths by hoisting
regexp.MustCompilecalls to package-level variables.
- Restore instant preview rendering from cached content during session navigation and immediately after returning from an attached session, removing placeholder delays introduced in
0.24.0.
- Add
internal/sendpackage consolidating all send verification functions (prompt detection, composer parsing, unsent-prompt checks) into a single location. - Add Codex readiness detection:
waitForAgentReadyandsendMessageWhenReadynow gate oncodex>prompt before delivering messages to Codex sessions. - Add session death detection in
--waitmode:waitForCompletiondetects 5 consecutive status errors and returns exit code 1 instead of hanging indefinitely. - Add heartbeat migration function (
MigrateConductorHeartbeatScripts) that auto-refreshes installed scripts to the latest template. - Add exit 137 (SIGKILL) investigation report documenting root cause as Claude Code limitation with reproduction steps and mitigation strategies.
- Add exit 137 mitigation guidance to shared conductor CLAUDE.md and GSD conductor SKILL.md.
- Promote 27 validated conductor learnings to shared docs: 10 universal orchestration patterns to conductor CLAUDE.md, 6 GSD-specific learnings to gsd-conductor SKILL.md, 11 operational patterns to agent-deck-workflow SKILL.md.
- Harden Enter retry loop: retry every iteration for first 5 attempts (previously every 3rd), increasing ambiguous budget from 2 to 4.
- Scope heartbeat scripts to conductor's own group instead of broadcasting to all sessions in the profile.
- Honor
heartbeat_interval = 0as disabled: skip heartbeat daemon installation during conductor setup. - Add enabled-status guard to heartbeat scripts so they exit silently when conductor is disabled.
- Fix
-cand-gflag co-parsing so both flags work together inagent-deck add. - Improve
--no-parenthelp text to referenceset-parentfor later parent linking.
- Clean up all six conductor LEARNINGS.md files: mark promoted entries, remove retired entries, consolidate duplicates.
- Add status detection integration tests: real tmux status transition cycles, pattern detection, and tool config verification.
- Add conductor pipeline integration tests: send-to-child delivery, cross-session event write-watch, heartbeat round-trips, and chunked send delivery.
- Add edge case integration tests: skills discover-attach verification.
- Complete milestone v1.1 Integration Testing (38 integration tests across 6 phases).
- Handle nested binary paths in release tarballs so self-update works with both flat and directory-wrapped archives.
- Add integration test framework: TmuxHarness (auto-cleanup real tmux sessions), polling helpers (WaitForCondition, WaitForPaneContent, WaitForStatus), and SQLite fixture helpers (NewTestDB, InstanceBuilder).
- Add session lifecycle integration tests (start, stop, fork, restart) using real tmux sessions with automatic cleanup.
- Add session lifecycle unit tests covering start, stop, fork, and attach operations with tmux verification.
- Add status lifecycle tests for sleep/wake detection and SQLite persistence round-trips.
- Add skills runtime tests verifying on-demand skill loading, pool skill discovery, and project skill application.
- Reformat agent-deck and session-share SKILL.md files to official Anthropic skill-creator format with proper frontmatter.
- Add $SKILL_DIR path resolution to session-share skill for plugin cache compatibility.
- Register session-share skill in marketplace.json for independent discoverability.
- Update GSD conductor skill content in pool directory with current lifecycle documentation.
- Propagate forked
AGENTDECK_INSTANCE_IDvalues correctly so Claude hook subprocesses update the child session instead of the parent. - Fully honor
[tmux].inject_status_line = falseby skipping tmux notification/status-line mutations when status injection is disabled. - Add Gemini
--yoloCLI overrides foragent-deck add,agent-deck session start, and TUI session creation. - Clamp final TUI frames to the terminal viewport so navigation cannot spill duplicate footer/help rows into scrollback.
- Add built-in Pi tool support, configurable hotkeys, session notes in the preview pane, and optional follow-CWD-on-attach behavior in the TUI.
- Add OpenClaw gateway integration with sync, status, list, send, and bridge commands for managing OpenClaw agents as agent-deck sessions.
- Add per-window tmux tracking in the session list with direct window navigation and AI tool badges.
- Add remote session creation from the TUI (
n/Non remote groups and remote sessions). - Add remote binary management with automatic install during
agent-deck remote addand the newagent-deck remote updatecommand. - Add configurable
[worktree].branch_prefixfor new worktree sessions. - Add Vimium-style jump mode for session-list navigation.
- Significantly reduce TUI lag during navigation, attach/return flows, preview rendering, and background status refreshes.
- Enable Claude-specific session management features for custom tools that wrap the
claudebinary. - Prevent non-interactive installs from hanging when
tmuxis missing by skipping interactive prompts and failing fast whensudowould block.
- Recover automatically when tmux startup fails due to a stale/unreachable default socket by quarantining the stale socket and retrying session creation once. This prevents
failed to create tmux session ... server exited unexpectedlystartup failures.
- Add Discord bot support to the conductor bridge with setup flow and config support (
[conductor.discord]), including slash commands (/ad-status,/ad-sessions,/ad-restart,/ad-help) and heartbeat alert delivery to Discord.
- Reduce tmux
%output-driven status update frequency for chatty sessions to lower parsing overhead and smooth CPU usage under heavy output.
- Restrict Discord slash commands to the configured Discord channel so conductor control stays channel-scoped.
- Add remote SSH session support with two workflows:
agent-deck add --ssh <user@host> [--remote-path <path>]to launch/manage sessions on remote hosts.agent-deck remote add/list/sessions/attach/renameto manage and interact with remote agent-deck instances.
- Add remote sessions to the TUI under
remotes/<name>, with keyboard attach (Enter) and rename (r) support. - Add JSON session fields
ssh_hostandssh_remote_pathinagent-deck list --jsonoutput.
- Recover repository state after the broken PR #260 merge and re-apply the feature cleanly on
main. - Harden SSH command handling by shell-quoting remote command parts and SSH host/path values.
- Prevent remote name parsing collisions by rejecting
:in remote names. - Preserve full multi-word titles in
agent-deck remote rename. - Stabilize remote session rendering order and snapshot-copy remote data during TUI rebuilds for safer async updates.
- Make Homebrew update installs resilient to stale local tap metadata by running
brew updatebeforebrew upgradeinagent-deck update. - Update Homebrew check/install guidance to show the full install command (
brew update && brew upgrade asheshgoplani/tap/agent-deck) so users can copy-paste a working path directly.
- Make
agent-deck updateHomebrew-aware end-to-end:--checknow shows the correctbrew upgradecommand and interactive install can execute the Homebrew upgrade path directly instead of failing after confirmation. - Harden conductor/daemon binary resolution to prefer the active executable path and robust PATH ordering, avoiding stale
/usr/local/binpicks that could drop parent transition notifications. - Prevent TUI freezes during create/fork worktree flows by moving worktree creation into async command execution instead of blocking the Enter key handler.
- Enforce Claude conversation ID deduplication on storage saves (CLI + TUI paths) so duplicate
claude_session_idownership does not persist, with deterministic older-session retention.
- Add conductor permission-loop troubleshooting guidance (
allow_dangerous_mode/dangerous_mode) in README and troubleshooting docs.
- Add Docker sandbox mode for sessions (TUI + CLI), including per-session containers, hardened container defaults, and sandbox docs/config references.
- Preserve non-sandbox tmux startup behavior while keeping sandbox dead-pane restart support.
- Strengthen
session send --no-wait/ launch no-wait initial-message delivery with retry+verification to reduce dropped prompt submits. - Route transition notifications through explicit parent linkage only (no conductor fallback), and align conductor/README guidance with parent-linked routing.
- Restore OpenCode/Codex status detection for active output by matching both
status_detailsandstatusfields in tmux JSON pane formats. - Eliminate a worktree creation TOCTOU race in
addby creating/checking candidate worktree paths in one flow and retrying with suffixed names when collisions happen. - Avoid false Claude tool detection for shell wrappers by validating shell executables exactly and only classifying wrappers as Claude when
claudeappears as a command token. - Resolve duplicate group-name move failures in the TUI by moving sessions using canonical group paths while preserving user-facing group labels.
- Add soft-select path editing and filterable recent-path suggestions in the New Session dialog, including matching-count hints and focused keyboard help text.
- Add compact notifications mode (
[notifications].minimal = true) with status icon/count summary in tmux status-left, includingstartingsessions in the active count. - Add conductor heartbeat rules externalization via
HEARTBEAT_RULES.md(global default plus per-profile override support in the bridge runtime). - Add proactive conductor context management with
clear_on_compactcontrols (conductor setup --no-clear-on-compactand per-conductor metadata) and synchronousPreCompacthook registration.
- Preserve ANSI color/styling in session preview rendering while keeping status/readiness parsing reliable by normalizing ANSI where plain-text matching is required.
- Restore original tmux
status-leftcorrectly when clearing notifications, including intentionally empty original values. - Guard analytics cache map access across UI and background worker paths to avoid concurrent map read/write races during background status updates.
- Prevent self-update prompts/flows on Homebrew-managed installs.
- Add automatic heartbeat script migration for existing conductors so managed
heartbeat.shfiles are refreshed to the current generated template during conductor migration checks. - Add
--cmdparsing support for tool commands with inline args inadd/launch(for example-c "codex --dangerously-bypass-approvals-and-sandbox"), with automatic wrapper generation when needed.
- Switch generated conductor heartbeat sends to non-blocking
session send --no-wait -q, eliminating recurringagent not ready after 80 secondstimeout churn for busy conductors. - Improve
add/launchCLI help and JSON output to expose resolved command/wrapper details and avoid confusing launch behavior when mixing tool names with extra args. - Fix parent/group friction for conductor-launched sessions by allowing explicit
-g/--groupto override inherited parent group while keeping parent linkage for notifications.
- Expand README and CLI reference guidance for conductor-launched sessions (
--no-parentvs auto-parent), transition notifier behavior, and safe command patterns.
- Add built-in event-driven transition notifications (
notify-daemon) that nudge a parent session first, then fall back to a conductor session when a child transitions fromrunningtowaiting/error/idle. - Add
--no-parentand default auto-parent linking foradd/launchwhen launched from a managed session (AGENT_DECK_SESSION_ID), with conflict protection for--parent+--no-parent. - Add
parent_session_idandparent_project_pathtoagent-deck session show --json. - Add conductor setup/status/teardown integration for the transition notifier daemon so always-on notifications can be installed and managed with conductor commands.
- Reduce SQLite lock contention under concurrent daemon and CLI usage by avoiding unnecessary schema-version writes and retrying transient busy errors during storage migration/open.
- Improve status-driven notification reliability for fast tool completions by combining watcher updates with direct hook-file fallback reads and hook-based terminal transition candidates.
- Add shared and per-conductor
LEARNINGS.mdsupport with setup/migration wiring so conductors can capture reusable orchestration lessons over time.
- Harden
launch -mandsession sendmessage delivery for Claude by using fresh pane captures, robust composer prompt parsing (including wrapped prompts), and stronger Enter retry verification to avoid pasted-but-unsent prompts. - Improve readiness detection for non-Claude tools (including Codex) by treating stable
idle/waitingstates as ready, preventing false startup timeouts when launching with an initial message. - Fix launch/session-start messaging semantics so non-
--no-waitflows correctly report message sent state (message_pending=false).
- Make
agent-deck session send --waitandagent-deck session outputresilient when Claude session IDs are missing/stale by using best-effort response recovery (tmux env refresh, disk sync fallback, and terminal parse fallback). - Improve Claude send verification to catch pasted-but-unsent prompts even after an initial
waitingstate, reducing false positives where a prompt was pasted but never submitted. - Update conductor bridge messaging to use single-call
session send --wait -q --timeout ...flow for Telegram/Slack and heartbeat handling, reducing extra polling steps and improving reliability. - Reject non-directory legacy file skills when attaching project skills, and harden skill materialization to recover from broken symlinks and symlinked target-path edge cases.
- Update conductor templates/docs and launcher helper scripts to prefer one-shot launch/send flows and single-call wait semantics for smoother orchestration.
- Fix terminal style leakage after tmux attach by waiting for PTY output to drain and resetting OSC-8/SGR styles before the TUI redraws.
- Harden
agent-deck session senddelivery by retryingEnteronly when Claude shows a pasted-but-unsent marker ([Pasted text ...]) and avoiding unnecessary retries once status is alreadywaiting/idle.
- Clarify tmux wait-bar shortcut docs: press
Ctrl+b, release, then press1–6to jump to waiting sessions.
- Fix
agent-deck session show --jsonMCP output marshalling by emitting concrete local/global/project values instead of a method reference inmcps.local(#213). - Fix conductor daemon Python resolution by preferring
python3from the active shellPATHbefore fallback absolute paths (#215).
- Fix heartbeat script profile text stamping so generated
heartbeat.shuses the real profile name in message text for non-default profiles (#207, contributed by @CoderNoveau). - Fix conductor bridge message delivery when the conductor session is idle by using non-blocking
session send --no-wait, and apply this in the embedded runtime bridge template with regression coverage (#210, contributed by @sjoeboo).
- Add
manage_mcp_jsonconfig option to disable all.mcp.jsonwrites, plus a LOCAL-scope MCP Manager warning when disabled (#197, contributed by @sjoeboo). - Split conductor guidance into shared mechanism (
CLAUDE.md) and policy (POLICY.md) with per-conductor policy override support (#201).
- Fix conductor setup migration so legacy generated per-conductor
CLAUDE.mdfiles are updated safely for the policy split while preserving custom and symlinked files (#201). - Fix launchd and systemd conductor daemon units to include the installed
agent-deckbinary directory inPATHso bridge/heartbeat jobs can find the CLI (#196, contributed by @sjoeboo). - Support environment variable expansion (
$VAR,${VAR}) in path-based config values and unify path expansion behavior across config consumers (#194, contributed by @tiwillia).
- Remap TUI shortcuts to reduce conflicts:
mopens MCP Manager,sopens Skills Manager (Claude), andMmoves sessions between groups.
- Reduce Codex session watcher CPU usage by rate-limiting expensive on-disk session scans and avoiding redundant tmux environment writes.
- Fix macOS installer crash on default Bash 3.2 by replacing associative arrays in
install.shwith Bash 3.2 compatible helper functions (#192, contributed by @slkiser).
- Add pool-focused type-to-jump navigation and scrolling in the Skills Manager (
P) dialog for long lists. - Add stricter Skills Manager available list behavior so project attach/detach is driven by the managed pool source.
- Update README and skill references with Skills Manager usage, skill CLI command coverage, and skills registry path documentation.
- Add
agent-deck webmode to run the TUI and web UI server together, with browser terminal streaming and session menu APIs (#174, contributed by @PatrickStraeter) - Add web push notification and PWA support for web mode (
--push,--push-vapid-subject,--push-test-every) (#174) - Add macOS MacPorts support to
install.shwith--pkg-managerselection alongside Homebrew (#187, contributed by @bronweg)
- Fix
allow_dangerous_modepropagation for Claude sessions created from the UI flow (#185, contributed by @daniel-shimon) - Fix TUI scroll artifacts caused by width-measurement inconsistency and control-character leakage in preview rendering (#182, contributed by @jsvana)
- Fix Claude busy-pattern false positives from welcome-banner separators by anchoring spinner regexes to line start (#179, contributed by @mtparet)
- Harden web mode by restricting WebSocket upgrades to same-host origins and preserving auth token in push deep links (#174)
- Add
--waitflag tosession sendfor blocking until command completion (#180)
- Add Codex notify hook integration for instant session status updates
- Add notification show_all mode to display all notifications at once
- Add automatic bridge.py updates when running
agent-deck update(#178)
- Fix: handle error returns in test cleanup functions
- Fix: bridge.py not updating with agent-deck binary updates (#178)
- Add top-level rename command with validation (#176, contributed by @nlenepveu)
- Add Slack user ID authorization for conductors (#170, contributed by @mtparet)
- Custom CLAUDE.md paths via symlinks for conductors (#173, contributed by @mtparet)
- Fix: remove thread context fetching from Slack handler (#175, contributed by @mtparet)
- Fix: prevent worktree nesting when creating from within worktrees (#177)
- Add
--teammate-modetmux option to Claude session launcher for shared terminal pairing (#168, contributed by @jonnocraig) - Add Slack integration and cross-platform daemon support (#169, contributed by @mtparet)
- Add Claude Code lifecycle hooks for real-time status detection (instant green/yellow/gray transitions without tmux polling)
- Add first-launch prompt asking users to install hooks (preserves existing Claude settings.json)
- Add
agent-deck hooks install/uninstall/statusCLI subcommands for manual hook management - Add
hooks_enabledconfig option under[claude]to opt out of hook-based detection - Add StatusFileWatcher (fsnotify) for instant hook status file processing
- Add
AGENTDECK_INSTANCE_IDenv var export for Claude hook subprocess identification - Add acknowledgment awareness to hook fast path (attach turns session gray,
ukey turns it orange) - Add
llms.txtfor LLM discoverability, fix schema version, add FAQ entries (#167)
- Fix middot
·spinner character not detected as busy indicator when followed by ellipsis (BusyPatterns regex now includes·)
- Sessions with active hooks skip tmux content polling entirely (2-minute timeout as crash safety net only)
- Existing sessions without hooks continue using polling (seamless hybrid mode)
- Add
inject_status_lineconfig option under[tmux]to disable tmux statusline injection, allowing users to keep their own tmux status bar (#157) - Add system theme option: sync TUI theme with OS dark/light mode (#162)
- Improve quick session creation: inherit path, tool, and options from hovered session (#165)
- Fix Claude session ID not updating after
/clear,/fork, or/compactby syncing from disk (#166) - Restore delay between paste and Enter in
SendKeysAndEnterto prevent swallowed input in tmux (#168)
- Add title-based status detection fast-path: reads tmux pane titles (Braille spinner / done markers) to determine Claude session state without expensive content scanning
- Add
RefreshPaneInfoCache()for zero-subprocess pane title fetching via PipeManager - Add worktree finish dialog (
Wkey): merge branch, remove worktree, delete branch, and clean up session in one step - Add worktree branch badge
[branch]in session list for worktree sessions - Add worktree info section in preview pane (branch, repo, path, dirty status)
- Add worktree dirty status cache with lazy 10s TTL checks
- Add repository worktree summary in group preview when sessions share a repo
- Add
esc to interruptfallback to Claude busy patterns for older Claude Code versions - Add worktree section to help overlay
- Fix busy indicator false negatives for
·and✻spinner chars with ellipsis (BusyRegexp now correctly catches all spinner frames with active context) - Remove unused
matchesDetectPatternsfunction (lint warning) - Fix
startingandinactivestatus mapping in instance status update
- Add quick session creation with
Shift+Nhotkey: instant session with auto-generated name and smart defaults (#161) - Add Docker-style name generator (adjective-noun) with ~10,000 unique combinations
- Add
--quick/-Qflag toagent-deck addCLI for auto-named sessions - Smart defaults: inherits tool, options, and path from most recent session in the group
- Fix busy detection window reduced from 25 to 10 lines for faster status transitions
- Fix conductor group permanently pinned to top of group list
- Optimize status detection pipeline for faster green/yellow transitions
- Add spinner movement detection tests for stuck spinner validation
- Fix
session sendintermittently dropping Enter key (and sometimes text) due to tmux race condition between two separatesend-keysprocess invocations (tmux#1185, tmux#1517, tmux#1778) - Fix all 6 send-keys + Enter code paths to use atomic tmux command chaining (
;) in a single subprocess - Add retry with verification to CLI
session sendfor resilience under heavy load or SSH latency
- Fix Shift+R restart race condition with animation guard on restart and fork hotkeys (#147)
- Fix settings menu viewport cropping in small terminals with scroll windowing (#149)
- Fix .mcp.json clobber by preserving existing entries when managing MCP sessions (#146)
- Fix --resume-session arg parsing by registering it in the arg reorder map (#145)
- Add tmux option overrides via
[tmux]config section in config.toml (#150) - Add opencode fork infrastructure with OpenCodeOptions for model/agent/fork support (#148)
- Multiple conductors per profile: create N named conductors in a single profile
agent-deck conductor setup <name>with--heartbeat,--no-heartbeat,--descriptionflagsagent-deck conductor teardown <name>or--allto remove conductorsagent-deck conductor listwith--jsonand--profilefiltersagent-deck conductor status [name]shows all or specific conductor health
- Two-tier CLAUDE.md for conductors: shared knowledge base + per-conductor identity
- Shared
CLAUDE.mdat conductor root with CLI reference, protocols, and rules - Per-conductor
CLAUDE.mdwith name and profile substitution
- Shared
- Conductor metadata via
meta.jsonfiles for name, profile, heartbeat settings, and description - Auto-migration of legacy single-conductor directories to new multi-conductor format
- Bridge (Telegram) updated for dynamic conductor discovery via
meta.jsonscanning normalizeArgsutility for consistent flag parsing across all CLI commands- Status field added to
agent-deck list --jsonoutput
- Add
allow_dangerous_modeoption to[claude]config section- Passes
--allow-dangerously-skip-permissionsto Claude (opt-in bypass mode) dangerous_mode = truetakes precedence when both are set- Based on contribution by @daniel-shimon (#152), with architectural fixes (#153)
- Passes
- New permission flag persists per-session across fork and restart operations
- Fix deleted sessions reappearing after reload or app restart
SaveInstances()now deletes stale rows from SQLite within the same transaction- Added explicit
DeleteInstance()call in the delete handler as a safeguard - Root cause:
INSERT OR REPLACEnever removed deleted session rows from the database
- Update profile detection to check for
state.db(SQLite) in addition to legacysessions.json - Update uninstall script to count sessions from SQLite instead of JSON
- Persist UI state (cursor position, preview mode, status filter) across restarts via SQLite metadata
- Save group expanded/collapsed state immediately on toggle
- Discord badge and link in README
- Simplify multi-instance coordination: remove periodic primary re-election from background worker
- Create new profiles with SQLite directly instead of empty
sessions.json - Update troubleshooting docs for SQLite-based recovery
- Enable notification bar on all instances, not just the primary
- Previously secondary instances had notifications disabled entirely
- All instances share the same SQLite state, so they produce identical bar content
- Replace file-based lock with SQLite heartbeat-based primary election for multi-instance coordination
- Dynamic failover: if the primary instance crashes, a secondary takes over the notification bar within ~12 seconds
- Eliminates stale
.lockfiles that required manual cleanup after crashes ElectPrimary()uses atomic SQLite transactions to prevent split-brain
- Remove
acquireLock,releaseLock,getLockFilePath,isProcessRunning(replaced by SQLite election)
- Replace
sessions.jsonwith SQLite (state.db) as the single source of truth- WAL mode for concurrent multi-instance reads/writes without corruption
- Auto-migrates existing
sessions.jsonon first run (renamed to.migratedas backup) - Removes fragile full-file JSON rewrites, backup rotation, and fsnotify dependency
- Tool-specific data stored as JSON blob in
tool_datacolumn for schema flexibility
- Replace fsnotify-based storage watcher with SQLite metadata polling
- Simpler, works reliably on all filesystems (9p, NFS, WSL)
- 2-second poll interval using
metadata.last_modifiedtimestamp
- Replace tmux rate limiter and watcher with control mode pipes (PipeManager)
- Event-driven status detection via
tmux -Ccontrol mode - Zero-subprocess architecture: no more
tmux capture-panefor idle sessions
- Event-driven status detection via
- Add
internal/statedbpackage: SQLite wrapper with CRUD, heartbeat, status sync, and change detection - Add cross-instance acknowledgment sync via SQLite (ack in instance A visible in instance B)
- Add instance heartbeat table for tracking alive TUI processes
- Add
StatusSettingsin user config (reserved for future status detection settings)
- Add
worktree finishcommand to merge branch, remove worktree, and delete session in one step (#140)- Flags:
--into,--no-merge,--keep-branch,--force,--json - Abort-safe: merge conflicts trigger
git merge --abort, leaving everything intact
- Flags:
- Auto-cleanup worktree directories when deleting worktree sessions (CLI
removeand TUIdkey)
- Fix orphaned MCP server processes (Playwright CPU leak) by killing entire process group
- Set
Setpgid=trueso grandchild processes (npx/uvx spawned) share a process group - Shutdown now sends SIGTERM/SIGKILL to
-pid(group) instead of just the parent
- Set
- Fix test cleanup killing user sessions with "test" in their title
- Fix session rename lost during reload race condition
- Fix session rename not persisting (#141)
lastLoadMtimewas not updated after saves, causing mtime check to incorrectly abort subsequent saves- Renames, reorders, and other non-force saves now persist correctly
- Add Codex CLI
--yoloflag support (#142)- Global config:
[codex] yolo_mode = truein config.toml - Per-session override in New Session dialog (checkbox)
- Flag preserved across session restarts
- Settings panel toggle for global default
- Global config:
- Add unified
OptionsPanelinterface for tool-specific options (#143)- New tools can add options by implementing interface + 1 case in
updateToolOptions() - Shared
renderCheckboxLine()helper ensures visual consistency across panels
- New tools can add options by implementing interface + 1 case in
- Fix
ClaudeOptionsPanel.Blur()not resetting focus stateIsFocused()now correctly returns false after blur
- Fix sessions disappearing after creation in TUI
- Critical saves (create, fork, delete, restore) now bypass mtime check that was incorrectly aborting saves
- Sessions created during reload are now properly persisted to JSON before triggering reload
- Fix import function to recover orphaned agent-deck sessions
- Press
ito import sessions that exist in tmux but are missing from sessions.json - Recovered sessions are placed in a "Recovered" group for easy identification
- Press
- Fix garbled input at update confirmation prompt
- Add
drainStdin()to flush terminal input buffer before prompting - Use
TCFLSHioctl to discard pending escape sequences and accidental keypresses - Switch from
fmt.Scanlntobufio.NewReaderfor more robust input handling
- Add
- Fix TUI overwriting CLI changes to sessions.json (#139)
- Add mtime check before save: compares file mtime against when we last loaded, aborts save and triggers reload if external changes detected
- Fix TOCTOU race condition:
isReloadingflag now protected by mutex in all 6 read locations - Add filesystem detection for WSL2/NFS: warns users when on 9p/NFS/CIFS/SSHFS mounts where fsnotify is unreliable
- Fix critical OOM crash: Global Search was loading 4.4 GB of JSONL content into memory and opening 884 fsnotify directory watchers (7,900+ file descriptors), causing agent-deck to balloon to 6+ GB RSS until macOS killed it
- Temporarily disable Global Search at startup until memory-safe implementation is complete
- Optimize directory traversal to skip
tool-results/andsubagents/subdirectories (never contain JSONL files) - Limit fsnotify watchers to project-level directories only (was recursively watching ALL subdirectories)
- Add max client cap (100) per MCP socket proxy to prevent unbounded goroutine growth from reconnect loops
- Broken MCPs (e.g.,
reddit-yilinwith 72 connects/30s) could spawn unlimited goroutines and scanner buffers
- Broken MCPs (e.g.,
- Global Search (
Gkey) is temporarily disabled pending a memory-safe reimplementation- Will be re-enabled once balanced tier is enforced for large datasets and memory limits are properly applied
- Migrate all logging to structured JSONL via
log/slogwith automatic rotation- JSONL output to
~/.agent-deck/debug.logwith component-based filtering (jq 'select(.component=="pool")') - Automatic log rotation via lumberjack (configurable size, backups, retention in
[logs]config) - Event aggregation for high-frequency MCP socket events (1 summary per 30s instead of 40 lines/sec)
- In-memory ring buffer with crash dump support (
kill -USR1 <pid>) - Optional pprof profiling on
localhost:6060 - 9 log components: status, mcp, notif, perf, ui, session, storage, pool, http
- New
[logs]config options:debug_level,debug_format,debug_max_mb,debug_backups,debug_retention_days,debug_compress,ring_buffer_mb,pprof_enabled,aggregate_interval_secs
- JSONL output to
- Fix MCP pool infinite restart loop causing 45 GB memory leak over 15 hours
- Add
StatusPermanentlyFailedstatus: broken MCPs are disabled after 10 consecutive failures - Fix leaked proxy context/goroutines when
Start()fails during restart - Reset failure counters after proxy is healthy for 5+ minutes (allows transient failure recovery)
- Skip permanently failed proxies in health monitor for both socket and HTTP pools
- Add
- Fix inconsistent debug flag check in tmux.go (
== "1"changed to!= ""to match rest of codebase)
- Fix tmux pane showing stale conversation history after session restart (#138)
- Clear scrollback buffer before respawn to remove old content
- Invalidate preview cache on restart for immediate refresh
- Kill old tmux session in fallback restart path to prevent orphans
- Add
mcp_default_scopeconfig option to control where MCPs are written (#137)- Set to
"global"or"user"to stop agent-deck from overwriting.mcp.jsonon restart - Affects MCP Manager default tab, CLI attach/detach defaults, and session restart regeneration
- Defaults to
"local"(no breaking change)
- Set to
- Add configurable worktree path templates via
path_templateconfig option (#135, contributed by @peteski22)- Template variables:
{repo-name},{repo-root},{branch},{session-id} - Overrides
default_locationwhen set; falls back to existing behavior when unset - Integrated at all 4 worktree creation points (CLI add, CLI fork, TUI new session, TUI fork)
- Backported from njbrake/agent-of-empires
- Template variables:
- Remove dead GoReleaser ldflags targeting non-existent
main.version/commit/datevars - Remove redundant
make releasetarget (superseded byrelease-local) - Remove unused deprecated wrappers
NewStorage()andGetStoragePath() - Remove unused test helpers file (
internal/ui/test_helpers.go) - Remove stale
home.go.bakbackup file
- Fix shell dying after tool exit by removing
execprefix from all tool commands (#133, contributed by @kurochenko)- When Claude, Gemini, OpenCode, Codex, or generic tools exit, users now return to their shell prompt instead of a dead tmux pane
- Enables workflows where tools run inside wrappers (e.g., nvim) that should survive tool exit
- Add
make release-localtarget for local GoReleaser releases (no GitHub Actions dependency)
- TUI freezes with 40+ sessions: Parallel status polling replaces sequential loop that couldn't complete within 2s tick
- 10-worker pool via errgroup for concurrent tmux status checks
- Instance-level RWMutex prevents data races between background worker and TUI rendering
- Tiered polling skips idle sessions with no activity (10s recheck gate)
- 3-second timeout on CapturePane/GetWindowActivity prevents hung tmux calls from blocking workers
- Timeout preserves previous status instead of flashing RED
- Race detector (
-race) enabled in tests and CI
- Fix intermittent
zsh: killeddue to memory exhaustion (#128): Four memory leaks causing macOS OOM killer (Jetsam) to SIGKILL agent-deck after prolonged use with many sessions:- Cap global search content buffer memory at 100MB (configurable via
memory_limit_mb), evict oldest 25% of entries when exceeded - Release all content memory and clear file trackers on index Close()
- Stop debounce timers on watcher shutdown to prevent goroutine leaks
- Prune stale analytics/activity caches every 20 seconds (were never cleaned up)
- Clean up analytics caches on session delete
- Clear orphaned MCP socket proxy request map entries on client disconnect and MCP failure
- Prune LogWatcher rate limiters for removed sessions every 20 seconds
- Cap global search content buffer memory at 100MB (configurable via
- Prevent nested agent-deck sessions (#127): Running
agent-deckinside a managed tmux session now shows a clear error instead of causing infinite...output. Read-only commands (version,help,status,list,session current/show/output,mcp list/attached) still work for debugging
- Global search unusable with large datasets (#125): Multiple performance fixes make global search work with multi-GB session data:
- Remove rate limiter from initial load (was causing 42+ minute "Loading..." on large datasets)
- Read only first 32KB of files for metadata in balanced tier (was reading entire files, some 800MB+)
- Early exit from parsing once metadata found (SessionID/CWD/Summary)
- Parallelize disk search with 8-worker pool (was sequential)
- Debounced async search on UI thread (250ms debounce + background goroutine)
- Default
recent_daysto 30 when not set (was 0 = all time)
- G key didn't open Global Search: Help bar showed
G Globalbut the key actually jumped to the bottom of the list.Gnow opens Global Search (falls back to local search if global search is disabled)
- Global search freezes when typing with many sessions (#125): Search ran synchronously on the UI thread, blocking all input while scanning files from disk. Now uses debounced async search (250ms debounce + background goroutine) so the UI stays responsive regardless of data size
- G key didn't open Global Search: Help bar showed
G Globalbut the key actually jumped to the bottom of the list.Gnow opens Global Search (falls back to local search if global search is disabled)
- GREEN status not detecting Claude 2.1.25+ spinners: Prompt detector only checked braille spinner chars (
⠋⠙⠹...) as busy guards, missing the asterisk spinners (✳✽✶✢) used since Claude 2.1.25. This caused sessions to show YELLOW instead of GREEN while Claude was actively working - Prompt detector missing whimsical word timing patterns: Only "thinking" and "connecting" were recognized as active processing. Now detects all 90+ whimsical words (e.g., "Hullaballooing", "Clauding") via the universal
…+tokenspattern - Spinner check range too narrow: Only checked last 3 lines for spinner chars, but Claude's UI can push the spinner line 6+ lines from the bottom (tip lines, borders, status bar). Expanded to last 10 lines
- Acknowledge override on attach: Attaching to a waiting (yellow) session would briefly acknowledge it, but the background poller immediately reset it back to waiting because the prompt was still visible. Prompt detection now respects the acknowledged state
- Group dialog defaults to root mode on grouped sessions: Pressing
gwhile the cursor is on a session inside a group now opens the "Create New Group" dialog in root mode instead of subgroup mode. Tab toggle still switches to subgroup. Group headers still default to subgroup mode. This makes it easier for users with all sessions in groups to create new root-level groups
- MCP socket pool resilience docs: README updated to mention automatic ~3s crash recovery via reconnecting proxy
- Pattern override documentation:
config.toml initnow includes documentation forbusy_patterns_extra,prompt_patterns_extra, andspinner_chars_extrafields for extending built-in tool detection patterns
- 492% CPU usage: Main TUI process was consuming 5 CPU cores due to reading 100-841MB JSONL files every 2 seconds per Claude session. Now uses tail-read (last 32KB only) with file-size caching to skip unchanged files entirely
- Duplicate notification sync: Both foreground TUI tick and background worker were running identical notification sync every 2 seconds, spawning duplicate tmux subprocesses. Removed foreground sync since background worker handles everything
- Excessive tmux subprocess spawns:
GetEnvironment()spawnedtmux show-environmentevery 2 seconds per Claude session for session ID lookup. Added 30-second cache since session IDs rarely change - Unnecessary idle session polling: Claude/Gemini/Codex session tracking updates now skip idle sessions where nothing changes
- Configurable pattern detection system:
ResolvedPatternswith compiled regexes replaces hardcoded busy/prompt detection, enabling pattern overrides viaconfig.toml
- MCP socket proxy 64KB crash:
bufio.Scannerdefault 64KB limit caused socket proxy to crash when MCPs like context7 or firecrawl returned large responses. Increased buffer to 10MB, preventing orphaned MCP processes and permanent "failed" status - Faster MCP failure recovery: Health monitor interval reduced from 10s to 3s for quicker detection and restart of failed proxies
- Active client disconnect on proxy failure: When socket proxy dies, all connected clients are now actively closed so reconnecting proxies detect failure immediately instead of hanging
- Reconnecting MCP proxy (
agent-deck mcp-proxy): New subcommand replacesnc -Uas the stdio bridge to MCP sockets. Automatically reconnects with exponential backoff when sockets drop, making MCP pool restarts invisible to Claude sessions (~3s recovery)
- Fork worktree isolation: Fork dialog (
Fkey) now includes an opt-in worktree toggle for git repos. When enabled, the forked session gets its own git worktree directory, isolating Claude Code project state (plan, memory, attachments) between parent and fork (#123) - Auto-suggested branch name (
fork/<session-name>) in fork dialog when worktree is enabled - CLI
session forkcommand gains-w/--worktree <branch>and-b/--new-branchflags for worktree-based forks - Branch validation in fork dialog using existing git helpers
- Session reorder persistence: Reordering sessions with Shift+K/J now persists across reloads. Added
Orderfield to session instances, normalized on every move, and sorted by Order on load. Legacy sessions (no Order field) preserve their original order via stable sort (#119)
- Claude Code 2.1.25+ busy detection: Claude Code 2.1.25 removed
"ctrl+c to interrupt"from the status line, causing all sessions to appear YELLOW/GRAY instead of GREEN while working. Detection now uses the unicode ellipsis (…) pattern: active state shows"✳ Gusting… (35s · ↑ 673 tokens)", done state shows"✻ Worked for 54s"(no ellipsis) - Status line token format detection updated to match new
↑/↓arrow format ((35s · ↑ 673 tokens)) - Content normalization updated for asterisk spinner characters (
·✳✽✶✻✢) to prevent false hash changes
- Analytics preview panel now defaults to OFF (opt-in via
show_analytics = truein config.toml)
- 6 new whimsical thinking words:
billowing,gusting,metamorphosing,sublimating,recombobulating,sautéing - Word-list-independent spinner detection regex for future-proofing against new Claude Code words
- CLI session ID capture:
session start,session restart,session fork, andtrynow persist Claude session IDs to JSON immediately, enabling fork and resume from CLI-only workflows without the TUI - Fork pre-check recovery:
session forkattempts to recover missing session IDs from tmux before failing, fixing sessions started before this fix - Stale comment in
loadSessionDatacorrected to reflect lazy loading behavior
PostStartSync()method on Instance for synchronous session ID capture after Start/Restart (CLI-only; TUI uses its existing background worker)
- HTTP Transport Support for MCP Servers: Native support for HTTP/SSE MCP servers with auto-start capability
- Add
[mcps.X.server]config block for auto-starting HTTP MCP servers (command, args, env, startup_timeout, health_check) - Add
mcp serverCLI commands:start,stop,statusfor managing HTTP MCP servers - Add transport type indicators in
mcp list:[S]=stdio,[H]=http,[E]=sse - Add TUI MCP dialog transport indicators with status:
●=running,○=external,✗=stopped - Add HTTP server pool with health monitoring and automatic restart of failed servers
- External server detection: if URL is already reachable, use it without spawning a new process
- MCP dialog now shows transport type and server status for each MCP
mcp listoutput now includes transport type column
- Performance: TUI startup ~3x faster (6s → 2s for 44 sessions)
- Batch tmux operations: ConfigureStatusBar (5→1 call), EnableMouseMode (6→2 calls) using command chaining
- Lazy loading: defer non-essential tmux configuration until first attach or background tick
- Skip UpdateStatus and session ID sync at load time (use cached status from JSON)
- Add
ReconnectSessionLazy()for deferred session configuration - Add
EnsureConfigured()method for on-demand tmux setup - Add
SyncSessionIDsToTmux()method for on-demand session ID sync - Background worker gradually configures unconfigured sessions (one per 2s tick)
- Add undo delete (Ctrl+Z) for sessions: press Ctrl+Z after deleting a session to restore it including AI conversation resume. Supports multiple undos in reverse order (stack of up to 10)
- Show ^Z Undo hint in help bar (compact and full modes) when undo stack is non-empty
- Add Ctrl+Z entry to help overlay (? screen)
- Update delete confirmation dialog: "This cannot be undone" → "Press Ctrl+Z after deletion to undo"
- Fix
gkey unable to create root-level groups when any group exists (#111). Add Tab toggle in the create-group dialog to switch between Root and Subgroup modes - Fix
nkey handler using display name constant instead of path constant for default group
- Group DefaultPath tracking: groups now track the most recently accessed session's project path via
updateGroupDefaultPath
- Fix CI test failure in
TestBindUnbindKeyby making default key restore best-effort inUnbindKey
- Fix TUI cursor not following notification bar session switch after detach (Ctrl+b N during attach now moves cursor to the switched-to session on Ctrl+Q)
- Fix quit dialog ("Keep running" / "Shut down") hidden behind splash screen, causing infinite hang on quit with MCP pool
- Fix
isQuittingflag not reset when canceling quit dialog with Esc - Add 5s safety timeouts to status worker and log worker waits during shutdown
- Fix shutdown hang when quitting with "shut down" MCP pool option (process
Wait()blocked forever on child-held pipes) - Set
cmd.Cancel(SIGTERM) andcmd.WaitDelay(3s) on MCP processes for graceful shutdown with escalation - Add 5s safety timeout to individual proxy
Stop()and 10s overall timeout to poolShutdown()
- Fix stale expanded group state during reload causing cursor jumps when CLI adds a session while TUI is running
- Fix new groups added via CLI appearing collapsed instead of expanded
- Eliminate redundant tree rebuild and viewport sync during reload (performance)
- Add
envfield to custom tool definitions for inline environment variables (closes #101) - Custom tools from config.toml now appear in the TUI command picker with icons
- CLI
agent-deck add -c <custom-tool>resolves tool to actual command automatically
- Fix
[worktree] default_location = "subdirectory"config not being applied (fixes #110) - Add
--locationCLI flag to override worktree placement per session (siblingorsubdirectory) - Worktree location now respects config in both CLI and TUI new session dialog
- Fix changelog display dropping unrecognized lines (plain text paragraphs now preserved)
- Fix trailing-slash path completion returning directory name instead of listing contents
- Reset path autocomplete state when reopening new session dialog
- Fix double-close on LogWatcher and StorageWatcher (move watcher.Close inside sync.Once)
- Fix log worker shutdown race (replace unused channel with sync.WaitGroup)
- Fix CapturePane TOCTOU race with singleflight deduplication
- Comprehensive test suite for update package (CompareVersions, ParseChangelog, GetChangesBetweenVersions, FormatChangelogForDisplay)
- Clear MCP cache before regeneration to prevent stale reads
- Cursor jump during navigation and view duplication bugs
- Resume with empty session ID opens picker instead of random UUID
- Subgroup creation under selected group
- Fast text copy (
c) and inter-session transfer (x)
- Gemini model selection dialog (
Ctrl+G) - Configurable maintenance system with TUI feedback
- Improved status detection accuracy and Gemini prompt caching
.envfile sourcing support for sessions ([shell] env_files)- Default dangerous mode for power users
- Sync session IDs to tmux env for cross-project search
- Write headers to Claude config for HTTP MCPs
- OpenCode session detection persistence and "Detecting session..." bug
- Preserve parent path when renaming subgroups
- MCP Manager user scope: attach MCPs to
~/.claude.json(affects all sessions) - Three-scope MCP system: LOCAL, GLOBAL, USER
- Session sharing skill (export/import sessions between developers)
- Scrolling support for help overlay on small screens
- Prevent orphaned test sessions
- MCP pool quit confirmation
- Notification bar enabled by default
- Thread-safe key bindings for background sync
- Background worker self-ticking for status updates during
tea.Exec ctrl+c to interruptas primary busy indicator detection- Debug logging for status transitions
- Reduced grace period from 5s to 1.5s for faster startup detection
- Removed 6-second animation minimum; uses status-based detection
- Hook-based polling replaces frequent tick-based detection
- Notification bar performance and active session detection
- Increased busy indicator check depth from 10 to 20 lines
- Replaced Aider with OpenCode - Full integration of OpenCode (open-source AI coding agent)
- OpenCode replaces Aider as the default alternative to Claude Code
- New icon: 🌐 representing OpenCode's open and universal approach
- Detection patterns for OpenCode's TUI (input box, mode indicators, logo)
- Updated all documentation, examples, and tests
0.1.0 - 2025-12-03
-
Terminal UI - Full-featured TUI built with Bubble Tea
- Session list with hierarchical group organization
- Live preview pane showing terminal output
- Fuzzy search with
/key - Keyboard-driven navigation (vim-style
hjkl)
-
Session Management
- Create, rename, delete sessions
- Attach/detach with
Ctrl+Q - Import existing tmux sessions
- Reorder sessions within groups
-
Group Organization
- Hierarchical folder structure
- Create nested groups
- Move sessions between groups
- Collapsible groups with persistence
-
Intelligent Status Detection
- 3-state model: Running (green), Waiting (yellow), Idle (gray)
- Tool-specific busy indicator detection
- Prompt detection for Claude Code, Gemini CLI, OpenCode, Codex
- Content hashing with 2-second activity cooldown
- Status persistence across restarts
-
CLI Commands
agent-deck- Launch TUIagent-deck add <path>- Add session from CLIagent-deck list- List sessions (table or JSON)agent-deck remove <id|title>- Remove session
-
Tool Support
- Claude Code - Full status detection
- Gemini CLI - Activity and prompt detection
- OpenCode - TUI element detection
- Codex - Prompt detection
- Generic shell support
-
tmux Integration
- Automatic session creation with unique names
- Mouse mode enabled by default
- 50,000 line scrollback buffer
- PTY attachment with
Ctrl+Qdetach
- Built with Go 1.24+
- Bubble Tea TUI framework
- Lip Gloss styling
- Tokyo Night color theme
- Atomic JSON persistence
- Cross-platform: macOS, Linux