Part V · The work lifecycleContext and memory
Chapter 26source checked

Context is provider-owned; history is T3-owned

T3 Code retains a product-visible thread history and an opaque provider continuation cursor, while each provider owns the prompt context it may resume or compact; the pinned system has no universal T3 long-term-memory subsystem.

What this chapter resolves
  • Separate a provider's prompt context from T3's durable thread history, session binding, and live context telemetry.
  • Explain what a persisted resume cursor can and cannot promise after a server or provider-session restart.
  • Read compaction as a provider event normalized into T3 activity, rather than as a universal T3 memory operation.
  • Keep client drafts, offline delivery, and historical usage accounting in their proper later or separate lanes.

“Memory” is an attractive word for a system with threads, histories, resumable sessions, cached screens, drafts, and transcript accounting. It is too imprecise to describe the pinned T3 Code implementation.

T3 owns a durable product record for a thread: messages, activities, plans, session projection, and related work state. It also constructs the visible current turn payload—message text, attachment paths, model and mode choices—before calling an adapter. The provider-native session owns the accumulated conversation context, hidden history, and any private compaction state used when that turn reaches a model. T3 stores a provider-specific, opaque resume cursor with the provider-session binding so it can ask that provider to continue later. That cursor is a continuation handle, not a portable copy of a prompt, summary, embedding index, or cross-provider memory format.

1. Five similarly named things have different owners

Thing Primary owner What T3 keeps What it does not establish
Current turn input T3 constructs the visible request; adapter maps it to native input user text, attachments, selected model/mode, and resulting observations the provider’s accumulated hidden conversation state
Accumulated native context Provider harness and its native session provider identity, runtime mode, optional cursor, and normalized observations hidden history, compaction result, model state, or portability to another provider
Thread history T3 orchestration projection durable messages, activities, plans, session and work overlays that every provider token, hidden message, or native item was captured
Resume cursor Provider defines the shape; T3 persists it opaquely JSON-valued cursor bound to one thread/provider instance a universal checkpoint, a durable provider callback, or a guarantee that native history still exists
Context-window telemetry Provider emits it; T3 normalizes/latest-selects it a context-window.updated activity when usable a full history, exact prompt contents, cost settlement, or a cross-provider meter
Client cache, draft, or outbox A client surface locally scoped presentation/delivery state server-side memory or a provider continuation

The provider-session contract explicitly makes resumeCursor an optional Unknown value. The persistent provider-runtime row stores it as JSON alongside provider/instance identity, session status, runtime mode, last-seen timestamp, and adapter payload. This is intentionally a narrow handoff boundary: a provider adapter receives its own cursor back at session start, rather than T3 decoding one generic “conversation memory” representation.

apps/server/src/persistence/ProviderSessionRuntime.ts:35–110 ↗verbatim · typescript · b92dc6c0
export const ProviderSessionRuntime = Schema.Struct({
  threadId: ThreadId,
  providerName: Schema.String,
  /**
   * User-defined routing key for the configured provider instance that
   * owns this session. Nullable only at the storage/migration boundary:
   * rows persisted before the driver/instance split carry only
   * `providerName`. Repository consumers must materialize a concrete
   * instance id before routing.
   */
  providerInstanceId: Schema.NullOr(ProviderInstanceId),
  adapterKey: Schema.String,
  runtimeMode: RuntimeMode,
  status: ProviderSessionRuntimeStatus,
  lastSeenAt: IsoDateTime,
  resumeCursor: Schema.NullOr(Schema.Unknown),
  runtimePayload: Schema.NullOr(Schema.Unknown),
});
export type ProviderSessionRuntime = typeof ProviderSessionRuntime.Type;
 
export const GetProviderSessionRuntimeInput = Schema.Struct({ threadId: ThreadId });
export type GetProviderSessionRuntimeInput = typeof GetProviderSessionRuntimeInput.Type;
 
export const DeleteProviderSessionRuntimeInput = Schema.Struct({ threadId: ThreadId });
export type DeleteProviderSessionRuntimeInput = typeof DeleteProviderSessionRuntimeInput.Type;
 
/**
 * ProviderSessionRuntimeRepository - Service tag for provider runtime persistence.
 */
export class ProviderSessionRuntimeRepository extends Context.Service<
  ProviderSessionRuntimeRepository,
  {
    /**
     * Insert or replace a provider runtime row.
     *
     * Upserts by canonical `threadId`, including JSON payload/cursor fields.
     */
    readonly upsert: (
      runtime: ProviderSessionRuntime,
    ) => Effect.Effect<void, ProviderSessionRuntimeRepositoryError>;
 
    /**
     * Read provider runtime state by canonical thread id.
     */
    readonly getByThreadId: (
      input: GetProviderSessionRuntimeInput,
    ) => Effect.Effect<
      Option.Option<ProviderSessionRuntime>,
      ProviderSessionRuntimeRepositoryError
    >;
 
    /**
     * List all provider runtime rows.
     *
     * Returned in ascending last-seen order.
     */
    readonly list: () => Effect.Effect<
      ReadonlyArray<ProviderSessionRuntime>,
      ProviderSessionRuntimeRepositoryError
    >;
 
    /**
     * Delete provider runtime state by canonical thread id.
     */
    readonly deleteByThreadId: (
      input: DeleteProviderSessionRuntimeInput,
    ) => Effect.Effect<void, ProviderSessionRuntimeRepositoryError>;
  }
>()("t3/persistence/ProviderSessionRuntime/ProviderSessionRuntimeRepository") {}
 
const ProviderSessionRuntimeDbRowSchema = ProviderSessionRuntime.mapFields(
  Struct.assign({
    resumeCursor: Schema.NullOr(Schema.fromJsonString(Schema.Unknown)),
    runtimePayload: Schema.NullOr(Schema.fromJsonString(Schema.Unknown)),
  }),
);
Read this as: The persisted runtime binding keeps provider/instance identity, session metadata, adapter payload, and JSON continuation state. It does not define a portable prompt representation.

2. A restart uses a handle, not a replayed prompt

The recovery path first looks for an active compatible session. If none is available, it requires a persisted provider binding and a non-null continuation cursor. It restores the stored working directory, selected model information when available, runtime mode, and the cursor, then asks the same provider adapter to start. The adapter is the place that interprets that cursor.

This distinction is concrete in the adapter implementations:

  • Codex turns a valid cursor into the native threadId supplied when opening its app-server thread, then returns the provider thread id as its next cursor.
  • Claude validates a provider-shaped resume state before choosing the native resume session id.
  • OpenCode treats its persisted ses_… id as a session lookup. It reuses the native session only when its directory matches; a directory move can fork the native session to preserve that provider’s conversation history, while a known missing session begins fresh.

These are adapter-specific policies—not an inter-provider migration protocol. A Codex thread id is not meaningful to Claude; an OpenCode session id is not an executable representation of a Codex prompt.

Figure 26.1 · A restart crosses ownership boundaries without copying a promptthe cursor is a handoff, not a transcript
Ownership and restart boundaryDiagram loading

Zoom with the controls, +/, or Ctrl/ + trackpad scroll. Enable Pan to drag, use two-finger scrolling, or use the arrow keys. 0 fits the diagram; Esc leaves Pan or expanded view.

Ownership and restart boundary
Text equivalent

A provider owns accumulated native context. T3 constructs a visible turn request and receives normalized runtime observations. T3 stores product thread history and a provider session binding containing an opaque cursor. On restart T3 gives that cursor to the same provider adapter. The adapter attempts provider-specific native-session recovery. A successful recovery can emit new observations into T3 history. A failed or missing provider session does not cause T3 to synthesize the provider's hidden context from the displayed thread history.

Figure 26.1. T3 commits thread history and stores a provider/instance-bound resume cursor. After live session loss, it sends that cursor back to the chosen adapter. The adapter asks its provider to reopen native history/context if it can. Provider observations may then become new T3 activities and messages. No arrow makes T3 history into a reconstructed provider prompt, or makes a cursor a portable long-term-memory record.

3. Compaction is performed upstream and recorded downstream

The generic runtime vocabulary can report thread.state.changed and a canonical context_compaction item type. The provider adapters turn their own native signals into those observations. Codex maps its native thread/compacted notification to the canonical compacted state. Claude maps a compact_boundary system message to both an updated usage snapshot (when it can normalize one) and a compacted thread-state event.

Runtime ingestion accepts a canonical thread.state.changed whose state is compacted and appends a durable context-compaction activity. It does not take T3’s message rows, create a provider summary, replace the provider’s native context, or reset a turn merely because a compaction activity was observed.

This matters for comparisons between provider capabilities. The canonical event union can represent a compaction signal, but an adapter that does not emit one will not fabricate it. A context compaction activity is useful provenance in the work log; it is not itself a complete history of what the provider retained, discarded, or summarized.

4. A context meter is current telemetry, not memory

thread.token-usage.updated carries a provider-normalized snapshot with required usedTokens and optional maximum/context categories. Runtime ingestion admits a usable snapshot as one context-window.updated activity. The client reducer supersedes earlier resolvable snapshots with the same turnId value. The web selector then walks backward across the activities returned for the thread and uses the newest valid context-window update it can find. That returned thread detail is itself bounded to the 500 most recent activities.

Thus the meter answers a narrow operational question: what is the latest usable provider-reported context observation available for this thread? It does not sum all past context sizes. It does not expose the prompt text. It does not turn a provider’s total-processed counter into historical usage, cost, or memory capacity.

At the pinned revision, the live emission paths inspected in Chapter 20 are Codex and Claude. Cursor, Grok, and OpenCode should not be shown as providing a T3 context meter merely because their model metadata or native runtimes may have a context-window concept.

packages/client-runtime/src/state/threadReducer.ts:562–592 ↗verbatim · typescript · ae9a3e38
    // ── Activities ──────────────────────────────────────────────────
    case "thread.activity-appended": {
      const activity = event.payload.activity;
      // A resolvable context-window update supersedes earlier resolvable ones
      // for the same turn: consumers only read the latest value (walking the
      // array backwards), and providers stream these updates continuously, so
      // retaining the history grows the thread by thousands of rows over a
      // long session. Mirrors the server-side snapshot rule in
      // dropStaleContextWindowActivities; retention stays per turn so a
      // thread.reverted that discards turns can still resolve a value from
      // the turns that survive.
      const supersedesContextWindow = isResolvableContextWindowActivity(activity);
      const activities = pipe(
        thread.activities,
        Arr.filter(
          (entry) =>
            entry.id !== activity.id &&
            !(
              supersedesContextWindow &&
              entry.turnId === activity.turnId &&
              isResolvableContextWindowActivity(entry)
            ),
        ),
        Arr.append(activity),
        Arr.sort(activityOrder),
      );
 
      return {
        kind: "updated",
        thread: { ...thread, activities, updatedAt: event.occurredAt },
      };
Read this as: The client reducer replaces earlier resolvable context-window activities sharing the same turn id; consumers then read backward for the newest usable value.

For the separate historical question—tokens/cost-shaped records from provider transcript files—read Chapter 20, “Usage accounting without a false ledger”. That scan is neither the source of the live context meter nor a T3 memory layer.

5. “Long-term memory” is absent as a universal product subsystem

Inference from the pinned generic contracts and recovery paths: this revision does not establish a universal T3 long-term-memory subsystem. Those inspected paths model projects, threads, messages, activities, plans, checkpoints, provider sessions, current-turn payloads, and opaque continuation state. They do not define a cross-provider memory entity or a generic contract for injecting retrieved facts into a future provider turn.

That is not a claim that a provider lacks its own native memory/history feature. It is a boundary claim about what T3 Code itself standardizes at the source lock. A provider-specific session resume, its own transcript files, a generated plan, a Git checkpoint, and a client draft are not interchangeable evidence of a universal product-memory feature.

6. Client-local state belongs to a different recovery story

The shared client runtime can cache an environment’s thread snapshot and seed its event-subscription afterSequence from the cached shell sequence. That helps a screen catch up; it does not act as provider context or server authority. Mobile additionally owns environment-scoped local drafts and a persisted command outbox. Those are client resilience/delivery mechanisms and receive their detailed treatment in Chapter 33 rather than being rebranded as memory here.

The distinction is particularly important after a disconnected mobile action: delivery retry can re-attempt a client command, while provider session recovery still depends on the server’s binding and the provider’s ability to use its cursor. Neither mechanism means a client has captured a complete native model context.

Work the ownership and restart ledger

Choose a teaching event, then inspect which record changes, who is authoritative, and what a later server restart can actually attempt. The lab has no autonomous motion; keyboard tab navigation and a complete static/print ledger are included.

Interactive ownership ledger

Ask what survives before calling it memory

Select a teaching event. The ledger identifies authority, durable records, and the narrow recovery claim; it never simulates a model or invents a provider prompt.

Event 1 of 5 · live provider work begins

A provider receives a turn in its own native session

T3 constructs the visible current-turn payload. The provider-native session owns the accumulated conversation context and private compaction state.

RecordAuthoritative ownerThis eventAfter server restart
Accumulated native contextprovider-native sessionT3's explicit request enters provider-owned historyprovider-specific resume only
T3 thread historyT3 orchestrationmessage/activity projection may commitdurable product record reloads
Resume cursorprovider shape; T3 persists bindingadapter may return/update itsame adapter receives opaque cursor
Context telemetryprovider emits; T3 latest-selectsonly if a usable event arriveslatest retained activity may render
Client cache/draft/outboxclient surfacesurface-specific local statenot a provider prompt or server authority
Boundary statement

T3 constructs and records the visible request around a turn. It does not own or serialize the provider's accumulated hidden conversation context.

context-current-turn-payloadprovider-session-contract

Selected event: Send a turn.

Static ownership and restart reference
QuestionAnswer at the pinned revision
Who owns exact model prompt context?T3 constructs the visible current-turn request; the selected provider's native session owns accumulated conversation context and hidden provider state.
What does T3 persist to attempt continuation?A provider/instance-bound runtime record with an opaque resume cursor, runtime/session metadata, plus separate thread projections.
What does compaction add to T3?A normalized context-compaction activity when an adapter reports a compacted provider thread; no generic T3 summary/prompt replacement is established.
What is the context meter?The newest valid provider-reported context-window activity available in the bounded thread snapshot, not a prompt archive, aggregate usage total, or cost ledger.
Is there universal long-term memory?No such cross-provider T3 subsystem is established by the inspected generic contracts/service paths. This is an audited inference, not a claim about native provider features.
What about local drafts/outbox/cache?Client-owned resilience/presentation state. It is deliberately deferred to Chapter 33 and cannot replace provider-session recovery.

Boundary checks to carry into another meta-harness

  1. Persist a provider-continuation handle only with its provider/instance identity; never treat it as a portable prompt serialization.
  2. Keep a durable product conversation useful on its own terms, while stating that it is not proof of hidden native context or tool state.
  3. Represent compaction as provider-originated provenance unless the product owns the summarization algorithm and its exact replay/retention semantics.
  4. Name context telemetry, task usage, and transcript accounting as distinct data products. Chapter 20’s historical ledger must not silently become a memory system.
  5. If a universal memory feature is proposed, design its user control, source provenance, deletion/retention, isolation, provider injection, and restart failure behavior explicitly rather than piggybacking on a resume cursor.
T3
Source-locked editionRead against fa219001d · 23 Aug 2026
Book search

Find a concept, module, or source path

Type two or more characters.