Load thread snapshots over HTTP before live sync - #3719
Conversation
- Fetch initial thread snapshots via HTTP and resume subscriptions after the snapshot sequence - Add not-found handling for thread snapshot requests
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
| retryExpectedFailureAfter: "250 millis", | ||
| }, | ||
| ).pipe(Stream.runForEach(applyItem), Effect.forkScoped); | ||
| yield* Effect.forkScoped( |
There was a problem hiding this comment.
🟡 Medium state/threads.ts:193
makeEnvironmentThreadState now awaits snapshotLoader.load(...) before calling subscribe(...), so when the HTTP snapshot endpoint is slow or times out, live WebSocket updates are blocked for the entire duration even though the socket session is already healthy. The UI stays in stale cached/synchronizing state and misses live updates until the HTTP fallback completes. Consider subscribing to live events immediately and applying the HTTP snapshot in parallel when it arrives — applyItem already deduplicates by sequence, so overlapping events are safe.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @packages/client-runtime/src/state/threads.ts around line 193:
`makeEnvironmentThreadState` now awaits `snapshotLoader.load(...)` before calling `subscribe(...)`, so when the HTTP snapshot endpoint is slow or times out, live WebSocket updates are blocked for the entire duration even though the socket session is already healthy. The UI stays in stale `cached`/`synchronizing` state and misses live updates until the HTTP fallback completes. Consider subscribing to live events immediately and applying the HTTP snapshot in parallel when it arrives — `applyItem` already deduplicates by sequence, so overlapping events are safe.
There was a problem hiding this comment.
Mitigated in c420e9e. The snapshot fetch requires the sequence before we can resume live events over the socket, so some coupling is inherent, but: the cached thread renders while the fetch runs (so first paint is not blocked), the wait is bounded (timeout lowered to 6s with fallback to the socket snapshot), and this only affects the initial mount — reconnects resume via the socket without re-fetching.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.
Autofix Details
Bugbot Autofix prepared fixes for all 3 issues found in the latest run.
- ✅ Fixed: PubSub attached after replay
- Added OrchestrationEngine.subscribeDomainEvents, which attaches the PubSub subscription (scoped to the RPC stream's lifetime) before subscribeThread reads its catch-up or snapshot baseline, so events published during the baseline read are buffered instead of dropped.
- ✅ Fixed: Thread catch-up hits replay cap
- readEvents now accepts an optional limit forwarded to the event store, and the afterSequence catch-up passes Number.MAX_SAFE_INTEGER so the replay is exhaustive (internally paged) instead of truncating at the global 1,000-event default.
- ✅ Fixed: HTTP snapshot reads race
- Added a transactional ProjectionSnapshotQuery.getThreadDetailSnapshot that reads the thread detail and snapshot sequence in one sql.withTransaction, now used by both the HTTP threadSnapshot endpoint and the WS snapshot path so the sequence never runs ahead of the embedded thread.
Or push these changes by commenting:
@cursor push 29677d1179
Preview (29677d1179)
diff --git a/apps/server/src/checkpointing/CheckpointDiffQuery.test.ts b/apps/server/src/checkpointing/CheckpointDiffQuery.test.ts
--- a/apps/server/src/checkpointing/CheckpointDiffQuery.test.ts
+++ b/apps/server/src/checkpointing/CheckpointDiffQuery.test.ts
@@ -107,6 +107,7 @@
}),
getThreadShellById: () => Effect.succeed(Option.none()),
getThreadDetailById: () => Effect.succeed(Option.none()),
+ getThreadDetailSnapshot: () => Effect.succeed(Option.none()),
}),
),
);
@@ -199,6 +200,7 @@
getFullThreadDiffContext: () => Effect.die("unused"),
getThreadShellById: () => Effect.succeed(Option.none()),
getThreadDetailById: () => Effect.succeed(Option.none()),
+ getThreadDetailSnapshot: () => Effect.succeed(Option.none()),
}),
),
);
@@ -281,6 +283,7 @@
getFullThreadDiffContext: () => Effect.die("unused"),
getThreadShellById: () => Effect.succeed(Option.none()),
getThreadDetailById: () => Effect.succeed(Option.none()),
+ getThreadDetailSnapshot: () => Effect.succeed(Option.none()),
}),
),
);
@@ -348,6 +351,7 @@
getFullThreadDiffContext: () => Effect.die("unused"),
getThreadShellById: () => Effect.succeed(Option.none()),
getThreadDetailById: () => Effect.succeed(Option.none()),
+ getThreadDetailSnapshot: () => Effect.succeed(Option.none()),
}),
),
);
@@ -400,6 +404,7 @@
getFullThreadDiffContext: () => Effect.succeed(Option.none()),
getThreadShellById: () => Effect.succeed(Option.none()),
getThreadDetailById: () => Effect.succeed(Option.none()),
+ getThreadDetailSnapshot: () => Effect.succeed(Option.none()),
}),
),
);
diff --git a/apps/server/src/observability/RpcInstrumentation.ts b/apps/server/src/observability/RpcInstrumentation.ts
--- a/apps/server/src/observability/RpcInstrumentation.ts
+++ b/apps/server/src/observability/RpcInstrumentation.ts
@@ -5,6 +5,7 @@
import * as Exit from "effect/Exit";
import * as Metric from "effect/Metric";
import * as References from "effect/References";
+import type * as Scope from "effect/Scope";
import * as Stream from "effect/Stream";
import { outcomeFromExit } from "./Attributes.ts";
@@ -123,7 +124,14 @@
method: string,
effect: Effect.Effect<Stream.Stream<A, StreamError, StreamContext>, EffectError, EffectContext>,
traceAttributes?: Readonly<Record<string, unknown>>,
-): Stream.Stream<A, StreamError | EffectError, StreamContext | EffectContext> => {
+ // `Stream.unwrap` scopes the setup effect to the stream's lifetime, so a
+ // `Scope` requirement (e.g. PubSub subscriptions attached before a snapshot
+ // is loaded) is satisfied by the stream itself rather than the caller.
+): Stream.Stream<
+ A,
+ StreamError | EffectError,
+ StreamContext | Exclude<EffectContext, Scope.Scope>
+> => {
const instrumented = Stream.unwrap(
Effect.gen(function* () {
const startedAt = yield* Clock.currentTimeNanos;
diff --git a/apps/server/src/orchestration/Layers/OrchestrationEngine.test.ts b/apps/server/src/orchestration/Layers/OrchestrationEngine.test.ts
--- a/apps/server/src/orchestration/Layers/OrchestrationEngine.test.ts
+++ b/apps/server/src/orchestration/Layers/OrchestrationEngine.test.ts
@@ -200,6 +200,7 @@
getFullThreadDiffContext: () => Effect.succeed(Option.none()),
getThreadShellById: () => Effect.succeed(Option.none()),
getThreadDetailById: () => Effect.succeed(Option.none()),
+ getThreadDetailSnapshot: () => Effect.succeed(Option.none()),
}),
),
Layer.provide(
diff --git a/apps/server/src/orchestration/Layers/OrchestrationEngine.ts b/apps/server/src/orchestration/Layers/OrchestrationEngine.ts
--- a/apps/server/src/orchestration/Layers/OrchestrationEngine.ts
+++ b/apps/server/src/orchestration/Layers/OrchestrationEngine.ts
@@ -306,8 +306,8 @@
Effect.annotateLogs({ sequence: commandReadModel.snapshotSequence }),
);
- const readEvents: OrchestrationEngineShape["readEvents"] = (fromSequenceExclusive) =>
- eventStore.readFromSequence(fromSequenceExclusive);
+ const readEvents: OrchestrationEngineShape["readEvents"] = (fromSequenceExclusive, limit) =>
+ eventStore.readFromSequence(fromSequenceExclusive, limit);
const dispatch: OrchestrationEngineShape["dispatch"] = (command) =>
Effect.gen(function* () {
@@ -329,6 +329,7 @@
get streamDomainEvents(): OrchestrationEngineShape["streamDomainEvents"] {
return Stream.fromPubSub(eventPubSub);
},
+ subscribeDomainEvents: Effect.map(PubSub.subscribe(eventPubSub), Stream.fromSubscription),
} satisfies OrchestrationEngineShape;
});
diff --git a/apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.ts b/apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.ts
--- a/apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.ts
+++ b/apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.ts
@@ -2033,6 +2033,23 @@
);
});
+ const getThreadDetailSnapshot: ProjectionSnapshotQueryShape["getThreadDetailSnapshot"] = (
+ threadId,
+ ) =>
+ sql.withTransaction(Effect.all([getThreadDetailById(threadId), getSnapshotSequence()])).pipe(
+ Effect.map(([threadDetail, { snapshotSequence }]) =>
+ Option.map(threadDetail, (thread) => ({ snapshotSequence, thread })),
+ ),
+ Effect.mapError((error) => {
+ if (isPersistenceError(error)) {
+ return error;
+ }
+ return toPersistenceSqlError("ProjectionSnapshotQuery.getThreadDetailSnapshot:query")(
+ error,
+ );
+ }),
+ );
+
return {
getCommandReadModel,
getSnapshot,
@@ -2047,6 +2064,7 @@
getFullThreadDiffContext,
getThreadShellById,
getThreadDetailById,
+ getThreadDetailSnapshot,
} satisfies ProjectionSnapshotQueryShape;
});
diff --git a/apps/server/src/orchestration/Services/OrchestrationEngine.ts b/apps/server/src/orchestration/Services/OrchestrationEngine.ts
--- a/apps/server/src/orchestration/Services/OrchestrationEngine.ts
+++ b/apps/server/src/orchestration/Services/OrchestrationEngine.ts
@@ -13,6 +13,7 @@
import type { OrchestrationCommand, OrchestrationEvent } from "@t3tools/contracts";
import * as Context from "effect/Context";
import type * as Effect from "effect/Effect";
+import type * as Scope from "effect/Scope";
import type * as Stream from "effect/Stream";
import type { OrchestrationDispatchError } from "../Errors.ts";
@@ -26,10 +27,14 @@
* Replay persisted orchestration events from an exclusive sequence cursor.
*
* @param fromSequenceExclusive - Sequence cursor (exclusive).
+ * @param limit - Optional maximum number of events to replay. Defaults to
+ * the event store's replay cap; pass `Number.MAX_SAFE_INTEGER` for an
+ * exhaustive catch-up replay.
* @returns Stream containing ordered events.
*/
readonly readEvents: (
fromSequenceExclusive: number,
+ limit?: number,
) => Stream.Stream<OrchestrationEvent, OrchestrationEventStoreError, never>;
/**
@@ -49,8 +54,26 @@
* Stream persisted domain events in dispatch order.
*
* This is a hot runtime stream (new events only), not a historical replay.
+ * The underlying PubSub subscription is only attached once the stream is
+ * pulled; use `subscribeDomainEvents` when the subscription must be
+ * attached before other work (e.g. loading a snapshot baseline).
*/
readonly streamDomainEvents: Stream.Stream<OrchestrationEvent>;
+
+ /**
+ * Attach a domain event subscription immediately and return the stream of
+ * events it receives.
+ *
+ * Unlike `streamDomainEvents`, events published between running this effect
+ * and pulling the returned stream are buffered by the subscription instead
+ * of dropped, which is required for snapshot/catch-up + live combinations.
+ * The subscription is released when the surrounding scope closes.
+ */
+ readonly subscribeDomainEvents: Effect.Effect<
+ Stream.Stream<OrchestrationEvent>,
+ never,
+ Scope.Scope
+ >;
}
/**
diff --git a/apps/server/src/orchestration/Services/ProjectionSnapshotQuery.ts b/apps/server/src/orchestration/Services/ProjectionSnapshotQuery.ts
--- a/apps/server/src/orchestration/Services/ProjectionSnapshotQuery.ts
+++ b/apps/server/src/orchestration/Services/ProjectionSnapshotQuery.ts
@@ -14,6 +14,7 @@
OrchestrationReadModel,
OrchestrationShellSnapshot,
OrchestrationThread,
+ OrchestrationThreadDetailSnapshot,
OrchestrationThreadShell,
ProjectId,
ThreadId,
@@ -157,6 +158,15 @@
readonly getThreadDetailById: (
threadId: ThreadId,
) => Effect.Effect<Option.Option<OrchestrationThread>, ProjectionRepositoryError>;
+
+ /**
+ * Read a single active thread detail together with the projection snapshot
+ * sequence, both observed inside one transaction so the sequence never runs
+ * ahead of the thread rows it is paired with.
+ */
+ readonly getThreadDetailSnapshot: (
+ threadId: ThreadId,
+ ) => Effect.Effect<Option.Option<OrchestrationThreadDetailSnapshot>, ProjectionRepositoryError>;
}
/**
diff --git a/apps/server/src/orchestration/http.ts b/apps/server/src/orchestration/http.ts
--- a/apps/server/src/orchestration/http.ts
+++ b/apps/server/src/orchestration/http.ts
@@ -45,18 +45,17 @@
Effect.fn("environment.orchestration.threadSnapshot")(function* (args) {
yield* annotateEnvironmentRequest(args.endpoint.name);
yield* requireEnvironmentScope(AuthOrchestrationReadScope);
- const [threadDetail, { snapshotSequence }] = yield* Effect.all([
- projectionSnapshotQuery.getThreadDetailById(args.params.threadId),
- projectionSnapshotQuery.getSnapshotSequence(),
- ]).pipe(
- Effect.catch((cause) =>
- failEnvironmentInternal("orchestration_thread_snapshot_failed", cause),
- ),
- );
- if (Option.isNone(threadDetail)) {
+ const snapshot = yield* projectionSnapshotQuery
+ .getThreadDetailSnapshot(args.params.threadId)
+ .pipe(
+ Effect.catch((cause) =>
+ failEnvironmentInternal("orchestration_thread_snapshot_failed", cause),
+ ),
+ );
+ if (Option.isNone(snapshot)) {
return yield* failEnvironmentNotFound("thread_not_found");
}
- return { snapshotSequence, thread: threadDetail.value };
+ return snapshot.value;
}),
)
.handle(
diff --git a/apps/server/src/project/ProjectSetupScriptRunner.test.ts b/apps/server/src/project/ProjectSetupScriptRunner.test.ts
--- a/apps/server/src/project/ProjectSetupScriptRunner.test.ts
+++ b/apps/server/src/project/ProjectSetupScriptRunner.test.ts
@@ -43,6 +43,7 @@
getFullThreadDiffContext: () => Effect.die("unused"),
getThreadShellById: () => Effect.die("unused"),
getThreadDetailById: () => Effect.die("unused"),
+ getThreadDetailSnapshot: () => Effect.die("unused"),
});
const makeTerminalManagerLayer = (
diff --git a/apps/server/src/provider/Layers/ProviderSessionReaper.test.ts b/apps/server/src/provider/Layers/ProviderSessionReaper.test.ts
--- a/apps/server/src/provider/Layers/ProviderSessionReaper.test.ts
+++ b/apps/server/src/provider/Layers/ProviderSessionReaper.test.ts
@@ -209,6 +209,7 @@
: Option.none(),
),
getThreadDetailById: () => Effect.die("unused"),
+ getThreadDetailSnapshot: () => Effect.die("unused"),
}),
),
Layer.provideMerge(NodeServices.layer),
diff --git a/apps/server/src/relay/AgentAwarenessRelay.test.ts b/apps/server/src/relay/AgentAwarenessRelay.test.ts
--- a/apps/server/src/relay/AgentAwarenessRelay.test.ts
+++ b/apps/server/src/relay/AgentAwarenessRelay.test.ts
@@ -461,6 +461,7 @@
readEvents: () => Stream.empty,
dispatch: () => Effect.succeed({ sequence: 1 }),
streamDomainEvents: Stream.fromQueue(events),
+ subscribeDomainEvents: Effect.sync(() => Stream.fromQueue(events)),
} satisfies OrchestrationEngineShape;
const snapshotQuery = {
@@ -650,6 +651,7 @@
readEvents: () => Stream.empty,
dispatch: () => Effect.succeed({ sequence: 1 }),
streamDomainEvents: Stream.fromQueue(events),
+ subscribeDomainEvents: Effect.sync(() => Stream.fromQueue(events)),
} satisfies OrchestrationEngineShape),
Layer.succeed(ProjectionSnapshotQuery, {
getShellSnapshot: () =>
diff --git a/apps/server/src/serverRuntimeStartup.test.ts b/apps/server/src/serverRuntimeStartup.test.ts
--- a/apps/server/src/serverRuntimeStartup.test.ts
+++ b/apps/server/src/serverRuntimeStartup.test.ts
@@ -96,6 +96,7 @@
getFullThreadDiffContext: () => Effect.succeed(Option.none()),
getThreadShellById: () => Effect.succeed(Option.none()),
getThreadDetailById: () => Effect.succeed(Option.none()),
+ getThreadDetailSnapshot: () => Effect.succeed(Option.none()),
}),
Effect.provideService(AnalyticsService.AnalyticsService, {
record: () => Effect.void,
@@ -158,6 +159,7 @@
getFullThreadDiffContext: () => Effect.succeed(Option.none()),
getThreadShellById: () => Effect.die("unused"),
getThreadDetailById: () => Effect.die("unused"),
+ getThreadDetailSnapshot: () => Effect.die("unused"),
}),
Effect.provideService(OrchestrationEngine.OrchestrationEngineService, {
readEvents: () => Stream.empty,
@@ -166,6 +168,7 @@
Effect.as({ sequence: 1 }),
),
streamDomainEvents: Stream.empty,
+ subscribeDomainEvents: Effect.succeed(Stream.empty),
} satisfies OrchestrationEngine.OrchestrationEngineService["Service"]),
Effect.provide(NodeServices.layer),
);
@@ -200,6 +203,7 @@
getFullThreadDiffContext: () => Effect.succeed(Option.none()),
getThreadShellById: () => Effect.die("unused"),
getThreadDetailById: () => Effect.die("unused"),
+ getThreadDetailSnapshot: () => Effect.die("unused"),
}),
Effect.provideService(OrchestrationEngine.OrchestrationEngineService, {
readEvents: () => Stream.empty,
@@ -208,6 +212,7 @@
Effect.as({ sequence: 1 }),
),
streamDomainEvents: Stream.empty,
+ subscribeDomainEvents: Effect.succeed(Stream.empty),
} satisfies OrchestrationEngine.OrchestrationEngineService["Service"]),
Effect.provide(NodeServices.layer),
);
@@ -248,6 +253,7 @@
getFullThreadDiffContext: () => Effect.succeed(Option.none()),
getThreadShellById: () => Effect.die("unused"),
getThreadDetailById: () => Effect.die("unused"),
+ getThreadDetailSnapshot: () => Effect.die("unused"),
}),
Effect.provideService(OrchestrationEngine.OrchestrationEngineService, {
readEvents: () => Stream.empty,
@@ -256,6 +262,7 @@
Effect.as({ sequence: 1 }),
),
streamDomainEvents: Stream.empty,
+ subscribeDomainEvents: Effect.succeed(Stream.empty),
} satisfies OrchestrationEngine.OrchestrationEngineService["Service"]),
Effect.provideService(Crypto.Crypto, {
...crypto,
diff --git a/apps/server/src/ws.ts b/apps/server/src/ws.ts
--- a/apps/server/src/ws.ts
+++ b/apps/server/src/ws.ts
@@ -1119,7 +1119,12 @@
event.aggregateId === input.threadId &&
isThreadDetailEvent(event);
- const liveStream = orchestrationEngine.streamDomainEvents.pipe(
+ // Attach the domain event subscription before loading the
+ // snapshot/catch-up baseline: the PubSub does not buffer for
+ // late subscribers, so events published while the baseline is
+ // read would otherwise be dropped. Overlapping events are
+ // deduped by sequence on the client.
+ const liveStream = (yield* orchestrationEngine.subscribeDomainEvents).pipe(
Stream.filter(isThisThreadDetailEvent),
Stream.map((event) => ({
kind: "event" as const,
@@ -1131,26 +1136,29 @@
// that snapshot's sequence, and we resume the live subscription by
// replaying persisted events after it instead of re-sending the
// (potentially multi-KB) snapshot frame over the socket. The
- // catch-up replay + live stream carry the same ordering guarantees
- // as the snapshot-then-live path below; overlapping events are
- // deduped by sequence on the client.
+ // catch-up replay must be exhaustive — a truncated replay would
+ // silently drop thread updates — so it bypasses the default
+ // replay cap.
if (input.afterSequence !== undefined) {
- const catchUpStream = orchestrationEngine.readEvents(input.afterSequence).pipe(
- Stream.filter(isThisThreadDetailEvent),
- Stream.map((event) => ({ kind: "event" as const, event })),
- Stream.mapError(
- (cause) =>
- new OrchestrationGetSnapshotError({
- message: `Failed to replay thread ${input.threadId} events`,
- cause,
- }),
- ),
- );
+ const catchUpStream = orchestrationEngine
+ .readEvents(input.afterSequence, Number.MAX_SAFE_INTEGER)
+ .pipe(
+ Stream.filter(isThisThreadDetailEvent),
+ Stream.map((event) => ({ kind: "event" as const, event })),
+ Stream.mapError(
+ (cause) =>
+ new OrchestrationGetSnapshotError({
+ message: `Failed to replay thread ${input.threadId} events`,
+ cause,
+ }),
+ ),
+ );
return Stream.concat(catchUpStream, liveStream);
}
- const [threadDetail, snapshotSequence] = yield* Effect.all([
- projectionSnapshotQuery.getThreadDetailById(input.threadId).pipe(
+ const threadSnapshot = yield* projectionSnapshotQuery
+ .getThreadDetailSnapshot(input.threadId)
+ .pipe(
Effect.mapError(
(cause) =>
new OrchestrationGetSnapshotError({
@@ -1158,20 +1166,9 @@
cause,
}),
),
- ),
- projectionSnapshotQuery.getSnapshotSequence().pipe(
- Effect.map(({ snapshotSequence }) => snapshotSequence),
- Effect.mapError(
- (cause) =>
- new OrchestrationGetSnapshotError({
- message: "Failed to load orchestration snapshot sequence",
- cause,
- }),
- ),
- ),
- ]);
+ );
- if (Option.isNone(threadDetail)) {
+ if (Option.isNone(threadSnapshot)) {
return yield* new OrchestrationGetSnapshotError({
message: `Thread ${input.threadId} was not found`,
cause: input.threadId,
@@ -1181,10 +1178,7 @@
return Stream.concat(
Stream.make({
kind: "snapshot" as const,
- snapshot: {
- snapshotSequence,
- thread: threadDetail.value,
- },
+ snapshot: threadSnapshot.value,
}),
liveStream,
);You can send follow-ups to the cloud agent here.
ApprovabilityVerdict: Needs human review 1 blocking correctness issue found. This PR introduces new HTTP snapshot loading that changes the client-server sync flow. Two unresolved review comments identify potential correctness issues: live updates may be blocked during HTTP fetch, and shell catch-up may use incorrect state. These substantive concerns combined with the new feature scope warrant human review. You can customize Macroscope's approvability policy. Learn more. |
- ws.ts (afterSequence resume): attach the live PubSub subscription into a scope-bound buffer BEFORE draining the catch-up replay, so events published during the replay window are not lost; read the full range after the cursor (readEvents limit) so the per-thread filter can't be starved by a global cap. - ProjectionSnapshotQuery: add getThreadDetailSnapshot that reads thread detail + snapshot sequence in one transaction, so the sequence is consistent with the returned state; use it in the HTTP handler and the WS snapshot path. - OrchestrationEngine.readEvents: accept an optional limit. - client loader: bound the HTTP snapshot timeout (cached data renders meanwhile) and treat a 404 as an expected defer-to-socket case rather than a warning. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The loader layer resolved ManagedRelayDpopSigner eagerly at build, hard-requiring it even though only relay/DPoP connections need it. Resolve it via Effect.serviceOption and pass it through to buildAuthHeaders, so the layer only requires HttpClient; bearer/primary connections no longer depend on a signer. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Effect service conventions require catchTags (object form) over catchTag even for a single tag. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…napshot Part 1 (thread warm-cache): persist the snapshot sequence alongside the cached thread (StoredThreadSnapshot v2) so a re-opened thread resumes from the cached sequence via afterSequence — receiving only events since then — instead of re-downloading its full body. Cold cache still loads the full snapshot over HTTP. Part 2 (shell): the shell subscription now resumes the same way. Added an afterSequence input to subscribeShell (server replays shell events after the cursor, buffering live events before the catch-up replay, as in the thread path) and a GET /api/orchestration/shell endpoint so a cold-cache full shell rides HTTP instead of the socket. The client passes the cached/loaded shell sequence. Shared the environment auth-header builder across the thread and shell HTTP loaders. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issue. You can view the agent here.
Reviewed by Cursor Bugbot for commit 9bc191b. Configure here.
| cause, | ||
| }), | ||
| ), | ||
| ); |
There was a problem hiding this comment.
Shell catch-up uses current DB
Medium Severity
When subscribeShell resumes with afterSequence, catch-up replays persisted events through toShellStreamEvent, which loads project/thread shells from the current projection (getProjectShellById / getThreadShellById). Those reads reflect today’s state, not the state at each replayed sequence, so the client can apply the wrong shell data (or drop upserts for deleted rows) while still advancing snapshotSequence.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 9bc191b. Configure here.
There was a problem hiding this comment.
Bugbot Autofix determined this is a false positive.
The shell stream replicates current state (whole-row upserts deduped by monotonic sequence), and because event append and projection update commit in one transaction, replayed events always carry data at a version >= their sequence while every deletion/archive emits its own payload-derived removal event later in the same replay, so the client provably converges to the server's current shell with no dropped changes — the same read-current-projection semantics the pre-existing live path already uses.
You can send follow-ups to the cloud agent here.
Primary/local environments with no bearer or DPoP credential authenticate the browser via a session cookie, which a cross-origin fetch does not send by default — so the thread/shell snapshot requests 401'd against a primary env on a different origin. Add withEnvironmentCredentials (shared in environmentHttpAuth) which opts those requests into credentials: "include"; bearer/DPoP connections carry their credential in a header and are unaffected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…pping Remove dead upstream pingdotgg#3719 snapshot-loader modules and restore the stack's versions of client-runtime rpc/connection files and the web connection runtime/auth, which referenced contracts the stack replaced. Integration tree only.
…pping Remove dead upstream pingdotgg#3719 snapshot-loader modules and restore the stack's versions of client-runtime rpc/connection files and the web connection runtime/auth, which referenced contracts the stack replaced. Integration tree only.
Ports main's features onto the V2 orchestrator and wire protocol: - HTTP snapshot loading (#3719): new OrchestrationV2ThreadDetailSnapshot contract, /api/orchestration/{shell,threads/:threadId} endpoints served from the V2 engine (orchestration-v2/http.ts), afterSequence resume on the V2 subscribeShell/subscribeThread WS methods, and V2-typed client snapshot loaders wired into shell/thread sync with warm-cache resume. - Thread cache now persists the snapshot sequence (cache schema v3) so warm caches resume via afterSequence instead of refetching. - Mobile: main's react-navigation architecture retained; branch's V2 surfaces (relationships banner, queue control, activity inspector, work-log thread links, fork-from-run) ported off expo-router; thread status presentation and awareness diagnostics mapped to V2 runtime fields; pending-task start-turn helper gains creationSource "mobile". - Retired v1-only additions from main (v1 RPC schemas, session/latestTurn awareness heuristics, v1 engine test updates) where the branch already replaced those systems with V2 equivalents. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nostics + snapshot loaders) - Regenerate pnpm-lock (client-runtime's react devDeps for the shared lazy-load hook were missing from the pnpm-11 lockfile). - Repair a doc comment the rebase union broke in Services/ProjectionSnapshotQuery. - Satisfy main's new @effect/language-service diagnostics: TUI tsconfig disables nodeBuiltinImport/globalDate/globalTimers (a Node/Bun-native terminal app); file directives for cli/tui.ts, connection.ts, and the terminal Manager's CPR-gate wall-clock reads (Clock threading is a follow-up); return yield* at generator exits. - Adapt the TUI to main's HTTP snapshot preloading (pingdotgg#3719): the in-memory cache stores {snapshotSequence, thread} detail snapshots, and no-op Thread/ShellSnapshotLoader layers fall back to the socket-embedded snapshots (the TUI's existing path). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ation and transport negotiation Opening a large thread still transfers the entire thread body — every message, activity, and inline base64 blob since the thread began. On cellular this never completes for media-heavy threads, and parsing the resulting payload can OOM-kill the mobile app outright (observed: a 268MB thread snapshot). pingdotgg#3719 moved the snapshot off the socket; this change bounds what is transferred at all. Measured on a physical Android device over Tailscale: - One media-heavy thread's snapshot was ~25MB on the wire; gzip only buys 1.6x on inline base64. With the bounded tail it renders in seconds over 5G. - Sequence-cursor reconnects: 21,528KB re-sent per reconnect before, 36-54KB after (~400x). What this adds, all capability-gated so old peers are unaffected: - subscribeThreadV2: a small thread head (metadata, latest turn, session, active plan, pending approval/input requests, counts) plus the last 32 messages / 128 compact activities under a 512KiB inline budget, emitted as <=256KiB chunks with keepalives between them, then live events after the snapshot watermark. Catch-up replays are epoch-checked and bounded to the watermark; a bounded (2048) live buffer signals an explicit resync instead of queueing unboundedly. - getThreadHistoryPage: keyset pagination for older messages and activities (scroll-up on mobile), invalidated across thread.reverted via a history epoch so pages never mix pre/post-revert history. - Activity payload externalization: base64 data-URLs and oversized payloads are stored as content-addressed attachments served by the existing /api/assets route; the wire carries references and mobile renders tap-to-load placeholders. (Message attachments already work this way — activity payloads were the unbounded route.) - Transport negotiation: the environment descriptor advertises rpcTransports and threadSyncVersions (with decode defaults, so new clients read old descriptors); /ws stays byte-for-byte plain JSON and an optional gzip transport lives at /ws-compressed behind an optional RpcCompressionCodec (defaults to null; only opted-in platforms provide one). Cached-token reuse treats the negotiation probe as best-effort so offline reconnects keep working. - Client: a distinct windowed thread state (never passed through APIs typed as a complete OrchestrationThread), atomic snapshot staging committed together with its cursor, resyncs that restart the subscription with a logged reason, and thread caches that store either a legacy detail snapshot or a v2 window (older records evict as cache misses). Array-by-copy methods are avoided in mobile-bound code: Hermes on current retail devices lacks toSorted and fails as a silent fiber defect. Tests: v2 contract decode/round-trip, transactional tail and keyset page queries with revert invalidation, wire round-trip -> staging integration, windowed merge/revert reducers, mobile feed windowing, and an opt-in real-data replay suite (T3_THREAD_SYNC_REALDATA_DB) that replays production-scale threads through the pipeline. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Add middle-click close for right panel tabs (#3161) Co-authored-by: Julius Marminge <jmarminge@gmail.com> * fix: warm WSL before preflight in WSL-only backend mode (#3588) * Add Claude Sonnet 5 as the default Claude model (#3620) * Restore the ultrathink frame border effect (#3625) * fix(dev): Fix electron dev launch and add test (#3662) * Add adaptive split-view layout for iPad/mobile workspace (#3514) Co-authored-by: codex <codex@users.noreply.github.com> Co-authored-by: Julius Marminge <julius@mac.lan> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * fix(mobile): compile patched native pods from source on EAS (#3667) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * Make the thread composer read as elevated liquid glass (#3668) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * Upgrade Vite Plus and enable bundled dev opt-in (#3679) * Surface pending tasks in mobile home and draft flow (#3670) * fix(mobile): combined test branch — scroll, back-swipe, thread lists, computer switching (#3687) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * Add repo-root favicon.svg so t3 code shows its own icon (#3683) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * Load thread snapshots over HTTP before live sync (#3719) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * Fix mobile legend anchor under automatic iOS insets (#3684) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * Improve live activity routing and diagnostics (#3685) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * Prevent Add Project sheet from collapsing on relayout (#3759) * Use variant-specific splash icons in mobile app (#3762) * Fix Expo widget asset wiring order (#3763) * Extend Done display to 15 minutes and show up to 5 Live Activity banner rows (#3761) * Clear VCS presentation state on finish (#3764) * Lead with the outcome when no agents are active in the Live Activity (#3768) * Add T3 Connect onboarding for mobile and web (#3765) * Revert "Add T3 Connect onboarding for mobile and web" (#3776) * Expose Clerk Google sign-in env vars to Expo (#3772) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * Set up Cursor Cloud dev environment (web + Android toolchain) (#3755) Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Theo Browne <t3dotgg@users.noreply.github.com> * Revert "Revert "Add T3 Connect onboarding for mobile and web"" (#3777) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * Use rounded depth logo for production splash screen (#3780) Co-authored-by: Cursor Agent <cursoragent@cursor.com> * fix(release): stage pnpm 11 allowBuilds for desktop installs (#3781) Co-authored-by: Cursor Agent <cursoragent@cursor.com> * Upgrade Clerk toolchain to latest versions (#3785) * fix(release): bump electron-builder so pnpm 11 deduped deps land in the asar (#3790) * Fix desktop native optional dependency packaging (#3816) * [codex] Upgrade Clerk stack (#3821) Co-authored-by: codex <codex@users.noreply.github.com> * [codex] Preserve worktree metadata during branch sync (#3822) Co-authored-by: codex <codex@users.noreply.github.com> * feat(client): persist offline environment data and mobile preferences (#3795) Co-authored-by: Julius Marminge <julius@mac.lan> Co-authored-by: codex <codex@users.noreply.github.com> * [codex] Label max and ultra reasoning (#3824) Co-authored-by: codex <codex@users.noreply.github.com> * fix(mobile): embed fonts and render project favicons reliably (#3823) Co-authored-by: codex <codex@users.noreply.github.com> * Show compact PR number badges in mobile thread rows (#3827) Co-authored-by: codex <codex@users.noreply.github.com> * Expose mobile PR indicator labels to accessibility (#3828) Co-authored-by: codex <codex@users.noreply.github.com> * Fix truncated chat error alert layout (#3899) * fix(marketing): show platform-appropriate commit shortcut on the website (#3644) * [codex] Add Android mobile support (#3579) Co-authored-by: Horus Lugo <horusgoul@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: maria-rcks <maria@kuuro.net> Co-authored-by: Shivam Sharma <91240327+shivamhwp@users.noreply.github.com> Co-authored-by: Ben Davis <45952064+bmdavis419@users.noreply.github.com> Co-authored-by: Alex <me@pixp.cc> Co-authored-by: codex <codex@users.noreply.github.com> Co-authored-by: Julius Marminge <julius@mac.lan> --------- Co-authored-by: Hugo Blom <6117705+huxcrux@users.noreply.github.com> Co-authored-by: Julius Marminge <jmarminge@gmail.com> Co-authored-by: Utkarsh Patil <73941998+UtkarshUsername@users.noreply.github.com> Co-authored-by: Julius Marminge <julius0216@outlook.com> Co-authored-by: Theo Browne <me@t3.gg> Co-authored-by: codex <codex@users.noreply.github.com> Co-authored-by: Julius Marminge <julius@mac.lan> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Theo Browne <t3dotgg@users.noreply.github.com> Co-authored-by: Rowan <rowan@cardow.co> Co-authored-by: Patricio Gómez Meneses <107218376+Prgm-code@users.noreply.github.com> Co-authored-by: Jake Leventhal <jakeleventhal@me.com> Co-authored-by: Vedank Purohit <VedankPurohit2@gmail.com> Co-authored-by: Horus Lugo <horusgoul@gmail.com> Co-authored-by: maria-rcks <maria@kuuro.net> Co-authored-by: Shivam Sharma <91240327+shivamhwp@users.noreply.github.com> Co-authored-by: Ben Davis <45952064+bmdavis419@users.noreply.github.com> Co-authored-by: Alex <me@pixp.cc>
…nostics + snapshot loaders) - Regenerate pnpm-lock (client-runtime's react devDeps for the shared lazy-load hook were missing from the pnpm-11 lockfile). - Repair a doc comment the rebase union broke in Services/ProjectionSnapshotQuery. - Satisfy main's new @effect/language-service diagnostics: TUI tsconfig disables nodeBuiltinImport/globalDate/globalTimers (a Node/Bun-native terminal app); file directives for cli/tui.ts, connection.ts, and the terminal Manager's CPR-gate wall-clock reads (Clock threading is a follow-up); return yield* at generator exits. - Adapt the TUI to main's HTTP snapshot preloading (pingdotgg#3719): the in-memory cache stores {snapshotSequence, thread} detail snapshots, and no-op Thread/ShellSnapshotLoader layers fall back to the socket-embedded snapshots (the TUI's existing path). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nostics + snapshot loaders) - Regenerate pnpm-lock (client-runtime's react devDeps for the shared lazy-load hook were missing from the pnpm-11 lockfile). - Repair a doc comment the rebase union broke in Services/ProjectionSnapshotQuery. - Satisfy main's new @effect/language-service diagnostics: TUI tsconfig disables nodeBuiltinImport/globalDate/globalTimers (a Node/Bun-native terminal app); file directives for cli/tui.ts, connection.ts, and the terminal Manager's CPR-gate wall-clock reads (Clock threading is a follow-up); return yield* at generator exits. - Adapt the TUI to main's HTTP snapshot preloading (pingdotgg#3719): the in-memory cache stores {snapshotSequence, thread} detail snapshots, and no-op Thread/ShellSnapshotLoader layers fall back to the socket-embedded snapshots (the TUI's existing path). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nostics + snapshot loaders) - Regenerate pnpm-lock (client-runtime's react devDeps for the shared lazy-load hook were missing from the pnpm-11 lockfile). - Repair a doc comment the rebase union broke in Services/ProjectionSnapshotQuery. - Satisfy main's new @effect/language-service diagnostics: TUI tsconfig disables nodeBuiltinImport/globalDate/globalTimers (a Node/Bun-native terminal app); file directives for cli/tui.ts, connection.ts, and the terminal Manager's CPR-gate wall-clock reads (Clock threading is a follow-up); return yield* at generator exits. - Adapt the TUI to main's HTTP snapshot preloading (pingdotgg#3719): the in-memory cache stores {snapshotSequence, thread} detail snapshots, and no-op Thread/ShellSnapshotLoader layers fall back to the socket-embedded snapshots (the TUI's existing path). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nostics + snapshot loaders) - Regenerate pnpm-lock (client-runtime's react devDeps for the shared lazy-load hook were missing from the pnpm-11 lockfile). - Repair a doc comment the rebase union broke in Services/ProjectionSnapshotQuery. - Satisfy main's new @effect/language-service diagnostics: TUI tsconfig disables nodeBuiltinImport/globalDate/globalTimers (a Node/Bun-native terminal app); file directives for cli/tui.ts, connection.ts, and the terminal Manager's CPR-gate wall-clock reads (Clock threading is a follow-up); return yield* at generator exits. - Adapt the TUI to main's HTTP snapshot preloading (pingdotgg#3719): the in-memory cache stores {snapshotSequence, thread} detail snapshots, and no-op Thread/ShellSnapshotLoader layers fall back to the socket-embedded snapshots (the TUI's existing path). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nostics + snapshot loaders) - Regenerate pnpm-lock (client-runtime's react devDeps for the shared lazy-load hook were missing from the pnpm-11 lockfile). - Repair a doc comment the rebase union broke in Services/ProjectionSnapshotQuery. - Satisfy main's new @effect/language-service diagnostics: TUI tsconfig disables nodeBuiltinImport/globalDate/globalTimers (a Node/Bun-native terminal app); file directives for cli/tui.ts, connection.ts, and the terminal Manager's CPR-gate wall-clock reads (Clock threading is a follow-up); return yield* at generator exits. - Adapt the TUI to main's HTTP snapshot preloading (pingdotgg#3719): the in-memory cache stores {snapshotSequence, thread} detail snapshots, and no-op Thread/ShellSnapshotLoader layers fall back to the socket-embedded snapshots (the TUI's existing path). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
## What's Changed * Add middle-click close for right panel tabs by @huxcrux in https://github.com/pingdotgg/t3code/pull/3161 * fix: warm WSL before preflight in WSL-only backend mode by @UtkarshUsername in https://github.com/pingdotgg/t3code/pull/3588 * Add Claude Sonnet 5 as the default Claude model by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3620 * Restore the ultrathink frame border effect by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3625 * fix(dev): Fix electron dev launch and add test by @t3dotgg in https://github.com/pingdotgg/t3code/pull/3662 * Add adaptive split-view layout for iPad/mobile workspace by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3514 * fix(mobile): compile patched native pods from source on EAS by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3667 * Make the thread composer read as elevated liquid glass by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3668 * Upgrade Vite Plus and enable bundled dev opt-in by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3679 * Surface pending tasks in mobile home and draft flow by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3670 * fix(mobile): combined test branch — scroll, back-swipe, thread lists, computer switching by @t3dotgg in https://github.com/pingdotgg/t3code/pull/3687 * Add repo-root favicon.svg so t3 code shows its own icon by @t3dotgg in https://github.com/pingdotgg/t3code/pull/3683 * Load thread snapshots over HTTP before live sync by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3719 * Fix mobile legend anchor under automatic iOS insets by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3684 * Improve live activity routing and diagnostics by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3685 * Prevent Add Project sheet from collapsing on relayout by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3759 * Use variant-specific splash icons in mobile app by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3762 * Fix Expo widget asset wiring order by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3763 * Extend Done display to 15 minutes and show up to 5 Live Activity banner rows by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3761 * Clear VCS presentation state on finish by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3764 * Lead with the outcome when no agents are active in the Live Activity by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3768 * Add T3 Connect onboarding for mobile and web by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3765 * Revert "Add T3 Connect onboarding for mobile and web" by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3776 * Expose Clerk Google sign-in env vars to Expo by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3772 * Set up Cursor Cloud dev environment (web + Android toolchain) by @t3dotgg in https://github.com/pingdotgg/t3code/pull/3755 * Revert "Revert "Add T3 Connect onboarding for mobile and web"" by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3777 * Use rounded depth logo for production splash screen by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3780 * fix(release): stage pnpm 11 allowBuilds for desktop installs by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3781 * Upgrade Clerk toolchain to latest versions by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3785 * fix(release): bump electron-builder so pnpm 11 deduped deps land in the asar by @avocardow in https://github.com/pingdotgg/t3code/pull/3790 * Fix desktop native optional dependency packaging by @Prgm-code in https://github.com/pingdotgg/t3code/pull/3816 * [codex] Upgrade Clerk stack by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3821 * [codex] Preserve worktree metadata during branch sync by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3822 * feat(client): persist offline environment data and mobile preferences by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3795 * [codex] Label max and ultra reasoning by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3824 * fix(mobile): embed fonts and render project favicons reliably by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3823 * Show compact PR number badges in mobile thread rows by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3827 * Expose mobile PR indicator labels to accessibility by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3828 * Fix truncated chat error alert layout by @jakeleventhal in https://github.com/pingdotgg/t3code/pull/3899 * fix(marketing): show platform-appropriate commit shortcut on the website by @VedankPurohit in https://github.com/pingdotgg/t3code/pull/3644 * [codex] Add Android mobile support by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3579 * Use client-side fallbacks for missing project favicons by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3959 * Skip stale working-task notifications by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3961 * Prepare Android beta branding and review diff UI by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3967 * perf(web): duty-cycle status animations and remove fixed noise overlay by @t3dotgg in https://github.com/pingdotgg/t3code/pull/3978 * fix(docs): correct CI task-runner commands in ci.md by @kridaydave in https://github.com/pingdotgg/t3code/pull/3990 * fix(docs): repair broken source links in architecture overview by @kridaydave in https://github.com/pingdotgg/t3code/pull/3991 * fix(docs): replace stale codething-mvp absolute paths with repo-relative links by @kridaydave in https://github.com/pingdotgg/t3code/pull/3992 * docs: Add T3 Code Legal Docs by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3972 * Fix Legal modal header crash by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4000 * [codex] Fix onboarding connection status by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4001 * Isolate native diff highlight grammar state by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4029 * Fix macOS fullscreen titlebar spacing by @D3OXY in https://github.com/pingdotgg/t3code/pull/4019 * Prevent duplicate project workspace roots by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3829 * Normalize over-indented markdown list items by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4020 * Resolve localhost preview URLs for remote environments by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4011 * fix(mobile): Send composer images in upload wire format by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4035 * Fix iOS terminal Enter input encoding by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4043 * Add native mobile share target support by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4021 * [codex] Expand real-route app store screenshot harness by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4014 * fix(server): use CLAUDE_CONFIG_DIR instead of HOME for Claude instanc… by @dmstoykov in https://github.com/pingdotgg/t3code/pull/4017 * Fix dropped events during initial thread snapshot by @D3OXY in https://github.com/pingdotgg/t3code/pull/4079 * feat: show nightly update changelog tooltip by @HugoVizcainoSantana in https://github.com/pingdotgg/t3code/pull/3832 * fix(git): treat selected commit paths literally by @EricTsai83 in https://github.com/pingdotgg/t3code/pull/3998 * fix(server): stabilize non-repository Git diagnostics by @EricTsai83 in https://github.com/pingdotgg/t3code/pull/4077 * Refresh app icons across release variants by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4080 * Update marketing GitHub star count by @AmoonPod in https://github.com/pingdotgg/t3code/pull/4088 * fix(marketing): correct Cursor icon color by @AmoonPod in https://github.com/pingdotgg/t3code/pull/4090 * Normalize protocol-relative remote host input as https by @kridaydave in https://github.com/pingdotgg/t3code/pull/3971 * fix(cursor): default binary path to cursor-agent (avoid path conflict w/ grok) by @BunnyGamezsc in https://github.com/pingdotgg/t3code/pull/4094 * Fix documented task-runner commands (bun run -> vp) by @kridaydave in https://github.com/pingdotgg/t3code/pull/3965 * Allow preview panel to grow on wide displays by @olivoil in https://github.com/pingdotgg/t3code/pull/4044 * fix: prevent initial right-click from selecting a context menu item by @Fazalkadivar21 in https://github.com/pingdotgg/t3code/pull/3877 * Fix duplicate keybinding rule when replacing with an existing rule by @kridaydave in https://github.com/pingdotgg/t3code/pull/3969 * fix(server): image upload crashed dispatchCommand with a stack overflow by @t3dotgg in https://github.com/pingdotgg/t3code/pull/3952 * Remove unused code parameter from describePreviewError by @kridaydave in https://github.com/pingdotgg/t3code/pull/3970 * [codex] prevent ACP assistant ID collisions after restarts by @maxwellyoung in https://github.com/pingdotgg/t3code/pull/3932 * fix(web): inset Windows desktop scrollbars from resize edge by @nateEc in https://github.com/pingdotgg/t3code/pull/4097 * [codex] fix mobile composer Enter behavior by @maxwellyoung in https://github.com/pingdotgg/t3code/pull/3930 * feat(server): include runtime model and effort in Codex developer instructions by @t3dotgg in https://github.com/pingdotgg/t3code/pull/3948 * fix(ux): spamming cmd + , no longer stack opening settings by @jamesx0416 in https://github.com/pingdotgg/t3code/pull/2757 * fix(terminal): strip AppImage runtime env from spawned terminals by @leorivastech in https://github.com/pingdotgg/t3code/pull/3108 * fix(server): thread cwd through Claude capability probe (#2048) by @mvanhorn in https://github.com/pingdotgg/t3code/pull/2124 * [codex] fix: guard invalid web timestamps by @StiensWout in https://github.com/pingdotgg/t3code/pull/3515 * [codex] fix: tolerate invalid latest user message timestamps by @StiensWout in https://github.com/pingdotgg/t3code/pull/3521 * [codex] Fix provider update checks restore defaults by @StiensWout in https://github.com/pingdotgg/t3code/pull/3531 * fix(server): skip undecodable provider runtime rows when listing sessions by @t3dotgg in https://github.com/pingdotgg/t3code/pull/3951 * Share MCP OAuth locks across Codex shadow homes by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4104 * Preserve T3 Code identity in macOS development launcher by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4102 * fix(web): increase contrast of question option descriptions by @xxashxx-svg in https://github.com/pingdotgg/t3code/pull/3867 * feat: draft hero landing on the index route by @yordis in https://github.com/pingdotgg/t3code/pull/4055 * feat: file explorer mention actions and zoom-aware context menus by @yordis in https://github.com/pingdotgg/t3code/pull/4054 * fix(mobile): restore iOS home screen branding by @PixPMusic in https://github.com/pingdotgg/t3code/pull/4025 * perf(client): defer active thread cache writes by @Chrrxs in https://github.com/pingdotgg/t3code/pull/4006 * Default diffs to working changes by @jakeleventhal in https://github.com/pingdotgg/t3code/pull/3974 * Add Grok to marketing site provider list by @Aditya190803 in https://github.com/pingdotgg/t3code/pull/3484 * Fix reopening existing Diff tab by @jakeleventhal in https://github.com/pingdotgg/t3code/pull/3973 * Fix sending messages during active turns by @jakeleventhal in https://github.com/pingdotgg/t3code/pull/3919 * [codex] Route OpenCode missing-session errors through Effect by @StiensWout in https://github.com/pingdotgg/t3code/pull/3608 * [fix/feat:ui] Show default option badge by @sandersonstabo in https://github.com/pingdotgg/t3code/pull/3232 * [fix/feat:ui] Preserve open-in editor brand colors by @sandersonstabo in https://github.com/pingdotgg/t3code/pull/3225 * fix(web): handle macOS Home and End in composer by @GuilhermeVieiraDev in https://github.com/pingdotgg/t3code/pull/2508 * Allow failed remote environments to be removed by @zepi2509 in https://github.com/pingdotgg/t3code/pull/4084 * [codex] canonicalize client timestamps by @maxwellyoung in https://github.com/pingdotgg/t3code/pull/4112 * [fix/feat:ui] Make selected menu checks blue by @sandersonstabo in https://github.com/pingdotgg/t3code/pull/3234 * fix(desktop): Validate WSL node version against engine range after probe success by @UtkarshUsername in https://github.com/pingdotgg/t3code/pull/3621 * Refresh splash screen and favicon branding by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4120 * Add terminal selection copy action by @tarik02 in https://github.com/pingdotgg/t3code/pull/2904 * Add isolated app testing workflow by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4121 * feat(web): themed sidebar header art for nightly and dev builds by @maria-rcks in https://github.com/pingdotgg/t3code/pull/4130 * feat: add headless `t3 connect` setup for SSH hosts by @t3dotgg in https://github.com/pingdotgg/t3code/pull/3749 * Refine T3 Connect authorization surfaces by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4159 * fix: increase OpenCode server startup timeout from 5s to 30s by @UtkarshUsername in https://github.com/pingdotgg/t3code/pull/4132 * fix(shared): delete unused agentAwareness phase predicates by @kridaydave in https://github.com/pingdotgg/t3code/pull/4134 * fix(mobile): Stabilize native stack option updates by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4037 * Make test-t3-app skill discoverable by Claude Code by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4162 * fix(web): improve dev sidebar backdrop contrast & remove version pills by @maria-rcks in https://github.com/pingdotgg/t3code/pull/4166 * Fix draft banner stack overlap by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4164 * Add portable mobile app testing guidance by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4165 * fix(client): use lightweight connection probe by @eeinarsson in https://github.com/pingdotgg/t3code/pull/4137 * fix(server): resolve Claude SDK executable path on Windows npm installs by @nsxdavid in https://github.com/pingdotgg/t3code/pull/3740 * Fix project action preview settings persistence by @keeperxy in https://github.com/pingdotgg/t3code/pull/3842 * fix(desktop): allow clipboard writes in the preview browser by @carlosricojr in https://github.com/pingdotgg/t3code/pull/3889 * fix(web): handle sidebar shortcut before editors by @Bortlesboat in https://github.com/pingdotgg/t3code/pull/3921 * fix(server): recognize Bedrock-backed Claude as authenticated by @PieterVanZyl-Dev in https://github.com/pingdotgg/t3code/pull/3931 * Fix incorrect pluralization of “entry” by @McMelonTV in https://github.com/pingdotgg/t3code/pull/3933 * feat(server): title background-task work-log rows with the task name by @t3dotgg in https://github.com/pingdotgg/t3code/pull/3751 * fix: delegate OpenCode session titles to provider by @tris203 in https://github.com/pingdotgg/t3code/pull/3720 * Archive selected threads from the context menu by @theduke in https://github.com/pingdotgg/t3code/pull/3895 * fix(cli): support force removing projects by @Bortlesboat in https://github.com/pingdotgg/t3code/pull/3922 * fix: allow sidebar to be shrunk when wider than viewport by @shoaib050326 in https://github.com/pingdotgg/t3code/pull/2456 * fix(codex): show web search query and url in tool call details by @GuilhermeVieiraDev in https://github.com/pingdotgg/t3code/pull/2093 * Add Codex launch arguments setting by @jamesx0416 in https://github.com/pingdotgg/t3code/pull/2892 * [orchestration] Clear stale active turn when session becomes inactive by @Andrew-Forster in https://github.com/pingdotgg/t3code/pull/3159 * Regenerate Codex reset credit protocol bindings by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4173 * fix(preview): preserve direct localhost navigation by @Chrrxs in https://github.com/pingdotgg/t3code/pull/3939 * Synchronize mobile threads with authoritative shell snapshots by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4163 * Gate iOS glass layout on native support by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4032 * fix(opencode): resume the OpenCode session on follow-ups instead of starting an empty one by @vdmkotai in https://github.com/pingdotgg/t3code/pull/3617 * fix(server): use CLI for OpenCode health check instead of spawning server by @UtkarshUsername in https://github.com/pingdotgg/t3code/pull/4153 * fix(web): scope timeline minimap hover target to the side gutter by @xxashxx-svg in https://github.com/pingdotgg/t3code/pull/3869 * [codex] show complete approval details by @maxwellyoung in https://github.com/pingdotgg/t3code/pull/4111 * fix(web): paint text selection over composer chips by @yordis in https://github.com/pingdotgg/t3code/pull/4139 * [codex] preserve custom model slugs by @maxwellyoung in https://github.com/pingdotgg/t3code/pull/4168 * fix(web): preview workspace images in the file panel by @Rhiz3K in https://github.com/pingdotgg/t3code/pull/3996 * feat(web): drag files from the explorer into the chat composer by @yordis in https://github.com/pingdotgg/t3code/pull/4140 * fix(desktop): preserve main window bounds by @anirudhsama in https://github.com/pingdotgg/t3code/pull/3851 * perf(orchestration): speed up new-chat propagation and offline catch-up by @RusiruSadathana in https://github.com/pingdotgg/t3code/pull/4177 * Finale: upgrade changed files card to fix various UI issues by @sandersonstabo in https://github.com/pingdotgg/t3code/pull/4113 * Pass CLI OAuth config to hosted web deploy by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4186 * fix(web): always show environment chip for remote projects by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4217 * fix(web): keep composer editable while disconnected by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4241 * fix: better defaults — Claude 1M context, Codex gpt-5.6, worktrees from origin main by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4240 * fix(claude): handle all SDK stream messages; stop spurious work-log warning rows by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4244 * Sidebar v2 beta: flat thread list with a server-backed settled lifecycle by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4026 * fix(settings): validate the add-provider wizard step before advancing (#2813) by @leorivastech in https://github.com/pingdotgg/t3code/pull/3100 * fix(claude): isolate capability probe from user MCP servers by @jbbottoms in https://github.com/pingdotgg/t3code/pull/4015 * Preserve connecting status while a turn starts by @D3OXY in https://github.com/pingdotgg/t3code/pull/4101 * fix(server): stop restoring stale OpenCode models by @nateEc in https://github.com/pingdotgg/t3code/pull/4095 * [codex] keep scoped package references as text by @maxwellyoung in https://github.com/pingdotgg/t3code/pull/4167 * fix(web): default provider selection for users without Codex by @mfazekas in https://github.com/pingdotgg/t3code/pull/4117 * Unify temporary worktree branch naming by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4278 * fix(web): use message-square icon for settled icon-less project threads in sidebar v2 by @UtkarshUsername in https://github.com/pingdotgg/t3code/pull/4279 * Stabilize sidebar settling animations by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4280 * Restore Copy Link in chat link context menu by @caezium in https://github.com/pingdotgg/t3code/pull/4161 * fix(desktop): handle EPIPE errors on stdout/stderr to prevent crash dialog by @UtkarshUsername in https://github.com/pingdotgg/t3code/pull/4213 * Preserve draft thread highlighting during promotion by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4283 * Move mobile working timer into the thread timeline by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4285 * Stabilize PR status lookups and provider session lifecycle by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4281 * fix: open command palette instead of custom dialog for new thread picker in SidebarV2 by @UtkarshUsername in https://github.com/pingdotgg/t3code/pull/4269 * fix(server): don't drop sticky PR fallback when remote URL can't be resolved by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4289 * feat(web): copy branch name via right-click in the branch selector by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4275 * Add remote server updates and standalone service management by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4286 * Refine light-mode sidebar surfaces by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4268 * fix(mobile): don't mark Android VPN/Tailscale as offline when connected by @Wraient in https://github.com/pingdotgg/t3code/pull/3949 * improve and prevent silent thread branch drift and PR fetching by @justsomelegs in https://github.com/pingdotgg/t3code/pull/2284 * Refresh web application surfaces and dark-mode dialogs by @maria-rcks in https://github.com/pingdotgg/t3code/pull/4319 * fix(web): new-thread defaults ignored for remote environments by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4276 * feat: add "Auto" runtime mode — AI-reviewed approvals for Codex and Claude by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4272 * Add shared t3.json project configuration support by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4317 * Unify dialog glass and fix composer overlays by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4365 * fix(web): warn before silent Windows updates by @nateEc in https://github.com/pingdotgg/t3code/pull/4350 * [codex] Move project grouping to General settings by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4313 * [codex] Group project scopes in mobile thread lists by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4314 * [codex] Move mobile project grouping to General settings by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4315 * [codex] Deduplicate connection failure messaging by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4367 * Restore grouped project filtering in Sidebar V2 by @shivamhwp in https://github.com/pingdotgg/t3code/pull/4282 * [codex] restore Sidebar V2 project actions by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4373 * [codex] Group projects in new-thread pickers by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4312 * fix(web): restore dark composer toolbar styling by @maria-rcks in https://github.com/pingdotgg/t3code/pull/4375 * Fix thread tooltip folder icon color by @maria-rcks in https://github.com/pingdotgg/t3code/pull/4383 * fix(server): parse CLI version in update preflight by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4389 * fix(web): sidebar v2 polish — jump hints, working duration, in-flight fade, settled sort by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4274 * Fix logical project grouping labels on mobile by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4391 * Add preview color scheme controls and simplify project grouping by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4385 * fix(cli): publish nightly branded favicons by @maria-rcks in https://github.com/pingdotgg/t3code/pull/4372 * Fix thread loading flash by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4396 * fix(client-runtime): keep a warm thread un-settled despite a merged/closed PR by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4309 * Fix composer context strip alignment and glass shell by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4404 * Polish iOS git progress overlay with glass effects by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4387 * Improve composer glass fallbacks by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4406 * feat(web): collapse large git diffs by default to make chat more readable by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4409 * Stop new threads inheriting checkout/branch from viewed thread by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4411 * fix: tone down branch-mismatch banner by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4416 * fix: Claude Code skills discoverable for the composer $ picker by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4414 * fix(web): keep settled threads reachable when opened directly by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4413 * feat(sidebar-v2): thread snoozing by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4311 * Upgrade Clerk packages and Expo integration by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4440 * Increase light-mode contrast for user message bubbles by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4441 * Restore model picker layout and retain iterative test state by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4450 * Color settled PR labels on hover by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4451 * [codex] Fix glass hover compositing artifacts by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4446 * Add Claude Opus 5 model by @thomaslittle in https://github.com/pingdotgg/t3code/pull/4472 * feat(web): add collapse-all toggle to diff panel by @0x4bs3nt in https://github.com/pingdotgg/t3code/pull/4475 * feat(web): show fast mode as a bolt instead of a "Normal" label by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4488 * feat(dev): keep worktree dev state isolated on T3 Code dev servers by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4555 * feat(dev): Make t3 code dev instances shareable over Tailscale by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4556 * fix(dev): skip browser-blocked ports by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4608 * fix: cut websocket throughput in half by pruning activity payloads by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4622 * perf(mobile): defer work-log detail serialization by @saphid in https://github.com/pingdotgg/t3code/pull/4607 * test: account for lazy thread feed details by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4628 * feat(relay): limit managed tunnels per user by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4530 * Add managed tunnel limits migration by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4635 * Add background preview capture and picture-in-picture support by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4397 * feat(web): prompt stash — cmd+S saves the composer to a per-provider queue by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4453 * [codex] Upgrade Effect and Alchemy betas by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4643 * feat: allow new thread creation through project breadcrumbs by @0x4bs3nt in https://github.com/pingdotgg/t3code/pull/4638 * fix(web): scope PR state to the thread branch by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4460 * Drop redundant Relay user indexes by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4648 * feat(connect): release the Cloudflare tunnel when the environment shuts down by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4531 * Fix Relay Worker RuntimeContext wiring by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4653 * Fix live sidebar resize limits and defer Alchemy runtime context by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4655 * fix(web): constrain branch toolbar context by @maxktz in https://github.com/pingdotgg/t3code/pull/4657 * Keep MCP credentials alive across provider turns by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4659 * fix: close actions dropdown when editing by @0x4bs3nt in https://github.com/pingdotgg/t3code/pull/4660 * fix(preview): stabilize PiP viewport identity by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4661 * Add glass styling for thread tooltips and simplify preview tab handling by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4665 * Use tarball archiving for hosted web deploys by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4669 * fix(server): bound editor discovery during config loading by @maria-rcks in https://github.com/pingdotgg/t3code/pull/4291 * Prevent draft thread detail polling before shell registration by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4670 * feat: add configurable source control writing settings by @maria-rcks in https://github.com/pingdotgg/t3code/pull/4204 * feat(diff-panel): show total line additions and deletions by @0x4bs3nt in https://github.com/pingdotgg/t3code/pull/4674 * Clear provider update actions while updating by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4676 * Fix sidebar highlighting for draft threads by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4679 * Use glass surfaces for web toasts by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4681 * Show origin ref in branch trigger label by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4680 * fix(mobile): match react version to react-native 0.85.3 vendored renderer (19.2.3) by @KrzysztofMoch in https://github.com/pingdotgg/t3code/pull/4675 ## New Contributors * @avocardow made their first contribution in https://github.com/pingdotgg/t3code/pull/3790 * @Prgm-code made their first contribution in https://github.com/pingdotgg/t3code/pull/3816 * @jakeleventhal made their first contribution in https://github.com/pingdotgg/t3code/pull/3899 * @VedankPurohit made their first contribution in https://github.com/pingdotgg/t3code/pull/3644 * @kridaydave made their first contribution in https://github.com/pingdotgg/t3code/pull/3990 * @dmstoykov made their first contribution in https://github.com/pingdotgg/t3code/pull/4017 * @HugoVizcainoSantana made their first contribution in https://github.com/pingdotgg/t3code/pull/3832 * @EricTsai83 made their first contribution in https://github.com/pingdotgg/t3code/pull/3998 * @AmoonPod made their first contribution in https://github.com/pingdotgg/t3code/pull/4088 * @BunnyGamezsc made their first contribution in https://github.com/pingdotgg/t3code/pull/4094 * @olivoil made their first contribution in https://github.com/pingdotgg/t3code/pull/4044 * @Fazalkadivar21 made their first contribution in https://github.com/pingdotgg/t3code/pull/3877 * @maxwellyoung made their first contribution in https://github.com/pingdotgg/t3code/pull/3932 * @nateEc made their first contribution in https://github.com/pingdotgg/t3code/pull/4097 * @leorivastech made their first contribution in https://github.com/pingdotgg/t3code/pull/3108 * @xxashxx-svg made their first contribution in https://github.com/pingdotgg/t3code/pull/3867 * @yordis made their first contribution in https://github.com/pingdotgg/t3code/pull/4055 * @Chrrxs made their first contribution in https://github.com/pingdotgg/t3code/pull/4006 * @Aditya190803 made their first contribution in https://github.com/pingdotgg/t3code/pull/3484 * @zepi2509 made their first contribution in https://github.com/pingdotgg/t3code/pull/4084 * @eeinarsson made their first contribution in https://github.com/pingdotgg/t3code/pull/4137 * @keeperxy made their first contribution in https://github.com/pingdotgg/t3code/pull/3842 * @carlosricojr made their first contribution in https://github.com/pingdotgg/t3code/pull/3889 * @Bortlesboat made their first contribution in https://github.com/pingdotgg/t3code/pull/3921 * @PieterVanZyl-Dev made their first contribution in https://github.com/pingdotgg/t3code/pull/3931 * @McMelonTV made their first contribution in https://github.com/pingdotgg/t3code/pull/3933 * @tris203 made their first contribution in https://github.com/pingdotgg/t3code/pull/3720 * @theduke made their first contribution in https://github.com/pingdotgg/t3code/pull/3895 * @shoaib050326 made their first contribution in https://github.com/pingdotgg/t3code/pull/2456 * @vdmkotai made their first contribution in https://github.com/pingdotgg/t3code/pull/3617 * @Rhiz3K made their first contribution in https://github.com/pingdotgg/t3code/pull/3996 * @anirudhsama made their first contribution in https://github.com/pingdotgg/t3code/pull/3851 * @RusiruSadathana made their first contribution in https://github.com/pingdotgg/t3code/pull/4177 * @jbbottoms made their first contribution in https://github.com/pingdotgg/t3code/pull/4015 * @mfazekas made their first contribution in https://github.com/pingdotgg/t3code/pull/4117 * @caezium made their first contribution in https://github.com/pingdotgg/t3code/pull/4161 * @Wraient made their first contribution in https://github.com/pingdotgg/t3code/pull/3949 * @thomaslittle made their first contribution in https://github.com/pingdotgg/t3code/pull/4472 * @0x4bs3nt made their first contribution in https://github.com/pingdotgg/t3code/pull/4475 * @saphid made their first contribution in https://github.com/pingdotgg/t3code/pull/4607 * @maxktz made their first contribution in https://github.com/pingdotgg/t3code/pull/4657 * @KrzysztofMoch made their first contribution in https://github.com/pingdotgg/t3code/pull/4675 **Full Changelog**: https://github.com/pingdotgg/t3code/compare/v0.0.28...v0.0.29 ## What's Changed * Add middle-click close for right panel tabs by @huxcrux in https://github.com/pingdotgg/t3code/pull/3161 * fix: warm WSL before preflight in WSL-only backend mode by @UtkarshUsername in https://github.com/pingdotgg/t3code/pull/3588 * Add Claude Sonnet 5 as the default Claude model by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3620 * Restore the ultrathink frame border effect by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3625 * fix(dev): Fix electron dev launch and add test by @t3dotgg in https://github.com/pingdotgg/t3code/pull/3662 * Add adaptive split-view layout for iPad/mobile workspace by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3514 * fix(mobile): compile patched native pods from source on EAS by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3667 * Make the thread composer read as elevated liquid glass by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3668 * Upgrade Vite Plus and enable bundled dev opt-in by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3679 * Surface pending tasks in mobile home and draft flow by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3670 * fix(mobile): combined test branch — scroll, back-swipe, thread lists, computer switching by @t3dotgg in https://github.com/pingdotgg/t3code/pull/3687 * Add repo-root favicon.svg so t3 code shows its own icon by @t3dotgg in https://github.com/pingdotgg/t3code/pull/3683 * Load thread snapshots over HTTP before live sync by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3719 * Fix mobile legend anchor under automatic iOS insets by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3684 * Improve live activity routing and diagnostics by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3685 * Prevent Add Project sheet from collapsing on relayout by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3759 * Use variant-specific splash icons in mobile app by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3762 * Fix Expo widget asset wiring order by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3763 * Extend Done display to 15 minutes and show up to 5 Live Activity banner rows by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3761 * Clear VCS presentation state on finish by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3764 * Lead with the outcome when no agents are active in the Live Activity by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3768 * Add T3 Connect onboarding for mobile and web by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3765 * Revert "Add T3 Connect onboarding for mobile and web" by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3776 * Expose Clerk Google sign-in env vars to Expo by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3772 * Set up Cursor Cloud dev environment (web + Android toolchain) by @t3dotgg in https://github.com/pingdotgg/t3code/pull/3755 * Revert "Revert "Add T3 Connect onboarding for mobile and web"" by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3777 * Use rounded depth logo for production splash screen by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3780 * fix(release): stage pnpm 11 allowBuilds for desktop installs by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3781 * Upgrade Clerk toolchain to latest versions by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3785 * fix(release): bump electron-builder so pnpm 11 deduped deps land in the asar by @avocardow in https://github.com/pingdotgg/t3code/pull/3790 * Fix desktop native optional dependency packaging by @Prgm-code in https://github.com/pingdotgg/t3code/pull/3816 * [codex] Upgrade Clerk stack by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3821 * [codex] Preserve worktree metadata during branch sync by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3822 * feat(client): persist offline environment data and mobile preferences by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3795 * [codex] Label max and ultra reasoning by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3824 * fix(mobile): embed fonts and render project favicons reliably by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3823 * Show compact PR number badges in mobile thread rows by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3827 * Expose mobile PR indicator labels to accessibility by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3828 * Fix truncated chat error alert layout by @jakeleventhal in https://github.com/pingdotgg/t3code/pull/3899 * fix(marketing): show platform-appropriate commit shortcut on the website by @VedankPurohit in https://github.com/pingdotgg/t3code/pull/3644 * [codex] Add Android mobile support by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3579 * Use client-side fallbacks for missing project favicons by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3959 * Skip stale working-task notifications by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3961 * Prepare Android beta branding and review diff UI by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3967 * perf(web): duty-cycle status animations and remove fixed noise overlay by @t3dotgg in https://github.com/pingdotgg/t3code/pull/3978 * fix(docs): correct CI task-runner commands in ci.md by @kridaydave in https://github.com/pingdotgg/t3code/pull/3990 * fix(docs): repair broken source links in architecture overview by @kridaydave in https://github.com/pingdotgg/t3code/pull/3991 * fix(docs): replace stale codething-mvp absolute paths with repo-relative links by @kridaydave in https://github.com/pingdotgg/t3code/pull/3992 * docs: Add T3 Code Legal Docs by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3972 * Fix Legal modal header crash by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4000 * [codex] Fix onboarding connection status by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4001 * Isolate native diff highlight grammar state by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4029 * Fix macOS fullscreen titlebar spacing by @D3OXY in https://github.com/pingdotgg/t3code/pull/4019 * Prevent duplicate project workspace roots by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/3829 * Normalize over-indented markdown list items by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4020 * Resolve localhost preview URLs for remote environments by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4011 * fix(mobile): Send composer images in upload wire format by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4035 * Fix iOS terminal Enter input encoding by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4043 * Add native mobile share target support by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4021 * [codex] Expand real-route app store screenshot harness by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4014 * fix(server): use CLAUDE_CONFIG_DIR instead of HOME for Claude instanc… by @dmstoykov in https://github.com/pingdotgg/t3code/pull/4017 * Fix dropped events during initial thread snapshot by @D3OXY in https://github.com/pingdotgg/t3code/pull/4079 * feat: show nightly update changelog tooltip by @HugoVizcainoSantana in https://github.com/pingdotgg/t3code/pull/3832 * fix(git): treat selected commit paths literally by @EricTsai83 in https://github.com/pingdotgg/t3code/pull/3998 * fix(server): stabilize non-repository Git diagnostics by @EricTsai83 in https://github.com/pingdotgg/t3code/pull/4077 * Refresh app icons across release variants by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4080 * Update marketing GitHub star count by @AmoonPod in https://github.com/pingdotgg/t3code/pull/4088 * fix(marketing): correct Cursor icon color by @AmoonPod in https://github.com/pingdotgg/t3code/pull/4090 * Normalize protocol-relative remote host input as https by @kridaydave in https://github.com/pingdotgg/t3code/pull/3971 * fix(cursor): default binary path to cursor-agent (avoid path conflict w/ grok) by @BunnyGamezsc in https://github.com/pingdotgg/t3code/pull/4094 * Fix documented task-runner commands (bun run -> vp) by @kridaydave in https://github.com/pingdotgg/t3code/pull/3965 * Allow preview panel to grow on wide displays by @olivoil in https://github.com/pingdotgg/t3code/pull/4044 * fix: prevent initial right-click from selecting a context menu item by @Fazalkadivar21 in https://github.com/pingdotgg/t3code/pull/3877 * Fix duplicate keybinding rule when replacing with an existing rule by @kridaydave in https://github.com/pingdotgg/t3code/pull/3969 * fix(server): image upload crashed dispatchCommand with a stack overflow by @t3dotgg in https://github.com/pingdotgg/t3code/pull/3952 * Remove unused code parameter from describePreviewError by @kridaydave in https://github.com/pingdotgg/t3code/pull/3970 * [codex] prevent ACP assistant ID collisions after restarts by @maxwellyoung in https://github.com/pingdotgg/t3code/pull/3932 * fix(web): inset Windows desktop scrollbars from resize edge by @nateEc in https://github.com/pingdotgg/t3code/pull/4097 * [codex] fix mobile composer Enter behavior by @maxwellyoung in https://github.com/pingdotgg/t3code/pull/3930 * feat(server): include runtime model and effort in Codex developer instructions by @t3dotgg in https://github.com/pingdotgg/t3code/pull/3948 * fix(ux): spamming cmd + , no longer stack opening settings by @jamesx0416 in https://github.com/pingdotgg/t3code/pull/2757 * fix(terminal): strip AppImage runtime env from spawned terminals by @leorivastech in https://github.com/pingdotgg/t3code/pull/3108 * fix(server): thread cwd through Claude capability probe (#2048) by @mvanhorn in https://github.com/pingdotgg/t3code/pull/2124 * [codex] fix: guard invalid web timestamps by @StiensWout in https://github.com/pingdotgg/t3code/pull/3515 * [codex] fix: tolerate invalid latest user message timestamps by @StiensWout in https://github.com/pingdotgg/t3code/pull/3521 * [codex] Fix provider update checks restore defaults by @StiensWout in https://github.com/pingdotgg/t3code/pull/3531 * fix(server): skip undecodable provider runtime rows when listing sessions by @t3dotgg in https://github.com/pingdotgg/t3code/pull/3951 * Share MCP OAuth locks across Codex shadow homes by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4104 * Preserve T3 Code identity in macOS development launcher by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4102 * fix(web): increase contrast of question option descriptions by @xxashxx-svg in https://github.com/pingdotgg/t3code/pull/3867 * feat: draft hero landing on the index route by @yordis in https://github.com/pingdotgg/t3code/pull/4055 * feat: file explorer mention actions and zoom-aware context menus by @yordis in https://github.com/pingdotgg/t3code/pull/4054 * fix(mobile): restore iOS home screen branding by @PixPMusic in https://github.com/pingdotgg/t3code/pull/4025 * perf(client): defer active thread cache writes by @Chrrxs in https://github.com/pingdotgg/t3code/pull/4006 * Default diffs to working changes by @jakeleventhal in https://github.com/pingdotgg/t3code/pull/3974 * Add Grok to marketing site provider list by @Aditya190803 in https://github.com/pingdotgg/t3code/pull/3484 * Fix reopening existing Diff tab by @jakeleventhal in https://github.com/pingdotgg/t3code/pull/3973 * Fix sending messages during active turns by @jakeleventhal in https://github.com/pingdotgg/t3code/pull/3919 * [codex] Route OpenCode missing-session errors through Effect by @StiensWout in https://github.com/pingdotgg/t3code/pull/3608 * [fix/feat:ui] Show default option badge by @sandersonstabo in https://github.com/pingdotgg/t3code/pull/3232 * [fix/feat:ui] Preserve open-in editor brand colors by @sandersonstabo in https://github.com/pingdotgg/t3code/pull/3225 * fix(web): handle macOS Home and End in composer by @GuilhermeVieiraDev in https://github.com/pingdotgg/t3code/pull/2508 * Allow failed remote environments to be removed by @zepi2509 in https://github.com/pingdotgg/t3code/pull/4084 * [codex] canonicalize client timestamps by @maxwellyoung in https://github.com/pingdotgg/t3code/pull/4112 * [fix/feat:ui] Make selected menu checks blue by @sandersonstabo in https://github.com/pingdotgg/t3code/pull/3234 * fix(desktop): Validate WSL node version against engine range after probe success by @UtkarshUsername in https://github.com/pingdotgg/t3code/pull/3621 * Refresh splash screen and favicon branding by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4120 * Add terminal selection copy action by @tarik02 in https://github.com/pingdotgg/t3code/pull/2904 * Add isolated app testing workflow by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4121 * feat(web): themed sidebar header art for nightly and dev builds by @maria-rcks in https://github.com/pingdotgg/t3code/pull/4130 * feat: add headless `t3 connect` setup for SSH hosts by @t3dotgg in https://github.com/pingdotgg/t3code/pull/3749 * Refine T3 Connect authorization surfaces by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4159 * fix: increase OpenCode server startup timeout from 5s to 30s by @UtkarshUsername in https://github.com/pingdotgg/t3code/pull/4132 * fix(shared): delete unused agentAwareness phase predicates by @kridaydave in https://github.com/pingdotgg/t3code/pull/4134 * fix(mobile): Stabilize native stack option updates by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4037 * Make test-t3-app skill discoverable by Claude Code by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4162 * fix(web): improve dev sidebar backdrop contrast & remove version pills by @maria-rcks in https://github.com/pingdotgg/t3code/pull/4166 * Fix draft banner stack overlap by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4164 * Add portable mobile app testing guidance by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4165 * fix(client): use lightweight connection probe by @eeinarsson in https://github.com/pingdotgg/t3code/pull/4137 * fix(server): resolve Claude SDK executable path on Windows npm installs by @nsxdavid in https://github.com/pingdotgg/t3code/pull/3740 * Fix project action preview settings persistence by @keeperxy in https://github.com/pingdotgg/t3code/pull/3842 * fix(desktop): allow clipboard writes in the preview browser by @carlosricojr in https://github.com/pingdotgg/t3code/pull/3889 * fix(web): handle sidebar shortcut before editors by @Bortlesboat in https://github.com/pingdotgg/t3code/pull/3921 * fix(server): recognize Bedrock-backed Claude as authenticated by @PieterVanZyl-Dev in https://github.com/pingdotgg/t3code/pull/3931 * Fix incorrect pluralization of “entry” by @McMelonTV in https://github.com/pingdotgg/t3code/pull/3933 * feat(server): title background-task work-log rows with the task name by @t3dotgg in https://github.com/pingdotgg/t3code/pull/3751 * fix: delegate OpenCode session titles to provider by @tris203 in https://github.com/pingdotgg/t3code/pull/3720 * Archive selected threads from the context menu by @theduke in https://github.com/pingdotgg/t3code/pull/3895 * fix(cli): support force removing projects by @Bortlesboat in https://github.com/pingdotgg/t3code/pull/3922 * fix: allow sidebar to be shrunk when wider than viewport by @shoaib050326 in https://github.com/pingdotgg/t3code/pull/2456 * fix(codex): show web search query and url in tool call details by @GuilhermeVieiraDev in https://github.com/pingdotgg/t3code/pull/2093 * Add Codex launch arguments setting by @jamesx0416 in https://github.com/pingdotgg/t3code/pull/2892 * [orchestration] Clear stale active turn when session becomes inactive by @Andrew-Forster in https://github.com/pingdotgg/t3code/pull/3159 * Regenerate Codex reset credit protocol bindings by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4173 * fix(preview): preserve direct localhost navigation by @Chrrxs in https://github.com/pingdotgg/t3code/pull/3939 * Synchronize mobile threads with authoritative shell snapshots by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4163 * Gate iOS glass layout on native support by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4032 * fix(opencode): resume the OpenCode session on follow-ups instead of starting an empty one by @vdmkotai in https://github.com/pingdotgg/t3code/pull/3617 * fix(server): use CLI for OpenCode health check instead of spawning server by @UtkarshUsername in https://github.com/pingdotgg/t3code/pull/4153 * fix(web): scope timeline minimap hover target to the side gutter by @xxashxx-svg in https://github.com/pingdotgg/t3code/pull/3869 * [codex] show complete approval details by @maxwellyoung in https://github.com/pingdotgg/t3code/pull/4111 * fix(web): paint text selection over composer chips by @yordis in https://github.com/pingdotgg/t3code/pull/4139 * [codex] preserve custom model slugs by @maxwellyoung in https://github.com/pingdotgg/t3code/pull/4168 * fix(web): preview workspace images in the file panel by @Rhiz3K in https://github.com/pingdotgg/t3code/pull/3996 * feat(web): drag files from the explorer into the chat composer by @yordis in https://github.com/pingdotgg/t3code/pull/4140 * fix(desktop): preserve main window bounds by @anirudhsama in https://github.com/pingdotgg/t3code/pull/3851 * perf(orchestration): speed up new-chat propagation and offline catch-up by @RusiruSadathana in https://github.com/pingdotgg/t3code/pull/4177 * Finale: upgrade changed files card to fix various UI issues by @sandersonstabo in https://github.com/pingdotgg/t3code/pull/4113 * Pass CLI OAuth config to hosted web deploy by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4186 * fix(web): always show environment chip for remote projects by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4217 * fix(web): keep composer editable while disconnected by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4241 * fix: better defaults — Claude 1M context, Codex gpt-5.6, worktrees from origin main by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4240 * fix(claude): handle all SDK stream messages; stop spurious work-log warning rows by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4244 * Sidebar v2 beta: flat thread list with a server-backed settled lifecycle by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4026 * fix(settings): validate the add-provider wizard step before advancing (#2813) by @leorivastech in https://github.com/pingdotgg/t3code/pull/3100 * fix(claude): isolate capability probe from user MCP servers by @jbbottoms in https://github.com/pingdotgg/t3code/pull/4015 * Preserve connecting status while a turn starts by @D3OXY in https://github.com/pingdotgg/t3code/pull/4101 * fix(server): stop restoring stale OpenCode models by @nateEc in https://github.com/pingdotgg/t3code/pull/4095 * [codex] keep scoped package references as text by @maxwellyoung in https://github.com/pingdotgg/t3code/pull/4167 * fix(web): default provider selection for users without Codex by @mfazekas in https://github.com/pingdotgg/t3code/pull/4117 * Unify temporary worktree branch naming by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4278 * fix(web): use message-square icon for settled icon-less project threads in sidebar v2 by @UtkarshUsername in https://github.com/pingdotgg/t3code/pull/4279 * Stabilize sidebar settling animations by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4280 * Restore Copy Link in chat link context menu by @caezium in https://github.com/pingdotgg/t3code/pull/4161 * fix(desktop): handle EPIPE errors on stdout/stderr to prevent crash dialog by @UtkarshUsername in https://github.com/pingdotgg/t3code/pull/4213 * Preserve draft thread highlighting during promotion by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4283 * Move mobile working timer into the thread timeline by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4285 * Stabilize PR status lookups and provider session lifecycle by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4281 * fix: open command palette instead of custom dialog for new thread picker in SidebarV2 by @UtkarshUsername in https://github.com/pingdotgg/t3code/pull/4269 * fix(server): don't drop sticky PR fallback when remote URL can't be resolved by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4289 * feat(web): copy branch name via right-click in the branch selector by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4275 * Add remote server updates and standalone service management by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4286 * Refine light-mode sidebar surfaces by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4268 * fix(mobile): don't mark Android VPN/Tailscale as offline when connected by @Wraient in https://github.com/pingdotgg/t3code/pull/3949 * improve and prevent silent thread branch drift and PR fetching by @justsomelegs in https://github.com/pingdotgg/t3code/pull/2284 * Refresh web application surfaces and dark-mode dialogs by @maria-rcks in https://github.com/pingdotgg/t3code/pull/4319 * fix(web): new-thread defaults ignored for remote environments by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4276 * feat: add "Auto" runtime mode — AI-reviewed approvals for Codex and Claude by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4272 * Add shared t3.json project configuration support by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4317 * Unify dialog glass and fix composer overlays by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4365 * fix(web): warn before silent Windows updates by @nateEc in https://github.com/pingdotgg/t3code/pull/4350 * [codex] Move project grouping to General settings by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4313 * [codex] Group project scopes in mobile thread lists by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4314 * [codex] Move mobile project grouping to General settings by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4315 * [codex] Deduplicate connection failure messaging by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4367 * Restore grouped project filtering in Sidebar V2 by @shivamhwp in https://github.com/pingdotgg/t3code/pull/4282 * [codex] restore Sidebar V2 project actions by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4373 * [codex] Group projects in new-thread pickers by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4312 * fix(web): restore dark composer toolbar styling by @maria-rcks in https://github.com/pingdotgg/t3code/pull/4375 * Fix thread tooltip folder icon color by @maria-rcks in https://github.com/pingdotgg/t3code/pull/4383 * fix(server): parse CLI version in update preflight by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4389 * fix(web): sidebar v2 polish — jump hints, working duration, in-flight fade, settled sort by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4274 * Fix logical project grouping labels on mobile by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4391 * Add preview color scheme controls and simplify project grouping by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4385 * fix(cli): publish nightly branded favicons by @maria-rcks in https://github.com/pingdotgg/t3code/pull/4372 * Fix thread loading flash by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4396 * fix(client-runtime): keep a warm thread un-settled despite a merged/closed PR by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4309 * Fix composer context strip alignment and glass shell by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4404 * Polish iOS git progress overlay with glass effects by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4387 * Improve composer glass fallbacks by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4406 * feat(web): collapse large git diffs by default to make chat more readable by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4409 * Stop new threads inheriting checkout/branch from viewed thread by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4411 * fix: tone down branch-mismatch banner by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4416 * fix: Claude Code skills discoverable for the composer $ picker by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4414 * fix(web): keep settled threads reachable when opened directly by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4413 * feat(sidebar-v2): thread snoozing by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4311 * Upgrade Clerk packages and Expo integration by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4440 * Increase light-mode contrast for user message bubbles by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4441 * Restore model picker layout and retain iterative test state by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4450 * Color settled PR labels on hover by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4451 * [codex] Fix glass hover compositing artifacts by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4446 * Add Claude Opus 5 model by @thomaslittle in https://github.com/pingdotgg/t3code/pull/4472 * feat(web): add collapse-all toggle to diff panel by @0x4bs3nt in https://github.com/pingdotgg/t3code/pull/4475 * feat(web): show fast mode as a bolt instead of a "Normal" label by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4488 * feat(dev): keep worktree dev state isolated on T3 Code dev servers by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4555 * feat(dev): Make t3 code dev instances shareable over Tailscale by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4556 * fix(dev): skip browser-blocked ports by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4608 * fix: cut websocket throughput in half by pruning activity payloads by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4622 * perf(mobile): defer work-log detail serialization by @saphid in https://github.com/pingdotgg/t3code/pull/4607 * test: account for lazy thread feed details by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4628 * feat(relay): limit managed tunnels per user by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4530 * Add managed tunnel limits migration by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4635 * Add background preview capture and picture-in-picture support by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4397 * feat(web): prompt stash — cmd+S saves the composer to a per-provider queue by @t3dotgg in https://github.com/pingdotgg/t3code/pull/4453 * [codex] Upgrade Effect and Alchemy betas by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4643 * feat: allow new thread creation through project breadcrumbs by @0x4bs3nt in https://github.com/pingdotgg/t3code/pull/4638 * fix(web): scope PR state to the thread branch by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4460 * Drop redundant Relay user indexes by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4648 * feat(connect): release the Cloudflare tunnel when the environment shuts down by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4531 * Fix Relay Worker RuntimeContext wiring by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4653 * Fix live sidebar resize limits and defer Alchemy runtime context by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4655 * fix(web): constrain branch toolbar context by @maxktz in https://github.com/pingdotgg/t3code/pull/4657 * Keep MCP credentials alive across provider turns by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4659 * fix: close actions dropdown when editing by @0x4bs3nt in https://github.com/pingdotgg/t3code/pull/4660 * fix(preview): stabilize PiP viewport identity by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4661 * Add glass styling for thread tooltips and simplify preview tab handling by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4665 * Use tarball archiving for hosted web deploys by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4669 * fix(server): bound editor discovery during config loading by @maria-rcks in https://github.com/pingdotgg/t3code/pull/4291 * Prevent draft thread detail polling before shell registration by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4670 * feat: add configurable source control writing settings by @maria-rcks in https://github.com/pingdotgg/t3code/pull/4204 * feat(diff-panel): show total line additions and deletions by @0x4bs3nt in https://github.com/pingdotgg/t3code/pull/4674 * Clear provider update actions while updating by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4676 * Fix sidebar highlighting for draft threads by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4679 * Use glass surfaces for web toasts by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4681 * Show origin ref in branch trigger label by @juliusmarminge in https://github.com/pingdotgg/t3code/pull/4680 * fix(mobile): match react version to react-native 0.85.3 vendored renderer (19.2.3) by @KrzysztofMoch in https://github.com/pingdotgg/t3code/pull/4675 ## New Contributors * @avocardow made their first contribution in https://github.com/pingdotgg/t3code/pull/3790 * @Prgm-code made their first contribution in https://github.com/pingdotgg/t3code/pull/3816 * @jakeleventhal made their first contribution in https://github.com/pingdotgg/t3code/pull/3899 * @VedankPurohit made their first contribution in https://github.com/pingdotgg/t3code/pull/3644 * @kridaydave made their first contribution in https://github.com/pingdotgg/t3code/pull/3990 * @dmstoykov made their first contribution in https://github.com/pingdotgg/t3code/pull/4017 * @HugoVizcainoSantana made their first contribution in https://github.com/pingdotgg/t3code/pull/3832 * @EricTsai83 made their first contribution in https://github.com/pingdotgg/t3code/pull/3998 * @AmoonPod made their first contribution in https://github.com/pingdotgg/t3code/pull/4088 * @BunnyGamezsc made their first contribution in https://github.com/pingdotgg/t3code/pull/4094 * @olivoil made their first contribution in https://github.com/pingdotgg/t3code/pull/4044 * @Fazalkadivar21 made their first contribution in https://github.com/pingdotgg/t3code/pull/3877 * @maxwellyoung made their first contribution in https://github.com/pingdotgg/t3code/pull/3932 * @nateEc made their first contribution in https://github.com/pingdotgg/t3code/pull/4097 * @leorivastech made their first contribution in https://github.com/pingdotgg/t3code/pull/3108 * @xxashxx-svg made their first contribution in https://github.com/pingdotgg/t3code/pull/3867 * @yordis made their first contribution in https://github.com/pingdotgg/t3code/pull/4055 * @Chrrxs made their first contribution in https://github.com/pingdotgg/t3code/pull/4006 * @Aditya190803 made their first contribution in https://github.com/pingdotgg/t3code/pull/3484 * @zepi2509 made their first contribution …
…nostics + snapshot loaders) - Regenerate pnpm-lock (client-runtime's react devDeps for the shared lazy-load hook were missing from the pnpm-11 lockfile). - Repair a doc comment the rebase union broke in Services/ProjectionSnapshotQuery. - Satisfy main's new @effect/language-service diagnostics: TUI tsconfig disables nodeBuiltinImport/globalDate/globalTimers (a Node/Bun-native terminal app); file directives for cli/tui.ts, connection.ts, and the terminal Manager's CPR-gate wall-clock reads (Clock threading is a follow-up); return yield* at generator exits. - Adapt the TUI to main's HTTP snapshot preloading (pingdotgg#3719): the in-memory cache stores {snapshotSequence, thread} detail snapshots, and no-op Thread/ShellSnapshotLoader layers fall back to the socket-embedded snapshots (the TUI's existing path). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nostics + snapshot loaders) - Regenerate pnpm-lock (client-runtime's react devDeps for the shared lazy-load hook were missing from the pnpm-11 lockfile). - Repair a doc comment the rebase union broke in Services/ProjectionSnapshotQuery. - Satisfy main's new @effect/language-service diagnostics: TUI tsconfig disables nodeBuiltinImport/globalDate/globalTimers (a Node/Bun-native terminal app); file directives for cli/tui.ts, connection.ts, and the terminal Manager's CPR-gate wall-clock reads (Clock threading is a follow-up); return yield* at generator exits. - Adapt the TUI to main's HTTP snapshot preloading (pingdotgg#3719): the in-memory cache stores {snapshotSequence, thread} detail snapshots, and no-op Thread/ShellSnapshotLoader layers fall back to the socket-embedded snapshots (the TUI's existing path). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>



Summary
Testing
vp checkvp run typecheckvp run lintvp test/vp run testfor the updated client-runtime state testsvp run lint:mobile)Note
Medium Risk
Changes the orchestration sync path end-to-end (HTTP + WS replay ordering) and bumps on-disk thread cache schema, so upgrades force a one-time cold cache until snapshots are refetched.
Overview
Shell and thread sync now prefer loading snapshots from local cache or new HTTP endpoints, then opening WebSocket subscriptions with
afterSequenceso large snapshot frames are not re-sent on the socket. HTTP failures (and thread 404) fall back to the socket-embedded snapshot; overlapping replay is deduped by sequence on the client.Server: Adds
GET /api/orchestration/shellandGET /api/orchestration/threads/:threadId,getThreadDetailSnapshot(thread detail + projection sequence in one transaction),EnvironmentResourceNotFoundError, and optionallimitonreadEvents.subscribeShell/subscribeThreadbuffer live events before catch-up replay whenafterSequenceis set.Clients (web/mobile): Thread cache schema v2 stores
OrchestrationThreadDetailSnapshot(sequence + thread); v1 entries no longer decode.ShellSnapshotLoader/ThreadSnapshotLoaderlayers and sharedenvironmentHttpAuth(cookies, Bearer, DPoP) wire into connection runtimes.Reviewed by Cursor Bugbot for commit 9254fe5. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Load thread and shell snapshots over HTTP before live WebSocket sync
GET /api/orchestration/shellandGET /api/orchestration/threads/:threadIdon the server to serve snapshots before a WebSocket connection is established.subscribeShellandsubscribeThreadRPCs to accept an optionalafterSequenceparameter; when provided, the server replays persisted events after that sequence instead of sending a full initial snapshot.ShellSnapshotLoaderandThreadSnapshotLoaderservices), then passes the snapshot sequence asafterSequenceto the WebSocket subscription, reducing initial socket payload.threadfield with anOrchestrationThreadDetailSnapshotthat includessnapshotSequence.Macroscope summarized 9254fe5.