Skip to content

perf(server): background service launcher uses 75% less memory - #29284

Merged
t3dotgg merged 1 commit into
mainfrom
t3/explore-extreme-performance-wins
Nov 6, 2026
Merged

t3dotgg merged 1 commit into
mainfrom
t3/explore-extreme-performance-wins

Conversation

@t3dotgg

@t3dotgg t3dotgg commented Nov 2, 2026 •

Copy link
Copy Markdown
Member

The background service runs t3 __service-launcher, a tiny supervisor that keeps the real server alive. It loaded the whole CLI just to reach its handler. In the packaged single executable, that is the full 18 MB module, so the launcher alone held ~260 MiB for as long as the service ran.

Now bin.ts is a 31 KB bootstrap. The service's exact t3 __service-launcher call runs straight from it. Every other command, including the launcher with flags or --help, loads the CLI from binMain.ts as before. In packaged builds, that CLI is a separate bundle embedded as a raw executable asset, so the executable is still one file.

Linux x64 packaged executables, medians of alternating runs against main:

main This PR
Launcher memory (PSS) 259 MiB 66 MiB (-75%)
Launcher time to start the server 467 ms 29 ms
Launcher CPU at startup 590 ms 20 ms
acp-mcp-call startup (wall / CPU) 288 / 294 ms 283 / 293 ms
t3 serve memory 420 MiB 418 MiB

Guards:

  • build:exe fails if the bootstrap grows past 1 MiB, so the CLI cannot slip back into it.
  • Both executable configs pass --require-module, so NODE_OPTIONS=--no-require-module cannot break the embedded load.
  • The release smoke test now also runs __service-launcher on every platform.

Proof:

  • check:changed, plus focused tests for the launcher, boot service, CLI loading, and the linux-arm64 executable. The CLI test fails if the bare-argv check or the launcher's full-CLI command is removed.
  • Linux x64 packaged executable: version, launcher errors, launcher --help and flags, symlinked paths, --no-require-module, the speech worker over IPC, and SIGTERM stopping launcher and child.
  • macOS arm64: built the real release archive on a Mac before the rebase, and the archive smoke test passed. Windows is covered by the release smoke test.

Council review

Rounds: 3

Delegate Round 1 Round 2 Round 3
Claude Opus 5.5 7/10 8/10 9/10
Muse Wonder Full 7/10 9/10 9/10
Codex GPT-6.1 Sol 9/10 9/10 9/10

Created with Claude Opus 5.5 in Claude Code, running in T3 Code.

🤖 Generated with Claude Code

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Nov 2, 2026
@macroscopeapp

macroscopeapp Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — The change keeps the full CLI out of the service launcher's startup graph and packages it as an embedded asset. New diagnostic suppressions in bin.ts and vite.config.ts require human review.

No code changes detected at 9c7369f. Prior analysis still applies.

You can add or adjust custom eligibility rules. Learn more.

@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 6.8 KiB ✅
Codex Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Codex Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅
Codex Live turn WebSocket decoded 21.5 KiB 21.5 KiB 0 B (0.0%) 24.4 KiB ✅
Codex Live turn messages 1 1 0 (0.0%) 8 ✅
Claude Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 6.8 KiB ✅
Claude Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Claude Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅
Claude Live turn WebSocket decoded 21.9 KiB 21.9 KiB 0 B (0.0%) 24.4 KiB ✅
Claude Live turn messages 1 1 0 (0.0%) 8 ✅

Baseline: 59ec1ba · PR result: 9c7369f · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 108.5 KiB
  • Claude decoded thread snapshot: 108.8 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@coderabbitai

coderabbitai Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

Important

Review skipped

Review was skipped as selected files did not have any reviewable changes.

Run configuration

Commits

Reviewing files that changed from the base of the PR and between c7810c2 and 9c7369f.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review

No actionable comments were generated in the recent review.

Walkthrough

The executable build now creates a separate bootstrap and CLI asset, validates bundle imports and bootstrap size, and embeds the CLI asset in SEA executables. Runtime startup loads the CLI through the bootstrap or runs the service launcher directly. Tests and an archive smoke check cover these paths.

Changes: CLI Bootstrap and Dispatch

Layer / File(s) Summary
Build and embed CLI asset
apps/server/vite.config.ts, apps/server/scripts/cli.ts, apps/server/scripts/cliErrors.ts, scripts/lib/linux-arm64-sea.ts
Executable packing creates a CLI bundle and a separate bootstrap. The build checks both bundles for external imports, rejects bootstraps larger than 1 MiB, and embeds the CLI asset in SEA executables.
Bootstrap loading and command dispatch
apps/server/src/bin.ts, apps/server/src/binMain.ts, apps/server/src/cli/serviceLauncher.ts, apps/server/src/binCli.ts
The entry point loads the CLI from the embedded asset in SEA runs or imports it directly otherwise. It invokes the service launcher for the exact launcher command with no extra arguments. Other invocations use the CLI dispatcher. The service launcher awaits its work and sets the exit code on failure.
CLI startup and archive checks
apps/server/src/cliCompileCache.test.ts, scripts/smoke-cli-archive.ts
Tests check CLI loading for normal and service-launcher invocations. The archive smoke check verifies the expected missing-T3CODE_HOME error.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Refactor

Sequence Diagram(s)

sequenceDiagram
  participant BinEntry as bin.ts
  participant Launcher as runServiceLauncherCli
  participant CliMain as binMain.ts
  participant BinCli as binCli.ts
  alt Exact __service-launcher invocation
    BinEntry->>Launcher: run service launcher
    Launcher->>Launcher: await runServiceLauncher
  else Other invocation
    BinEntry->>CliMain: load CLI and call runCliCommand
    CliMain->>BinCli: import and run CLI
  end
Loading

Possibly related issues

Suggested reviewers: maria-rcks, voltcrash

Merge Risk: Minimal · previous review c7810

This change moves the background service launcher into a small bootstrap to cut its memory use, and no merge-blocking defect was found. Windows and macOS SEA loading was not run directly and depends on the PR's reported release smoke tests.

Pre-merge checks: Passed 4

Check name Status Explanation
Title check Passed The title describes the launcher memory reduction, which is the main change.
Description check Passed The description covers the problem, change, and verification. It does not include the required scope and approval information.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Finishing Touches

Generate docstrings

  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)

  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Recent review info

Run configuration

Commits

Reviewing files that changed from the base of the PR and between f56def2 and c7810c2.

Files selected for processing: 6

  • apps/server/scripts/cli.ts
  • apps/server/src/bin.ts
  • apps/server/src/binCli.ts
  • apps/server/src/cliCompileCache.test.ts
  • apps/server/vite.config.ts
  • scripts/lib/linux-arm64-sea.ts

Limit details: You’ve used all 10 included reviews currently available.

@Alvin-MN

Alvin-MN commented Nov 5, 2026

Copy link
Copy Markdown

Independent test of this PR on Linux x64 (build:exe at head 61ccc10 against base 47f2c8d, Node 26.12.1, memory measured as PSS). Your numbers hold.

base this PR
Launcher, same binary file as the server 215 MB 31 MB
Launcher + server 581 MB 405 MB
Launcher, separate binary file from the server 248 MB 50 MB
Direct t3 serve 400 MB 383 MB

These also behaved correctly:

  • SIGTERM with a live server: launcher exits 0 and the server stops.
  • kill -9 on the server: launcher exits 1, the same as base.
  • Missing home or state: same errors as base.
  • Executable paths containing spaces, #, %20 and é, and a symlink.
  • NODE_OPTIONS=--no-require-module.
  • PR launcher running a base server.
  • The PR merged onto main at a07be97: clean merge and build, launcher at 50 MB.

Two things that aren't in the PR description:

  1. Existing installs may not get the saving. A launcher pinned by an older service unit stays large. Base launcher with PR server: 248 MB. A 0.0.46 launcher with PR server: 315 MB. Both run and stop cleanly, but the memory saving needs t3 service install or a fix for [Bug]: Service unit stays pinned to the runtime that installed it, so deleting old runtimes breaks the next restart #17490.
  2. Small start-up cost on fast paths. About 36 ms (6%): acp-mcp-call went from 557 to 593 ms median, and acp-mcp-bridge from 557 to 589 ms (10 runs each, one batch per build). This looks like a fair trade, though acp-mcp-call pays it on every tool call.

Not tested: update handoff and rollback through the real update flow, Windows, macOS, and the web UI (client not built, so / returned 503).

I ran this with an AI coding agent.

@t3dotgg
t3dotgg force-pushed the t3/explore-extreme-performance-wins branch 2 times, most recently from f56def2 to c7810c2 Compare November 6, 2026 11:00
@t3dotgg t3dotgg changed the title perf(server): background service launcher uses 85% less memory perf(server): background service launcher uses 75% less memory Nov 6, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@t3dotgg
t3dotgg force-pushed the t3/explore-extreme-performance-wins branch from c7810c2 to 9c7369f Compare November 6, 2026 11:06
@t3dotgg
t3dotgg merged commit 6577c6b into main Nov 6, 2026
33 checks passed
@t3dotgg
t3dotgg deleted the t3/explore-extreme-performance-wins branch November 6, 2026 11:12
danielyc added a commit to danielyc/t3code that referenced this pull request Nov 6, 2026
Native Windows runners generate the server compile cache in afterPack,
which upstream's Linux-hosted Windows packaging skips. Since pingdotgg#29284 split
the server bundle, the cache pushes the Windows x64 payload to 82 files,
over upstream's 80-file limit, so every patched nightly failed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
github-actions Bot added a commit to omarcresp/t3code-flake that referenced this pull request Nov 6, 2026
**v0.1.8-nightly.20261106.4275** · 12 changes from 6 contributors

**8 bug fixes and performance improvements.**

<details>
<summary>Full changelog</summary>

## What's Changed
* fix(desktop): arm64 macOS builds no longer ship x64-only objc-js binary by @joshuarossi in pingdotgg/t3code#31285
* fix(web): keep task updates static in the timeline by @Yash-Singh1 in pingdotgg/t3code#31888
* fix(devices): keep devices listed when simulator discovery fails by @shivamhwp in pingdotgg/t3code#25971
* fix(web): dragging a sidebar thread no longer scrolls the list to the bottom by @juliusmarminge in pingdotgg/t3code#27691
* fix(web): tagging a thread by drag no longer scrolls the sidebar by @t3dotgg in pingdotgg/t3code#31924
* ci: stacked PRs stop evicting the shared pnpm cache by @t3dotgg in pingdotgg/t3code#31937
* fix(web): remote subagents no longer split from the lineage list by @t3dotgg in pingdotgg/t3code#29285
* perf(ci): release uploads stop recompressing installers and CLI archives by @t3dotgg in pingdotgg/t3code#31942
* feat(antigravity): identify as T3 Code to agy acp 1.5.1+ by @patrick-toulme in pingdotgg/t3code#31158
* ci(release): JS bundle jobs stop building an unused Linux helper by @t3dotgg in pingdotgg/t3code#31941
* feat(marketing): help search engines tell t3.codes apart from copycat sites by @t3dotgg in pingdotgg/t3code#31142
* perf(server): background service launcher uses 75% less memory by @t3dotgg in pingdotgg/t3code#29284

## New Contributors
* @joshuarossi made their first contribution in pingdotgg/t3code#31285
* @patrick-toulme made their first contribution in pingdotgg/t3code#31158

**Full Changelog**: pingdotgg/t3code@v0.1.8-nightly.20261106.4262...v0.1.8-nightly.20261106.4275

</details>


Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.1.8-nightly.20261106.4275
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 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.

2 participants