You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[FEATURE]: Read-only historical execution changesets for V2 plugins #52870
I have verified this feature I'm about to request hasn't been suggested before.
Describe the enhancement you want to request
Updated request: read-only historical changesets for V2 plugin consumers, rather than awaited plugin capture callbacks. Related discussions include #23503, #35540 and #9272; I am happy to consolidate if maintainers prefer.
Snapshot/review plugins need to inspect a completed execution after the next execution has already started. Reading the current filesystem can mix their changes. V2 already stores step snapshot references, but the public session diff does not expose an exact execution closure with verified snapshot boundaries and capture/rendering coverage.
Could plugins retrieve a historical changeset by an exact execution closure, with:
the corresponding initial/final snapshot references, or an explicit boundary-unavailable result;
frozen scope/coverage and typed omissions or failures, such as ignored relevant paths, capture limits, binary content and patch truncation;
rendering independent of the current worktree, ignore rules, attributes and Git presentation configuration?
An empty patch should distinguish a complete empty delta from unavailable or incomplete evidence. Initial support could be Git text only, with other cases explicitly unavailable. This would not certify exclusive authorship, task fulfillment or settlement of detached writers. No fallback to the current worktree, prompt injection or loop continuation is requested.
A local offline experiment with the real execution coordinator, Bus and native snapshots, but a scripted runner, preserved E1's historical delta while E2 changed the same file; closure association survived database reopening and replay. Coverage remained UNKNOWN. Establishing execution boundaries required two additional host captures in that experiment, so it does not demonstrate zero latency or that exposing Snapshot.diff alone is sufficient.
I am requesting design review before a production implementation. Would a closure-addressed changeset fit V2, and which parts of boundary identity, coverage and retention should belong in the public contract? Complete delivery-history access remains a separate requirement for my consumer.
Thanks for flagging these. I checked all three, including the diff of #9272. There is real overlap: #35540 asks for an awaited final flush, #23503 shares the snapshot/review use case, and #9272 adds awaited work before idle plus a resumePrompt continuation path.
The distinction here is paired observation boundaries in V2: a baseline before the first drain and a final observation after cleanup, awaited before terminal publication and a same-session successor. The callbacks would have a total phase deadline, reject late results, and neither resume the loop nor inject prompts or change the runner outcome. On timeout, pending I/O may continue; its result must not become accepted evidence.
A completion notification alone does not establish that ordering. I am happy to consolidate this into an existing discussion if maintainers prefer, rather than introduce a competing hook. Which direction fits the V2 plugin API best?
changed the title [-][FEATURE]: Bounded plugin hooks at V2 session execution boundaries[/-][+][FEATURE]: Read-only historical execution changesets for V2 plugins[/+]on Oct 3, 2026
Sorry for the change in direction and the earlier callback-focused proposal. After inspecting and testing V2's native snapshots, I think a read-only historical changeset contract is a better starting point than asking plugins to duplicate capture through awaited hooks.
I updated the title and description rather than opening another overlapping issue. The revised request is for exact execution-closure correlation and explicit capture/rendering coverage, not merely exposing the current session diff. Our experiment still has UNKNOWN coverage and used a scripted runner; it is not a production patch, and its extra host captures do not imply zero latency.
The earlier comment describes the superseded approach. Please let me know if this belongs in an existing discussion or should be split. I would appreciate design feedback before implementing the definitive interface.
Thanks for the detailed write-up, @pablozr. As I understand it, you're asking for a read-only way for V2 plugins to fetch the changeset of one specific, completed execution after a newer execution has started. The result would carry its start and end snapshot references (or an explicit "boundary unavailable"), frozen coverage with typed omissions, and rendering that doesn't depend on the current worktree or Git config.
For reference, V2 already has a turn-level diff (SessionDiff.turn) that compares a turn's first recorded start snapshot with its last end snapshot. It isn't addressed by execution, it doesn't report coverage or omissions (ignored paths are filtered out silently), and plugins can't call it. So this needs a new plugin API surface; a plugin can't build it on what exists today.
Maintainers will look at the design questions you raised (boundary identity, coverage and retention in the public contract) and decide how this fits V2.
Thanks for the summary, that matches the request. To make the design questions concrete, here is the smallest contract that would cover my use case (a review plugin that inspects each completed execution):
Boundary identity.session.execution.succeeded (and failed / interrupted) carries an executionID plus the start and end snapshot references, or boundary: "unavailable" with a reason. Today these events only carry sessionID, so a plugin can't tell which snapshots belong to which execution.
Read-only, execution-addressed diff. Something like ctx.session.diff({ executionID }), returning the files plus coverage: { complete: boolean, omitted: [{ path, reason: "ignored" | "size" | "binary" }] }. An empty file list with complete: true would then mean "no changes", distinct from incomplete evidence.
Retention. The result stays available at least until the session's next execution has finished, so a consumer reacting to succeeded can still read it after a queued message has already started the next execution.
Why the current workaround falls short: on 2.2.2 I take ctx.vcs.diff snapshots at execution.started and execution.succeeded. It works for simple cases, but:
more: true was never returned, even for a ~2.6 MB patch, so a plugin can't detect truncation;
ignored paths are invisible, the same gap as SessionDiff.turn;
boundary race: with delivery: "queue", the next execution can start right after succeeded, before the plugin's end snapshot completes, so writes from execution N+1 can leak into N. The only safe option today is to mark N as unavailable.
Point 2 alone would already help; points 1 and 3 are what close the race. Happy to help test a prototype on 2.2.x.
Activity
github-actions commentedon Oct 2, 2026
This issue might be a duplicate of existing issues. Please check:
session.before.idlehook for asynchronous plugin work around subagent completion, overlapping with the callback timing.pablozr commentedon Oct 3, 2026
Thanks for flagging these. I checked all three, including the diff of #9272. There is real overlap: #35540 asks for an awaited final flush, #23503 shares the snapshot/review use case, and #9272 adds awaited work before idle plus a resumePrompt continuation path.
The distinction here is paired observation boundaries in V2: a baseline before the first drain and a final observation after cleanup, awaited before terminal publication and a same-session successor. The callbacks would have a total phase deadline, reject late results, and neither resume the loop nor inject prompts or change the runner outcome. On timeout, pending I/O may continue; its result must not become accepted evidence.
A completion notification alone does not establish that ordering. I am happy to consolidate this into an existing discussion if maintainers prefer, rather than introduce a competing hook. Which direction fits the V2 plugin API best?
[-][FEATURE]: Bounded plugin hooks at V2 session execution boundaries[/-][+][FEATURE]: Read-only historical execution changesets for V2 plugins[/+]pablozr commentedon Oct 3, 2026
Sorry for the change in direction and the earlier callback-focused proposal. After inspecting and testing V2's native snapshots, I think a read-only historical changeset contract is a better starting point than asking plugins to duplicate capture through awaited hooks.
I updated the title and description rather than opening another overlapping issue. The revised request is for exact execution-closure correlation and explicit capture/rendering coverage, not merely exposing the current session diff. Our experiment still has UNKNOWN coverage and used a scripted runner; it is not a production patch, and its extra host captures do not imply zero latency.
The earlier comment describes the superseded approach. Please let me know if this belongs in an existing discussion or should be split. I would appreciate design feedback before implementing the definitive interface.
opencodejr commentedon Oct 27, 2026
Thanks for the detailed write-up, @pablozr. As I understand it, you're asking for a read-only way for V2 plugins to fetch the changeset of one specific, completed execution after a newer execution has started. The result would carry its start and end snapshot references (or an explicit "boundary unavailable"), frozen coverage with typed omissions, and rendering that doesn't depend on the current worktree or Git config.
For reference, V2 already has a turn-level diff (
SessionDiff.turn) that compares a turn's first recorded start snapshot with its last end snapshot. It isn't addressed by execution, it doesn't report coverage or omissions (ignored paths are filtered out silently), and plugins can't call it. So this needs a new plugin API surface; a plugin can't build it on what exists today.Related items I found, none of which covers this:
session.turn.completedbus event for plugin hooks (closed)session.before.idlehook PR (closed)Maintainers will look at the design questions you raised (boundary identity, coverage and retention in the public contract) and decide how this fits V2.
pablozr commentedon Nov 1, 2026
Thanks for the summary, that matches the request. To make the design questions concrete, here is the smallest contract that would cover my use case (a review plugin that inspects each completed execution):
session.execution.succeeded(andfailed/interrupted) carries anexecutionIDplus the start and end snapshot references, orboundary: "unavailable"with a reason. Today these events only carrysessionID, so a plugin can't tell which snapshots belong to which execution.ctx.session.diff({ executionID }), returning the files pluscoverage: { complete: boolean, omitted: [{ path, reason: "ignored" | "size" | "binary" }] }. An empty file list withcomplete: truewould then mean "no changes", distinct from incomplete evidence.succeededcan still read it after a queued message has already started the next execution.Why the current workaround falls short: on 2.2.2 I take
ctx.vcs.diffsnapshots atexecution.startedandexecution.succeeded. It works for simple cases, but:more: truewas never returned, even for a ~2.6 MB patch, so a plugin can't detect truncation;SessionDiff.turn;delivery: "queue", the next execution can start right aftersucceeded, before the plugin's end snapshot completes, so writes from execution N+1 can leak into N. The only safe option today is to mark N as unavailable.Point 2 alone would already help; points 1 and 3 are what close the race. Happy to help test a prototype on 2.2.x.