Repository navigation
feat: add keep_alive so a background session's future survives its starting turn - #3
Merged
Merged
Conversation
A subagent's session has no future of its own. The turn that spawned it ends, the parent detaches, and nothing re-enters that session again -- so work that outlives its starting turn dies with it, and the agent never gets the chance to report back. create_loop now takes keep_alive. The loop becomes a durable heartbeat for the session it was created in, and the scheduler stops deciding when that future ends. Only the agent does, by calling stop_loop once the work is resolved or abandoned. Three paths could previously end such a future without the agent asking: - Age expiry stopped any loop past max_loop_age_days (7 by default). This was the only one that also hit interval loops, and the only way to avoid it was max_loop_age_days: 0, which would make every loop immortal. keep-alive loops are now exempt; ordinary loops are unchanged. - A prompt failure in a session this process never observed returned early without recording the failure or re-arming, leaving the loop on nothing but the claimDueRun lease. A detached child emits no events for this process to observe, which is exactly the case keep-alive is for, so those loops now record the failure and re-arm. claimDueRun still keeps concurrent processes off the same run, and ordinary loops still defer to their owning process. - Dynamic loops stop when a turn ends without schedule_next_run, and are stopped on restart when no next run was persisted. Both are correct for dynamic pacing, so rather than weaken them keep_alive requires a fixed interval and is rejected at create time without one. Verified end to end against a live OpenCode 2.0.5 server: a real parent spawned a child subagent, the parent's task completed and detached, and the child then ran nine further assistant turns on its own before the agent stopped the loop. The parent received no iterations -- handing the result back remains the agent's responsibility, not the plugin's.
jutaz
force-pushed
the
feat/target-parent
branch
from
September 21, 2026 07:41
aa86ee8 to
03816da
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
Add
create_loop({ interval: "5m", keep_alive: true })for background or subagent work that outlives its starting turn. Keep-alive loops are exempt from age expiry and restore their timers after restart when the current host can access their session.The option requires a fixed interval and defaults to false for existing persisted records. Returning results to the parent remains the agent's responsibility.
Ownership and lifecycle
Recovery verifies session identity and current directory/workspace before acquiring a session lease. Concurrent instances retain the ownership and run-claim fencing introduced in #2. Unavailable or foreign sessions remain dormant. Recovering a keep-alive does not wake ordinary sibling loops without authoritative observation. V1 recovery checks authoritative busy status before delivery.
Explicit
max_runs, session deletion, and manual pause/stop still apply. Provider failures use bounded exponential backoff and pause aftermax_consecutive_failures;resume_looprestores scheduling after the failure is resolved. The README and tool descriptions spell out these exceptions.Validation
dist/server.js.