From 0825c74b693efa4c6c260ff882275b6e79c9cf89 Mon Sep 17 00:00:00 2001
From: marcusquinn <6428977+marcusquinn@users.noreply.github.com>
Date: Thu, 5 Mar 2026 23:14:14 +0000
Subject: [PATCH 1/2] fix: add process guard to setup.sh and enable pulse
RunAtLoad for reboot survival
Two changes to prevent kernel panics from runaway processes:
1. Pulse plist: RunAtLoad=true so the supervisor pulse restarts after
reboot/panic. Previously RunAtLoad=false meant the pulse never
restarted, leaving the system unmonitored after crashes.
2. Process guard: Added to setup.sh so all users get it on install/update.
Previously the guard plist was manually created and not managed by
setup. Now installs automatically:
- macOS: launchd plist, 30s interval (was 120s), RunAtLoad=true
- Linux: cron entry, every minute (cron minimum granularity)
- No consent needed (safety net, not autonomous action)
- Kills ShellCheck processes >512MB RSS or >120s runtime
- Kills other AI processes >8GB RSS or >2h runtime
Context: 5 kernel panics in one day from watchdog timeouts caused by
ShellCheck memory bloat (2GB+ per instance) exhausting the compressor
segment limit. The shellcheck-wrapper.sh (PR #2918) fixes the root
cause; this ensures the guard catches any remaining edge cases.
---
setup.sh | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 78 insertions(+), 1 deletion(-)
diff --git a/setup.sh b/setup.sh
index 87ad5514a1..46790bafd6 100755
--- a/setup.sh
+++ b/setup.sh
@@ -900,7 +900,7 @@ main() {
1800
RunAtLoad
-
+
KeepAlive
@@ -977,6 +977,83 @@ PLIST
fi
fi
+ # Process guard — kills runaway AI processes (ShellCheck bloat, stuck workers)
+ # before they exhaust memory and cause kernel panics. Always installed when the
+ # script exists; no consent needed (safety net, not autonomous action).
+ # macOS: launchd plist (30s interval, RunAtLoad=true) | Linux: cron (every minute)
+ local guard_script="$HOME/.aidevops/agents/scripts/process-guard-helper.sh"
+ local guard_label="sh.aidevops.process-guard"
+ if [[ -x "$guard_script" ]]; then
+ mkdir -p "$HOME/.aidevops/logs"
+
+ if [[ "$(uname -s)" == "Darwin" ]]; then
+ local guard_plist="$HOME/Library/LaunchAgents/${guard_label}.plist"
+
+ # Unload old plist if upgrading
+ if _launchd_has_agent "$guard_label"; then
+ launchctl unload "$guard_plist" 2>/dev/null || true
+ fi
+
+ cat >"$guard_plist" <
+
+
+
+ Label
+ ${guard_label}
+ ProgramArguments
+
+ ${guard_script}
+ kill-runaways
+
+ StartInterval
+ 30
+ StandardOutPath
+ ${HOME}/.aidevops/logs/process-guard.log
+ StandardErrorPath
+ ${HOME}/.aidevops/logs/process-guard.log
+ EnvironmentVariables
+
+ PATH
+ /opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
+ SHELLCHECK_RSS_LIMIT_KB
+ 524288
+ SHELLCHECK_RUNTIME_LIMIT
+ 120
+ CHILD_RSS_LIMIT_KB
+ 8388608
+ CHILD_RUNTIME_LIMIT
+ 7200
+
+ RunAtLoad
+
+ KeepAlive
+
+
+
+GUARD_PLIST
+
+ if launchctl load "$guard_plist" 2>/dev/null; then
+ print_info "Process guard enabled (launchd, every 30s, survives reboot)"
+ else
+ print_warning "Failed to load process guard LaunchAgent"
+ fi
+ else
+ # Linux: cron entry (every minute — cron minimum granularity)
+ if ! crontab -l 2>/dev/null | grep -qF "aidevops: process-guard" 2>/dev/null; then
+ (
+ crontab -l 2>/dev/null | grep -v 'aidevops: process-guard'
+ echo "* * * * * SHELLCHECK_RSS_LIMIT_KB=524288 SHELLCHECK_RUNTIME_LIMIT=120 CHILD_RSS_LIMIT_KB=8388608 CHILD_RUNTIME_LIMIT=7200 /bin/bash ${guard_script} kill-runaways >> \$HOME/.aidevops/logs/process-guard.log 2>&1 # aidevops: process-guard"
+ ) | crontab - 2>/dev/null || true
+ fi
+ if crontab -l 2>/dev/null | grep -qF "aidevops: process-guard" 2>/dev/null; then
+ print_info "Process guard enabled (cron, every minute)"
+ else
+ print_warning "Failed to install process guard cron entry"
+ fi
+ fi
+ fi
+
echo ""
echo "CLI Command:"
echo " aidevops init - Initialize aidevops in a project"
From 97cbf06d5cf7f741266f39da13ca45af7dfe8cd9 Mon Sep 17 00:00:00 2001
From: marcusquinn <6428977+marcusquinn@users.noreply.github.com>
Date: Thu, 5 Mar 2026 23:56:10 +0000
Subject: [PATCH 2/2] =?UTF-8?q?fix:=20address=20review=20feedback=20?=
=?UTF-8?q?=E2=80=94=20dynamic=20PATH,=20HOME=20env,=20quoted=20cron=20pat?=
=?UTF-8?q?hs,=20remove=20stderr=20suppression?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Use dynamic ${PATH} and add ${HOME} to guard plist env vars for
consistency with the pulse plist pattern (CodeRabbit, Gemini)
- Remove 2>/dev/null from launchctl unload/load — || true handles
errors, stderr aids debugging (Gemini)
- Quote paths in cron entry to handle spaces in paths (Gemini)
- Always regenerate cron entry to pick up config changes, matching
macOS plist behavior (CodeRabbit)
---
setup.sh | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/setup.sh b/setup.sh
index 46790bafd6..3d3f0b7eb1 100755
--- a/setup.sh
+++ b/setup.sh
@@ -991,7 +991,7 @@ PLIST
# Unload old plist if upgrading
if _launchd_has_agent "$guard_label"; then
- launchctl unload "$guard_plist" 2>/dev/null || true
+ launchctl unload "$guard_plist" || true
fi
cat >"$guard_plist" <EnvironmentVariables
PATH
- /opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
+ ${PATH}
+ HOME
+ ${HOME}
SHELLCHECK_RSS_LIMIT_KB
524288
SHELLCHECK_RUNTIME_LIMIT
@@ -1033,19 +1035,18 @@ PLIST
GUARD_PLIST
- if launchctl load "$guard_plist" 2>/dev/null; then
+ if launchctl load "$guard_plist"; then
print_info "Process guard enabled (launchd, every 30s, survives reboot)"
else
print_warning "Failed to load process guard LaunchAgent"
fi
else
# Linux: cron entry (every minute — cron minimum granularity)
- if ! crontab -l 2>/dev/null | grep -qF "aidevops: process-guard" 2>/dev/null; then
- (
- crontab -l 2>/dev/null | grep -v 'aidevops: process-guard'
- echo "* * * * * SHELLCHECK_RSS_LIMIT_KB=524288 SHELLCHECK_RUNTIME_LIMIT=120 CHILD_RSS_LIMIT_KB=8388608 CHILD_RUNTIME_LIMIT=7200 /bin/bash ${guard_script} kill-runaways >> \$HOME/.aidevops/logs/process-guard.log 2>&1 # aidevops: process-guard"
- ) | crontab - 2>/dev/null || true
- fi
+ # Always regenerate to pick up config changes (matches macOS behavior)
+ (
+ crontab -l 2>/dev/null | grep -v 'aidevops: process-guard'
+ echo "* * * * * SHELLCHECK_RSS_LIMIT_KB=524288 SHELLCHECK_RUNTIME_LIMIT=120 CHILD_RSS_LIMIT_KB=8388608 CHILD_RUNTIME_LIMIT=7200 /bin/bash \"${guard_script}\" kill-runaways >> \"\$HOME/.aidevops/logs/process-guard.log\" 2>&1 # aidevops: process-guard"
+ ) | crontab - 2>/dev/null || true
if crontab -l 2>/dev/null | grep -qF "aidevops: process-guard" 2>/dev/null; then
print_info "Process guard enabled (cron, every minute)"
else