Mem Watchdog
Prevents VS Code from being OOM-killed on ChromeOS Crostini by running an independent systemd daemon that monitors memory pressure and kills Chrome/Playwright processes before the Linux kernel decides to kill VS Code instead.
Why this exists: earlyoom crashes immediately on Crostini with exit code 104 — a strtol() overflow caused by a bogus SwapFree sentinel value in the kernel's /proc/meminfo. It has never provided protection on this platform. This extension installs a bash-based replacement that avoids the broken value entirely, adds VS Code-aware RSS thresholds, and now includes a Chat Continuity Guard for rescuing oversized Copilot sessions before they trigger extension-host restart loops.
Kill Hierarchy
The daemon acts on these conditions (checked every 2 seconds):
| Condition |
Action |
MemAvailable ≤ 15% (~945 MB on 6 GB) |
SIGKILL Chrome / Playwright |
MemAvailable ≤ 25% (~1.6 GB on 6 GB) |
SIGTERM Chrome / Playwright |
PSI full avg10 > 25% |
SIGTERM Chrome (sustained memory stall) |
| VS Code RSS > 3.4 GB |
RSS warn path: kill disposable targets or lowest-value VS Code helper if RSS is accelerating |
| VS Code RSS > 3.8 GB |
RSS emergency circuit-breaker: critical helper kill, then controlled VS Code main restart if needed |
| RSS velocity spike |
Kill lowest-value VS Code helper — never a language server or Extension Host at normal severity |
Language-server protection: Built-in language servers (HTML, JSON, CSS, Markdown, ESLint) and the Extension Host process (hosting Copilot, Playwright MCP, and all extensions) are excluded from the helper-kill candidate pool at normal severity. These small processes (80–120 MB) are subject to VS Code's 5-crash-in-3-minutes permanent death threshold — killing one saves negligible memory while permanently disabling language intelligence or all extensions. They are only considered as last-resort targets at true emergency severity (RSS ≥ 3.8 GB).
Automation awareness: When an automation session is active (detected via TIER_DISPOSABLE_PATTERN_AUX, default (node|python|claude).*(playwright|puppeteer|cypress|selenium-webdriver|mcp|vision|visualization)), the daemon automatically defers non-critical disposable kills. The disposable process cap (DISPOSABLE_COUNT_MAX) is also skipped during active sessions. At true emergency severity (≤ 15% free RAM), disposable targets are always killed regardless.
Startup mode: when new VS Code PIDs appear, the daemon switches to 0.5 s polling for 90 s and raises the RSS emergency threshold to 4.0 GB — catching the extension-host spike that caused the crash this tool was built to prevent (0 → 4 GB RSS in under 2 seconds during startup).
Status Bar
A live memory indicator in the bottom bar updates every 2 seconds:
| Appearance |
Meaning |
GUARDING — green |
Healthy patrol state |
ALERT — amber |
Near warning pressure |
RECOVERING — amber |
Warning threshold reached or post-action settling |
ATTACKING — red |
Emergency pressure / active protective action |
SLEEPING — yellow |
Managed-window mode (mode=SLEEP) |
OFF — red |
Service not running |
Click the status bar item to open the full Memory Dashboard.
Commands
Access all commands via Ctrl+Shift+P → Mem Watchdog:
| Command |
Description |
| Show Memory Dashboard |
Full snapshot in an output channel: system RAM, PSI stall index, VS Code RSS by PID, Chrome RSS totals, service status, last 8 journal lines |
| Playwright Pre-flight Check |
Pass/fail modal: RAM%, VS Code RSS, disposable process presence, watchdog state. Offers "Kill Disposable Processes Now" inline if disposable targets are running. |
| Kill Disposable Processes Now |
Immediately sends SIGTERM to disposable targets matching browser + automation patterns |
| Optimize VS Code for Low Memory |
Audits settings.json and argv.json against the recommended low-memory profile and applies missing settings |
| Guide Low-Memory Profile Setup |
Audits installed extensions by estimated memory impact, opens the Profiles workflow, and recommends which heavy extensions to disable in a dedicated LowMem profile |
| Rescue Oversized Chat Session |
Archives a large Copilot chat session, generates a continuity pack + resume prompt, and optionally reloads VS Code before the extension host re-parses the giant JSON |
| Restart Service |
systemctl --user restart mem-watchdog with live status feedback |
Copilot Chat Integration
Type @memwatchdog in Copilot Chat for AI-assisted memory operations:
| Command |
Description |
/memwatchdog status |
Thematic state + description, RAM%, VS Code RSS, WARN/EMERG thresholds, PSI |
/memwatchdog logs |
Last 40 journal lines with action markers |
/memwatchdog tune balanced |
Apply a tuning profile (balanced / conservative / playwright) |
/memwatchdog optimize |
Audit VS Code settings and argv flags against the low-memory baseline |
/memwatchdog lowmem |
Estimate extension memory load, recommend a LowMem profile, and suggest which heavy extensions to disable |
/memwatchdog rescue |
Run the oversized-chat rescue flow and generate a resumable continuity pack |
/memwatchdog act kill disposable |
Kill disposable processes, restart service, or open dashboard |
The extension also installs a Copilot skill at ~/.copilot/skills/mem-watchdog-ops/ so the assistant carries watchdog context across all repositories.
Requires VS Code ≥ 1.93 for Chat API. On older versions the chat participant is silently skipped.
Settings
Configure all thresholds via VS Code Settings → Mem Watchdog. Changes take effect immediately — the extension rewrites ~/.config/mem-watchdog/config.sh and restarts the daemon automatically.
| Setting |
Default |
Description |
sigtermThresholdPct |
25 |
SIGTERM Chrome when MemAvailable falls below this % of total RAM |
sigkillThresholdPct |
15 |
Escalate to SIGKILL below this % |
psiThresholdPct |
25 |
SIGTERM on PSI full avg10 above this % |
vscodeRssWarnMB |
3400 |
Warn + SIGTERM Chrome when total VS Code RSS exceeds this many MB |
vscodeRssEmergencyMB |
3800 |
SIGKILL Chrome (or SIGTERM extension host) above this MB |
chatGuard.enabled |
true |
Enable oversized-chat detection and rescue prompting (including preemptive inactive-workspace archival) |
chatGuard.sessionSizeMB |
120 |
Session JSON size that triggers rescue eligibility |
chatGuard.autoRescue |
prompt |
off, prompt, or auto behavior when an oversized chat is detected |
chatGuard.restartAfterRescue |
true |
Reload the window after rescue so the extension host doesn't re-parse the giant archived session |
chatGuard.preserveCount |
3 |
Number of rescue archives to keep under ~/.config/mem-watchdog/chat-archives/ |
interactiveKillApproval.enabled |
true |
Show a modal approval prompt before non-critical disposable-process kills |
interactiveKillApproval.deferSeconds |
120 |
Cooldown applied when you choose Hold fire in the kill-approval modal |
All settings use scope: "machine" — they do not sync across machines via Settings Sync. A threshold tuned for 6 GB RAM would be dangerously wrong on a 16 GB machine.
RAM Tuning Guide
| System RAM |
vscodeRssWarnMB |
vscodeRssEmergencyMB |
| 4 GB |
1500 |
2000 |
| 6 GB (default) |
3400 |
3800 |
| 8 GB |
3500 |
5000 |
| 16 GB |
6000 |
10000 |
Architecture
The daemon is intentionally a separate systemd process — not a thread inside the extension host. VS Code's JS runtime can freeze under OOM pressure; if the watchdog ran inside it, the watchdog would freeze too. The extension manages the daemon; it does not replace it.
VS Code Extension (this) Systemd Daemon (independent process)
──────────────────────── ──────────────────────────────────────
• Auto-installs daemon → ~/.local/bin/mem-watchdog.sh
• Writes config on change → ~/.config/mem-watchdog/config.sh
• Status bar + 7 commands • Polls /proc/meminfo + PSI every 2 s
• @memwatchdog chat participant • Kills Chrome on threshold breach
• GitHub Releases update checker • Survives VS Code freezing / crashing
• Copilot skill installer • oom_score_adj tuning every loop
• Upgrade detection via hash • Config sourcing (no script modification)
• OOM-resilient service monitoring • Language-server + ExtHost protection
• Chat Continuity Guard • RSS circuit-breaker before kernel OOM
How It Works
On every VS Code activation:
- The bundled
mem-watchdog.sh is SHA-256 compared to the installed version. If different, it is upgraded and the service is restarted automatically. Downgrade protection ensures a newer manually-deployed daemon is never overwritten by an older bundled version.
- A Copilot skill is installed/refreshed at
~/.copilot/skills/mem-watchdog-ops/.
- VS Code Settings are written to
~/.config/mem-watchdog/config.sh. The daemon sources this file so threshold changes take effect on the next restart — without reinstalling.
- OOM scores are tuned:
oom_score_adj=0 for VS Code (counters Electron's default 200–300), oom_score_adj=1000 for Chrome (kernel kills it first, no root required).
- If the Chat API is available, the
@memwatchdog chat participant is registered.
The extension is OOM-resilient by design: it reads kernel virtual files directly rather than spawning processes that could themselves fail under ENOMEM — the exact condition it is monitoring.
Requirements
- Linux only —
extensionKind: ["ui"] prevents accidental activation on a remote machine via Remote SSH
- ChromeOS Crostini (Debian 12, kernel 6.6+) is the primary target; works on any Linux with systemd user services
systemctl --user available (no sudo required)
notify-send optional — enables desktop notifications when Chrome is killed
Install (from source)
cd vscode-extension
npm run build
npm install -g @vscode/vsce
vsce package
code --install-extension mem-watchdog-status-*.vsix
Reload the window (Developer: Reload Window). The daemon installs and starts automatically on first activation.
Uninstall
Removing the extension stops and disables the mem-watchdog service. The daemon binary at ~/.local/bin/mem-watchdog.sh is intentionally left in place — remove it manually if desired.
License
PolyForm Noncommercial 1.0.0 — free for personal, educational, and non-commercial use.
Commercial use requires a paid license. See COMMERCIAL-LICENSE.md or contact curtisfranks@gmail.com.
Contributing
git clone https://github.com/chf3198/crostini-mem-watchdog.git
cd crostini-mem-watchdog/vscode-extension
npm run build # populate resources/ from repo root
npm test # 191 JS unit tests via node:test (zero-install)
npm run test:coverage # same + c8 V8 coverage report
npm run test:stress # stress scenarios: pileup guard, EL lag, heap usage
191 unit tests covering readMeminfo/readPsi/sh()/checkServiceStatus() plus thematic state helpers (readWatchdogMode(), readRssThresholds(), determineState(), stateDescription()), chat continuity archival/resume generation (including preemptive inactive-workspace rescue), low-memory profile classification/guidance, config validation, command handlers, installer decision logic, activate() singleton lifecycle, the update() state machine + pileup guard, update checker (version comparison, throttling, dismissal), installer MIN_SAFE_DAEMON_VERSION guard, installer downgrade protection (export-prefix version parsing), skill installer (install/update/skip), and @memwatchdog chat participant (status, logs, tune, optimize, lowmem, rescue, followups, API availability guard).