-
Notifications
You must be signed in to change notification settings - Fork 194
Description
Context
There are currently two separate heartbeat mechanisms that both send messages to the conductor session every N minutes:
1. heartbeat.sh (systemd timer / launchd plist)
- Installed by
conductor setupunconditionally (unless--no-heartbeat) - Sends a generic message asking Claude to check sessions:
"Heartbeat: Check all sessions in the default profile. List any waiting sessions, auto-respond where safe, and report what needs my attention." - Claude has to call
brigade statusitself and do the work
2. heartbeat_loop() in bridge.py (async loop)
- Runs inside the bridge process, installed only when Telegram or Slack is configured
- Calls
agent-deck brigade status --json, formats a summary, and sends it:
"[HEARTBEAT] [ai-platform] Status: 6 waiting, 0 running, 3 idle, 1 error. Waiting sessions: ..." - Claude receives a pre-formatted summary and just needs to react
The install logic in conductor_cmd.go
conductor setup runs both steps independently:
- Step 6:
InstallHeartbeatScript()+InstallHeartbeatDaemon()— always (if heartbeat enabled) - Step 7:
InstallBridgeScript()+InstallBridgeDaemon()— only if Telegram/Slack configured
There is no check to skip the systemd heartbeat timer when the bridge is also being installed.
Result
When Telegram or Slack is configured (which is the common case for conductor users), the conductor receives two heartbeat messages every interval — one asking it to check, and one giving it the answer. This doubles token usage for essentially the same purpose.
Suggestion
The systemd/launchd heartbeat timer makes sense as a fallback for setups without Telegram/Slack (no bridge running). But when the bridge is active, its heartbeat_loop already covers the same need more efficiently (pre-computes the summary, saves tokens).
Would you be open to a PR that makes the systemd heartbeat timer conditional — skip installation when the bridge is also being installed?