Skip to content

feat(server): spike orchestration code mode - #11853

Draft
juliusmarminge wants to merge 460 commits into
t3code/codex-turn-mappingfrom
t3code/code-mode-spike
Draft

juliusmarminge wants to merge 460 commits into
t3code/codex-turn-mappingfrom
t3code/code-mode-spike

Conversation

@juliusmarminge

Copy link
Copy Markdown
Member

Draft spike based on #2829.

This lets an agent run multi-step orchestration as a JavaScript async function body through t3_code_mode_exec. Existing orchestration and thread tools are exposed as t3.<tool_name>(args), so a script can list threads, read them concurrently with Promise.all, and return a compact result without another model turn for each step.

The evaluator is one persistent Rust/native QuickJS process per environment, with up to eight reusable threads and a fresh guest heap for each script. The TypeScript server keeps tool permissions, schema validation, admission limits, cancellation, and durable call journals. Execution handles support wait/cancel and retained submission-key deduplication. Interrupted scripts are never replayed, and cancellation does not undo accepted commands or stop delegated tasks. Development and desktop/CLI/npm release packaging include the native binary.

Whether this is worth shipping is still an open question. Many harnesses already provide their own code mode, including Codex, and can overlap these same MCP calls. T3-owned code mode adds another execution layer, a native artifact, and build dependencies. Its possible value is consistent behavior across providers plus server-owned execution handles and recovery. Keeping this as a separate draft lets us evaluate that tradeoff before including it in the orchestrator work.

Validation:

  • 40 focused backend tests passed, including production orchestrator dispatch, concurrent calls, cancellation, revocation, host replacement, and durable recovery without replay.
  • Three Rust tests, 29 desktop tests, and 73 packaging tests passed. One Windows cross-architecture probe test also fails on unchanged HEAD and remains separate from this spike.
  • Scoped lint/typechecks and native Clippy passed. The full T3 executable builds, and its actual code mode broker works with five concurrent scripts without Node on PATH.
  • Manual end-to-end agent testing completed a thread list and two parallel thread reads through t3_code_mode_exec; its durable journal records all three calls as completed.
  • On macOS arm64, the native release binary is about 1.6 MiB. Host RSS measured 6.3 MiB idle, 8.4 MiB with five scripts waiting on tool calls, and 9.3 MiB with eight. The TS host measured about 207, 293, and 332 MiB respectively on that workload. Heap-heavy scripts use more memory.

The client currently uses ordinary tool rows. A dedicated script view with nested call grouping is outside this spike, and the manual run still displayed raw code mode tool names.

juliusmarminge and others added 30 commits September 14, 2026 17:21
Complete the #5449 architecture on the v2 timeline, following the
LegendList author's direction to lean on the list's native mechanisms
instead of app-side scroll layers:

- maintainScrollAtEnd is enabled and owned by LegendList, gated off only
  while the user reads history (liveFollowEnabled), while a sent turn
  anchors near the top (anchoredEndSpace), or during the two-frame settle
  of a fold toggle.
- maintainVisibleContentPosition compensates size changes natively
  ({data, size, shouldRestorePosition}); fold toggles anchor compensation
  to the toggled row via a disclosure anchor key, so the trigger stays
  under the pointer instead of the viewport chasing the end.
- ChatView's hand-rolled streaming follow (double-rAF scrollToEnd on
  every data change) is gone; the app now only owns streaming
  adjustments during anchored-end-space mode, mirroring main.
- timelineLiveFollowEnabled state mirrors the follow refs so the
  render-visible gate switches native follow off when a gesture breaks
  follow and back on when the viewport returns to the end band.

Timeline tests updated to assert the native-ownership invariants.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Keep success feedback visible in the Git action control for 10 seconds
- Move the running elapsed timer into the panel menu slot
…s with v2

Post-rebase reconciliation sweep:
- Sidebar: main's folded Sidebar.tsx/Sidebar.logic.ts adapted to v2 shells
  (latestRun/runtime naming, waiting status instead of monitoring), with
  subagent-thread filtering and main's pinned-reorder helpers re-exported
- Pinned drag reorder (#5581) ported into v2: thread.pin orderKey +
  thread.pin.reorder command, thread.pin-reordered event, Orchestrator fold,
  ProjectionStore/Maintenance, client-runtime commands and shell mapping
- Project favicon (#4849-era) and defaultThreadEnvMode flowed through v2
  contracts (OrchestrationProjectShell, application event payloads)
- ChatView: main's #5592 header props, pull-request right-panel surfaces,
  liveAgentCount badge (#5745) wired into the v2 panel layout
- enableAssistantStreaming -> enableLegacyTokenStreaming rename applied to
  v2 RunExecutionService and replay testkit
- Removed v1 zombies resurrected by the rebase (provider service/reaper/
  ingestion + v1 layer tests, server.test.ts, integration harness)
- routeTree: main's tree + branch's /settings/scheduled-tasks route
- Misc marker-sweep syntax repairs (rpc.ts, entities.ts, localApi.test.ts,
  rightPanelStore.test.ts, GitManager.test.ts, mobile model menu helpers)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… 038-040

Main released ProjectionThreadsPinOrderKey (038),
ProjectionProjectsDefaultThreadEnvMode (039) and
ProjectionProjectFaviconPath (040), so the branch-private v2 stack shifts
up by three. Registry ids were already 41-49; this renames the files and
identifiers to match and updates the ledger expectations and through-id
boundaries in the migration tests (released boundary 37 -> 40).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- a6c9b41 (agents open pasted images): ClaudeAdapterV2 now grants the
  attachments dir alongside cwd via additionalDirectories and appends
  '[Attached ... is saved at: path]' lines to the turn text so tools can
  dereference pasted images (pixels alone are not tool-readable).
- 5bb8c03 (settle leaves monitors running): thread.settle now joins
  archive/delete in the provider-session detach set, so PR monitors, dev
  servers and subagent fleets stop when the user parks the thread. The
  settle guard already rejects active runs, and serialized dispatch closes
  the re-engage race the v1 fix handled with onlyIfSettled.
- e70cdb4 (Claude resume handshakes) and 2c7267a (reaper vs live
  background subagents) are already covered structurally in v2: results
  are turn-scoped with explicit zero-turn handshake drops, and idle
  release is pinned while background work is pending.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e panel-visibility merge

The keep-both merge nested main's plan-surface migration test inside a
branch popover test and dropped the threadPanelVisibilityByThreadKey key
from the migration results. Restore main's test body and include the
branch's (empty) visibility map in the expected persisted shape.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n text

Follow-up to the #5757 port: start and steer turns now append the
'[Attached ... is saved at: path]' line, so the adapter fixtures assert it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The round-3 reconciliation took main's ChatHeader wholesale and wired its
full prop set, resurrecting the scripts/open-in/git-actions cluster the
branch had deliberately relocated into the thread panel. Restore the
79-line slim header (project favicon + name + thread title) and its
minimal ChatView call. #5592's header actions stay a documented v2
follow-up, as decided in round 2.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Add ready, merge, and conflict-resolution actions to the PR row
- Share pull request action and handoff logic with the detail panel
- Fix thread details scrolling and row alignment
…reens

Round-4 reconciliation of #5986/#5988 with the v2 cutover files:
- PendingUserInputCard adopts main's collapsible overlay redesign with the
  v2 RuntimeRequestId/responseCapability plumbing (dead provider processes
  still read-only the card)
- ThreadFeed adopts the thread-feed-live-follow transition model, the
  user-scroll settle window, momentum handoff, and env-scoped feed keys
  while keeping the v2 nearListEnd layout gating
- ThreadDetailScreen hides (not unmounts) the composer while a user-input
  request owns the slot; multi-select answers flow as arrays end to end
  (threadActivity toggle/build helpers + tests, ThreadUserInputQuestion)
- ThreadComposer keeps the v2 canStopThread stop gate under main's
  onEditorFocusChange rename; standalone stop reuses the shared renderer
- Restored the branch's steer stop/send tests alongside main's composer
  test suite

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- PullRequestDetailPanel takes main's #6039 rework wholesale (reactions,
  update-branch, auto-merge, in-place editing); the thread-details action
  hooks stay in usePullRequestActions with label maps extended for the
  new action variants
- CommandPalette #6330 provider subtitles adapted to the v2 shell
  (session -> runtime for provider instance and display name)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Add conflict, draft, failing-check, and merge action ranking
- Show check progress and pull request details in row tooltips
… PR panel

The round-5 ChatView reconciliation kept the round-3-era PullRequestDetailPanel
call, so the panel mounted without chromeVariant="collapse" — the #6039
scroll-condensing chrome never engaged and the description scrolled under a
full-height chrome. Restore main's call exactly: collapse chrome,
composerDraftTarget for same-thread hand-offs, the isThreadOwnPullRequest
context check, and tab statuses keyed by the active surface id via
updatePullRequestTabStatus instead of a key rebuilt from the status payload.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Add paginated thread history with bounded snapshots and replay limits
- Trim oversized wire payloads and support progressive mobile history loading
- Add optional title regeneration request and start time to thread shells
- Cover cache serialization on mobile and client runtime
- ChatView: #5880 auto-settle-on-merge setting flows into effectiveSettled,
  #5644 browser favicon project registration effect, activeProjectRef memo,
  desktopByTabId on both RightPanelTabs mounts
- server: provide ServerSecretStore to the McpSessionRegistry's
  ServerEnvironment layer (#6325 reads publish opt-in per descriptor)
- mobile: 3-way merged main's deltas into the v2 thread screens
  (NewTaskDraftScreen keeps the branch title seed + main's environmentId,
  threadListV2 keeps both new test suites, queries imports deduped)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…toggles

Restores main's one-inset rule (#5226) that a rebase resolution had
overridden with a conditional right-2 offset, which made the controls jump
sideways whenever the right panel opened. Also restores the live-agent
count badge on the right-panel toggle (#5745) that the round-6 replay
dropped, and applies the same fixed-position rule to the pull requests
page: the toggle now stays mounted at one absolute inset in both states,
with a footprint spacer in the list header so the refresh button never
slides underneath it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The right controls carry mr-px (main's border compensation for anchoring
inside the panel frame), which left the sidebar trigger one pixel closer
to its edge and the sheet-mode tab bar one pixel tighter than the closed
state. Mirror the pixel on the trigger and the sheet layout-controls slot
so all three read the same inset.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gger

The trigger's icon falls through to the Button default (size-4) while the
right cluster hard-coded size-3.5, so the two ends of the titlebar read a
pixel apart on every edge. All five layout-control icons now use size-4,
matching the trigger and the pull requests page's refresh icon.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Omit transcript bodies from shell rows
- Query archived threads separately and stream compact resume metadata
Re-applies the deltas that mid-stack blob reverts discarded, and merges
main's work into the v2-owned surfaces:

- keybindings: main's STATIC_KEYBINDING_COMMANDS rename plus both new
  commands (rightPanel.toggleMaximized alongside threadPanel.toggle)
- OpenInPicker: main's remote-open/SSH routing and favorite-editor
  shortcut layered onto the branch's panel/toolbar variants; the
  extracted shouldShowOpenInPicker now takes remoteOpenMode
- ChatMarkdown: main's bare-filename resolver (#6297) ported into the
  branch's module-level component factory, plus #4133 title-attribute
  stripping on links and images
- ComposerPrimaryActions: main's #4781 model (stop stays reachable, send
  joins it when Enter-to-send is unavailable) carrying the branch's
  steering send button
- ComposerPendingUserInputPanel: main's collapsible redesign with the v2
  RuntimeRequestId and responseCapability gate
- ChatComposer: main's oversized-prompt submission guard wrapping the
  branch's dispatch-mode send
- preview shell: main's container-aware width clamp ported into the
  branch's usePreviewPanelInlineSize hook
- MessagesTimeline/Sidebar: main's day-aware timestamps, code-font tool
  bodies and provider accent badges on the v2 runtime shell
- index.css: main's @variant dark migration (#6381) replaces the branch's
  standalone .dark block
- contracts: main's send-turn image mime allowlist re-homed to
  chatAttachment.ts, where v2 keeps the other send-turn limits

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ports v1's #5246 guard into the v2 dispatcher: a stored receipt only
proves that this exact command already ran for the thread it was recorded
against, so returning it for a command aimed at a different thread reports
success for work that never happened there. The check is extracted as
canReplayCommandReceipt so the rule is unit-testable, and reuse now fails
with OrchestratorCommandIdConflictError like the v1 path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Keep prominent activity rows visible with lifecycle status and provider metadata
- Move feed sizing logic into tested helpers and preserve native measurement for activity groups
Re-applies the deltas that mid-stack blob reverts discarded, and merges
main's round-9 work into the v2-owned surfaces:

- settings: main's Integrations page (#7082) coexists with the branch's
  Scheduled Tasks page in the path union, section labels, icons, and
  search catalog
- contracts: main's preview appearance/zoom/viewport settings imports
  restored beside the branch's modelSelection home for ModelSelection
- mobile: main's built-in themes (#6619) re-applied to the v2 thread
  screens and work log (useThemeColor over hand-rolled color-scheme
  ternaries)
- MessagesTimeline: main's #7157 cleanup adopted (toolCallExpandedBody
  class name unexported, implementation-detail test dropped)
- ChangedFilesTree: main's styled tooltip (#7209) carrying the v2 runId
- pullRequestDetail tests: branch's row-action coverage renamed onto
  main's buildAddSelectionToAgentHandoff (#6597)
- lint: migrated the six branch-owned native title tooltips that main's
  new no-native-title-tooltip rule (#7209) flags to styled Tooltips
  (GitActionsControl, QueuedRunsControl, TimelineSystemDivider,
  MessagesTimeline intent badge and MCP tool logo)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ports #7083 into the v2 session path, which replaced the v1
ProviderService where main's gate lives. Instead of withholding the whole
t3-code MCP credential — on this branch it also carries the thread
orchestration and worktree toolkits — the credential is minted without
the "preview" capability when enableAgentBrowserAccess is off, so every
preview tool call rejects while orchestration stays available.

ProviderSessionManager reads the setting at prepare time (deny on an
unreadable settings file, matching main), rotates a reused credential
whose capability set no longer reflects the setting, and the session
config now carries browserToolsAvailable so the Codex adapter keeps its
developer instructions truthful via main's parameterized instruction
builders instead of the removed constants.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s style simplification

Main's #6381 deleted the shared .workspace-topbar and scroll-fade rules
from index.css after inlining them at main's own call sites, but this
branch's slim chat chrome still references both classes. The round-8
rebase took the deletion without migrating the branch call sites, so the
header collapsed to zero height — the breadcrumb sat on the window edge,
timeline rows scrolled unfaded through it, and the thread-details popover
anchored to the collapsed header.

Restores both as composable utilities in #6381's own style: a
workspace-topbar utility for the titlebar rows, and the branch's
chat-timeline-scroll-fade mask (soft ramp plus a full-height scrollbar
column). Also drops the duplicated media override and its dead
settings-page-scroll-fade selector.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ation

A follow-up sweep against #6381 found the branch still carrying the
pre-simplification forms it replaced, which my earlier fix had papered
over with a compat utility instead of finishing the migration:

- ChatView now uses main's inlined titlebar sizing and the
  data-workspace-titlebar-controls hook on both control clusters. The
  class-based markup was silently missing the themed-toggle bridge
  (html[data-theme-id] [data-workspace-titlebar-controls] …), so custom
  themes lost their titlebar accent in the thread view.
- The scroll-to-end pill becomes main's Button size="xs" variant="glass"
  instead of a hand-rolled button recreating it.
- MessagesTimeline uses main's consolidated topbar-scroll-fade utility;
  the byte-identical chat-timeline-scroll-fade copy and the
  workspace-topbar compat utility are gone.
- The composer-glass dark rules move into nested @variant dark like
  main's (the raw .dark duplicates could drift from the nested copies
  they shadowed), including the branch-only queue strip.
- The pre-#6381 dialog-glass/dialog-backdrop/dropdown-glass class rules
  and their .dark variants are deleted: the #6381 utilities plus
  call-site shadow utilities own every declaration, and the stale
  dropdown rule still had the saturate-less backdrop-filter. The dead
  model-picker-surface dark rule goes with them.

index.css now has zero raw .dark selectors outside the variant
definitions, matching the doctrine in
.macroscope/check-run-agents/ui-consistency.md. Verified against the
emitted production CSS: dark variants compile to :is(.dark,.dark *) with
their @supports color-mix fallbacks intact.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Complete retry items when provider activity resumes
- Keep retry progress visible across web and mobile clients
Ten days of main (194 commits, 640 files) re-integrated with the v2
re-architecture. The headline mechanics:

- migrations: main added 041-043 (AuthSessionClientConnection,
  ProjectionThreadLinkedPullRequest, ProjectionThreadsUnsettledAt), so the
  v2 block renumbers 041-049 → 044-052 with the migration tests shifted to
  match
- contracts: OrchestrationClientOrigin (#7774) and the origin metadata
  field live in applicationEvent.ts and re-export through the legacy
  path; ProviderApprovalOption + acceptAlways + mcp-elicitation (#8058)
  land in providerPolicy.ts; OrchestrationDispatchCommandError (#8824)
  added; the send-turn image-mime home stays chatAttachment.ts
- threadSettled: main's settle-once-on-merge semantics (#7454) and
  un-settle re-anchor (#8231) hand-merged onto the v2 duck-typed shells
  (latestRun ?? latestTurn reads); web callers pass the new
  ChangeRequestSettleSource shape
- timeline anchoring: main's #7897 (follow-up sends no longer push to the
  top) ported by scanning user rows only; the branch test now encodes the
  new semantics, as does mobile's #7969 settled-pinned shelf behavior
- vcs: branch's deleteLocalBranch coexists with main's pruneWorktrees and
  the #7674 submodule checkout tests
- ws: v2 RPC surface keeps its dispatch path; main's attachment upload
  RPCs (#8048) and client-connection analytics recording are wired;
  providerUploadFeedback (#7949) fails explicitly pending a v2 route
- approvals: main's option-driven approval buttons (#8058) render through
  the v2 canRespond gate on web and mobile
- ChatView/ChatComposer/MessagesTimeline/Sidebar/session-logic/
  threadActivity keep the branch's v2 architecture; main's v1-coupled
  deltas to those files are recorded for follow-up rather than
  force-fitted

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…in the v2 work log

Ports main's #7999/#7893 failure policy onto the v2 turn-item work log:
output text that reports a failure (command not found, ENOENT, nonzero
exit markers) now flags a row even when the provider item completed
"successfully", while the rendered row judges only its displayed result —
a command that merely greps for failure strings stays calm. Success now
also requires the failure check to pass, so recovered failures no longer
get the blue check.

The server half of #7893 needs no port: CodexAdapterV2 already projects
item.status directly, so a failed item never masquerades as completed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge and others added 25 commits September 14, 2026 17:22
…11518)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
ConnectionCatalogEntry gained a required enabled flag in #11478, but the
threadShell harness never set it, so enabled-gated atoms filtered every
environment out and two tests failed. Two dead exports also tripped knip.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…d composer state

ThreadNotificationCoordinator presents raw OrchestrationV2ThreadShell
records, but its tests still fed the pre-v2 thread shape (session /
latestTurn), which crashed presentThreadShell on missing DateTime fields.
Rebuild the fixtures as v2 shells with pendingRuntimeRequest and run
statuses, and remove the composerHasUnsentContent binding left unused by
the compaction gating change.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
#11566)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…ed restarts (#11565)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…ation fails (#11557)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…ords (#11505)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Sep 15, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thread transfer impact

⚠️ The latest CI run did not produce a thread transfer result for 82ada70.

This comment will update automatically after the next completed run.

@juliusmarminge
juliusmarminge force-pushed the t3code/codex-turn-mapping branch 2 times, most recently from 463d0c6 to e10a1e2 Compare September 15, 2026 06:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants