|
| 1 | +# OpenCode Session Runtime |
| 2 | + |
| 3 | +OpenCode sessions preserve durable conversational history while assembling the runtime context an agent needs to act correctly in its current environment. |
| 4 | + |
| 5 | +## Language |
| 6 | + |
| 7 | +**System Context**: |
| 8 | +The structured collection of contextual facts presented to the model as initial instructions and chronological updates. |
| 9 | +_Avoid_: System prompt |
| 10 | + |
| 11 | +**Session History**: |
| 12 | +The projected chronological conversation selected for a provider turn after applying the active compaction and **Context Epoch** cutoffs. |
| 13 | +_Avoid_: Session Context |
| 14 | + |
| 15 | +**Context Source**: |
| 16 | +One independently observed typed value within the **System Context**, represented by a stable key, JSON codec, infallible loader, pure baseline/update renderers, and an optional removal renderer for dynamic sources. |
| 17 | +_Avoid_: Prompt fragment |
| 18 | + |
| 19 | +**System Context Registry**: |
| 20 | +The Location-scoped registry of ordered, scoped producers that contribute to the current **System Context**. |
| 21 | + |
| 22 | +**Mid-Conversation System Message**: |
| 23 | +A durable chronological instruction that tells the model the newly effective state of a changed **Context Source**. |
| 24 | +_Avoid_: System update, system notification, raw text diff |
| 25 | + |
| 26 | +**Context Epoch**: |
| 27 | +The span during which one effective agent's initially rendered **System Context** remains immutable, ending at compaction or another baseline-replacing transition. |
| 28 | + |
| 29 | +**Baseline System Context**: |
| 30 | +The full **System Context** rendered at the start of a **Context Epoch**. |
| 31 | +_Avoid_: Live system prompt |
| 32 | + |
| 33 | +**Context Snapshot**: |
| 34 | +The overwriteable model-hidden JSON state used to compare each **Context Source** with the value last admitted to a provider turn. |
| 35 | + |
| 36 | +**Unavailable Context**: |
| 37 | +An expected temporary inability to observe a **Context Source** value; the runtime retains its prior effective state and emits no update, or omits it until first successfully loaded. |
| 38 | + |
| 39 | +**Safe Provider-Turn Boundary**: |
| 40 | +The point immediately before a provider call, after durable input promotion and any required tool settlement, where context changes may be admitted chronologically. |
| 41 | + |
| 42 | +**Model Tool Output**: |
| 43 | +The bounded projection of a Core-executed tool result persisted in Session history and replayed to the model. A tool may shape this projection semantically, but the Tool Registry enforces the final size limit. |
| 44 | + |
| 45 | +**Managed Tool Output File**: |
| 46 | +A temporary file created under OpenCode's shared tool-output directory to retain complete output that was too large for Session history. |
| 47 | + |
| 48 | +**Model Request Options**: |
| 49 | +Provider-semantic model settings selected from the Catalog and active Session variant before the LLM protocol adapter encodes them for a provider request. |
| 50 | +_Avoid_: Request body, wire options |
| 51 | + |
| 52 | +**Generation Controls**: |
| 53 | +Provider-neutral sampling and output controls, partitioned from provider semantics and compatibility wire fields when model metadata enters the Catalog. |
| 54 | + |
| 55 | +## Relationships |
| 56 | + |
| 57 | +- A **System Context** is an opaque carrier composed from zero or more **Context Sources**. |
| 58 | +- **Session History** contains projected conversational messages and admitted **Mid-Conversation System Messages**; the active **Baseline System Context** remains separate provider-request state. |
| 59 | +- The **System Context Registry** uses stable-keyed scoped contributions to assemble the current **System Context**; contributor removal naturally removes its sources at the next **Safe Provider-Turn Boundary**. |
| 60 | +- A changed **Context Source** may produce one **Mid-Conversation System Message** containing its newly effective state. |
| 61 | +- A **Mid-Conversation System Message** persists the exact combined rendered text sent to the model. |
| 62 | +- The current **Context Snapshot** advances atomically with the corresponding durable **Mid-Conversation System Message**. |
| 63 | +- A **Context Snapshot** stores one codec-encoded JSON value and, for removable dynamic sources, a pre-rendered removal message per stable **Context Source** key. |
| 64 | +- Changes from multiple **Context Sources** admitted at one safe boundary combine into one **Mid-Conversation System Message**. |
| 65 | +- Context changes are sampled and admitted lazily at a **Safe Provider-Turn Boundary**, never pushed asynchronously when their source changes. |
| 66 | +- At a **Safe Provider-Turn Boundary**, newly promoted user input or settled tool results precede any combined **Mid-Conversation System Message**. |
| 67 | +- The first provider turn renders the latest complete **Baseline System Context** and initializes its **Context Snapshot** without emitting a redundant **Mid-Conversation System Message**; unavailable initial context blocks the turn instead of persisting an incomplete baseline. |
| 68 | +- Initial **System Context** preparation precedes the first durable input promotion so an unavailable baseline leaves that input pending and retryable; ordinary reconciliation remains after promotion. |
| 69 | +- Compaction starts a new **Context Epoch** with a freshly rendered **Baseline System Context** and **Context Snapshot**; prior **Mid-Conversation System Messages** remain durable audit history but leave projected model history. |
| 70 | +- A newly registered core or plugin-defined **Context Source** absent from the current snapshot emits its baseline rendering once at the next **Safe Provider-Turn Boundary**. |
| 71 | +- **Context Source** keys are stable and namespaced; duplicate keys fail composition. `SystemContext.combine(...)` preserves caller order; the **System Context Registry** evaluates producers concurrently and combines them in stable contribution-key order so rendered context remains deterministic. |
| 72 | +- Each **Context Source** loader returns one coherent typed value. `SystemContext.make(...)` hides that value type so differently typed sources compose uniformly. Its codec compares and stores that value; its pure renderers produce model-visible baseline, update, and removal text only when needed. |
| 73 | +- `SystemContext.initialize(...)` observes a composed **System Context** once and produces a fresh **Baseline System Context** with its **Context Snapshot**. |
| 74 | +- `SystemContext.reconcile(...)` observes a composed **System Context** once and returns exactly one next action: unchanged, updated, replacement ready, or replacement blocked. |
| 75 | +- `SystemContext.replace(...)` represents an explicit baseline-replacing transition such as compaction or model/provider switch; it either produces a fresh generation or reports that replacement is blocked by unavailable admitted context. |
| 76 | +- Context Epoch preparation retries until stable after optimistic revision mismatches so concurrent replacement requests cannot terminate an otherwise valid safe-boundary run. |
| 77 | +- **Unavailable Context** uses stale-while-revalidate semantics and is distinct from a successfully loaded absence, which may emit removal text. |
| 78 | +- Ordinary **Context Source** loaders return values directly; loaders that intentionally use stale-while-revalidate may explicitly return **Unavailable Context**. |
| 79 | +- Nested project instruction discovery after successful reads remains a follow-up; when implemented, discovered instructions must be admitted durably at the next **Safe Provider-Turn Boundary**. |
| 80 | +- Location-scoped services naturally re-resolve effective context when a moved session next runs in its destination location. |
| 81 | +- Moving a Session clears its active **Context Epoch**, so the destination must initialize a complete baseline before another prompt can promote. |
| 82 | +- Context Epoch initialization is fenced against the authoritative Session Location, so an old-Location runner cannot recreate source context after a concurrent move. |
| 83 | +- Instruction discovery, source identity, persistence, and file loading belong to the instruction service; the **System Context** abstraction only composes effectful producers and renders loaded values. |
| 84 | +- The first instruction-service slice observes global and upward project `AGENTS.md` files as one ordered aggregate **Context Source** at each **Safe Provider-Turn Boundary**. |
| 85 | +- Built-in and instruction context producers register through the **System Context Registry** with stable contribution keys. Plugin-defined context registration and hot-reload lifecycle remain a follow-up built on the same scoped registry seam. |
| 86 | +- Selected-agent available-skill guidance is a **Context Source** composed with Location-wide registry sources immediately before Context Epoch admission. It lists only names and descriptions permitted for that agent; skill bodies and locations are exposed only through the permission-checked `skill` tool. |
| 87 | +- Switching the selected agent requests **Context Epoch** replacement. A switch admitted after the current **Safe Provider-Turn Boundary** applies to the next provider turn while leaving the already-prepared baseline durable. Epoch creation is fenced against the authoritative effective agent, and retries re-observe the current agent. |
| 88 | +- A cross-agent replacement must complete before another provider turn; unavailable admitted context blocks that replacement instead of exposing the previous agent's privileged baseline. |
| 89 | +- Local tool authorization and pending permission requests retain the effective agent of the provider turn that issued the call; a later agent switch cannot change that call's policy. |
| 90 | +- Context source changes never wake idle sessions; the next naturally scheduled **Safe Provider-Turn Boundary** loads and compares current values lazily. |
| 91 | +- Once admitted, a **Mid-Conversation System Message** remains durable even if the following provider attempt fails and is replayed unchanged on retry. |
| 92 | +- **Mid-Conversation System Messages** remain durable Session-message history; normal user-facing transcript surfaces may hide them. |
| 93 | +- The date **Context Source** initially preserves host-local calendar-date behavior; a configured user timezone may replace that default later. |
| 94 | +- A **Context Epoch** begins with one immutable **Baseline System Context**. |
| 95 | +- A **Context Epoch** durably records the effective agent that owns its **Baseline System Context**. |
| 96 | +- A **Baseline System Context** is stored durably and reused verbatim across process restarts within its **Context Epoch**. |
| 97 | +- A **Baseline System Context** durably preserves the exact joined text used for the active provider-cache prefix. |
| 98 | +- Compaction or a model/provider switch starts a new **Context Epoch** because the baseline can be replaced without preserving the prior provider cache. |
| 99 | +- A model/provider switch always starts a new **Context Epoch** while preserving chronological conversation history. |
| 100 | +- **Model Request Options** remain provider-semantic through Catalog resolution. The Session runner maps them into the LLM package's provider-option namespace; the selected protocol adapter alone owns provider wire encoding. |
| 101 | +- **Generation Controls**, protocol-semantic **Model Request Options**, and compatibility request body fields are separate Catalog domains. A shared ingestion adapter partitions legacy and models.dev AI-SDK-shaped options before routing. |
| 102 | +- A **Mid-Conversation System Message** lowers to the provider's native chronological instruction role when supported and to a wrapped chronological fallback otherwise. |
| 103 | +- When the effective aggregate instruction set changes, its **Mid-Conversation System Message** includes the complete current ordered set and supersedes the prior aggregate value; when no ambient instructions remain, the message states that previously loaded instructions no longer apply. |
| 104 | +- Ambient project instruction discovery honors `OPENCODE_DISABLE_PROJECT_CONFIG`; global instructions remain eligible. |
| 105 | +- Oversized textual **Model Tool Output** retains a bounded preview in Session history while its complete text moves to managed tool-output storage. Arbitrary structured-result size is a separate concern. |
| 106 | +- One tool settlement receives one aggregate textual limit, using the configured maximum lines or UTF-8 bytes, whichever is reached first. The limit is provider-independent; token pressure belongs to context assembly and compaction. |
| 107 | +- Generic truncation preserves the beginning and end of textual output. Tools may apply a more meaningful strategy before the Tool Registry enforces the final limit. |
| 108 | +- A truncated **Model Tool Output** identifies its complete text both in the bounded model-visible preview and as a typed managed output path. Managed output paths do not modify the tool's validated structured result. |
| 109 | +- A **Managed Tool Output File** is temporary and may expire after its retention period. The bounded **Model Tool Output**, not the file, is the durable replayable record. |
| 110 | +- Failure to retain a **Managed Tool Output File** does not change a successful tool operation into a failed one. The Session records an explicitly lossy bounded output without a path, while operators receive diagnostics for the storage failure. |
| 111 | +- Once a tool operation succeeds, bounding its **Model Tool Output** and publishing its one durable settlement form an interruption-safe completion region. Raw oversized success is never published before a later correction. |
| 112 | +- When a structured-only result would exceed the **Model Tool Output** limit, its validated structured value remains unchanged for Session consumers while model replay uses a bounded textual JSON preview and optional managed output path. |
| 113 | +- Existing tool-managed output paths survive generic bounding. A fallback file retains exactly the complete projected text received by the Tool Registry and never claims to reconstruct output already discarded by tool-specific shaping. |
| 114 | +- **Managed Tool Output Files** use globally unique names in one shared flat directory. Their absolute paths are readable and searchable by ordinary tools; other absolute paths remain outside Location-scoped filesystem authority. |
| 115 | +- Provider-executed tool results remain provider-native transcript facts outside generic Tool Registry bounding. Their context control requires provider-aware pruning or compaction because some providers require exact structured round-trip payloads. |
| 116 | + |
| 117 | +## Example dialogue |
| 118 | + |
| 119 | +> **Dev:** "The date changed while the session was active. Should the **Mid-Conversation System Message** say what the old date was?" |
| 120 | +> **Domain expert:** "No. Emit the newly effective date so the agent can act on the current **System Context**." |
| 121 | +
|
| 122 | +## Flagged ambiguities |
| 123 | + |
| 124 | +- Legacy `experimental.chat.system.transform` can mutate the assembled baseline system prompt arbitrarily, but V2 plugins do not yet expose an equivalent hook. Decide separately whether to port it, replace dynamic uses with plugin-defined **Context Sources**, or narrow its semantics. |
0 commit comments