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]: ability to revert/fork from the ai message, not only from the user's #8689
I have verified this feature I'm about to request hasn't been suggested before.
Describe the enhancement you want to request
PROBLEM: Currently, we can only respond to or create a fork from the user's message, which is suboptimal in many ways. We cannot revert to the middle of the AI model's actions or some of the model's thoughts, to correct/address them right away.
E.g., it's common for me to only have one message at the start of the session, which effectively prevents me from using these options. Sometimes, when I realise that the AI model is behaving incorrectly, I can’t do anything about it except start the session again from the very beginning.
If OpenCode provided the ability to revert or fork from one of the model's messages or tool calls, we could choose the exact moment when the model started to malfunction, which would increase the efficiency of the whole workflow tremendously.
Is it possible to support that?
Reacted by Yassine Erraqui, Joscha Götzer, OverHash, Simone Cervini, mutageneral, Harry, NightRare, Bernat Pericàs, Nathnael Desta, Michael Yochpaz and 13 more
We can fork only from our own messages. Why? Is there any particular reason for that?
Most of the time, I want to branch out with whatever the current state of the conversation is, not my own message, which might be 200 messages up...
Workaround: Abort streaming, send a dummy message, fork from that, continue
This one was bugging me, so I've prepared a diff that implements it with a nice little tab modifier in the "fork" dialog that lets you toggle between user messages and assistant messages as fork points. If you'd like, I'd be happy to contribute it upstream!
Edit: Just reviewed the contributor guidelines. Understandable that anything touching the UX has more guardrails around the process. Happy to submit my changes through that, but definitely understand if you're not taking outsider contributions on this.
yes pls. mimo is asking me what to work on next, I would like to be able to just choose an answer no stress and be able to click on my answer later to fork and it would ask me the question again in the new copied session, so I could pick a different answer. even better if you can switch models inbetwix!!!
I'd also be happy to have this option. I have an issue where an agent attempted to open an image, and it failed, and any subsequent messages fail with the same error because of this image.
I have to revert a long session of many agent messages back to my original message because I can't just remove this last agent message trying to load the image, causing the issue.
This is ridiculous that this feature was present before and was REMOVED at some point THEN unaddressed for almost a year.
I asked AI to write simple and easy bat script that can fork ANY session from ANY message. Quick and elegant without any deep work inside OpenCode itself AND without waiting for mercy from contributors.
Especially relevant for sessions where instead of new messages, there are just questions replied by the user (which count as AI messages, not the user's).
Thanks for the detailed write-up, @art-shen! You're asking to be able to fork (or revert) from an assistant message or tool call, not only from your own messages, so you can branch from the exact point where the model went off track. That matters most in sessions that started with a single prompt.
In the current version the fork dialog only lists user messages. The session backend can already fork at any message, though, so this is mainly about what the TUI and app let you pick. Maintainers will consider it.
Related issues:
[FEATURE]: more fork points #3903: the same request (fork from model messages). It was closed automatically for inactivity, not rejected.
+1 — and I'd extend the scope: an answer to the question tool is a user message in substance, so it deserves to be a first-class revert/fork point, not just a side effect of the AI turn.
Why this hurts in practice:
A session driven through question answers can end up with a single user prompt in the transcript. The answer arrives as form.replied { id, sessionID, answer } into the pending tool call, no Session.Message.User is created, so the whole "ask → answer → 30 tool calls" block collapses into one revert unit.
There is no setting to change it: Session.Message.Info has no message type for a form answer, and session.undo selects the last type === "user" && text.trim(). The answer simply never enters the transcript as a message.
What I'd expect:
revert.stage / fork can target the message (or part) that carries the question tool call, so /undo lands back on the question and it can be answered differently.
Ideally the answer is recorded as a real user-role message (either type: "user" or a distinct type that session.undo treats as a boundary), so it shows up in the transcript and in session.context.
Note: Session.Revert already accepts partID and POST /api/session/{id}/revert/stage supports it — the TUI just doesn't pass it. So part-level reverting may be mostly a client-side change.
Real cost of the current behaviour: my orchestrator agent asks 5–10 clarifying questions per session, and each answer is a decision point I may want to revisit. Because one /undo can wipe hours of work, I've stopped using the question tool and ask in plain text instead — worse UX for both sides.
I’d find this very useful for debugging agent behavior: fork immediately after a tool call, ask the agent why it took that action, and use that feedback to improve skills or prompts.
The challenge is exposing that power without cluttering the UI. I’d separate this into two workflows:
1. Keep the command-palette fork dialog simple: user messages plus “Full session.”
The TUI already offers “Full session,” and I think the web/desktop app should follow that approach. It lets you duplicate the conversation while retaining the latest assistant reply.
For an earlier assistant reply, there’s already a workable shortcut if another user message follows it: fork from that following user message, then clear the restored text from the composer. That preserves the preceding assistant output. It’s slightly counterintuitive, but I’d prefer it over listing every assistant message in the dialog just to avoid clearing the input.
2. Put granular fork actions directly in the conversation trace.
For individual tool calls, reasoning blocks, edits, or other supported boundaries, the fork action should appear beside the item itself—for example, on hover or keyboard focus.
The decision to fork from a particular action usually happens while reading that action. The user has already scrolled through the trace and found the relevant point. Sending them to a separate “fork from action” picker would force them to find that same item again among potentially hundreds of entries.
Making that picker sufficiently navigable could also mean recreating much of the conversation view inside another dialog. An inline action avoids that disconnected workflow and keeps the main fork dialog focused.
This shouldn’t be hover-only: touch users need an equivalent way to reveal the action, perhaps through a long press or contextual menu. A confirmation could also help prevent accidental forks, although the exact interaction would need consideration.
In short: “Full session” in the existing fork dialog, and contextual actions in the trace for finer-grained branching. That provides both capabilities without turning the message picker into an exhaustive list of everything the agent did.
please add this feature in the UI. In the meantime I resorted to a plugin providing /fork-full-session:
ctx.add(Command,()=>{constcurrent=ctx.sessions.current()return{id: "fork-full-session",title: "Fork full session",group: "Sidecar",slash: {name: "fork-full-session"},enabled:
!!current&&!current.pending&¤t.server.connected&¤t.server.compatible,run: async()=>{constsession=ctx.sessions.current()if(!session||session.pending||!session.server.connected||!session.server.compatible)returnconstclient=session.server.clientconstserver=session.server.idconstsessionID=session.idtry{constfork=awaitclient.session.fork({ sessionID },{signal: ctx.signal})if(!ctx.signal.aborted){ctx.tabs.open({ server,id: fork.id},{focus: true})}}catch{if(!ctx.signal.aborted){ctx.toast.show({title: "Could not confirm the fork",description: "Check your sessions before trying again; the fork may have been created.",variant: "error",})}}},}})
I read the current dev code (7b830a4) to see how far off this is. It's closer than the thread suggests.
Already there
The stored fork already has two boundaries: before a message and through a message (packages/schema/src/session-fork.ts). The projector copies < seq or <= seq.
In v2 each assistant step is its own message with its own snapshot. So "through this step" already means "right after this tool round".
The TUI fork dialog has Full session.
Missing
The API only takes before (ForkInput in packages/core/src/session.ts). through is only used for "no message given = whole session". So you can't say "through this assistant message", and that's why the dummy-message trick exists. A through?: messageID input looks like a small change.
Web/desktop dialog has no Full session (packages/app/src/session/commands/fork-dialog.tsx lists user messages only). The TUI does.
The inline "Fork" action is user-only (MessageAction in session-ui/src/message/action-machine.ts). With (1), the same action could show on settled assistant steps.
Smallest version, in order
through on the fork API.
Full session in the web/desktop dialog, matching the TUI.
"Fork from here" on a settled assistant step in the timeline, as @yassine-safraoui suggested. Keep the dialog short and put the action where you're reading.
Later, separate: re-answering a question. The answer sits inside the same step's tool part, so "through" keeps the old answer and "before" drops the question. That needs a part-level boundary or the answer stored as its own user row (@Cossack13's point). It's worth its own issue so it doesn't hold up the simple part.
Activity
github-actions commentedon Jan 15, 2026
This issue might be a duplicate of existing issues. Please check:
Feel free to ignore if none of these address your specific case.
JosXa commentedon Feb 16, 2026
Yes please!
bigs commentedon Feb 17, 2026
This one was bugging me, so I've prepared a diff that implements it with a nice little tab modifier in the "fork" dialog that lets you toggle between user messages and assistant messages as fork points. If you'd like, I'd be happy to contribute it upstream!
Edit: Just reviewed the contributor guidelines. Understandable that anything touching the UX has more guardrails around the process. Happy to submit my changes through that, but definitely understand if you're not taking outsider contributions on this.
OverHash commentedon Mar 11, 2026
Related to #3903
mutageneral commentedon Mar 24, 2026
yes pls. mimo is asking me what to work on next, I would like to be able to just choose an answer no stress and be able to click on my answer later to fork and it would ask me the question again in the new copied session, so I could pick a different answer. even better if you can switch models inbetwix!!!
MichaelYochpaz commentedon Apr 4, 2026
I'd also be happy to have this option. I have an issue where an agent attempted to open an image, and it failed, and any subsequent messages fail with the same error because of this image.
I have to revert a long session of many agent messages back to my original message because I can't just remove this last agent message trying to load the image, causing the issue.
iamvaibhav commentedon Jun 23, 2026
very much needed!
MaciejGorczyca commentedon Aug 16, 2026
This is ridiculous that this feature was present before and was REMOVED at some point THEN unaddressed for almost a year.
I asked AI to write simple and easy bat script that can fork ANY session from ANY message. Quick and elegant without any deep work inside OpenCode itself AND without waiting for mercy from contributors.
Usage: opencode_fork_any_message.bat ^<sessionID^> ^<messageID^> [basic_auth] [cookie_token] [port]
You can set OPENCODE_AUTH and OPENCODE_TOKEN as env variables to not pass it every time you fork something.
If you are coding, you can probably easily find session tokens, cookies, headers, etc by yourself. Or ask your favorite AI agent.
opencode_fork_any_message.txt
m0wer commentedon Aug 26, 2026
Especially relevant for sessions where instead of new messages, there are just questions replied by the user (which count as AI messages, not the user's).
amanteaux commentedon Oct 13, 2026
This feature would be very appreciated, especially since questions from agent are not considered as user messages.
opencodejr commentedon Oct 29, 2026
Thanks for the detailed write-up, @art-shen! You're asking to be able to fork (or revert) from an assistant message or tool call, not only from your own messages, so you can branch from the exact point where the model went off track. That matters most in sessions that started with a single prompt.
In the current version the fork dialog only lists user messages. The session backend can already fork at any message, though, so this is mainly about what the TUI and app let you pick. Maintainers will consider it.
Related issues:
Until then, a workaround mentioned in the comments here is to stop the response, send a short dummy message, and fork from that message.
Cossack13 commentedon Nov 3, 2026
+1 — and I'd extend the scope: an answer to the
questiontool is a user message in substance, so it deserves to be a first-class revert/fork point, not just a side effect of the AI turn.Why this hurts in practice:
questionanswers can end up with a single user prompt in the transcript. The answer arrives asform.replied { id, sessionID, answer }into the pending tool call, noSession.Message.Useris created, so the whole "ask → answer → 30 tool calls" block collapses into one revert unit./undojumps straight back to the start of the session. bug: hitting /undo after answering question undoes last prompt #12625 describes exactly this — "Answer it → hit /undo → back at the start :(".Session.Message.Infohas no message type for a form answer, andsession.undoselects the lasttype === "user" && text.trim(). The answer simply never enters the transcript as a message.What I'd expect:
revert.stage/forkcan target the message (or part) that carries thequestiontool call, so/undolands back on the question and it can be answered differently.type: "user"or a distinct type thatsession.undotreats as a boundary), so it shows up in the transcript and insession.context.Note:
Session.Revertalready acceptspartIDandPOST /api/session/{id}/revert/stagesupports it — the TUI just doesn't pass it. So part-level reverting may be mostly a client-side change.Real cost of the current behaviour: my orchestrator agent asks 5–10 clarifying questions per session, and each answer is a decision point I may want to revisit. Because one
/undocan wipe hours of work, I've stopped using the question tool and ask in plain text instead — worse UX for both sides.yassine-safraoui commentedon Nov 4, 2026
I’d find this very useful for debugging agent behavior: fork immediately after a tool call, ask the agent why it took that action, and use that feedback to improve skills or prompts.
The challenge is exposing that power without cluttering the UI. I’d separate this into two workflows:
1. Keep the command-palette fork dialog simple: user messages plus “Full session.”
The TUI already offers “Full session,” and I think the web/desktop app should follow that approach. It lets you duplicate the conversation while retaining the latest assistant reply.
For an earlier assistant reply, there’s already a workable shortcut if another user message follows it: fork from that following user message, then clear the restored text from the composer. That preserves the preceding assistant output. It’s slightly counterintuitive, but I’d prefer it over listing every assistant message in the dialog just to avoid clearing the input.
2. Put granular fork actions directly in the conversation trace.
For individual tool calls, reasoning blocks, edits, or other supported boundaries, the fork action should appear beside the item itself—for example, on hover or keyboard focus.
The decision to fork from a particular action usually happens while reading that action. The user has already scrolled through the trace and found the relevant point. Sending them to a separate “fork from action” picker would force them to find that same item again among potentially hundreds of entries.
Making that picker sufficiently navigable could also mean recreating much of the conversation view inside another dialog. An inline action avoids that disconnected workflow and keeps the main fork dialog focused.
This shouldn’t be hover-only: touch users need an equivalent way to reveal the action, perhaps through a long press or contextual menu. A confirmation could also help prevent accidental forks, although the exact interaction would need consideration.
In short: “Full session” in the existing fork dialog, and contextual actions in the trace for finer-grained branching. That provides both capabilities without turning the message picker into an exhaustive list of everything the agent did.
dluc commentedon Nov 4, 2026
please add this feature in the UI. In the meantime I resorted to a plugin providing
/fork-full-session:balabommablock-cpu commentedon Nov 11, 2026
I read the current
devcode (7b830a4) to see how far off this is. It's closer than the thread suggests.Already there
beforea message andthrougha message (packages/schema/src/session-fork.ts). The projector copies< seqor<= seq.Missing
before(ForkInputinpackages/core/src/session.ts).throughis only used for "no message given = whole session". So you can't say "through this assistant message", and that's why the dummy-message trick exists. Athrough?: messageIDinput looks like a small change.packages/app/src/session/commands/fork-dialog.tsxlists user messages only). The TUI does.MessageActioninsession-ui/src/message/action-machine.ts). With (1), the same action could show on settled assistant steps.Smallest version, in order
throughon the fork API.Later, separate: re-answering a
question. The answer sits inside the same step's tool part, so "through" keeps the old answer and "before" drops the question. That needs a part-level boundary or the answer stored as its own user row (@Cossack13's point). It's worth its own issue so it doesn't hold up the simple part.