Coordinate loop scheduling across OpenCode plugin instances - #2
Open
Romnet wants to merge 1 commit into
Open
Conversation
Romnet
force-pushed
the
fix/loop-scheduler-ownership
branch
from
September 8, 2026 20:20
1f508a4 to
ca19b35
Compare
Romnet
force-pushed
the
fix/loop-scheduler-ownership
branch
from
September 8, 2026 20:23
ca19b35 to
99b0ef9
Compare
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.
Summary
Coordinate persisted loop scheduling across multiple OpenCode plugin instances.
Loops are stored in shared state. Previously, every plugin instance rehydrated all active loops on startup,
including loops belonging to sessions that the instance had never observed. A scheduler could therefore resume
a loop from another session while
list_loopsin the current session showed nothing.This PR adds session ownership leases, owner-aware run claims, and cross-process state coordination. Rehydrated
loops remain dormant until an event, hook, or tool call establishes that the plugin instance has observed the
corresponding session.
The existing public loop tool APIs remain unchanged.
Changes
Session ownership
Run coordination
Shared state
Failure handling
Documentation and distribution
dist/server.js.Concurrency guarantees
The shared-state lock makes lease acquisition, run claiming, and conditional state transitions atomic across
cooperating plugin processes.
Owner revisions and run claim tokens fence persisted state updates. After ownership changes, a stale process
cannot record its run as sent or failed, reschedule it, or stop it.
The scheduler also checks its session lease and run claim immediately before submitting a prompt. This prevents
normal concurrent rehydration and scheduling from producing duplicate sends.
Known limitation
Prompt delivery itself remains a check-then-send operation. The current OpenCode prompt API does not expose a
receiver-side lease token, expected ownership epoch, or equivalent compare-and-set condition.
A process that is paused after the final claim validation, remains paused until its lease expires, and then
resumes could theoretically submit a stale prompt after another process has acquired ownership. The stale process
would be unable to commit any subsequent loop-state update, but the external prompt submission could already have
occurred.
Therefore, this PR provides cross-process coordination and fencing for persisted loop state, but it does not claim
strict exactly-once prompt delivery or receiver-side fencing. Closing that final race requires support from the
OpenCode session API.
Verification
Checklist
bun testpassesbun run lintpassesbun run typecheckpassesbun run buildpassesdist/server.jsrebuilt and committed