Skip to content

feat: add keep_alive so a background session's future survives its starting turn - #3

Merged
danyel117 merged 2 commits into
prevalentWare:mainfrom
jutaz:feat/target-parent
Oct 13, 2026
Merged

danyel117 merged 2 commits into
prevalentWare:mainfrom
jutaz:feat/target-parent

Conversation

@jutaz

@jutaz jutaz commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

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 after max_consecutive_failures; resume_loop restores scheduling after the failure is resolved. The README and tool descriptions spell out these exceptions.

Validation

  • Full local gate: lint, typecheck, 89 tests passed, build, pack dry-run.
  • Rebuilt dist/server.js.
  • Added V1/V2 coverage for restart recovery, age exemption, unavailable sessions, foreign locations, ordinary sibling dormancy, retry pause/resume, and concurrent recovery.
  • Added V1 regression for restoring an already-busy session.
  • Preserved existing scheduler, persistence, Promise API, and tool-result tests.

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
jutaz force-pushed the feat/target-parent branch from aa86ee8 to 03816da Compare September 21, 2026 07:41
@jutaz jutaz changed the title feat: add target option so a loop can wake the parent session feat: add keep_alive so a background session's future survives its starting turn Sep 21, 2026
@danyel117
danyel117 merged commit 79aac0b into prevalentWare:main Oct 13, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants