feat(ops-speedup): v2 parity — GPU/ANE + power hogs + OS-agnostic actions#140
feat(ops-speedup): v2 parity — GPU/ANE + power hogs + OS-agnostic actions#140auroracapital merged 2 commits intomainfrom
Conversation
…s + OS-agnostic actions Brings ops-speedup to parity with the local hyper-tuned speedup script while keeping the cross-platform contract (macOS / Linux / WSL / Windows). ## Binary (bin/ops-speedup) New flags: --scan, --clean, --deep, --aggressive (combinable with --json) ### Probes (parallel, OS-dispatched) - CPU hogs, power/Energy Impact hogs (top -stats power on macOS, powertop on Linux) - GPU + Neural Engine hogs (powermetrics on macOS, nvidia-smi on Linux) - Disk reclaimable: brew, npm, pnpm, yarn, Xcode DerivedData+DeviceSupport, Metal shader cache, Docker, Trash, logs, Downloads, /tmp, apt, journal - Memory + swap, network (iface + DNS), startup (login items, launch agents, systemd enabled/failed units) ### Actions (OS-agnostic dispatcher) - Cache cleanup (OS-specific paths) - Package manager prune (brew / pnpm / cargo / docker) - CPU + power hog kill (protected-process regex blocks shells, IDEs, daemons) - Background daemon demotion (taskpolicy -b on macOS; renice +10 + ionice -c3 on Linux) - Kernel tuning — only raise, never lower (vnodes/somaxconn on macOS; somaxconn/file-max + BBR under --aggressive on Linux) - DNS flush (dscacheutil on macOS; systemd-resolve on Linux; ipconfig.exe on WSL) - Memory purge (macOS purge; drop_caches on Linux) - Deep mode: Xcode DerivedData + simulators, Trash empty, apt autoremove, UI animation cuts (macOS only) - Aggressive: launch-agent unload (macOS) / systemd-unit mask (Linux), stale node_modules/.next/dist >14 days, docker --volumes ### Reliability - Idempotency guard: skips DerivedData/Metro/journal if last run <1h ago - Structured telemetry: appends JSONL to ~/.ops-speedup/history.jsonl - Single pre-seeded sudo for parallel-phase auth - All destructive actions gated behind mode flags ## Skill (skills/ops-speedup/SKILL.md) - Removed duplicated serial probe block (binary runs them parallel) - Added OS-capability matrix - Added per-action confirmation flow for --aggressive (Rule 5 compliance) - Added trend analysis snippet using history.jsonl ## Testing - tests/test-no-secrets.sh: 11/11 pass - tests/test-bin-scripts.sh: 88/88 pass (shellcheck clean) - End-to-end macOS: --scan, --clean, --deep all exit 0 - Reclaimed 2.4 GB disk, 695 MB RAM, 32 MB swap on first run - Idempotency guard correctly skips DerivedData on subsequent <1h run Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 22 minutes and 50 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
…ection (SEV-9) Four eval blocks loading probe vars from subprocess output accepted arbitrary keys including shell metacharacters. Replaced with declare -g and an alphanumeric+underscore key allowlist. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| elif $IS_LINUX || $IS_WSL; then | ||
| if sudo -n true 2>/dev/null; then | ||
| sync; echo 3 | sudo tee /proc/sys/vm/drop_caches >/dev/null 2>&1 || true | ||
| echo " ${GRN}✓${RST} Memory caches dropped" | ||
| fi | ||
| fi |
There was a problem hiding this comment.
Bug: Linux drop_caches fires unconditionally — defeats the tool's purpose on dev machines
The macOS branch correctly gates purge on actual memory pressure:
if (( pressure < 30 || swap > 200 )) && sudo -n true 2>/dev/null; thenThe Linux/WSL branch has no such guard — it drops all page cache, inodes, and dentries on every --clean run as long as sudo -n succeeds. On a developer machine in the middle of a build or with a large open codebase, echo 3 > /proc/sys/vm/drop_caches forces the kernel to evict all cached file data, causing the next git grep, make, or IDE file-watcher pass to repopulate the cache from disk — potentially making the machine measurably slower for several minutes after the "speedup" run.
Suggested fix — apply the same pressure threshold as macOS:
elif $IS_LINUX || $IS_WSL; then
local pressure swap
pressure=${MEM_pressure_pct:-100}
swap=${MEM_swap_mb:-0}
pressure=$(echo "$pressure" | awk -F. '{print int($1+0)}')
swap=$(echo "$swap" | awk -F. '{print int($1+0)}')
if (( pressure < 30 || swap > 200 )) && sudo -n true 2>/dev/null; then
sync; echo 3 | sudo tee /proc/sys/vm/drop_caches >/dev/null 2>&1 || true
echo " ${GRN}✓${RST} Memory caches dropped (pressure=${pressure}% free, swap=${swap}MB)"
fi
fiNote: MEM_pressure_pct on Linux is already the free percentage (avail * 100 / total), so the < 30 threshold matches the macOS semantics.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b877e870e7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if $MODE_SCAN; then | ||
| probe_power_hogs "$tmp/power" & | ||
| probe_gpu_ane "$tmp/gpu" & | ||
| fi |
There was a problem hiding this comment.
Run power-hog probe for cleanup modes
action_kill_hogs tries to terminate entries from POWER_HOGS_FILE, but run_parallel_scan only launches probe_power_hogs when MODE_SCAN is true. Standard cleanup paths (--clean, --deep, --aggressive) set MODE_CLEAN without MODE_SCAN, so no power-hog file is produced and power-hog termination is silently skipped in the modes where killing hogs is expected.
Useful? React with 👍 / 👎.
| "reclaimable_mb": { | ||
| "brew_cache": $BREW_CACHE, | ||
| "npm_cache": $NPM_CACHE, | ||
| "xcode_derived": $XCODE_DERIVED, | ||
| "docker": $DOCKER_RECLAIMABLE, | ||
| "trash": $TRASH_SIZE, | ||
| "logs": $LOG_SIZE, | ||
| "downloads": $DOWNLOADS_SIZE, | ||
| "tmp": $TMP_SIZE | ||
| "brew_cache": ${DISK_brew_cache:-0}, | ||
| "npm_cache": ${DISK_npm_cache:-0}, | ||
| "pnpm_cache": ${DISK_pnpm_cache:-0}, | ||
| "yarn_cache": ${DISK_yarn_cache:-0}, |
There was a problem hiding this comment.
Include hog probe results in scan JSON
--scan is documented and consumed as the full probe payload, but emit_json serializes disk/memory/network/startup only and omits cpu_hogs/power_hogs/gpu data entirely. That means downstream automation cannot render or act on top hog lists from scan output, despite run_parallel_scan collecting those probe files.
Useful? React with 👍 / 👎.
| `~/.ops-speedup/history.jsonl` is append-only. For trend questions ("is my disk filling up?", "is swap growing over time?"), read + graph: | ||
|
|
||
| ```bash | ||
| tail -30 ~/.ops-speedup/history.jsonl | jq -r '[.ts, .ram_free_mb, .swap_mb, .disk_pct] | @tsv' |
There was a problem hiding this comment.
Read telemetry from the correct Linux state path
This command hardcodes ~/.ops-speedup/history.jsonl, but the binary writes Linux/WSL state under ${XDG_STATE_HOME:-$HOME/.local/state}/ops-speedup (it only uses ~/.ops-speedup on macOS). On Linux/WSL, trend analysis will look at the wrong file and report missing/empty history.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 4 potential issues.
Bugbot Autofix is ON, but it could not run because the branch was deleted or merged before autofix could start.
Reviewed by Cursor Bugbot for commit b877e87. Configure here.
| # Load disk vars — key must be alphanumeric+underscore to prevent injection | ||
| while IFS='=' read -r k v; do | ||
| [[ "$k" =~ ^[a-zA-Z0-9_]+$ ]] || continue | ||
| declare -g "DISK_${k}=${v}" |
There was a problem hiding this comment.
declare -g breaks on macOS stock bash 3.2
High Severity
declare -g requires bash 4.2+ but macOS ships bash 3.2 (GPLv3 licensing freeze). Inside run_parallel_scan(), all four declare -g calls will error on stock macOS bash, leaving every DISK_*, MEM_*, NET_*, and STARTUP_* variable unset. This causes emit_json to emit all-default values and, more critically, action_memory_purge to always trigger (MEM_pressure_pct defaults to 0, satisfying pressure < 30). Consider printf -v (available since bash 3.1) or direct assignment with eval (key is already validated).
Additional Locations (2)
Reviewed by Cursor Bugbot for commit b877e87. Configure here.
| sync; echo 3 | sudo tee /proc/sys/vm/drop_caches >/dev/null 2>&1 || true | ||
| echo " ${GRN}✓${RST} Memory caches dropped" | ||
| fi | ||
| fi |
There was a problem hiding this comment.
Linux memory purge ignores pressure/swap thresholds
Medium Severity
On macOS, action_memory_purge gates the purge on pressure < 30 || swap > 200. On Linux/WSL, drop_caches runs unconditionally whenever sudo is cached — no pressure or swap check. This contradicts the PR's test plan ("Memory purge fires when swap > 200MB OR pressure < 30% free") and causes unnecessary filesystem cache eviction on every --clean run, degrading I/O performance for no benefit when memory is healthy.
Reviewed by Cursor Bugbot for commit b877e87. Configure here.
| echo "${BWHT}Cleanup (${OS}):${RST}" | ||
| action_clean_caches | ||
| action_clean_package_managers | ||
| action_kill_hogs |
There was a problem hiding this comment.
Process killing runs in documented non-destructive mode
Medium Severity
action_kill_hogs is called during --clean mode, which the SKILL.md CLI reference table documents as having "Non-destructive" side effects ("Safe cleanup: caches, tmp, logs, demote daemons, DNS flush, kernel tune"). Sending SIGTERM to processes exceeding 30% CPU is destructive and could terminate user workloads. This action fits better in the --deep or --aggressive mode gate.
Reviewed by Cursor Bugbot for commit b877e87. Configure here.
| } | ||
|
|
||
| # ── Helpers ────────────────────────────────────────────────────── | ||
| num() { local v="${1:-0}"; v=$(echo "$v" | tr -cd '0-9.-'); echo "${v:-0}"; } |
There was a problem hiding this comment.
Unused num helper function is dead code
Low Severity
The num() helper function is defined but never called anywhere in the script. A grep for its usage returns only the definition. This is dead code that adds clutter without serving any purpose.
Reviewed by Cursor Bugbot for commit b877e87. Configure here.
| echo "${BWHT}Cleanup (${OS}):${RST}" | ||
| action_clean_caches | ||
| action_clean_package_managers | ||
| action_kill_hogs |
There was a problem hiding this comment.
🔴 --clean mode kills CPU hog processes despite being documented as "Non-destructive"
action_kill_hogs is called at line 714 inside the $MODE_CLEAN block. This function sends SIGTERM to processes identified as CPU hogs (claude-ops/bin/ops-speedup:436). Both the script header (line 9: "safe cleanup (caches, tmp, logs)") and the SKILL.md (line 38: "Safe cleanup: caches, tmp, logs, demote daemons, DNS flush, kernel tune | Non-destructive") explicitly document --clean as non-destructive. Killing processes contradicts this contract. Additionally, the SKILL.md Phase 4 maps the "Quick" option directly to --clean, so users selecting "Quick — caches, tmp, logs, DNS flush" will have processes killed without any indication this would happen.
Documented vs actual --clean behavior
Documented (SKILL.md line 38): caches, tmp, logs, demote daemons, DNS flush, kernel tune
Actual (lines 712-718):
- action_clean_caches ✓
- action_clean_package_managers ✗ (not documented)
- action_kill_hogs ✗ (destructive — kills processes)
- action_demote_background ✓
- action_kernel_tune ✓
- action_dns_flush ✓
- action_memory_purge ✗ (not documented)
Prompt for agents
The action_kill_hogs call on line 714 is inside the MODE_CLEAN block but --clean is documented as non-destructive. Similarly, action_clean_package_managers (line 713) and action_memory_purge (line 718) are not part of --clean's documented scope.
The --clean block (lines 710-731) should be restructured so that only the documented actions run in --clean mode, and the extra actions (kill hogs, package manager cleanup including docker prune, memory purge) are moved into the MODE_DEEP block.
Suggested restructure for lines 710-726:
if MODE_CLEAN:
action_clean_caches
action_demote_background
action_kernel_tune
action_dns_flush
if MODE_DEEP:
action_clean_package_managers (including brew, docker)
action_clean_deep
action_launch_offenders
action_animation_cuts
action_kill_hogs
action_memory_purge
if MODE_AGGRESSIVE:
action_clean_stale_builds
This aligns the code with the header comment (line 10: --deep adds docker prune, brew cleanup) and the SKILL.md contract.
Was this helpful? React with 👍 or 👎 to provide feedback.
| if $MODE_CLEAN; then | ||
| echo "${BWHT}Cleanup (${OS}):${RST}" | ||
| action_clean_caches | ||
| action_clean_package_managers |
There was a problem hiding this comment.
🔴 --clean runs docker system prune -f and brew cleanup — documented as --deep features
action_clean_package_managers() is called at line 713 inside the $MODE_CLEAN block. This function runs docker system prune -f (claude-ops/bin/ops-speedup:374) which permanently removes stopped containers, dangling images, and unused networks, and brew cleanup -s --prune=all (claude-ops/bin/ops-speedup:358). The script's own header comment on line 10 explicitly states --deep adds "docker prune, brew cleanup", and the SKILL.md line 38 says --clean is "Non-destructive". Docker prune destroys data that cannot be recovered. This also conflicts with CLAUDE.md Rule 5 which requires confirmation for "Purging container images (ECR, Docker)".
Prompt for agents
Move the action_clean_package_managers call from the MODE_CLEAN block (line 713) into the MODE_DEEP block (after line 719). This aligns with the header comment on line 10 which says --deep adds docker prune and brew cleanup, and with the SKILL.md which documents --clean as Non-destructive.
The function action_clean_package_managers at line 355 includes docker system prune -f (line 374) and brew cleanup -s --prune=all (line 358). Both are destructive operations that should only run in --deep or --aggressive mode.
Was this helpful? React with 👍 or 👎 to provide feedback.
| elif $IS_LINUX || $IS_WSL; then | ||
| if sudo -n true 2>/dev/null; then | ||
| sync; echo 3 | sudo tee /proc/sys/vm/drop_caches >/dev/null 2>&1 || true | ||
| echo " ${GRN}✓${RST} Memory caches dropped" | ||
| fi | ||
| fi |
There was a problem hiding this comment.
🔴 Linux action_memory_purge drops page caches unconditionally — missing pressure guard
On Linux/WSL (lines 586-590), action_memory_purge unconditionally writes 3 to /proc/sys/vm/drop_caches whenever passwordless sudo is available, with no check on actual memory pressure. The macOS path (line 582) properly guards the purge with (( pressure < 30 || swap > 200 )). Dropping all page caches, dentries, and inodes on a system with healthy memory pressure degrades I/O performance significantly, as subsequent file reads must hit disk. This runs in --clean mode which is documented as "Non-destructive".
| elif $IS_LINUX || $IS_WSL; then | |
| if sudo -n true 2>/dev/null; then | |
| sync; echo 3 | sudo tee /proc/sys/vm/drop_caches >/dev/null 2>&1 || true | |
| echo " ${GRN}✓${RST} Memory caches dropped" | |
| fi | |
| fi | |
| elif $IS_LINUX || $IS_WSL; then | |
| local pressure_l swap_l | |
| pressure_l=$(echo "${MEM_pressure_pct:-100}" | awk -F. '{print int($1+0)}') | |
| swap_l=$(echo "${MEM_swap_mb:-0}" | awk -F. '{print int($1+0)}') | |
| [ -z "$pressure_l" ] && pressure_l=100 | |
| [ -z "$swap_l" ] && swap_l=0 | |
| if (( pressure_l < 30 || swap_l > 200 )) && sudo -n true 2>/dev/null; then | |
| sync; echo 3 | sudo tee /proc/sys/vm/drop_caches >/dev/null 2>&1 || true | |
| echo " ${GRN}✓${RST} Memory caches dropped (free=${pressure_l}%, swap=${swap_l}MB)" | |
| fi |
Was this helpful? React with 👍 or 👎 to provide feedback.
Minor release bundling three feature PRs and multiple security/stability fixes: - PR #141: /gtm — cross-channel go-to-market planning skill - PR #139: /ops:projects portfolio dashboard + GSD registry sync - PR #140: ops-speedup v2 parity (GPU/ANE monitoring, power hogs, OS actions) - PR #138: ops-memory-extractor Claude Code OAuth support + wacli persistent --follow fix Bug fixes (see CHANGELOG.md [1.7.0] for full detail): - SEV-9: ops-speedup eval shell-injection (Seer) - SEV-9: ops-projects hardcoded /Users/ path breaking for all other users (Seer + blocksorg + cursor + devin + codex) - SEV-8: ops-speedup RETURN trap race + systemd mask allowlist - SEV-7: ops-speedup lsof +D probe wedge, daemon-services backing-script gap, ops-projects AskUserQuestion allowed-tools mismatch - wacli --follow torn down by immediate backfill (now INITIAL_BACKFILL_DELAY=30 + reentrant guard) Bumps claude-ops/package.json, claude-ops/.claude-plugin/plugin.json, and .claude-plugin/marketplace.json plugins[0].version 1.6.2 → 1.7.0.


Summary
Brings
ops-speedupto parity with a hyper-tuned local speedup script while keeping the cross-platform contract (macOS / Linux / WSL / Windows). Single binary now handles both probes and actions, OS-dispatched.What's new
New binary flags (combinable):
--scan,--clean,--deep,--aggressiveProbes (parallel, OS-dispatched)
top -stats poweron macOS,powertopon Linux)powermetricson macOS,nvidia-smion Linux)Actions (OS-agnostic dispatcher)
taskpolicy -bon macOS;renice +10+ionice -c3on Linux)--aggressiveon Linux)dscacheutilon macOS;systemd-resolveon Linux;ipconfig.exevia WSL bridge)purge;drop_cacheson Linux)bootout(macOS) /systemctl mask(Linux), stalenode_modules/.next/dist>14d prune,docker --volumesReliability
~/.ops-speedup/history.jsonl(append-only, diffable)sudo -vso parallel phases don't stack promptsSKILL.md updates
--aggressive(Rule 5 compliance)Test plan
Generated with Claude Code
Note
High Risk
Adds and changes system-cleanup behaviors (file deletion, Docker prune, process termination, kernel/sysctl tuning, launch agent/systemd masking) across macOS/Linux/WSL, which can impact developer environments if detection/guards misfire.
Overview
ops-speedupis upgraded from a simple scan/JSON emitter into a v2 scanner+cleaner with--json,--scan,--clean,--deep, and--aggressivemodes. Probes are refactored into parallel, OS-specific functions (disk reclaimables expanded to more caches, plus memory/net/startup;--scanadds CPU/power/GPU/ANE hog detection) and JSON output is extended accordingly.Adds OS-dispatched cleanup actions including cache/log/tmp pruning, package manager pruning (brew/pnpm/cargo/docker), protected-regex-aware hog termination, daemon demotion, DNS flush, memory purge, and kernel tuning;
--deepadds Trash/Xcode/simulator cleanup + UI animation cuts, while--aggressiveadds launch-agent unloading/systemd masking, stale build-dir pruning, and Docker volume pruning. Telemetry/history logging and a 1h idempotency guard for selected heavy actions are added, andSKILL.mdis updated to treat the binary as the single source of truth and to align the UX/confirmation flow (esp. for aggressive actions).Reviewed by Cursor Bugbot for commit b877e87. Bugbot is set up for automated code reviews on this repo. Configure here.