Original research: English · 中文 · Research Center
The UI says Project B. The next test runs in B. Yet an Agent terminal still writes into Project A, an old file watcher emits events from A, and the evidence report is saved under B.
This is the local-Agent equivalent of a construction crew moving sites: the supervisor changes the sign, the workers keep demolishing the old building, the tool truck arrives at the new one, and the inspector records everything in the new site diary. Every component can report success while the delivery is wrong.
The current project is not one path string. It is a distributed binding shared by an execution chain.
Seven consumers can hold seven different roots
| Component | Plain role | How it becomes stale |
|---|---|---|
| Runtime | coordinator | Keeps the previous in-memory project binding |
| MCP Server | tool process | Was started with the old root or environment |
| file Watcher | site camera | Still subscribes to Project A |
Agent / terminal cwd
|
worker location | A child process keeps its original working directory |
| task write root | work-order desk | New tasks go to B while execution stays in A |
| FCoP lifecycle root | delivery ledger | State files describe a different project |
| logs and evidence root | inspection diary | Evidence is attributed to the new root for old work |
Changing the toolbar only updates one observer. Safe rebinding must move the whole group.
Figure 1. The old root becomes inactive before a new execution identity is allowed to produce effects.
A four-phase safe switch
1. Stop admitting new work
Freeze new dispatches before changing any root. Otherwise work can enter while half the system still points to A and half already points to B.
Existing sessions should enter graceful draining: block new tool calls, ask cooperative work to stop at a safe boundary, wait for a bounded grace period, and only then terminate remaining child processes. A forced kill must leave a visible dirty-state record; it must not be presented as a clean switch.
2. Quiesce old side effects
Stop watchers, MCP tool processes, terminals, build jobs, and other children that can still touch A. On Windows, process termination does not guarantee immediate handle release. A Git process, language server, or orphaned tool may retain a file or directory handle and cause EBUSY or EPERM errors.
Use bounded retry with evidence:
request cooperative stop
wait for child exit
probe old-root handles / operations
retry within a fixed deadline
if still busy: reject the switch and retain diagnostics
Silently continuing after a handle error creates a split workspace.
3. Persist one canonical new root
Normalize more than slash direction and letter case. Modern Node.js projects commonly use symlinks through package managers. Two different strings may reach the same physical directory, while one friendly-looking path may escape the intended root.
Resolve a real path (fs.realpathSync.native() on Node.js/Windows where appropriate), validate that it exists and is permitted, then persist the canonical form. Task context should become immutable: once one task starts, its project identity cannot change underneath it.
4. Rebuild and prove the binding
Restart the Runtime-facing components from the saved canonical root. Give the new execution chain a new identity or epoch. Before dispatch resumes, verify:
- Runtime root equals the persisted root;
- MCP/tool roots equal the Runtime root;
- watcher subscriptions cover only the new root;
- new child-process
cwdequals the new root; - task, report, log, and evidence roots agree;
- no old-epoch process may write.
The switch is complete only when these facts agree—not when the UI label changes.
Fail visibly on four classes of error
- Invalid destination: missing, forbidden, or unresolved path. Keep A active or stop safely; do not half-switch.
- Draining timeout: an in-flight model/tool call does not reach a safe boundary. Preserve its state and require an explicit recovery decision.
- Windows handle retention: old processes still lock A. Retry within bounds, identify the owner when possible, then reject rather than guess.
- Binding mismatch: any component reports a different canonical root or execution epoch. Block dispatch.
What 27 tests do—and do not—prove
The pinned CodeFlowMu implementation passed 27/27 related tests for the current Windows-local project switch path. They verify the tested order, conflicts, and binding behavior in that implementation.
They do not prove that graceful draining, orphan-handle discovery, symlink behavior on every filesystem, or every third-party MCP Server is already covered. Those are explicit engineering requirements and next validation targets, not retroactive claims about the current test suite.
The practical rule
Treat project switching like changing an execution identity:
stop old effects
→ persist one canonical new address
→ rebuild every root consumer
→ prove task and evidence share that address
→ reopen dispatch
If your system cannot enumerate every component that consumes the project root, it cannot yet claim to switch projects safely.
The complete source matrix and implementation boundaries are in the canonical English article. A Chinese version is also available.
More bilingual Agent engineering research: JoinWell52 Research Center

Top comments (0)