You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Rush is a CLI-first application: @microsoft/rush is a thin launcher that resolves the workspace's rushVersion, loads the matching @microsoft/rush-lib, and runs the entire engine in-process, once per
invocation. Every command re-reads configuration, rebuilds the operation graph, re-resolves state, and
throws it all away on exit.
This RFC proposes rushd, a long-lived, per-workspace daemon that owns the engine and keeps build
state warm (config, project graph, operation graph, file watchers, plugins). rush becomes a very thin
client that forwards the command to the daemon and pumps stdout/stderr/stdin back to the terminal — an
interaction transparent to the user and to scripts. All interesting work happens in the daemon; the
client only owns presentation. There is one daemon per Rush workspace, and it auto-starts on
first use.
The model is directly inspired by Bazel's client/server architecture.
It reuses the watch-mode overhaul (PR #5378) to keep the build graph warm, and the Reporter Overhaul
(#5858) for the presentation-free event contract that flows over the wire. The default flip ships as Rush 6.
2. Context and Motivation
Cold start every time. Config parsing, graph construction, and snapshotting are repeated on every rush build/rush install/rush update, even when nothing changed.
No resident watch state. The watch-mode overhaul makes the operation graph stateful and warm-able, but
a CLI process cannot keep it resident across invocations.
Presentation is fused to the engine. rush-lib writes ANSI/English directly, which blocks non-terminal
clients (agents, IDEs, web) and makes output hard to adapt for CI/agents.
Concurrency is hostile. A second rush command today races or fails ("another rush is running")
instead of coordinating.
Agent/AI ergonomics. Long-running foreground processes (rush start) and verbose output are poor for agents; a daemon
plus a structured client protocol fixes both.
3. Goals and Non-Goals
Goals
A per-workspace daemon that keeps RushConfiguration + operation graph + watchers + plugins warm.
A thin client that is byte-for-byte transparent: identical stdout/stderr, exit codes, TTY/color/width
behavior, stdin, and Ctrl+C semantics as today.
Terminal rendering lives in the client wrapper — no SIGWINCH/terminal-control signals sent to the
daemon; the client owns width/color/resize.
Auto-start the daemon on demand; new rush daemon start|stop|restart|status|logs subcommands.
The daemon handles rush install / rush update and restarts itself (with socket handoff) when
they change installed state.
Queue-and-wait concurrency: a conflicting command waits rather than failing, with exclusivity
classes and shared-build merging.
Presentation on the client. The engine emits a structured, presentation-free event stream
(adopting @rushstack/reporter's event contract, [rush] Rush Reporter Overhaul #5858); the client renders it. The daemon never touches
terminal-control state.
Transparency via a request envelope, not shared TTY. The client sends columns/colorLevel/cwd/env
per request; the daemon injects these per-request (never process.chdir/mutating global process.env).
Queue-and-wait scheduling with SHARED-BUILD / SHARED-READ / EXCLUSIVE classes; install/update
are EXCLUSIVE and trigger reload tiers.
Self-managing lifecycle. After install/update, the daemon sends the client its exit code, then
drains, restarts a successor, and hands off the socket; version-mismatch also triggers a restart.
Warm-set bounding. LRU idle eviction under a memory budget + telemetry-weighted warm selection;
best-effort, never correctness-affecting.
Split packages from day one (protocol / transport / renderer / client-core / daemon), with a separate
CLI-specific client package (@rushstack/rush-cli-client) until cutover, so @microsoft/rush is untouched
pre-6.
5. Relationship to In-Flight Work
Watch-mode overhaul (PR [rush] (BREAKING CHANGE) Overhaul watch-mode to facilitate orchestration #5378) — hard prerequisite. Provides the stateful IOperationGraph
(setEnabledStates, invalidateOperations, scheduled iterations, terminal-destination management) the
daemon keeps warm. Its hook churn is @alpha/@beta (not a Rush 5 stable-API break).
Reporter Overhaul ([rush] Rush Reporter Overhaul #5858) — reused, not duplicated. Supplies the presentation-free event envelope +
NDJSON wire adapter + built-in reporters. Its "daemon-aligned major default flip" is the Rush 6 cutover;
the two efforts share a breaking-change set (ILogger.terminal, RushSession.terminalProvider, plugin-API
gating) and cut over together.
1. Summary
Rush is a CLI-first application:
@microsoft/rushis a thin launcher that resolves the workspace'srushVersion, loads the matching@microsoft/rush-lib, and runs the entire engine in-process, once perinvocation. Every command re-reads configuration, rebuilds the operation graph, re-resolves state, and
throws it all away on exit.
This RFC proposes
rushd, a long-lived, per-workspace daemon that owns the engine and keeps buildstate warm (config, project graph, operation graph, file watchers, plugins).
rushbecomes a very thinclient that forwards the command to the daemon and pumps stdout/stderr/stdin back to the terminal — an
interaction transparent to the user and to scripts. All interesting work happens in the daemon; the
client only owns presentation. There is one daemon per Rush workspace, and it auto-starts on
first use.
The model is directly inspired by Bazel's client/server architecture.
It reuses the watch-mode overhaul (PR #5378) to keep the build graph warm, and the Reporter Overhaul
(#5858) for the presentation-free event contract that flows over the wire. The default flip ships as Rush 6.
2. Context and Motivation
rush build/rush install/rush update, even when nothing changed.a CLI process cannot keep it resident across invocations.
clients (agents, IDEs, web) and makes output hard to adapt for CI/agents.
rushcommand today races or fails ("another rush is running")instead of coordinating.
rush start) and verbose output are poor for agents; a daemonplus a structured client protocol fixes both.
3. Goals and Non-Goals
Goals
RushConfiguration+ operation graph + watchers + plugins warm.behavior, stdin, and
Ctrl+Csemantics as today.SIGWINCH/terminal-control signals sent to thedaemon; the client owns width/color/resize.
rush daemon start|stop|restart|status|logssubcommands.rush install/rush updateand restarts itself (with socket handoff) whenthey change installed state.
classes and shared-build merging.
mainat0.x, then a Rush 6 cutover.Non-Goals
4. Proposed Solution
Key architectural decisions:
(adopting
@rushstack/reporter's event contract, [rush] Rush Reporter Overhaul #5858); the client renders it. The daemon never touchesterminal-control state.
columns/colorLevel/cwd/envper request; the daemon injects these per-request (never
process.chdir/mutating globalprocess.env).SHARED-BUILD/SHARED-READ/EXCLUSIVEclasses;install/updateare
EXCLUSIVEand trigger reload tiers.install/update, the daemon sends the client its exit code, thendrains, restarts a successor, and hands off the socket; version-mismatch also triggers a restart.
best-effort, never correctness-affecting.
CLI-specific client package (
@rushstack/rush-cli-client) until cutover, so@microsoft/rushis untouchedpre-6.
5. Relationship to In-Flight Work
IOperationGraph(
setEnabledStates,invalidateOperations, scheduled iterations, terminal-destination management) thedaemon keeps warm. Its hook churn is
@alpha/@beta(not a Rush 5 stable-API break).NDJSON wire adapter + built-in reporters. Its "daemon-aligned major default flip" is the Rush 6 cutover;
the two efforts share a breaking-change set (
ILogger.terminal,RushSession.terminalProvider, plugin-APIgating) and cut over together.