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
v2: --continue reopens a session whose tab was closed; picks by time.updated with no closed/archived filter #52655
opencode --continue (-c) reopens sessions whose tabs the user has closed. Closing a session's tab is a client-side UI action only — the session row and its time.updated are untouched — so the closed session remains the most recently updated root session and -c reopens it on every launch. The only reliable way to retire it is opencode session delete.
Sending prompts in other tabs does not fix this when those sessions are out of scope: the candidate list is project/directory-scoped (sessionListQuery() in packages/tui/src/context/sync.tsx filters by worktree-relative path), and the pick is purely sort by time.updated desc, first session with parentID === undefined (packages/tui/src/app.tsx; same logic in packages/opencode/src/cli/cmd/run.ts via session.list().find(item => !item.parentID)). Additionally, time.updated is written by non-prompt operations (setSummary, setMetadata, setPermission, setWorkspace in packages/opencode/src/session/session.ts), so a background summary on the old session can out-rank a prompt sent elsewhere. Neither the TUI nor the CLI path filters archived sessions — Session.list() → listByProject() has no time_archived filter, unlike listGlobal() which excludes archived by default.
This is the same root cause as #22175 (closed not_planned) and overlaps #35058 (archive does not close tabs) and #38852 (stale session after restart, labeled 2.0).
Steps to reproduce
Open opencode, work in session A, close its tab (Ctrl+X W).
Start session B in another tab, send prompts there.
Exit and run opencode -c.
Session A reopens instead of B; repeats on every -c launch.
Expected Behavior
-c should resume the session the user was last actively using (last prompted in, or last viewed), and should skip sessions the user closed — or at minimum, closing a tab should be persisted so -c can honor it. Archived sessions should be excluded, consistent with listGlobal().
Actual Behavior
-c reopens the most recently written-to root session regardless of whether the user closed it, prompted elsewhere, or archived it. Closing a tab has no effect on which session -c picks.
OpenCode version
v2 (behavior present on dev branch, code inspected 2026-10-01)
Thanks for the detailed report. I reproduced this on v2.2.0 and on the latest dev (891a020), run from source.
Steps (the script below reproduces it with a simulated model):
Prompt in session A in the TUI.
/new, then prompt in session B, and exit.
Archive session A.
Run opencode --continue.
Archived session A opens instead of B; the recording below shows it. Archiving also updates the session's time.updated, so the archived session becomes the newest one, and --continue doesn't exclude archived sessions when it picks.
Making --continue skip sessions whose tab you closed is a separate request. Tab state is TUI-only today, so that part is more of a feature request than this bug.
Related: #58364 (archived sessions in the Ctrl+O picker), #22175 (the same --continue/archived problem, closed as stale), #57381 (import overwrites time.updated).
recording.mp4
Reproduction script (drive.ts)
// Repro for anomalyco/opencode#52655: `opencode --continue` reopens an archived// session instead of the session last worked in.// It writes a small wrapper (oc.sh) that opencode-drive runs instead of `opencode`:// on the second TUI launch it archives session A through the API and then starts// the TUI with --continue. OC_DEV=/path/to/checkout runs the CLI from source.import{Effect}from"effect"import{Llm,OpenCodeDriver}from"opencode-drive"constwrapper="/tmp/opencode/oc.sh"awaitBun.write(wrapper,`#!/usr/bin/env bash# Wrapper around \`opencode\` used by drive.ts. When /tmp/opencode/repro-archive# holds a session ID and this is a TUI launch (\`--server URL\`), archive that# session through the API and then start the TUI with \`--continue\`.if [ -n "$OC_DEV" ]; then OC=(bun --conditions=browser --preload="$OC_DEV/packages/tui/node_modules/@opentui/solid/scripts/preload.js" "$OC_DEV/packages/cli/src/index.ts")else OC=(opencode)fiMARK=/tmp/opencode/repro-archiveif [ "$1" = "--server" ] && [ -s "$MARK" ]; then ID=$(cat "$MARK"); rm -f "$MARK" "\${OC[@]}" api --server "$2" session.update --param sessionID="$ID" -d '{"archived":true}' >>/tmp/opencode/repro-api.log 2>&1 exec "\${OC[@]}" "$@" --continuefiexec "\${OC[@]}" "$@"`)awaitBun.$`chmod +x ${wrapper}`exportdefaultOpenCodeDriver.use({opencode: {command: [wrapper],env: process.env.OC_DEV ? {OC_DEV: process.env.OC_DEV} : {}},tui: {recording: true},},(oc)=>Effect.gen(function*(){const{ ui, llm }=ocyield*llm.queue(Llm.text("Reply in session A."))// Session Ayield*ui.submit("work in session A")yield*ui.waitFor("work in session A",{timeout: 20000}).pipe(Effect.andThen(Effect.sleep("3 seconds")))yield*Effect.sleep("1 second")// Session B, the one the user is actively usingyield*llm.queue(Llm.text("ok"))yield*llm.queue(Llm.text("Reply in session B."))yield*llm.queue(Llm.text("Reply in session B."))yield*ui.type("/new")yield*Effect.sleep("500 millis")yield*ui.enter()yield*Effect.sleep("1 second")yield*Effect.log(yield*ui.screenshot("after-new"))yield*ui.submit("work in session B")yield*Effect.log("waiting B")yield*ui.waitFor("work in session B",{timeout: 20000}).pipe(Effect.andThen(Effect.sleep("3 seconds")))yield*Effect.log(yield*ui.screenshot("in-session-B"))yield*Effect.sleep("1 second")constlist=yield*oc.opencode.session.list({order: "desc",parentID: null}asany)constsessions=(listasany).dataasArray<{id: string;title: string}>yield*Effect.log(sessions.map((s)=>`${s.id}${s.title}`).join("\n"))consta=sessions[sessions.length-1]!yield*Effect.promise(()=>Bun.write("/tmp/opencode/repro-archive",a.id))yield*ui.screenshot("before-exit-in-session-B")yield*oc.tui.close()// Relaunch: wrapper archives session A, then runs `opencode --server … --continue`constsecond=yield*oc.tuis.launch("continue",{recording: true})yield*Effect.sleep("4 seconds")yield*second.ui.screenshot("after-continue")constafter=yield*oc.opencode.session.get({sessionID: a.id}asany)yield*Effect.log(`session A after archive: ${JSON.stringify((afterasany).time)}`)yield*Effect.log("waiting continue")yield*second.ui.waitFor("work in session A",{timeout: 10000})yield*Effect.log("BUG: --continue reopened archived session A instead of session B")}),)
Run it with opencode-drive: opencode-drive run ./drive.ts. It drives opencode from your PATH; set OC_DEV to the path of an OpenCode checkout to run that from source instead.
Appreciate you taking the time to confirm the bug. The root cause makes sense - archiving updates time.updated, so the archived session becomes the "newest" and --continue picks it up.
The workaround in the meantime is to be careful about when I archive sessions. For a proper fix, I understand this would need to track tab state separately from session timestamps - more of a feature request than a quick fix.
Activity
github-actions commentedon Oct 2, 2026
This issue might be a duplicate of or overlap with existing issues. Please check:
--continueresumes archived sessions instead of skipping them, reflecting the same archived-session filtering behavior.For keybind-related issues, please also check our pinned keybinds documentation: #4997
opencodejr commentedon Oct 28, 2026
Thanks for the detailed report. I reproduced this on v2.2.0 and on the latest
dev(891a020), run from source.Steps (the script below reproduces it with a simulated model):
/new, then prompt in session B, and exit.opencode --continue.Archived session A opens instead of B; the recording below shows it. Archiving also updates the session's
time.updated, so the archived session becomes the newest one, and--continuedoesn't exclude archived sessions when it picks.Making
--continueskip sessions whose tab you closed is a separate request. Tab state is TUI-only today, so that part is more of a feature request than this bug.Related: #58364 (archived sessions in the Ctrl+O picker), #22175 (the same
--continue/archived problem, closed as stale), #57381 (import overwritestime.updated).recording.mp4
Reproduction script (drive.ts)
Run it with opencode-drive:
opencode-drive run ./drive.ts. It drivesopencodefrom yourPATH; setOC_DEVto the path of an OpenCode checkout to run that from source instead.DEAD1nsane commentedon Oct 28, 2026
Thanks for reproducing this!
Appreciate you taking the time to confirm the bug. The root cause makes sense - archiving updates
time.updated, so the archived session becomes the "newest" and--continuepicks it up.The workaround in the meantime is to be careful about when I archive sessions. For a proper fix, I understand this would need to track tab state separately from session timestamps - more of a feature request than a quick fix.
Thanks again for looking into this!
fix(tui): close archived session tabs