feat: opt-in smart heartbeat that only fires when session state changes#592
Open
c2keesey wants to merge 17 commits intoasheshgoplani:mainfrom
Open
feat: opt-in smart heartbeat that only fires when session state changes#592c2keesey wants to merge 17 commits intoasheshgoplani:mainfrom
c2keesey wants to merge 17 commits intoasheshgoplani:mainfrom
Conversation
…hgoplani#366) Check existing terminal-features before appending to avoid duplicates that balloon the list to 260+ entries over multiple session starts. Committed by Ashesh Goplani
When the name field is left empty, a random adjective-noun name (e.g., "golden-eagle") is shown as a dimmed placeholder and used on submit. The worktree branch placeholder also reflects the generated name. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Branch shows as dimmed placeholder (not filled input) when using generated name; only fills when user types a custom name - Align Validate() and GetValuesWithWorktree() branch derivation logic - Add tests for generated name fallback, branch placeholder behavior, and worktree branch derivation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nal-features-spam Fix asheshgoplani#366: prevent terminal-features spam by checking before appending
Feat: auto-generate session names as placeholders when name field is empty
…-happy Feat: add happy wrapper support for Claude and Codex (opt-in via use_happy config)
…ranch Feat: worktree branch reuse (local+remote) and fzf branch picker via Ctrl+F
…key input The extended-keys option was set server-wide (`set -sq`), which caused tmux to activate xterm modifyOtherKeys mode on the outer terminal (iTerm2, etc.). This persisted even after the tmux option was turned off, causing Ctrl+R and other modified keys to be sent as escape sequences that Bubble Tea cannot parse — breaking the recent sessions picker and other Ctrl-key shortcuts in the dashboard. Two fixes: - tmux.go: changed `set -sq extended-keys on` to per-session `set-option -t <session> -q extended-keys on` at both call sites - keyboard_compat.go: also disable xterm modifyOtherKeys (ESC[>4;0m) on TUI startup alongside the existing Kitty protocol disable, as a defense-in-depth measure Fixes regression introduced in b427418 (asheshgoplani#342).
…o avoid breaking dashboard Ctrl shortcuts
# Conflicts: # internal/git/git.go # internal/git/git_test.go # internal/session/instance.go # internal/tmux/tmux.go # internal/ui/branch_picker.go # internal/ui/claudeoptions.go # internal/ui/forkdialog.go # internal/ui/forkdialog_test.go # internal/ui/home.go # internal/ui/keyboard_compat.go # internal/ui/keyboard_compat_test.go # internal/ui/newdialog.go # internal/ui/settings_panel.go # skills/agent-deck/references/config-reference.md
Adds a `heartbeat_smart` flag under `[conductor]` settings. When enabled, the per-conductor heartbeat.sh installed by `agent-deck conductor setup` snapshots session state on each tick and only forwards a check-in to the conductor session when the snapshot differs from the previous run. The default remains unchanged (every tick fires a heartbeat) so behavior is backward compatible. The state snapshot is the sorted set of "title:status" pairs from `agent-deck list --json`, excluding the conductor session itself, parsed with portable awk that works on both GNU and BSD. Snapshots are written atomically to `heartbeat.state` next to `heartbeat.sh`. `MigrateConductorHeartbeatScripts` now respects the same setting, so toggling `heartbeat_smart` and rerunning conductor setup (or letting the migration sweep run) refreshes existing managed scripts in place. The managed-script detector recognizes both header variants. Tests cover: - Smart template structure (state diffing, atomic write, status guard, group-scoped message) - `InstallHeartbeatScript(..., false)` writes the standard script and strips `-p` for the default profile - `InstallHeartbeatScript(..., true)` interpolates an absolute state file path, preserves `-p` for non-default profiles, and emits an executable file - `bash -n` syntax check on the rendered smart script so awk/quoting regressions surface at `go test` time - `HeartbeatSmart` defaults to false - Migration sweep recognizes the smart header
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a
heartbeat_smartflag under[conductor]settings. When enabled, the per-conductorheartbeat.shinstalled byagent-deck conductor setupsnapshots session state on each tick and only sends a check-in to the conductor when the snapshot differs from the previous run.The default is
false, so behavior is unchanged unless the user opts in.Closes #545 (this PR replaces that earlier, rougher attempt).
Motivation
On profiles where the conductor is mostly idle, the timer-driven heartbeat wakes the conductor every N minutes just to have it report "all clear". For users running the conductor against expensive models (or who just want quieter tmux output), that's wasted work. With
heartbeat_smart = true, the heartbeat tick is a cheap shell snapshot when nothing has moved, and the conductor is only woken when there's actually something to look at.How it works
The smart variant of
heartbeat.sh:conductor statusenabled-guard as the standard script.title:statuspairs fromagent-deck list --json, sorted, with the conductor's own session filtered out. Parsing uses portableawk(works on GNU and BSD/macOS), matching the parser style used by the existing heartbeat script.heartbeat.state(an absolute path interpolated next toheartbeat.shat install time, so the script doesn't depend on$0).tmp+mv) before sending, so a crash mid-send can't cause a re-fire loop.Migration
MigrateConductorHeartbeatScriptshonours the same setting, so flippingheartbeat_smartand re-runningagent-deck conductor setup(or letting the migration sweep run on next start) refreshes existing managed scripts in place. The managed-script detector recognises both the standard# Heartbeat for conductor:header and the new# Smart heartbeat for conductor:header, so neither variant is mistaken for a user-authored custom script.Setup output
When
heartbeat_smart = false(the default), the existing(every 15 min)line is unchanged.Tests
8 new tests in
internal/session/conductor_test.go:TestConductorSmartHeartbeatScript_TemplateStructure— smart template contains the diffing comparison, atomic state write, status guard, and group-scoped message.TestInstallHeartbeatScript_StandardWritesScriptWithoutSmartMarkers—InstallHeartbeatScript(name, "default", false)writes the standard script viat.Setenv("HOME", tmpHome), strips-pfor the default profile, and contains no smart markers.TestInstallHeartbeatScript_SmartInterpolatesStateFileAndPreservesProfile— smart install interpolates the absoluteheartbeat.statepath, leaves no{STATE_FILE}placeholder, keeps-pfor non-default profiles, and produces an executable file.TestInstallHeartbeatScript_SmartDefaultProfileStripsFlag— smart install with the default profile still strips-p.TestInstallHeartbeatScript_SmartScriptIsExecutableShell— runsbash -nagainst the rendered smart script so awk/quoting regressions surface atgo testtime.TestConductorSettings_HeartbeatSmartDefault—HeartbeatSmartdefaults tofalse.TestMigrateConductorHeartbeatScripts_DetectsSmartHeader— both header variants are recognised by the migration sweep's managed-script check.All existing conductor tests still pass.
Test plan
go test ./internal/session/ -run "Heartbeat|Smart|Conductor" -count=1— passesgo build ./...— passesgofmtcleanbash -nsyntax check on rendered smart script (covered by test above)heartbeat_smart = true, observeheartbeat.statepopulating and conductor only being poked on real state changes