Skip to content

feat(conductor): local-first conductor support#1362

Open
spawnia wants to merge 11 commits into
asheshgoplani:mainfrom
mll-lab:local-first-conductors
Open

feat(conductor): local-first conductor support#1362
spawnia wants to merge 11 commits into
asheshgoplani:mainfrom
mll-lab:local-first-conductors

Conversation

@spawnia

@spawnia spawnia commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Make conductors work without remote channels (Telegram/Slack/Discord). A conductor is just a session — you interact with it in the TUI or via session send from the CLI. Remote channels become optional add-ons configured behind a setup gateway question.

Changes

  • Setup wizard restructured — "Add remote channels?" gateway (defaults N) hides all channel prompts. Local-only setup skips bridge config and heartbeat daemon.
  • Heartbeat logic fixed — heartbeat auto-enables only when remote channels are configured. --heartbeat force-enables it for local use. --no-heartbeat actually disables it (previously --heartbeat=false was ignored due to a fs.Visit bug).
  • Templates channel-agnostic — conductor instructions reference TUI/CLI as primary interaction, remote channels as optional. No behavioral branching between local and remote.
  • Documentation consolidated — removed docs/CONDUCTOR-SETUP.md and documentation/CONDUCTOR.md, replaced with docs/conductor/README.md (local-first framing) plus per-channel pages (telegram, slack, discord).
  • Diagrams regenerated — replaced opaque PNGs with d2 source files + rendered SVGs. Diagrams now reflect the local-first model (User → TUI/CLI direct, remote channels optional). Open to restoring PNGs if someone knows how the originals were produced — the SVGs are functionally correct but less polished.
  • Setup summary — "Next steps" output adapts: shows TUI/CLI instructions for local-only, shows bridge logs + bot test commands when channels are configured.

Design decisions

  • Local is NOT a channel — it's the default. No new TUI features needed.
  • Conductor template is unified. Escalation = ask a question and enter waiting state. Delivery mechanism is transparent.
  • condDir computation moved inside channels-configured branch (dead code in local path).

Test plan

  • go build passes
  • go test ./cmd/agent-deck/ -run Conductor passes
  • conductor setup local-test (answer N to channels) — clean output, no heartbeat installed
  • conductor setup remote-test with channels — heartbeat installed, bridge logs path shown
  • --no-heartbeat flag actually disables heartbeat
  • --heartbeat force-enables heartbeat without channels

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Redesigned setup wizard: gateway prompt to optionally add remote channels and conditional prompts for Telegram/Slack/Discord.
    • Improved heartbeat controls: explicit force-enable, idle-minute handling, and installer skips heartbeat when not forced and no remote channels (emits “Heartbeat skipped…”).
  • Documentation

    • Added diagrams: channels topology, conductor overview, fleet topology.
    • Updated setup “Next steps”, shortened help text, and revised instruction templates and messaging for notifications/quick-commands.

spawnia added 7 commits June 9, 2026 11:18
The wizard now explains that conductors work locally by default and gates
all channel prompts (Telegram/Slack/Discord) behind a single "Add remote
channels?" question that defaults to N. When no channels are configured
the bridge and heartbeat daemon are not installed, and the "next steps"
output focuses on TUI and CLI usage.

Heartbeat is still installable in local-only mode via explicit
--heartbeat flag for users who want periodic nudges without a bridge.

🤖 Generated with Claude Code
The conductor doesn't need to know HOW escalations reach the user.
Whether via TUI or a remote channel bridge is transparent — the
conductor asks its question and enters a waiting state.

🤖 Generated with Claude Code
…aming

Merge docs/CONDUCTOR-SETUP.md and documentation/CONDUCTOR.md into a single
authoritative guide at docs/conductor/README.md that leads with a two-minute
local quickstart (no Telegram required). Channel-specific setup extracted
into sibling files (telegram.md, slack.md, discord.md).

All cross-references in README.md, WATCHER-SETUP.md, and SKILL.md updated.
Images moved to docs/conductor/assets/.

🤖 Generated with Claude Code
- Fix wrong CLI command in local-only next-steps: `conductor send` → `session send`
- Restructure heartbeat skip condition to positive form for readability
- Extract yesAnswer() helper for repeated y/yes check pattern

🤖 Generated with Claude Code
The summary printed `Heartbeat: true` even when the heartbeat was
skipped due to no remote channels being configured. Move the effective
heartbeat decision to after the wizard completes so meta.json and the
summary reflect whether the daemon will actually run.

🤖 Generated with Claude Code
The `--heartbeat=false` flag installed heartbeat anyway because fs.Visit
set heartbeatExplicit=true regardless of the flag value. Replace with
direct value checks so --no-heartbeat actually disables heartbeat.

Update templates and docs to not assume remote channels (Telegram/Slack)
are always present — local-first conductors interact via TUI/CLI.

🤖 Generated with Claude Code
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: bbe79c5f-6ad5-4bbd-89e7-97186654771c

📥 Commits

Reviewing files that changed from the base of the PR and between 700a53b and ce30830.

⛔ Files ignored due to path filters (1)
  • skills/agent-deck/SKILL.md is excluded by !**/*.md
📒 Files selected for processing (1)
  • internal/session/conductor_templates.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/session/conductor_templates.go

📝 Walkthrough

Walkthrough

The PR refactors the conductor setup command to gate remote-channel configuration behind an initial yes/no gateway prompt, tightens heartbeat enablement logic to respect explicit forcing and channel presence, updates post-setup guidance, adds three architecture diagrams, and aligns conductor instruction templates to describe direct user interaction via TUI/CLI/remote channels rather than legacy bridge forwarding.

Changes

Conductor Setup Refinement and Documentation

Layer / File(s) Summary
Input Parsing and Heartbeat Enablement Logic
cmd/agent-deck/conductor_cmd.go
Added yesAnswer helper for consistent yes/no parsing. Updated --heartbeat flag description to clarify force-enable semantics. Restructured heartbeat decision logic with heartbeatExplicit derived from both --heartbeat and --heartbeat-idle-minutes flags, introduced channelsConfigured to auto-disable heartbeat when no Telegram/Slack/Discord are configured unless explicitly forced, and added a skip message when heartbeat is bypassed due to missing remote channels.
Interactive Remote-Channel Setup with Gateway Prompt
cmd/agent-deck/conductor_cmd.go
Reworked first-time remote-channel configuration to ask a gating question ("Add remote channels…") and conditionally prompt for Telegram/Slack/Discord details only if the user opts in, using the new yesAnswer helper and conditional skip logic; updates stored config and presence flags accordingly.
Post-Setup Guidance Messages
cmd/agent-deck/conductor_cmd.go
Updated "Next steps" output: reordered session-start instructions when remote channels are configured; replaced per-channel "add later" messaging with a numbered start/interact/CLI-send instruction set and a single reminder to re-run setup to add remote channels later.
System Architecture Diagrams
docs/conductor/assets/channels-topology.d2, docs/conductor/assets/conductor-overview.d2, docs/conductor/assets/fleet-topology.d2
Added three D2 diagrams: channels-topology visualizes users/bots/conductors with a "one bot per conductor" footer; conductor-overview depicts TUI/channels/watchers/children interactions around a central conductor; fleet-topology illustrates conductor orchestration of child sessions and watchers.

Conductor Instruction Template Updates

Layer / File(s) Summary
Shared CLAUDE Template Messaging Model
internal/session/conductor_templates.go
Updated shared CLAUDE template's heartbeat response guidance, quick commands section, and important notes to describe forwarding via configured remote channels or TUI/task-log and CLI-based interaction instead of Telegram/Slack bridge forwarding.
Per-Conductor Interaction Descriptions
internal/session/conductor_templates.go
Updated interaction bullets in CLAUDE per-conductor templates (standard, pre-learnings, legacy variants) and Hermes per-conductor template to describe direct TUI/CLI/remote-channel user interaction instead of bridge message forwarding.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • asheshgoplani
🚥 Pre-merge checks | ✅ 6 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Test_coverage_per_surface ⚠️ Warning Repo has only flag-arg parsing tests for conductor setup (cmd/agent-deck/conductor_cmd_test.go). Repo-wide search finds 0 tests mentioning “Add remote channels?”, “Next steps”, or “Heartbeat skip... Add CLI tests that exercise conductor setup local-only (answer N) vs remote (answer Y), asserting bridge config + heartbeat daemon/script install/skip, and verify --no-heartbeat/--heartbeat behavior and “Next steps” output.
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title follows Conventional Commits format with 'feat' prefix and describes the main architectural change of enabling local-first conductor support.
Docstring Coverage ✅ Passed Docstring coverage is 75.00% which is sufficient. The required threshold is 70.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Remote_parity ✅ Passed RemoteSession is handled by TUI: internal/ui/home.go renders RemoteSession rows (renderRemoteSessionItem uses item.RemoteSession), and remote_session_* tests assert behavior without any t.Skip.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@spawnia spawnia changed the title local first conductors feat(conductor): local-first conductor support Jun 10, 2026
Replace opaque PNGs with d2 source files and rendered SVGs.
Diagrams now reflect the local-first model: User connects via
TUI/CLI (direct) or remote channels (optional).

🤖 Generated with Claude Code
@spawnia spawnia marked this pull request as ready for review June 10, 2026 09:00
@spawnia spawnia requested a review from asheshgoplani as a code owner June 10, 2026 09:00

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
internal/session/conductor_templates.go (1)

93-93: ⚡ Quick win

Consider depersonalizing "the bridge" reference for local-only accuracy.

Line 93 states "The bridge parses your response" but in local-only mode (with --heartbeat flag), there is no bridge—an OS daemon (launchd/systemd) triggers heartbeats and the conductor's output remains in the TUI/task-log. While the conductor's behavior is unchanged, the architectural description is imprecise.

📝 Suggested rewording for architectural accuracy
-The bridge parses your response: if it contains ` + "`" + `NEED:` + "`" + ` lines, those get forwarded to the user (via remote channels if configured, or visible in the TUI/task-log).
+Your response is parsed: if it contains ` + "`" + `NEED:` + "`" + ` lines, those get forwarded to the user (via remote channels if configured, or visible in the TUI/task-log).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/session/conductor_templates.go` at line 93, Replace the phrase "The
bridge parses your response" in the template (the exact string "The bridge
parses your response: if it contains `NEED:` lines, those get forwarded to the
user...") with a depersonalized description such as "Responses are parsed: if
they contain `NEED:` lines, those get forwarded to the user (via remote channels
if configured, or visible in the TUI/task-log)." Update the string in
internal/session/conductor_templates.go so it no longer references "the bridge"
but preserves the rest of the sentence and meaning.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/agent-deck/conductor_cmd.go`:
- Around line 292-430: The gateway/channel prompt block must run not only when
settings.Enabled is false but also when the conductor is enabled yet has no
remote channels configured; move the entire prompt sequence (the code
interacting with reader and setting telegram/slack/discord and the boolean flags
telegramConfigured/slackConfigured/discordConfigured) out of the strict if
!settings.Enabled guard and wrap it in a condition like if !settings.Enabled ||
!(settings.TelegramConfigured || settings.SlackConfigured ||
settings.DiscordConfigured); after collecting answers, merge non-empty
session.TelegramSettings, session.SlackSettings, session.DiscordSettings back
into the existing settings object (updating settings.TelegramSettings,
settings.SlackSettings, settings.DiscordSettings and settings.Enabled as
appropriate) instead of creating new local-only values so the config persists
for later runs.
- Around line 147-148: printConductorHelp() still describes "setup <name>" as
creating a “bridge” and thus advertises the old pre-local-first behavior; update
the help strings inside printConductorHelp() (the function that prints the
top-level conductor --help) to reflect the new local-first behavior (replace
language like "create a bridge" with the new behavior description for setup
<name>) and scan other hard-coded help lines in that function to ensure they
match the updated setup subcommand text (including any mention of heartbeat or
remote channels).
- Around line 694-696: The printed CLI example for sending to a session omits
the profile flag, which will mis-target non-default profiles: update the usage
message that references sessionTitle so it includes the resolvedProfile flag
(use resolvedProfile and sessionTitle from this function) — replace the current
fmt.Printf that prints "agent-deck session send %s ..." with one that includes
"-p %s" before "session send" and formats both resolvedProfile and sessionTitle
accordingly so the example targets the same profile used to register the
conductor.

---

Nitpick comments:
In `@internal/session/conductor_templates.go`:
- Line 93: Replace the phrase "The bridge parses your response" in the template
(the exact string "The bridge parses your response: if it contains `NEED:`
lines, those get forwarded to the user...") with a depersonalized description
such as "Responses are parsed: if they contain `NEED:` lines, those get
forwarded to the user (via remote channels if configured, or visible in the
TUI/task-log)." Update the string in internal/session/conductor_templates.go so
it no longer references "the bridge" but preserves the rest of the sentence and
meaning.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b4e0df03-fa36-4beb-816c-ef032ba2622c

📥 Commits

Reviewing files that changed from the base of the PR and between 4541d10 and 9ffc4ad.

⛔ Files ignored due to path filters (13)
  • README.md is excluded by !**/*.md
  • conductor/conductor-claude.md is excluded by !**/*.md
  • docs/CONDUCTOR-SETUP.md is excluded by !**/*.md
  • docs/WATCHER-SETUP.md is excluded by !**/*.md
  • docs/conductor/README.md is excluded by !**/*.md
  • docs/conductor/assets/channels-topology.svg is excluded by !**/*.svg
  • docs/conductor/assets/conductor-overview.svg is excluded by !**/*.svg
  • docs/conductor/assets/fleet-topology.svg is excluded by !**/*.svg
  • docs/conductor/discord.md is excluded by !**/*.md
  • docs/conductor/slack.md is excluded by !**/*.md
  • docs/conductor/telegram.md is excluded by !**/*.md
  • documentation/CONDUCTOR.md is excluded by !**/*.md, !documentation/**
  • skills/agent-deck/SKILL.md is excluded by !**/*.md
📒 Files selected for processing (5)
  • cmd/agent-deck/conductor_cmd.go
  • docs/conductor/assets/channels-topology.d2
  • docs/conductor/assets/conductor-overview.d2
  • docs/conductor/assets/fleet-topology.d2
  • internal/session/conductor_templates.go

Comment thread cmd/agent-deck/conductor_cmd.go
Comment thread cmd/agent-deck/conductor_cmd.go
Comment thread cmd/agent-deck/conductor_cmd.go Outdated
spawnia added 2 commits June 10, 2026 11:30
- Add missing -p profile flag in local-only CLI example
- Remove stale "bridge" reference in help and template text
- Allow re-running setup to add channels when none configured

🤖 Generated with Claude Code
The channel-configured flags are now set after the merge logic at the
end of the setup block, making the mid-wizard assignments dead code.

🤖 Generated with Claude Code

Copy link
Copy Markdown
Owner

🤖 autopilot: CI green + Claude review clean; FLAGGED for local Codex dual-review before merge (data-sensitive area).

This PR touches conductor template generation, heartbeat config writing, and conductor setup flow — all config-writing paths. Per autopilot policy, PRs modifying config-writing or conductor persistence require a local Codex dual-review before merge. No code issues found in this review pass; the flag is precautionary.


Generated by Claude Code

@asheshgoplani asheshgoplani added needs-design Requires design work before implementation enhancement New feature or request labels Jun 11, 2026
@asheshgoplani

Copy link
Copy Markdown
Owner

Maintainer design decision: local-first conductor support is an architectural direction call rather than a routine fix, so it's outside tonight's merge batch and awaiting maintainer sign-off. Labeled needs-design.

Copy link
Copy Markdown
Owner

🤖 autopilot: CI is green, but this PR carries a needs-design label and represents a significant conductor architecture change (local-first reframing, setup wizard restructure, docs consolidation). Not merging without explicit maintainer approval. Holding for design sign-off.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request needs-design Requires design work before implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants