Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 38 additions & 8 deletions .agents/scripts/commands/runners.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ See `pulse.md` for the full spec.

### Pulse Scheduler Setup

The pulse runs via a macOS launchd plist. If the plist doesn't exist (fresh install, new machine, or after a crash that deleted it), create it:
The pulse scheduler runs every 2 minutes and dispatches workers. Setup depends on your OS.

#### macOS (launchd)

If the plist doesn't exist (fresh install, new machine, or after a crash that deleted it), create it:

```bash
# 1. Get the opencode binary path and user PATH for the plist
Expand Down Expand Up @@ -92,25 +96,51 @@ launchctl load ~/Library/LaunchAgents/com.aidevops.aidevops-supervisor-pulse.pli
- `StartInterval: 120` — fires every 2 minutes
- The `pgrep` guard prevents overlapping pulses (if a previous pulse is still running, skip)

#### Linux (cron)

One cron entry with a pgrep guard to prevent overlapping pulses:

```bash
mkdir -p ~/.aidevops/logs

# Add to crontab (every 2 minutes)
(crontab -l 2>/dev/null; echo "*/2 * * * * pgrep -f 'Supervisor Pulse' >/dev/null || $(which opencode) run \"/pulse\" --dir $HOME/Git/aidevops -m anthropic/claude-sonnet-4-6 --title \"Supervisor Pulse\" >> $HOME/.aidevops/logs/pulse.log 2>&1 # aidevops: supervisor-pulse") | crontab -
```

**Key settings:**
- `*/2 * * * *` — fires every 2 minutes
- `pgrep` guard prevents overlapping pulses (if a previous pulse is still running, skip)
- Uses full path to `opencode` since cron has a minimal `PATH`

### Enable / Disable / Verify

```bash
# Enable automated pulse
## macOS
# Enable
launchctl load ~/Library/LaunchAgents/com.aidevops.aidevops-supervisor-pulse.plist

# Disable automated pulse
# Disable
launchctl unload ~/Library/LaunchAgents/com.aidevops.aidevops-supervisor-pulse.plist

# Check if loaded
# Check
launchctl list | grep aidevops-supervisor-pulse

# Check recent output
## Linux
# Check
crontab -l | grep supervisor-pulse
# Disable
crontab -l | grep -v 'supervisor-pulse' | crontab -
# Re-enable — run the install command above

# Both platforms — check recent output
tail -50 ~/.aidevops/logs/pulse.log
```

### After Reboot

The pulse auto-starts on login (`RunAtLoad: true`). Old workers don't survive reboot — the first pulse cycle sees 0 workers, 6 empty slots, and dispatches fresh work. No manual intervention needed.
**macOS:** The pulse auto-starts on login (`RunAtLoad: true`).

**Linux:** Cron runs automatically after reboot — no extra config needed.

Old workers don't survive reboot on either platform — the first pulse cycle sees 0 workers, 6 empty slots, and dispatches fresh work. No manual intervention needed.

## Interactive Mode: `/runners`

Expand Down
70 changes: 39 additions & 31 deletions setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -663,49 +663,58 @@ main() {
fi

# Enable supervisor pulse scheduler if not already installed
# This is REQUIRED for autonomous task orchestration (dispatch, evaluation, cleanup)
local supervisor_script="$HOME/.aidevops/agents/scripts/supervisor-helper.sh"
if [[ -x "$supervisor_script" ]] && [[ "${AIDEVOPS_SUPERVISOR_PULSE:-true}" != "false" ]]; then
# The pulse dispatches AI workers via opencode run "/pulse" every 2 minutes.
# macOS: launchd plist | Linux: cron entry
local opencode_path
opencode_path=$(command -v opencode 2>/dev/null) || opencode_path=""
if [[ -n "$opencode_path" ]] && [[ "${AIDEVOPS_SUPERVISOR_PULSE:-true}" != "false" ]]; then
local _pulse_installed=false
if _launchd_has_agent "com.aidevops.aidevops-supervisor-pulse"; then
_pulse_installed=true
elif _launchd_has_agent "com.aidevops.supervisor-pulse"; then
# Old label — re-running install will migrate to new label
if bash "$supervisor_script" cron install >/dev/null 2>&1; then
print_info "Supervisor pulse LaunchAgent migrated to new label"
else
print_warning "Supervisor pulse label migration failed. Run: supervisor-helper.sh cron install"
fi
_pulse_installed=true
elif crontab -l 2>/dev/null | grep -qF "aidevops-supervisor-pulse"; then
if [[ "$(uname -s)" == "Darwin" ]]; then
# macOS: cron entry exists but no launchd plist — migrate
if bash "$supervisor_script" cron install >/dev/null 2>&1; then
print_info "Supervisor pulse migrated from cron to launchd"
else
print_warning "Supervisor pulse cron→launchd migration failed. Run: supervisor-helper.sh cron install"
fi
local _aidevops_dir
_aidevops_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

if [[ "$(uname -s)" == "Darwin" ]]; then
# macOS: check launchd
if _launchd_has_agent "com.aidevops.aidevops-supervisor-pulse"; then
_pulse_installed=true
fi
fi
# Both platforms: check cron
if [[ "$_pulse_installed" == "false" ]] && crontab -l 2>/dev/null | grep -qF "aidevops: supervisor-pulse"; then
_pulse_installed=true
fi

if [[ "$_pulse_installed" == "false" ]]; then
local _install_pulse=false
if [[ "$NON_INTERACTIVE" == "true" ]]; then
bash "$supervisor_script" cron install >/dev/null 2>&1 || true
print_info "Supervisor pulse enabled (every 2 min). Disable: supervisor-helper.sh cron uninstall"
_install_pulse=true
else
echo ""
echo "The supervisor pulse enables autonomous orchestration:"
echo " - Dispatches AI workers to implement tasks from TODO.md"
echo " - Evaluates results, merges passing PRs, cleans up branches"
echo " - Auto-picks up #auto-dispatch tasks across all managed repos"
echo " - Dispatches AI workers to implement tasks from GitHub issues"
echo " - Merges passing PRs, observes outcomes, files improvement issues"
echo " - 4-hourly strategic review (opus-tier) for queue health"
echo " - Circuit breaker pauses dispatch on consecutive failures"
echo ""
read -r -p "Enable supervisor pulse? [Y/n]: " enable_pulse
if [[ "$enable_pulse" =~ ^[Yy]?$ || -z "$enable_pulse" ]]; then
bash "$supervisor_script" cron install
_install_pulse=true
else
print_info "Skipped. Enable later — see: runners.md 'Pulse Scheduler Setup'"
fi
fi

if [[ "$_install_pulse" == "true" ]]; then
mkdir -p "$HOME/.aidevops/logs"
local _pulse_cmd="$opencode_path run \"/pulse\" --dir $_aidevops_dir -m anthropic/claude-sonnet-4-6 --title \"Supervisor Pulse\""
# Install as cron entry (works on both macOS and Linux)
(
crontab -l 2>/dev/null | grep -v 'aidevops: supervisor-pulse'
echo "*/2 * * * * pgrep -f 'Supervisor Pulse' >/dev/null || $_pulse_cmd >> $HOME/.aidevops/logs/pulse.log 2>&1 # aidevops: supervisor-pulse"
) | crontab - 2>/dev/null || true
if crontab -l 2>/dev/null | grep -qF "aidevops: supervisor-pulse"; then
print_info "Supervisor pulse enabled (cron, every 2 min). Disable: crontab -e and remove the supervisor-pulse line"
else
print_info "Skipped. Enable later: supervisor-helper.sh cron install"
print_warning "Failed to install supervisor pulse cron entry. See runners.md for manual setup."
fi
fi
fi
Expand Down Expand Up @@ -758,7 +767,7 @@ main() {
echo "2. Setup Git CLI tools and authentication (shown during setup)"
echo "3. Setup API keys: bash .agents/scripts/setup-local-api-keys.sh setup"
echo "4. Test access: ./.agents/scripts/servers-helper.sh list"
echo "5. Enable orchestration: supervisor-helper.sh cron install (autonomous task dispatch)"
echo "5. Enable orchestration: see runners.md 'Pulse Scheduler Setup' (autonomous task dispatch)"
echo "6. Read documentation: ~/.aidevops/agents/AGENTS.md"
echo ""
echo "For development on aidevops framework itself:"
Expand Down Expand Up @@ -809,8 +818,7 @@ main() {
echo "• Circuit breaker - Pauses dispatch on consecutive failures"
echo ""
echo " The supervisor pulse was offered during setup. If skipped, enable later:"
echo " supervisor-helper.sh cron install"
echo " See: ~/.aidevops/agents/reference/orchestration.md"
echo " See: ~/.aidevops/agents/scripts/commands/runners.md 'Pulse Scheduler Setup'"
echo ""
echo " Run /onboarding in your AI assistant to configure services interactively."
echo ""
Expand Down