Skip to content

feat(orchestrator): introduce new orchestrator - #2829

Open
juliusmarminge wants to merge 655 commits into
mainfrom
t3code/codex-turn-mapping
Open

juliusmarminge wants to merge 655 commits into
mainfrom
t3code/codex-turn-mapping

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented May 27, 2026

Copy link
Copy Markdown
Member

Summary

  • wire orchestration V2 provider adapter registry/factory flow for Codex and Claude provider instances
  • add Claude replay/query primitives, native fork/rollback fixtures, subagent fixture coverage, and provider replay harness updates
  • update debugger model/provider picker and improve user-facing orchestration errors

Validation

  • bun fmt
  • bun lint
  • bun typecheck
  • bun run test -- src/orchestration-v2/testkit/OrchestratorReplayFixtures.integration.test.ts -t claudeAgent
  • bun run test -- src/orchestration-v2/testkit/ClaudeReplayFixtures.integration.test.ts
  • bun run test -- src/orchestration-v2/testkit/ThreadFork.integration.test.ts -t Claude

Notes

  • Draft PR for review of current branch state. Codex all-provider replay still needs schema alignment with latest app-server behavior before it can be treated as a full-suite signal.

Closes

Verified against the branch with code/commit evidence. Issues listed under High confidence have a concrete V2 mechanism (named in the note). Medium confidence items belong to a V1 race or lifecycle class that V2 structurally removes; prune any you want to re-verify after merge.

High confidence

Closes #871 — V2 mints message identity itself in orchestration-v2/IdAllocator.ts (random id scoped by thread + ordinal) instead of keying projections on provider-supplied message…
Closes #4673 — V2 owns queue state in the orchestrator with explicit queue controls and pending-question commands (fix(queue): preserve and hold queued messages after restart, fea… Closes #2778 — V2 tracks delegated children in projections and wakes the parent when they finish (fix(orchestrator): Stop treating a wait timeout as a dead child (#7427), fix(orch…
Closes #4952
Closes #4873
Closes #4775
Closes #4795
Closes #4710
Closes #4668
Closes #4619
Closes #4584
Closes #4561
Closes #4713
Closes #4198
Closes #4452
Closes #3797
Closes #4232
Closes #3666
Closes #3580
Closes #2785
Closes #2789
Closes #3138
Closes #1404
Closes #231
Closes #216
Closes #12940 — CursorAdapterV2 passes enableAgentRetries: true to the Cursor SDK session (apps/server/src/orchestration-v2/Adapters/CursorAdapterV2.ts:331)
Closes #12928 — AcpAdapterV2 maps ACP tool kind search to file_search and only fetch to web_search, replacing main's canonicalItemTypeFromAcpToolKind which lumps search and…
Closes #12915 — The buggy schedulePromptAdmissionRecovery path lives only in V1's OpenCodeAdapter.ts, which V2 removes in favour of OpenCodeAdapterV2 plus commits 'correlate OpenCode…
Closes #12904 — V2 deletes the V1 provider adapter layer that raised ProviderAdapterSessionClosedError and replaces it with ProviderSessionManager plus ProviderRuntimeRecoveryService,…
Closes #12679 — The branch carries 'fix(server): preserve provider history across repeated rollbacks (#12676)' and 'fix(pi): use native forks and preserve rollback session identity',…
Closes #12285 — The settledDeliveryCount cohort cap no longer exists on the branch.
Closes #12100 — V2 makes queuing server-owned with a queued_turn intent released as a separate turn after the active turn (fix(web): retain server-side queuing on v2, fix(orchestratio…
Closes #11968 — V2's orchestrator MCP toolkit ships t3_thread_update with action='rename' that defaults to the calling thread (apps/server/src/mcp/ThreadMetadataMcpService.ts, toolkit…
Closes #11889 — V2 deletes the reactor-based path (orchestration-v2/ThreadDeletion.ts runs through the serialized orchestrator and effect worker) and lands 'fix(server): cancel pendin…
Closes #11799 — V2's ProviderSessionManager release path writes runtime-request.updated with a not_resumable capability for every pending approval_request and user_input_request bound…
Closes #11730 — V2's server-owned settlement rejects threads with pendingBackgroundTasks/live activity (ThreadSettlementService.isAutoSettlementCandidate) and adds 'feat(orchestrator)…
Closes #11711 — V2's isAutoSettlementCandidate in orchestration-v2/ThreadSettlementService.ts returns false when pinnedAt is set (covered by ThreadSettlementService.test.ts 'excludes…
Closes #11428 — V2 commit "fix: stop retained background work after a turn settles" makes ProviderTurnControlService.interrupt accept a non-running run that still has pending backgrou…
Closes #10928 — orchestration-v2/RestartContinuation.ts dispatches the automatic continuation with the source run's modelSelection, whose options carry reasoningEffort, so the restart…
Closes #10786 — V2 records the reply on the user_input_request turn item itself as questionAnswer (answers plus questionTextById) in Orchestrator.ts rather than synthesizing a u…
Closes #10545 — V2 adds a distinct Limited stop state with resume/snooze-at-reset ("feat(v2): show provider limit stops as Limited (#12677)", "#12686", "#12687"), documented in the V2…
Closes #10480 — V2 runs Cursor through the official @cursor/sdk and explicitly does not use Cursor's ACP transport for V2 execution (user-cursor.md.
Closes #10099 — V2 makes settlement server-owned in ThreadSettlementService.
Closes #9107 — V2 models provider-owned background work as first-class turn items (background_task/background_command/monitor in orchestrationV2.ts) with normalized post-settlement W…
Closes #9047 — apps/server/src/provider/Layers/CursorAdapter.ts does not exist on V2.
Closes #9029 — ClaudeAdapterV2 projects TodoWrite todos into todo_list plan items rather than depending on Task tools, surfaced by "fix(web): surface v2 todo-list plans as task progr…
Closes #8946 — V2's deriveTurnFolds pulls subagent items and background work entries into the run fold and drops main's agent-spawn never-fold exclusion.
Closes #8594 — The V1 ClaudeAdapter is deleted on V2.
Closes #8499 — V2 models native subagents and maps nested Codex subagent threads into thread lineage, rendered by "feat(web): show subagent models and running count in Lineage" after…
Closes #8091 — Task steps are projected from the persisted event log, and "fix(orchestrator): preserve task-step elapsed time across restart (#10051)" restores the list after relaunch.
Closes #7328 — V2 ports title regeneration to the orchestrator with tracked contract state: 'feat(contracts): track thread title regeneration', 'feat(orchestration): port thread titl…
Closes #7281 — V2 carries per-subagent model through projections: 'fix(claude): retain requested subagent models', 'fix(server): preserve Claude subagent models', 'feat(web): show su…
Closes #7244 — V2 runs Cursor on the official @cursor/sdk and treats CURSOR_API_KEY as the auth method (docs/user/cursor.md prerequisites.
Closes #7155 — V2's provider session recovery plus '[orchestrator-v2] fix(orchestrator): Restore Claude session continuity for resume, wake, and idle release (#3860)' rebuilds the re…
Closes #7075 — V2's CodexSessionRuntime sends thread/resume with excludeTurns: true on the main resume path (apps/server/src/provider/Layers/CodexSessionRuntime.ts:751 on the branch,…
Closes #5953 — V2 models native Codex subagents as separate projected child threads (feat(orchestration-v2): model native subagents.
Closes #5750 — ProviderRuntimeRecoveryService reconciles non-terminal runs against actual provider inventory at startup/shutdown and retires the outbox effects tied to the lost proce…
Closes #5518 — V2 tracks delegated children in projections and settlement (fix(notifications): silence subagent threads.
Closes #5476 — Server-owned ThreadSettlementService returns no settlement whenever any linked pull request snapshot is missing or still open, and the guarded thread.auto-settle comma…
Closes #5454 — ProviderRuntimeRecoveryService reconciles on startup/shutdown and cancels every pending runtimeRequest with a user-facing 'server restarted before the provider work co…
Closes #5436 — V2 makes the follow-up queue server-owned and durable (queued messages keep order and are held across a server restart.
Closes #5110 — V2 adds ProviderTextDeltaCoalescer and ThreadLiveEventCoalescer, which buffer and flush provider text deltas before persistence/publication instead of writing one dura…
Closes #4650ClaudeAdapterV2 handles the SDK compact_boundary message and publishes usedTokens: afterTokenCount from compact_metadata.post_tokens, replacing V1's monotonic…
Closes #4495 — The failing call site (context.query.setPermissionMode wrapped as turn/setPermissionMode in apps/server/src/provider/Layers/ClaudeAdapter.ts) does not exist in V2.
Closes #2477 — V2 models native subagents as distinct lineage nodes with their own projection rows rather than splicing their text into the parent stream — `feat(orchestration-v2): m…

Medium confidence (under review)

Closes #4568
Closes #4766
Closes #4456
Closes #4399
Closes #3744
Closes #2921
Closes #3624
Closes #3149
Closes #2336
Closes #538
Closes #2173
Closes #2065
Closes #12926 — The 'Provider session did not survive a server restart' path exists only on main (serverRuntimeStartup.ts:346)
Closes #12885 — Cross-thread session eviction is a V1 session-lifecycle race.
Closes #12762 — V2 never replays the V1 event log: LegacyV1ThreadImporter reads projection_thread_messages from a statev2.sqlite snapshot, so a legacy thread.message-sent row missing…
Closes #12694 — V2 replaces ensureSessionForThread's restart branch with ProviderSessionTransitionPolicy plus recovery that checks providerThreadHasPendingBackgroundTasks before retir…
Closes #12502 — Stuck-Working class that V2 addresses via run finalization separate from provider turn completion plus 'fix(grok): Prevent spurious wake run after in-turn monitors' an…
Closes #12467 — The branch adds 'fix(server): recover Pi resumes without reusing native history (#12933)' and 'fix(pi): use native forks and preserve rollback session identity', which…
Closes #12456 — The recovery path it skips (schedulePromptAdmissionRecovery in V1's OpenCodeAdapter) is deleted in V2, whose OpenCode admission and stream-EOF handling is rebuilt in O…
Closes #12374 — Same Cursor ACP transport-drop class as #12940, which V2 addresses by enabling enableAgentRetries in CursorAdapterV2.
Closes #12325 — Same never-terminating tool-row class.
Closes #12206 — ProviderAdapterSessionClosedError is the ACP session-lifecycle class V2 rewrites ('feat(providers): standardize ACP providers', 'fix(antigravity): accept supported leg…
Closes #12187 — V2's run interrupt explicitly handles runs in preparing/starting with no provider turn, emitting an interrupt result and marking attempt/node/run interrupted ('Handle…
Closes #12155 — V2 carries reasoning as typed turn items across clients ('fix(providers): enable Codex and Claude reasoning summaries in V2', 'fix(timeline): align V2 reasoning disclo…
Closes #12136 — Same OpenCode prompt-admission rework as #11889 ('guard OpenCode prompt admission races', 'abort external OpenCode sessions on release') plus V2's interrupt path that…
Closes #12131 — V2 tracks subagents in server projections and replaces the ad-hoc agents panel with projection-backed lineage/workspace-card surfaces ('refactor(web): remove the agent…
Closes #12094 — The V2 timeline rewrite re-lays out these exact rows ('fix(web): anchor turn duration below the initiating prompt', 'fix: keep working timers anchored to the active ru…
Closes #12072 — V2's mobile timeline is rebuilt on paged V2 turn items with LegendList owning end-follow and anchoring ('fix(mobile): keep scroll bounds current after animations', 'pe…
Closes #12037 — V2 keeps a failed turn as a settled transcript item instead of wedging the thread ('fix(v2): keep failed turns visible in the transcript', 'fix(server): preserve gener…
Closes #11992 — V2 reworks the mobile running-turn UI so the pill is part of the composer hub and scroll bounds track animations ('feat(mobile): make the composer pill the hub for the…
Closes #11907 — V2 commits intent, projection and command receipt in one transaction with idempotent receipts, and holds sends as server-side queued turns, removing the V1 admission r…
Closes #11903 — Mobile timelines are rebuilt from V2 typed turn items ('Render mobile timelines from V2 turn items', 'Enrich mobile V2 execution items', 'fix(chat): present and summar…
Closes #11796 — The V1 processTurnInterruptRequested path is gone.
Closes #11777 — V2 projects native Codex subagents as durable child nodes with results ('Map nested Codex subagent threads correctly', 'feat(subagents): disclose projected results con…
Closes #11670 — V2 standardizes ACP providers behind one adapter with session recovery and surfaces typed failures ('feat(providers): standardize ACP providers', 'fix(server): surface…
Closes #11432 — V2 maps Codex background command completions to typed turn items (codexBackgroundCommandDetail, source kind background_command) and renders background completions as t…
Closes #11353 — V2 persists each assistant text block as its own ordered assistant_message turn item with its own messageId, so a later item in the same turn cannot overwrite an earli…
Closes #11182 — Branch-only "perf(server): stop decoding unrelated events during startup" (#12846) rewrites ProjectionPipeline bootstrap to read cursor metadata instead of full event…
Closes #10973 — V2 commit "fix(server): recover OpenCode status reconciliation" ignores stale timers and duplicate evidence so an older prompt's idle event cannot finish newer steerin…
Closes #10934 — The "Provider session did not survive a server restart" path exists only on main.
Closes #10798 — V2 replaces the Codex adapter with scoped session runtimes plus a provider session recovery service, and run state is orchestrator-owned rather than derived from the a…
Closes #10684 — Same mechanism as #10202: V2's durable thread.model-selection.set command and thread.model-selection-updated projection replace per-client sticky model state.
Closes #10375 — ClaudeAdapterV2 classifies local_bash task types explicitly and never fabricates a subagent for them, and V2 rebuilt the worklog rows ("fix(timeline): unify worklog…
Closes #10202 — V2 makes thread model selection durable server state via the thread.model-selection.set command and thread.model-selection-updated event, which every subscribed cl…
Closes #10192 — V2 projects questions as turn items rendered identically across clients and makes settlement server-owned ("fix: align V2 question and checkpoint timelines across clie…
Closes #10185 — V2 models native subagents in projections and surfaces their models in Lineage, replacing the Agents right panel ("feat(web): show subagent models and running count in…
Closes #9892 — V2 tracks subagents in projections and maps Grok task envelopes to subagent lineage ("Map Grok task envelopes to subagent lineage", "feat(orchestration-v2): model nati…
Closes #9772 — V2 orders the transcript from the append-only event log and pages history by keyset rather than by wall-clock timestamps ("perf(orchestration): bound history reads in…
Closes #9698 — V2 separates run finalization from provider turn completion and retires background work after a turn settles ("fix: stop retained background work after a turn settles"…
Closes #9672 — V2 models queued messages as first-class durable queued_turn intents promoted by the serialized orchestrator ("fix(queue): preserve and hold queued messages after re…
Closes #9607 — V2's provider session recovery restarts live sessions after dead/stale records and reopens Claude queries on credential rotation ("fix(server): restart the live sessio…
Closes #9586 — V2 makes liveness an orchestrator projection and the settlement service detaches idle provider sessions ("fix(orchestrator): Restore Claude session continuity for resu…
Closes #9414 — V2 adds bounded per-thread history loading with true-end paging and bounded snapshots ("perf(orchestration): bound complete thread snapshots", "fix(orchestration): pag…
Closes #9352 — V2 shows live context usage in the composer meter as a first-class V2 surface ("feat(orchestration-v2): show live context usage in the meter (#8144)", "fix(server): ke…
Closes #9214 — Fold derivation now keys on server-owned runIds instead of provider turn ids, and "fix(server): recover OpenCode status reconciliation" makes OpenCode run state author…
Closes #8945 — V2 folds group by server-owned runId and deliberately keep every provider turn since the initiating prompt in one visual response, so a mid-turn pause no longer starts…
Closes #8896 — V2 isolates its migrations from the V1 database and flags divergent migration ids ("test(server): prove v1 to v2 cutover on a copied database and flag divergent migrat…
Closes #8873 — V2 replaces the checkpoint reactor with effect-worker checkpointing that starts the provider turn when baseline capture fails (#12153) and finalizes runs when checkpoi…
Closes #8648 — V2 bounds history reads in SQL, bounds complete thread snapshots and resume payloads, releases thread history after turn startup, and keeps tool payloads out of comple…
Closes #8618 — Stop is a serialized V2 command whose intent commits with a durable receipt, and "fix(orchestrator): report terminal runs after wait timeout" ends the stuck Thinking s…
Closes #8382 — V2 adds AcpRuntimeModel parsing of ACP usage_update/state_update usage into a per-session contextUsage snapshot that feeds "feat(orchestration-v2): show live context u…
Closes #8320 — V2 records provider session lifecycle as persisted typed events with a session recovery service, plus "fix(server): surface actionable provider failure messages (#1256
Closes #8263 — ProviderTurnStartService prunes and recreates a missing worktree at the thread's branch before starting the provider turn ("fix(orchestration): recreate missing worktr…
Closes #8259 — V2 shares Codex sessions across orchestration threads and maps turns to provider instances.
Closes #8146 — V2 replaces the hand-written Codex wire with the generated effect-codex-app-server schemas and app-server integration, so initialize payload decoding is regenerated fr…
Closes #8105 — V2 projects file-change and diff items per run and thread and narrows subscriptions to the viewed thread, so opening a second thread cannot capture another thread's li…
Closes #8022 — V2 Cursor execution and provider checks no longer use the ACP transport or cursor/list_available_models — it goes through the official SDK ('Switch Cursor provider to…
Closes #7781 — V2 replaces the inferred turn→checkpoint range with durable run identity and checkpoint coordination ('fix(orchestration): stabilize Codex turn mapping and settlement'…
Closes #7722 — V2 models native Codex subagents as first-class threads with orchestrator-owned stop ('Map nested Codex subagent threads correctly', 'fix(server): wait for native Code…
Closes #7589 — V2 records provider turn state independently from run finalization and settles threads server-side, and 'fix(server): restore Claude resume compaction' covers the comp…
Closes #7314 — V2 models subagents in projections and re-derives status from events ('feat(orchestration-v2): model native subagents', 'refactor(mobile): share subagent status indica…
Closes #6517 — V1's ProviderCommandReactor semaphore is replaced by the serialized orchestrator plus effect worker.
Closes #6389 — The V2 Claude adapter emits into the orchestrator where events and projections commit in one transaction, removing the in-flight-tool map race at finalize.
Closes #6368 — Thread settlement and snooze become server-owned in ThreadSettlementService ('fix(server): keep old failures from waking snoozed V2 threads (#9903)', 'fix: reconcile m…
Closes #6358 — V2's server-owned settlement evaluates without a connected client and 'fix(orchestration): reanchor unsettled threads' removes the stuck-unsettled state that pins the…
Closes #6128 — The V1 thread read model that caused the archived_at asymmetry is replaced by V2's projection store and ThreadLifecycleService, with archive handled as a domain comman…
Closes #5958 — The reported 'Orchestration command invariant failed' comes from the V1 OrchestrationEngine command path, which V2 replaces with the serialized Orchestrator and EventS…
Closes #5952 — V2 SubagentProjection plus OpenCodeAdapterV2 child-session mapping (fix(opencode): route child-session approvals through the v2 adapter) projects native child sessions…
Closes #5754 — CodexAdapterV2 maps collab wait/spawn items and empty receiver sets explicitly (replay fixture subagent_v2 covers a wait with empty receiverThreadIds), and RunFinaliza…
Closes #5685 — V2 CheckpointRollbackService coordinates workspace rollback with the provider conversation and the timeline (fix: align V2 question and checkpoint timelines across cli…
Closes #5514 — V2 ThreadPullRequestService skips settled threads in ordinary discovery and only stamps a link.
Closes #5447 — Commands are serialized through one orchestrator with idempotent receipts and sessions are owned by ProviderSessionManager, removing the duplicate-dispatch race that p…
Closes #5395 — ClaudeAdapterV2 maps sidechain items onto V2's native subagent model (feat(orchestration-v2): model native subagents.
Closes #5323 — Shutdown/startup runtime reconciliation records an explicit cancellation for work interrupted by the quit, replacing the stale 'stream failed' state a killed provider…
Closes #5035 — V2 drops the V1 per-event runProjectorForEvent nesting: EventSink commits events, projections, receipt and outbox in a single sql.withTransaction, removing the nested-…
Closes #4962 — V2 projects delegated-child progress server-side and shares it with mobile (refactor(mobile): share subagent status indicators.
Closes #4944 — V2 owns provider switching through ProviderSwitchService/ProviderSessionTransitionPolicy/ProviderSessionManager (Allow provider switching via handoff in chat threads.
Closes #4818 — V2 threads no longer write through the V1 receipt repository.
Closes #4728 — V2 reprojects Claude assistant text blocks and buffers streaming output per block (fix(timeline): preview live reasoning and buffer complete paragraphs), so text emi…
Closes #4723fix(orchestration): recreate missing worktrees before turns prunes stale registrations and recreates the saved branch/path in ProviderTurnStartService, and Provid… Closes #4560 — V2 binds each thread to its own provider session record (orchestration_v2_projection_provider_sessions, keyed by provider instance + thread) and serializes commands… Closes #4225 — V2 commits the user-message event before any provider work runs in the effect worker, so a provider auth failure leaves the prompt persisted and rendered instead of sw… Closes #4178 — V2 bounds the read model and subscription payloads: perf(orchestration): bound complete thread snapshots, feat(orchestration): bound thread history and resume paylo…
Closes #2644 — V2 separates provider turn completion from run finalization and rewrites the OpenCode adapter's turn mapping, so a finished provider turn settles the thread rather tha…
Closes #2519 — V2 projects proposed plans as first-class rows (fix(server): project Claude plans and todos, fix(server): preserve Claude planning lifecycle, inline-plans rework),…
Closes #2343 — V2 provider session recovery plus budgeted context handoff rebuild a resumed thread's context from the persisted transcript when the native provider session is gone, r…
Closes #881 — Run and turn state are derived from the committed event log and recovered at startup by the V2 recovery services, so a resumed thread shows real provider activity inst…

Supersedes

These pull requests target the V1 orchestration/provider layers this PR replaces, and V2 already delivers the same fix or feature by another route. They are linked here (not auto-closed) so their authors can find the replacement; most were closed pending V2, the rest stay open for maintainer review.

High confidence

Partially / likely superseded

Closes discussions

Discussions cannot be auto-closed; these are linked so they can be resolved by hand after merge.

Note

Introduce orchestration V2 runtime, services, provider adapters, and MCP toolkits

  • Adds a complete orchestration V2 server runtime: projection store, event store, effect outbox, command receipts, checkpoint capture/rollback, thread management, run execution, provider session management, context handoff, runtime policy, and legacy V1 thread importer, composed through runtimeLayer.ts
  • Adds V2 provider adapters for Codex, Claude, Cursor, Grok, OpenCode, and ACP Registry with a shared adapter contract, driver registry, and selection-transition policy
  • Adds MCP toolkit services and HTTP registration for orchestrator delegation, thread operations, worktree handoff, project lifecycle, attachments, environment preferences, and preview controls
  • Adds scheduled-task persistence, scheduling logic, server service, client runtime atoms, and a settings UI surface
  • Migrates client-runtime and web/mobile UI from legacy session/turn fields to V2 projection-based runtime/run state, including thread details panel, queue controls, relationship graph, history loading, and item inspector
  • Registers database migrations 050–061 for V2 foundation tables, subagents, provider-session bindings, launch workflows, application event sourcing, effect cancellation, scheduled tasks, legacy import state, and recovery/shell indexes
  • Risk: replaces the legacy EnvironmentApi orchestration interface with orchestrationV2; removes serverUpdateThreadContinuation capability; CursorSettings no longer exposes binaryPath or apiEndpoint; ProviderUsageLimitsIngestionLive no longer subscribes to runtime events; thread routing resolves existing non-deleted threads directly to ready instead of loading

Macroscope summarized 6102d00.


Note

Medium Risk
Mobile thread persistence and list/archive/stop behavior change with V2 runtime semantics; removing the thread-transfer report workflow reduces PR visibility into transfer budget regressions.

Overview
This slice of the orchestration V2 rollout retires the thread-transfer PR comment pipeline (trusted publisher script, tests, and workflow_run workflow) while CI can still emit transfer artifacts; it also installs build-essential in CI so ACP process-tree fixtures compile instead of soft-skipping.

Mobile moves onto shared V2 client-runtime pieces: SQLite cache uses ORCHESTRATION_CACHE_SCHEMA_VERSION and stored V2 shell/thread snapshots, runtime wiring swaps in bounded thread snapshot loading and history control, and thread detail/review/archive flows read projections (runtime, RuntimeRequestId, checkpoint summaries from runId) instead of V1 session/turn shapes. UX additions include activity inspector, queue control, relationships banner, progressive history controls, server visit watermarking, stricter archive rules via threadCanArchive, and approval/user-input cards that honor live vs dead provider responseCapability.

Smaller touches: shared brand mark module, new uniwind adaptive color tokens, desktop env test for user-data dir names, README link to appearance docs, and marketing copy for Cursor harness.

Reviewed by Cursor Bugbot for commit 9eeed8c. Bugbot is set up for automated code reviews on this repo. Configure here.


Devin Review

@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels May 27, 2026
Comment thread apps/server/src/orchestration-v2/EventStore.ts Outdated
Comment on lines +116 to +120
return decodeTranscript({
...metadata,
entries,
});
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Low testkit/ReplayTranscriptNdjson.ts:116

The call to decodeTranscript at line 116 invokes Schema.decodeUnknownSync, which throws on validation failure. Since this isn't wrapped in Effect.try, any validation error becomes an uncaught exception (defect) instead of a typed ProviderReplayNdjsonParseError. This breaks the function's declared error contract. Consider wrapping the call in Effect.try to catch the exception and convert it to the declared error type.

-    return decodeTranscript({
-      ...metadata,
-      entries,
-    });
+    return yield* Effect.try({
+      try: () =>
+        decodeTranscript({
+          ...metadata,
+          entries,
+        }),
+      catch: (cause) =>
+        new ProviderReplayNdjsonLineParseError({
+          lineNumber: lines.length,
+          line: "<transcript validation>",
+          cause,
+        }),
+    });
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file apps/server/src/orchestration-v2/testkit/ReplayTranscriptNdjson.ts around lines 116-120:

The call to `decodeTranscript` at line 116 invokes `Schema.decodeUnknownSync`, which throws on validation failure. Since this isn't wrapped in `Effect.try`, any validation error becomes an uncaught exception (defect) instead of a typed `ProviderReplayNdjsonParseError`. This breaks the function's declared error contract. Consider wrapping the call in `Effect.try` to catch the exception and convert it to the declared error type.

Evidence trail:
apps/server/src/orchestration-v2/testkit/ReplayTranscriptNdjson.ts lines 50-53: `decodeTranscript = Schema.decodeUnknownSync(ProviderReplayTranscript)` — throws on failure.
Line 116-118: `return decodeTranscript({...metadata, entries})` — called directly inside Effect.gen without Effect.try wrapper.
Lines 55-68 (`parseReplayRecord`): same pattern but correctly wrapped in `Effect.try`.
Line 80: function declares error type `ProviderReplayNdjsonParseError`.
packages/contracts/src/orchestrationV2.ts lines 1561-1568: `ProviderReplayTranscript` schema with `TrimmedNonEmptyString` fields that can fail validation.

Comment thread apps/server/src/orchestration-v2/ProviderAdapterRegistry.ts Outdated
Comment thread packages/client-runtime/src/wsRpcClient.ts Outdated
Comment thread apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts
Comment thread apps/server/src/orchestration-v2/EventSink.ts
duncan4123 pushed a commit to duncan4123/t3code that referenced this pull request Jun 1, 2026
…der adapters (t3-29f.6)

Assessment of upstream PR pingdotgg#2829 (pingdotgg/t3code) from juliusmarminge:
WIP wire orchestration v2 provider adapters with Codex and Claude adapters,
event sourcing, provider session management, and replay testkit.

Relevance to target issues:
- pingdotgg#2838 (session resume): HIGH — ProviderSessionManager persists session
  IDs and separates startSession/resumeSession operations
- pingdotgg#2778 (subagent hang): MEDIUM — ProviderEventIngestor provides
  infrastructure to forward permission events, but UI plumbing not yet wired
- pingdotgg#2886 (thread stuck working): HIGH — event-sourced projections replace
  mutable state flags, eliminating sticky "working" states

The PR is a draft (34 commits, not merged). No OpenCode ACP adapter
exists yet in v2 — OpenCode would need its own adapter wired into the
ProviderAdapterRegistry. Recommend watching for merge and adding an
OpenCode adapter post-merge.
duncan4123 pushed a commit to duncan4123/t3code that referenced this pull request Jun 2, 2026
duncan4123 pushed a commit to duncan4123/t3code that referenced this pull request Jun 2, 2026
The upstream PR pingdotgg#2829 added orchestrationV2 methods to the WsRpcClient
interface. The test mock in service.threadSubscriptions.test.ts was
missing the orchestrationV2 property, causing a typecheck failure:
'Property orchestrationV2 is missing in type...'

Added orchestrationV2 mock with dispatchCommand, getThreadProjection,
subscribeShell, and subscribeThread as vi.fn() stubs.
duncan4123 pushed a commit to duncan4123/t3code that referenced this pull request Jun 2, 2026
The upstream PR pingdotgg#2829 targets a newer Effect version than our fork's
pinned effect@4.0.0-beta.73. Fixes:

- Replace Random.nextUUIDv4 with Crypto.randomUUIDv4 (beta.73 API)
- Fix deterministic Service tag keys to match fork convention
  (include file path segments; e.g. Adapters/ClaudeAdapterV2/...)
- Replace Schema.decodeSync with Schema.decodeUnknownEffect inside
  Effect.gen generators (tsgo schemaSyncInEffect rule)
- Replace inline Schema.encodeUnknownSync with module-level wrappers
  to avoid schemaSyncInEffect rule inside generators
@github-actions

github-actions Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

🚀 Expo continuous deployment is ready!

  • Project → t3-code
  • Platforms → android, ios
  • Scheme → t3code-preview
  🤖 Android 🍎 iOS
Fingerprint fe5a51f2e189da69dfc4c2cd458e6cfb5fdff2ea ae3bd597809dfd7771d0898f735d172973d4c1c8
Build Details Build Permalink
DetailsDistribution: INTERNAL
Build profile: preview:dev
Runtime version: fe5a51f2e189da69dfc4c2cd458e6cfb5fdff2ea
App version: 0.1.0
Git commit: 1d5a64460414f9a2c6ff4a5e4f977932228b7f1b
Build Permalink
DetailsDistribution: INTERNAL
Build profile: preview:dev
Runtime version: ae3bd597809dfd7771d0898f735d172973d4c1c8
App version: 0.1.0
Git commit: eea0dcae4150df8341606520c074dc651ae7c00a
Update Details Update Permalink
DetailsBranch: pr-2829
Runtime version: fe5a51f2e189da69dfc4c2cd458e6cfb5fdff2ea
Git commit: 1d5a64460414f9a2c6ff4a5e4f977932228b7f1b
Update Permalink
DetailsBranch: pr-2829
Runtime version: ae3bd597809dfd7771d0898f735d172973d4c1c8
Git commit: 1d5a64460414f9a2c6ff4a5e4f977932228b7f1b
Update QR

Comment thread apps/server/src/orchestration-v2/RunExecutionService.ts
Comment thread apps/server/src/ws.ts
Comment thread apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts
Comment thread apps/server/src/orchestration-v2/RunExecutionService.ts
@juliusmarminge juliusmarminge changed the title WIP: wire orchestration v2 provider adapters feat(orchestrator): introduce new orchestrator Jun 14, 2026
Comment thread apps/server/src/orchestration-v2/RunExecutionService.ts
Comment on lines +109 to +128
Effect.gen(function* () {
const threadId = payloadInput.threadId ?? input.threadId;
const eventId = yield* idAllocator.allocate.event({
threadId,
providerSessionId: input.providerSessionId,
});
const occurredAt = yield* DateTime.now;
return yield* Schema.decodeUnknownEffect(OrchestrationV2DomainEvent)(
compactUndefined({
id: eventId,
type: payloadInput.type,
threadId,
runId: payloadInput.runId ?? input.runId,
nodeId: payloadInput.nodeId ?? input.nodeId,
provider: input.event.provider,
rawEventId: input.rawEventId,
occurredAt,
payload: payloadInput.payload,
}),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium orchestration-v2/ProviderEventIngestor.ts:109

In makeDomainEvent, the ?? operator on lines 121 and 123 treats explicit null as equivalent to undefined, causing payloadInput.runId ?? input.runId to fall back to input.runId when payloadInput.runId is explicitly null. Since the type is readonly runId?: RunId | null, this means explicit null values from the caller (e.g., input.event.node.runId being null on line 172) are incorrectly overwritten instead of preserved. Consider using === undefined checks like lines 161-162 and 210-211, or use payloadInput.runId === undefined ? input.runId : payloadInput.runId.

          const threadId = payloadInput.threadId ?? input.threadId;
-          const runId = payloadInput.runId ?? input.runId;
-          const nodeId = payloadInput.nodeId ?? input.nodeId;
+          const runId = payloadInput.runId === undefined ? input.runId : payloadInput.runId;
+          const nodeId = payloadInput.nodeId === undefined ? input.nodeId : payloadInput.nodeId;
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/server/src/orchestration-v2/ProviderEventIngestor.ts around lines 109-128:

In `makeDomainEvent`, the `??` operator on lines 121 and 123 treats explicit `null` as equivalent to `undefined`, causing `payloadInput.runId ?? input.runId` to fall back to `input.runId` when `payloadInput.runId` is explicitly `null`. Since the type is `readonly runId?: RunId | null`, this means explicit `null` values from the caller (e.g., `input.event.node.runId` being `null` on line 172) are incorrectly overwritten instead of preserved. Consider using `=== undefined` checks like lines 161-162 and 210-211, or use `payloadInput.runId === undefined ? input.runId : payloadInput.runId`.

Evidence trail:
apps/server/src/orchestration-v2/ProviderEventIngestor.ts lines 105-106 (payloadInput type with `RunId | null`), line 121 (`runId: payloadInput.runId ?? input.runId`), line 122 (`nodeId: payloadInput.nodeId ?? input.nodeId`), lines 161-162 and 210-211 (codebase uses `=== undefined` pattern elsewhere). packages/contracts/src/orchestrationV2.ts line 358 (`runId: Schema.NullOr(RunId)` on ExecutionNode - confirms null is a valid value), line 857 (`runId: Schema.optional(RunId)` on EventBase - domain event uses optional/undefined, not null). apps/server/src/orchestration-v2/ProviderEventIngestor.ts lines 80-81 (compactUndefined only strips undefined, not null).

Comment thread apps/server/src/orchestration-v2/Orchestrator.ts
Comment thread apps/web/src/routes/debug.orchestration-v2.tsx Outdated
Comment thread apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts
@juliusmarminge
juliusmarminge force-pushed the t3code/codex-turn-mapping branch from 79031a1 to 4e68dcb Compare June 14, 2026 23:55
@juliusmarminge
juliusmarminge force-pushed the t3code/codex-turn-mapping branch from 4e68dcb to c7539b9 Compare June 17, 2026 07:30
Comment thread apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts
Comment thread apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts
Comment thread apps/server/src/orchestration-v2/ProviderSessionManager.ts Outdated
Comment thread apps/server/src/orchestration-v2/Orchestrator.ts Outdated
Comment thread apps/server/src/mcp/OrchestratorMcpService.ts Outdated
Comment thread apps/server/src/ws.ts Outdated
function nativeThreadId(provider: ProviderKind, thread: OrchestrationV2ProviderThread): string {
const id = thread.nativeThreadRef?.nativeId;
if (id === null || id === undefined || id.trim().length === 0) {
throw new ProviderAdapterProtocolError({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium Adapters/AcpAdapterV2.ts:271

When nativeThreadId is called inside Effect.gen generators (e.g., lines 899, 1813), the thrown ProviderAdapterProtocolError becomes an untyped defect instead of a typed failure. This bypasses Effect.mapError and other typed error handlers, causing the error to propagate as an unexpected defect. Consider converting nativeThreadId to return Effect<string, ProviderAdapterProtocolError> and yielding it at each call site, or inlining the validation with yield* new ProviderAdapterProtocolError(...) so the failure is properly typed.

Also found in 1 other location(s)

apps/server/src/orchestration-v2/ThreadManagementService.ts:278

The statement return yield* managementError(...) cannot work correctly because managementError() returns a ThreadManagementError instance, not an Effect. The yield* operator in Effect.gen expects an Effect value. This should be return yield* Effect.fail(managementError(...)). The correct pattern is demonstrated elsewhere in this file (lines 241-246) where Effect.fail(managementError(...)) is properly used. This same bug pattern repeats at lines 291, 333, 357, 374, 390, 406, and 427.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.ts around line 271:

When `nativeThreadId` is called inside `Effect.gen` generators (e.g., lines 899, 1813), the thrown `ProviderAdapterProtocolError` becomes an untyped defect instead of a typed failure. This bypasses `Effect.mapError` and other typed error handlers, causing the error to propagate as an unexpected defect. Consider converting `nativeThreadId` to return `Effect<string, ProviderAdapterProtocolError>` and yielding it at each call site, or inlining the validation with `yield* new ProviderAdapterProtocolError(...)` so the failure is properly typed.

Evidence trail:
1. nativeThreadId function with throw: apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.ts lines 268-277
2. Call site inside Effect.gen: apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.ts line 899
3. Call site inside Effect.gen: apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.ts line 1813
4. Correct yield* pattern for comparison: apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.ts line 1808
5. ProviderAdapterProtocolError class definition: apps/server/src/orchestration-v2/ProviderAdapter.ts lines 316-327
6. Effect.gen implementation delegating to fromIteratorUnsafe: https://github.com/Effect-TS/effect-smol packages/effect/src/internal/effect.ts lines 1104-1125
7. fromIteratorUnsafe calling iter.next() without try/catch: https://github.com/Effect-TS/effect-smol packages/effect/src/internal/effect.ts lines 1285-1307
8. FiberImpl.runLoop catch block converting thrown errors to exitDie: https://github.com/Effect-TS/effect-smol packages/effect/src/internal/effect.ts lines 646-650
9. die = exitDie producing Effect<never> (untyped): https://github.com/Effect-TS/effect-smol packages/effect/src/internal/effect.ts line 947

Also found in 1 other location(s):
- apps/server/src/orchestration-v2/ThreadManagementService.ts:278 -- The statement `return yield* managementError(...)` cannot work correctly because `managementError()` returns a `ThreadManagementError` instance, not an `Effect`. The `yield*` operator in `Effect.gen` expects an Effect value. This should be `return yield* Effect.fail(managementError(...))`. The correct pattern is demonstrated elsewhere in this file (lines 241-246) where `Effect.fail(managementError(...))` is properly used. This same bug pattern repeats at lines 291, 333, 357, 374, 390, 406, and 427.

juliusmarminge and others added 28 commits September 23, 2026 20:59
)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Background-task notifications and delegated completions queued behind a
held queue are hidden from the queue UI, so the Resume queue control never
appeared, yet thread.settle counted them as active work. Settle now cancels
those automatic runs in the same transaction; user-queued messages still
block it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep main's recycled mobile list and per-row clock scoping alongside V2 runtime ownership, subagent filtering, and unread completion labels. Preserve provider compatibility diagnostics and shared PR badge controls while retaining V2 authentication actions and linked-PR tooltips. Port main's PR batching and settlement quota improvements into the V2 services.
…13311)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…erk bridge (#13204)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…3347)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

This branch was successfully deployed

1 active (outdated) deployment
production 3e4ca4c5 Deployed Sep 23, 2026 by juliusmarminge via Resolve T3 Connect public config #2177
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet