Correct CLI --continue --session syntax for persisting sessions is malfunctioning. #8256

Open
opened 2026-02-16 18:09:32 -05:00 by yindo · 3 comments
Owner

Originally created by @davidbernat on GitHub (Feb 1, 2026).

Originally assigned to: @thdxr on GitHub.

Description

Howdy OpenCoders. This is an easy one, and most likely either a corrupted opencode functionality or a badly configured configuration from my stupider days.

The question is how to persist a session across multiple prompts from my using the CLI.
The docs indicate that the proper syntax requires --continue and --session.

Caveats:

  • if the --session flag is not used the opencode platform will find the most recent session and continue that
  • the first message to opencode can force create any session as long as that session_id starts with "ses_"
    -- this is particularly useful when driving new opencode sessions from external uuid constraints.

Anyway. The syntax is simple so that just needs double checking.
As you can see from the terminal logs below, the opencode run is definitely not persisting across calls.
What should we do?
Let's double check, and debug together.
PS these operations are being conducted from my LLC so I hope no spoliating factors are langoliering my logerinos!

Image

.
.
.
.
You can see from this shorter exchange below that the session persistence is definitely malfunctioning.

Image

Thanks.
Jazzed about testing out the new Code-Reviewer agent.

Originally created by @davidbernat on GitHub (Feb 1, 2026). Originally assigned to: @thdxr on GitHub. ### Description Howdy OpenCoders. This is an easy one, and most likely either a corrupted opencode functionality or a badly configured configuration from my stupider days. The question is how to persist a session across multiple prompts from my using the CLI. The docs indicate that the proper syntax requires `--continue` and `--session`. Caveats: - if the `--session` flag is not used the opencode platform will find the most recent session and continue that - the first message to opencode can force create any session as long as that session_id starts with "ses_" -- this is particularly useful when driving new opencode sessions from external uuid constraints. Anyway. The syntax is simple so that just needs double checking. As you can see from the terminal logs below, the `opencode run` is definitely not persisting across calls. What should we do? Let's double check, and debug together. PS these operations are being conducted from my LLC so I hope no spoliating factors are langoliering my logerinos! <img width="1152" height="743" alt="Image" src="https://github.com/user-attachments/assets/0a368177-7a3b-4a05-8973-efa20f00e17e" /> . . . . You can see from this shorter exchange below that the session persistence is definitely malfunctioning. <img width="1158" height="215" alt="Image" src="https://github.com/user-attachments/assets/7013be8c-2d0a-4894-957e-44b52c54a828" /> Thanks. Jazzed about testing out the new Code-Reviewer agent.
yindo added the bug label 2026-02-16 18:09:32 -05:00
Author
Owner

@github-actions[bot] commented on GitHub (Feb 1, 2026):

This issue might be a duplicate of existing issues. Please check:

  • #4378: --continue doesn't always continue the project's previous session
  • #8850: opencode --continue --prompt does not work

Feel free to ignore if none of these address your specific case.

@github-actions[bot] commented on GitHub (Feb 1, 2026): This issue might be a duplicate of existing issues. Please check: - #4378: --continue doesn't always continue the project's previous session - #8850: opencode --continue --prompt does not work Feel free to ignore if none of these address your specific case.
Author
Owner

@justfortheloveof commented on GitHub (Feb 1, 2026):

Image (I don't know if it believing I sent 4 message prior to the last one is because the model sucks at math or perhaps opencode injected a user message or it's counting the system prompt?.. anyhow!)

The above is with v1.1.48 - I wonder what version you're running.
Notice I was using one of -c (2nd and 3rd messages) or -s (4th message).


Also found this:
https://github.com/anomalyco/opencode/blob/b39c1f158f5e78b41edd944dce792a8b602819c1/packages/opencode/src/cli/cmd/run.ts#L356-L361
where if you pass -c, -s is ignored (regardless of the short or long form).


Perhaps they should be made mutually exclusive to avoid confusion.

@justfortheloveof commented on GitHub (Feb 1, 2026): <img width="3582" height="2020" alt="Image" src="https://github.com/user-attachments/assets/9045d446-6f0f-4483-812a-87d68848e567" /> (I don't know if it believing I sent 4 message prior to the last one is because the model sucks at math or perhaps opencode injected a user message or it's counting the system prompt?.. anyhow!) --- The above is with v1.1.48 - I wonder what version you're running. Notice I was using **one of** `-c` (2nd and 3rd messages) or `-s` (4th message). --- Also found this: https://github.com/anomalyco/opencode/blob/b39c1f158f5e78b41edd944dce792a8b602819c1/packages/opencode/src/cli/cmd/run.ts#L356-L361 where if you pass `-c`, `-s` is ignored (regardless of the short or long form). --- Perhaps they should be made mutually exclusive to avoid confusion.
Author
Owner

@davidbernat commented on GitHub (Feb 1, 2026):

Thanks for inspecting the code. I did as well, and I agree with you.
Using --continue will deploy the most recent session_id, regardless of whether the --session flag has been used with a different session_id. The --continue flag takes precedence with the most recent session_id.

I also read the logic to MessageV2.toModelMessages() which is responsible for constructing the "context" for the next request to the LLM. It is unfortunately much more nuanced with hard won adaptations than simply reconstructing linear parts of the individual logs from opencode run --format json.

https://github.com/anomalyco/opencode/blob/d35956fd9272e302201d99548a1389315a20cdaf/packages/opencode/src/session/message-v2.ts#L438

I read through to see how much I would want to replicate, and also had OpenCode inspect the OpenCode repository and as usual congratulations; when the software works it works. I do wish OpenCode offered a command line utility for reconstructing this information from the multitude of logs directly. It is more complicated than it is accessible to the average public, which makes me really wishful how best to offline manage the construction of contexts from the opencode run --format json outputs themselves.

For those who want more information:

Image Image

Context Construction Process Flow

Step 1: Message Collection and Filtering

In SessionPrompt.loop() around Line 276:

let msgs = await MessageV2.filterCompacted(MessageV2.stream(sessionID))

Step 2: Last Message Analysis (Lines 278-293)

Finds the most recent user and assistant messages to understand conversation state.

Step 3: Reminder Injection (Lines 519-596)

The insertReminders() function adds system reminders and plan mode instructions.

Step 4: Tool Resolution (Lines 560-568)

The resolveTools() function determines which tools are available for the LLM.

Step 5: Message Processing (Lines 600-619)

CRITICAL CONTEXT BUILDING CODE:

const result = await processor.process({
  user: lastUser,
  agent,
  abort,
  sessionID,
  system: [...(await SystemPrompt.environment(model)), ...(await InstructionPrompt.system())],
  messages: [
    ...MessageV2.toModelMessages(sessionMessages, model),  // <- KEY CONVERSION
    ...(isLastStep ? [{ role: "assistant" as const, content: MAX_STEPS }] : []),
  ],
  tools,
  model,
})

Step 6: Message to Model Format Conversion

The most important context conversion happens in MessageV2.toModelMessages() (Lines 345-500 in message-v2.ts):

  • Processes each message part (text, file, tool, reasoning)
  • Converts internal message format to AI SDK's ModelMessage format
  • Handles tool calls, attachments, and content transformation
  • Filters out ignored parts and manages compaction state

Step 7: System Prompt Assembly (Lines 5-50 in system.ts)

Environment context includes:

  • Working directory
  • Git repository status
  • Platform information
  • Current date
  • File tree (limited to 200 files)

Step 8: Context Overflow Management

When context exceeds limits, SessionCompaction.isOverflow() triggers compaction:

  • Summarizes old messages
  • Prunes tool call outputs
  • Maintains conversation context within model limits

Key Plugin Hooks for Context Modification

  1. experimental.chat.messages.transform (Line 598 in prompt.ts): Allows plugins to modify messages before LLM call
  2. experimental.chat.system.transform (Line 358 in llm.ts): Allows plugins to modify system prompts
  3. experimental.session.compacting (Line 134 in compaction.ts): Allows plugins to influence context compaction

Context Construction Logic Summary

The context construction process follows this sequence:

  1. Message Collection → Gather conversation history with filtering
  2. Message Analysis → Identify relevant user/assistant messages
  3. Tool Resolution → Determine available tools based on permissions
  4. System Prompt Building → Add environment context and provider instructions
  5. Message Format Conversion → Convert internal MessageV2 format to ModelMessage format
  6. Plugin Transformations → Apply plugin-based modifications
  7. Context Assembly → Combine system prompts, conversation history, and tools
  8. LLM Call → Send constructed context to the language model
  9. Overflow Management → Compact context if it exceeds model limits

The MessageV2.toModelMessages() function is the most critical piece for understanding how message objects are converted into LLM context, as it handles all the complex logic for transforming internal message parts into the final format that language models can understand.

@davidbernat commented on GitHub (Feb 1, 2026): Thanks for inspecting the code. I did as well, and I agree with you. Using `--continue` will deploy the most recent session_id, regardless of whether the `--session` flag has been used with a different session_id. The `--continue` flag takes precedence with the most recent session_id. I also read the logic to `MessageV2.toModelMessages()` which is responsible for constructing the "context" for the next request to the LLM. It is unfortunately much more nuanced with hard won adaptations than simply reconstructing linear parts of the individual logs from `opencode run --format json`. https://github.com/anomalyco/opencode/blob/d35956fd9272e302201d99548a1389315a20cdaf/packages/opencode/src/session/message-v2.ts#L438 I read through to see how much I would want to replicate, and also had OpenCode inspect the OpenCode repository and as usual congratulations; when the software works it works. I do wish OpenCode offered a command line utility for reconstructing this information from the multitude of logs directly. It is more complicated than it is accessible to the average public, which makes me really wishful how best to offline manage the construction of contexts from the `opencode run --format json` outputs themselves. For those who want more information: <img width="1260" height="563" alt="Image" src="https://github.com/user-attachments/assets/2b02a968-a938-4e5b-8d2b-cdb32e4ca1ea" /> <img width="1214" height="172" alt="Image" src="https://github.com/user-attachments/assets/5e18aac4-95a0-44cc-850e-0a880cc917ee" /> ## Context Construction Process Flow ### Step 1: Message Collection and Filtering In `SessionPrompt.loop()` around **Line 276**: ```typescript let msgs = await MessageV2.filterCompacted(MessageV2.stream(sessionID)) ``` ### Step 2: Last Message Analysis (Lines 278-293) Finds the most recent user and assistant messages to understand conversation state. ### Step 3: Reminder Injection (Lines 519-596) The `insertReminders()` function adds system reminders and plan mode instructions. ### Step 4: Tool Resolution (Lines 560-568) The `resolveTools()` function determines which tools are available for the LLM. ### Step 5: Message Processing (Lines 600-619) **CRITICAL CONTEXT BUILDING CODE:** ```typescript const result = await processor.process({ user: lastUser, agent, abort, sessionID, system: [...(await SystemPrompt.environment(model)), ...(await InstructionPrompt.system())], messages: [ ...MessageV2.toModelMessages(sessionMessages, model), // <- KEY CONVERSION ...(isLastStep ? [{ role: "assistant" as const, content: MAX_STEPS }] : []), ], tools, model, }) ``` ### Step 6: Message to Model Format Conversion **The most important context conversion happens in `MessageV2.toModelMessages()`** (Lines 345-500 in message-v2.ts): - Processes each message part (text, file, tool, reasoning) - Converts internal message format to AI SDK's ModelMessage format - Handles tool calls, attachments, and content transformation - Filters out ignored parts and manages compaction state ### Step 7: System Prompt Assembly (Lines 5-50 in system.ts) Environment context includes: - Working directory - Git repository status - Platform information - Current date - File tree (limited to 200 files) ### Step 8: Context Overflow Management When context exceeds limits, `SessionCompaction.isOverflow()` triggers compaction: - Summarizes old messages - Prunes tool call outputs - Maintains conversation context within model limits ## Key Plugin Hooks for Context Modification 1. **`experimental.chat.messages.transform`** (Line 598 in prompt.ts): Allows plugins to modify messages before LLM call 2. **`experimental.chat.system.transform`** (Line 358 in llm.ts): Allows plugins to modify system prompts 3. **`experimental.session.compacting`** (Line 134 in compaction.ts): Allows plugins to influence context compaction ## Context Construction Logic Summary The context construction process follows this sequence: 1. **Message Collection** → Gather conversation history with filtering 2. **Message Analysis** → Identify relevant user/assistant messages 3. **Tool Resolution** → Determine available tools based on permissions 4. **System Prompt Building** → Add environment context and provider instructions 5. **Message Format Conversion** → Convert internal MessageV2 format to ModelMessage format 6. **Plugin Transformations** → Apply plugin-based modifications 7. **Context Assembly** → Combine system prompts, conversation history, and tools 8. **LLM Call** → Send constructed context to the language model 9. **Overflow Management** → Compact context if it exceeds model limits The **`MessageV2.toModelMessages()` function** is the most critical piece for understanding how message objects are converted into LLM context, as it handles all the complex logic for transforming internal message parts into the final format that language models can understand. ```
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#8256