{{ message }}
Repository navigation
feat: add durable heartbeat monitoring - #47193
Closed
MacroModel wants to merge 1 commit into
Closed
MacroModel wants to merge 1 commit into
MacroModel wants to merge 1 commit into
Conversation
Persist heartbeat schedules and policy across restarts, recover pending checks on startup, and present heartbeat turns as collapsible timeline cards in the web app.
Contributor
Contributor
hunterchristian
added a commit
to chipp-ai/opencode
that referenced
this pull request
Sep 23, 2026
A monitor tool (plus monitor_list/monitor_stop) lets the model watch a long-running background command's output for a pattern, or until it exits, and get notified back into the session as new messages -- a standing watch, not just a one-shot check. Analogous to Claude Code's own Monitor tool. Gated behind OPENCODE_EXPERIMENTAL_MONITOR, matching the existing experimentalBackgroundSubagents convention. Ported from upstream anomalyco/opencode PR anomalyco#33806 "feat: add Monitor tool" (1,398 lines, closed by the automated PR-cleanup bot, never reviewed) -- built directly on this fork's existing BackgroundJob primitive rather than modifying it. Reused nearly word-for-word: the re-arm/replace parameter shape, session-scoped list/stop logic, the untrusted-output fence with an unpredictable id so watched output can't forge its own closing tag, control-character stripping, the never-grant-"always"-for-a-glob-command permission rule, the detached-process-plus-parent-death-watchdog design, the flood guard, and most of the tool description and test scenarios. Rewritten rather than ported: avoided anomalyco#33806's own change to core BackgroundJob (a WakeScope to dodge a self-re-arm deadlock) by forking notifications into the tool's own scope instead, the same pattern task.ts already uses; its hand-written reader/debounce became an Effect Stream pipeline; its base64 command-wrapper isn't needed since this repo's bash tool already runs commands through plain ChildProcess.make; permission goes through the existing bash permission rather than a new one, so existing bash rules govern monitors too. Also considered anomalyco#44191 (cron scheduler, closed by the same bot the same week, praised by a human reviewer first) and the anomalyco#47166/anomalyco#47193/anomalyco#47284 durable-heartbeat resubmits (each closed within hours by a different, 2-hour PR-template-compliance bot, never reviewed) -- neither ported; see known gaps. Found and fixed a real, generalizable bug along the way: a command that writes output continuously with no pause (e.g. `yes`) hung teardown and starved timers, because the stdout read pipeline never yielded control back to the scheduler while data kept arriving. Fixed with a single Stream.tap(() => Effect.yieldNow), documented inline -- the same issue could affect other handle.stdout readers facing a non-pausing producer. Known gaps (deliberately scoped): not durable, in-memory only; no scheduler (only a shell poll-loop inside the watched command); opencode run's non-interactive mode exits once idle, killing active monitors; no UI (model-only via monitor_list); stdout only, 4000-char line cap, 5000-line flood guard; parent-death watchdog is POSIX-only; no external/webhook delivery. New packages/opencode/src/tool/monitor.ts (~360 lines) + monitor.txt. New packages/opencode/test/tool/monitor.test.ts (13 tests: self-cancel re-arm without deadlock, concurrency, list/stop, byte-flood guard, multi-line commands) -- passes 3 runs in a row. Verified against this fork's current dev (not just the agent's own stale worktree base): bun typecheck clean; full packages/opencode suite 3600 pass, only the 4 pre-existing, confirmed-unrelated cf-ai-gateway failures. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Persist heartbeat schedules and policy across restarts, recover pending checks on startup, and present heartbeat turns as collapsible timeline cards in the web app.
Type of change
What does this PR do?
Adds durable heartbeat monitoring for long-running external commands.
Heartbeat checks can be scheduled, inspected, or cancelled. Their timing, check count, and backoff policy are stored in SQLite, so pending checks survive an OpenCode restart. A revision check prevents stale timers from firing twice.
Heartbeat is enabled by default and can be disabled with
experimental.heartbeat.enabled: false. Disabling it hides the tool and its shell guidance, and automatically cancels pending heartbeat jobs.The web timeline groups each heartbeat turn into a collapsible card showing its task, check count, state, and latest progress.
How did you verify your code works?
Screenshots / recordings
Checklist