Appearance
Windows Build Environment & Repo Relocation
When to use this page. You are building the Expo/React Native app (
apps/mobile) on Windows and hit one of: a native build failing withFilename longer than 260 characters, Metro crashing on startup, a C: drive at 0 bytes, or you need to relocate the repo to another drive without losing Claude Code memory. This is the finalized, verified reference — follow it instead of re-deriving the fix. It records the 2026-07-21 migration of the repo from a deep OneDrive path on C: toD:\WorkSpace\DevArea\qrsetu. Tracked in Track B.
TL;DR — the golden rules
- Never keep the repo in a deep or OneDrive-synced path on Windows. React Native's native (CMake/ninja) build generates paths that blow past Windows' 260-character
MAX_PATHlimit. Keep the project base path short:D:\WorkSpace\DevArea\qrsetu(27 chars), notC:\Users\<u>\OneDrive\WorkSpace\DevArea\qrsetu(48+). - Keep dev caches and build temp off C:. Gradle/npm/Playwright caches live on
D:\DevCache; the Android SDK and all projects live onD:;TEMP/TMPpoint toD:\DevCache\tempso Metro/Hermes/Gradle-transforms/aapt2/clangwrite their (multi-GB) build scratch to D:, not C:. C: only ever holds regenerable browser/editor cache (wiped on demand). WhyTEMP/TMPmatter specifically: Windows' page file isC:\pagefile.sys(system- managed), so a full C: caps how large it can grow → caps the commit limit → release builds OOM (see Memory / commit limit). Build scratch on C: fills C: and starves the page file — a double hit. (2026-07-24:TEMP/TMPwere the one relocation gap — they had defaulted to C: since setup.) The guarded build script now enforces this regardless of the shell's inherited env — use it. - Relocating is half the job — artifacts must also be pruned. Growth is monotonic, so "not on C:" only moves the wall to D:.
npm run clean:dev(dry-run) /clean:dev:applyenforce a published retention policy, run automatically, andnpm run check:diskverifies both the layout and that the automation is installed. Full standard: development never touches C:. - Metro watches
packages/+node_modules, never the whole monorepo root — watching the root pulls inlegacy/,documentation/,supabase/and crashes Metro's file watcher. - Maestro runs from WSL Ubuntu against the Windows emulator (WSL2 sees it directly); dev-client flows use
extendedWaitUntil, not bareassertVisible.
The root problem: Windows MAX_PATH (260 chars)
RN native builds compile per-package C++ under node_modules/<pkg>/android/.cxx/... and read prefab headers out of the Gradle transforms cache. Header names like RuntimeSchedulerIntersectionObserverDelegate.h nested under the Gradle-home transform path exceed 260 chars once the project base path is long. The build dies with:
> Task :react-native-screens:buildCMakeDebug[x86_64] FAILED
ninja: error: Stat(D:/…/GradleHome/caches/…/transformed/react-android-…/prefab/modules/reactnative/
include/react/renderer/runtimescheduler/RuntimeSchedulerIntersectionObserverDelegate.h):
Filename longer than 260 charactersTwo independent levers shorten these paths; use both:
| Lever | Effect |
|---|---|
Short project base path (D:\WorkSpace\DevArea\qrsetu) | Shortens the node_modules/<pkg>/android/.cxx/... side |
Short GRADLE_USER_HOME (D:\DevCache\gradle, not a long custom dir) | Shortens the prefab-header transforms side (≈238 chars, under 260) |
Gotcha — stale
.cxxbakes in old paths. A package's generated ninja files cache the absolute Gradle-home path from the build that created them. After changingGRADLE_USER_HOME(or moving the repo), delete stale native build dirs or the old long path resurfaces for just that package:powershellGet-ChildItem node_modules,apps/mobile/android -Recurse -Directory -Force | Where-Object Name -eq ".cxx" | Remove-Item -Recurse -Force Remove-Item apps/mobile/android/{build,app/build,.gradle} -Recurse -ForceAlso set
git config core.longpaths true(helps git; does not fix ninja on its own).
Machine layout (this dev box, 2026-07-21)
User environment variables (set once; survive reboots):
| Variable | Value |
|---|---|
GRADLE_USER_HOME | D:\DevCache\gradle |
PLAYWRIGHT_BROWSERS_PATH | D:\DevCache\playwright |
npm cache (npm config get cache) | D:\DevCache\npm |
TEMP | D:\DevCache\temp — build scratch (Metro/Hermes/aapt2/clang) off C: |
TMP | D:\DevCache\temp — same value as TEMP |
ANDROID_HOME | D:\WorkSpace\DevArea\AppBuilding\AndroidSdk |
JAVA_HOME | JDK 17 (Adoptium) |
Set
TEMP/TMP(no admin):New-Item -ItemType Directory -Force D:\DevCache\temp; setx TEMP D:\DevCache\temp; setx TMP D:\DevCache\temp.setxpersists to the user registry (survives reboots) but does not update already-running processes — open a new terminal (or reboot) for it to take effect.qrsetu-dev-relocate.ps1must set these two alongside the others.
Reusable scripts (kept in
~\Downloads):qrsetu-disk-cleanup.ps1(deletes only regenerable caches — browser/VS Code/Claude vm_bundles/npm/temp; never code, settings, or memory) andqrsetu-dev-relocate.ps1(createsD:\WorkSpace+D:\DevCacheand sets the env vars above). Run cleanup with editors/browsers closed.
Repo relocation runbook (C: OneDrive → D:)
This is the procedure that was executed and verified. It is clone-based (not a folder copy) so no stale absolute paths or OneDrive placeholder files travel along. Budget one native rebuild (~20 min) at the end.
- Commit + push everything. A clone is only lossless once the working tree is on GitHub. Check
git status --shortis clean (or committed). - Clone to the short path.
git clone <url> D:\WorkSpace\DevArea\qrsetuthengit checkout <working-branch>. Confirmgit log --oneline -1matches the commit you pushed. (If the destination already holds unrelated data — e.g. an oldbkp/— move it aside first; never clobber.) - Carry the gitignored files that don't travel via git — copy from the old copy:
supabase/.env.dev,supabase/.env.prod,legacy/.env.test(and any local.env, never.env.example). npm installat the new root (npm cache on D: makes this fast).android/is gitignored and regenerates via prebuild, so nothing else to carry.- Migrate Claude Code memory (see next section) — the one non-obvious step.
- Reopen VS Code at
D:\WorkSpace\DevArea\qrsetu. This starts a fresh Claude Code session keyed to the new path; with memory migrated it resumes with full history + memory intact. - Rebuild (
cd apps/mobile && npx expo run:android) and run the Maestro smoke. Once green, delete the old OneDrive copy.
Migrating Claude Code memory (the non-obvious part)
Claude Code stores each project's memory + conversation transcripts under a folder named after the project's absolute path, at C:\Users\<user>\.claude\projects\<slug>\. The slug rule: lowercase the drive letter, and replace every : and \ with -.
| Path | Slug folder |
|---|---|
C:\Users\bnlah\OneDrive\WorkSpace\DevArea\qrsetu | c--Users-bnlah-OneDrive-WorkSpace-DevArea-qrsetu |
D:\WorkSpace\DevArea\qrsetu | d--WorkSpace-DevArea-qrsetu |
Copy (don't move — keep the old as a safety net) the whole slug folder to the new name before reopening:
powershell
$base = "$env:USERPROFILE\.claude\projects"
Copy-Item "$base\c--Users-bnlah-OneDrive-WorkSpace-DevArea-qrsetu" `
"$base\d--WorkSpace-DevArea-qrsetu" -RecurseThis carries memory\ (MEMORY.md + all memory files) and the conversation *.jsonl. Verify the new MEMORY.md has content after reopening. (The cleanup script never touches .claude — memory is only ever moved deliberately, here.)
Metro on a monorepo (watch scope)
Watching the whole monorepo root crashes Metro's file watcher when it indexes the legacy/ reference SPA (worsened by OneDrive file churn):
Error: TreeFS: Failed to make parent directory entry for ..\..\legacy\src\components\…\PublicImageBlock.jsxFix in apps/mobile/metro.config.js — watch only what the app consumes:
js
config.watchFolders = [
path.resolve(workspaceRoot, 'packages'),
path.resolve(workspaceRoot, 'node_modules'),
];Maestro from WSL
Maestro is installed in WSL Ubuntu (~/.maestro/bin), not Windows. WSL2 sees the Windows emulator (emulator-5554) over adb directly — no bridge configuration needed (adb devices in WSL already lists it).
bash
# from Windows: make Metro reachable from the device (dev-client builds)
adb reverse tcp:8081 tcp:8081
# from WSL: run the flow (repo is under /mnt/<drive>/…)
wsl -d Ubuntu -- bash -lc \
'cd /mnt/d/WorkSpace/DevArea/qrsetu/apps/mobile && \
export PATH="$PATH:$HOME/.maestro/bin" && \
maestro test .maestro/smoke.yaml'Dev-client race. A dev-client cold
launchAppfetches the JS bundle from Metro (a few seconds) before it renders. Flows must wait for content rather than assert instantly, or the assertion races the load:yaml- launchApp - extendedWaitUntil: visible: "QRSETU" timeout: 30000A release build embeds the bundle and renders immediately, so it wouldn't need the wait — but
extendedWaitUntilis correct for both and is whatapps/mobile/.maestro/smoke.yamluses.Fresh-install seeding. On a brand-new dev-client install the first
launchApplands on the "development servers" launcher and won't auto-connect (no remembered URL), so evenextendedWaitUntiltimes out. Seed it once — open the dev-client deep link (adb shell am start -a android.intent.action.VIEW -d "qrsetu://expo-development-client/?url=http://localhost:8081") so the client connects and remembers the URL, or simply run the flow twice. After the URL is remembered, everylaunchAppreconnects on its own.
Memory / commit limit (local release builds)
Local release builds (assembleRelease) fail on this 16 GB box with an out-of-memory abort — either the Gradle JVM (hs_err_pid*.log, "daemon disappeared") or, more often, node/Metro during the cold JS bundle (createBundleReleaseJsAndAssets → Process 'command 'cmd'' finished with non-zero exit value -1073740791/ -2147483645, i.e. 0xC0000409 / 0x80000003 — V8 aborting because it can't get memory). This is commit-limit exhaustion, not physical-RAM: commit limit = RAM + page file.
The mechanism (and why C: matters): the page file is C:\pagefile.sys, system-managed — it only grows while C: has free disk. With C: near-full the commit limit is pinned (~33.5 GB here) and ~30 GB is already held by the OS + editors + browsers, leaving too little for a cold RN release bundle. Metro compounds it by spawning one worker per CPU core, each reserving a V8 heap.
Fixes, in order:
- Keep build scratch off C: —
TEMP/TMPonD:\DevCache\temp(see the env table). Frees C:, letting the page file grow, and stops builds filling C:. - Cap Metro workers —
metro.config.jshonorsMETRO_MAX_WORKERS(unset → Metro default). Build withMETRO_MAX_WORKERS=1(or2) so the bundle runs in one/two node processes. - Cap native parallelism — single ABI + serialized Gradle:
-PreactNativeArchitectures=arm64-v8a --no-daemon --max-workers=1 CMAKE_BUILD_PARALLEL_LEVEL=1. - Durable fix (needs admin + reboot): put a page file on D:. D: has the free space C: lacks. System → Advanced system settings → Performance → Advanced → Virtual memory → uncheck "automatically manage" → set D: to system-managed (or a fixed 16–24 GB) → reboot. This lifts the commit limit off C:'s free-space hostage entirely. Alternatively move release builds to EAS/CI (cloud, unconstrained) — the recommended long-term path.
Full local release-APK recipe (arm64, sideloadable, debug-signed):
bash
# free memory first: kill stray gradle/metro (java/node < ~15 min old), then:
cd apps/mobile/android
TEMP='D:\DevCache\temp' TMP='D:\DevCache\temp' METRO_MAX_WORKERS=1 CMAKE_BUILD_PARALLEL_LEVEL=1 \
./gradlew assembleRelease -PreactNativeArchitectures=arm64-v8a --no-daemon --max-workers=1
# → android/app/build/outputs/apk/release/app-release.apkNever pipe
gradlewtotail/head— a pipeline's exit code is the last command's, so a failed build reports "success". Redirect to a file or read the exit code directly, and confirm the APK's timestamp is current.
Guarded build script — the only sanctioned local build path
The recipe above is fragile: it depends on the operator's shell having the right env, and setx does not update already-running shells — so a terminal (or an automation/agent shell) opened before the relocation still inherits TEMP/TMP on C: and silently reintroduces the OOM regression. That is exactly how the 2026-07-24 breach recurred.
apps/mobile/scripts/build-android.mjs (run via npm run build:android / build:android:clean) removes the foot-gun by owning the environment instead of trusting the shell:
- Refuses to build with scratch or the Gradle cache on the system drive. It forces the child build's
TEMP/TMP/TMPDIR→D:\DevCache\tempandGRADLE_USER_HOME→ a non-system drive regardless of what the shell inherited (creating the dirs if missing), and hard-fails only if no non-system drive is available. Override the scratch target withQRSETU_BUILD_TMP. A build can no longer leak to C:, even from a stale shell. - Caps memory-parallelism — sets
METRO_MAX_WORKERS=1+CMAKE_BUILD_PARALLEL_LEVEL=1for the child, so the cold release bundle can't overrun the commit limit. - Self-maintains disk — before the build it removes the previous APK (so a failed build can't leave a stale one masquerading as success) and prunes Metro/Haste/Gradle scratch older than 24 h (crashed-build residue; never the warm cache, which would force an expensive cold bundle); it prunes again after the build.
- Runs the unchanged
gradlew assembleRelease -PreactNativeArchitectures=arm64-v8a --no-daemon --max-workers=1(never piped — real exit code), then verifies the APK's mtime is newer than the build start before declaring success, and prints path + size.
bash
cd apps/mobile
npm run build:android # guarded release build (arm64)
npm run build:android:clean # also wipes stale .cxx + android/{build,app/build,.gradle} firstThis script — not the raw
gradlewline — is the sanctioned local build path going forward. The raw recipe above is retained only to explain the mechanism the script automates.expo-build-propertieswas evaluated for pinning Gradle memory/ABI durably across prebuilds but not adopted: it cannot setreactNativeArchitectures(the ABI cap lives on the script's-Pflag), and the currentgradle.propertiesheap default already matches Expo's, so a new build-time dependency would add surface without moving the OOM needle.
Disk hygiene — npm run check:disk
Relocating caches by environment variable was necessary but incomplete, and nothing verified it. On 2026-07-27 C: was back to 4.2 GB free — yet nothing had regressed: TEMP/TMP, GRADLE_USER_HOME, ANDROID_HOME and PLAYWRIGHT_BROWSERS_PATH were all still on D:, and the Android AVDs were on D: behind the .android junction. Three different things had happened instead (QRS-204):
- Docker Desktop's WSL2 disk — 15.1 GB, and structurally out of reach of the whole strategy. Every other relocation is an env var; Docker's data folder is a GUI setting, so an env-var strategy has a blind spot shaped exactly like Docker. Compounding it, a
.vhdxnever shrinks:docker system prunefrees space inside the VM while the host file stays at its high-water mark. It only ever grows. - Caches never in scope — npm's cache (
npm_config_cachewas unset), tool runtimes under~/.cache. - The guard was bypassed. An agent ran
gradlew.bat assembleReleasedirectly instead ofnpm run build:android, which is precisely the stale-shell case the guarded script exists to prevent. A guard that can be walked around is a convention, not a control — and the walk-around is now demonstrated, not hypothetical.
Measurement trap, worth knowing before you audit this yourself.
Get-ChildItem -Recursefollows junctions. The first pass billed ~8 GB ofD:\Androidcontent to C: because.androidandAppData\Local\Androidare junctions to D:. Resolve the target (dir /a:l, orfs.realpathSync) before attributing size to a drive; the hygiene script skips reparse points for this reason.
npm run check:disk (tools/check-disk-hygiene.js) asserts the invariants instead of trusting the agreement:
- every relocated env var resolves — through junctions — off the system drive, and flags any that are unset (an unset var silently falls back to a C: default, which is how npm's cache got there);
- the repo itself is on the work drive (the standard covers source, not only caches);
- both drives are above a 15 GB floor (see the next section for why the work drive is not exempt);
- the scheduled sweep is actually registered — an uninstalled automation looks identical to a working one until a drive fills;
- the caches no env var can move (Docker, npm,
.expo) are printed with their sizes and their specific fix, so they stay visible rather than creeping back.
It runs standalone and is also called (advisory, non-fatal) from the guarded build's preflight, so a doomed build fails in the first second with a clear message rather than ten minutes in with 0xC0000409.
On macOS/Linux it reports and exits 0 — the Mac builds iOS from this same repo and has one volume, so there is no rule to apply and inventing one would just add a false gate.
The standard: development never touches the system drive
Non-negotiable (QRS-205, codified in CLAUDE.md). No source, build artifacts, caches, temp/scratch, dependencies, SDKs, VM disks or generated output on C:. D: is the dedicated development volume. C: holds the OS and regenerable browser/editor cache, nothing else.
| Concern | Location |
|---|---|
| Source / projects | D:\WorkSpace\DevArea\<project> (short path — MAX_PATH) |
| Shared tool caches | D:\DevCache\{gradle,npm,playwright,temp} |
| Android SDK + AVDs | D:\WorkSpace\DevArea\AppBuilding\AndroidSdk (+ the .android junction) |
| Docker data disk | D:\DevCache\DockerDesktopWSL (GUI setting, not an env var) |
| Cleanup log | D:\DevCache\logs\dev-cleanup.log |
Relocation alone is not a solution — it moves the wall
This is the correction QRS-205 makes to QRS-204. Relocating growth off C: is necessary and it worked; what it does not do is bound the growth. Dev artifacts are monotonic by nature — every release build writes a fresh ~49 MB APK, every OOM-killed Gradle daemon leaves a multi-MB replay_pid*.log, every Metro run seeds another scratch directory, and Gradle's build cache has no bound at all. Within days of the relocation the measured picture was:
| Drive | Free | |
|---|---|---|
| C: | 20.2 GB | fixed — Docker moved off it |
| D: | 21.8 GB | now the tighter drive, and it carries D:\WorkSpace (41.4 GB) + D:\DevCache (11.7 GB) + D:\Android (8.1 GB) |
A standard that only says "not C:" therefore reaches the same wall on a different letter. The floor and the retention policy below apply to both drives for that reason.
Retention policy
tools/clean-dev-artifacts.js is the policy engine. Dry-run is the default — a destructive tool whose default is destruction gets run by accident exactly once.
bash
npm run clean:dev # report what WOULD be freed (safe, default)
npm run clean:dev:apply # delete it
npm run clean:dev:deep # also the expensive-to-rebuild tierSafe tier — runs unattended, safe mid-session:
| Class | Keep | Why it is safe |
|---|---|---|
Build scratch (metro-*, haste-map-*, expo-*, …) | 3 days | Regenerated by the next bundle |
JVM crash dumps (hs_err_pid*, replay_pid*) | 0 days | Diagnostic value expires with the session |
| Superseded APK/AAB outputs | newest per variant, then 7 days | Only the newest is ever sideloaded |
Playwright test-results / reports | 7 days | Per-run; only the last is ever opened |
| Expo web/metro cache | 14 days | Pure cache. apps/mobile/dist is never touched — the web preview serves it |
| Gradle daemon logs | 7 days | One per daemon, forever, in a directory nothing prunes |
| Claude Code scratchpads | 14 days | Session temp only. Never ~/.claude (memory + transcripts) |
| Xcode DerivedData (macOS) | 14 days | The Mac's equivalent runaway |
Deep tier (--deep) — correct but costs a rebuild, so it is not automatic:
| Class | Keep | Cost of removing |
|---|---|---|
| Gradle build-cache entries (1400+ here) | 30 days | One slower build |
Superseded Gradle distributions (wrapper/dists) | 60 days | Re-download on wrapper change |
Native build dirs (android/{build,app/build,.gradle}, .cxx) | 21 days | ~20 min cold rebuild |
Two rules that are load-bearing, not incidental. (1) The sweeper never follows reparse points —
.androidandAppData\Local\Androidare junctions to D:, and a recursive delete that follows them destroys the target, not the link. (2) It deliberately does not age outcaches/<version>directories: a directory's mtime does not update when Gradle writes into its subdirectories, so an age test there can flag the version currently in use and force a multi-GB re-resolve.wrapper/distsis unambiguous; the version caches are not.
Automation — three triggers, escalation on pressure
bash
npm run setup:disk-automation # install (no admin)
powershell -File tools/setup-disk-automation.ps1 -Remove # uninstall- Scheduled task
QRSetu-DevDiskCleanup— daily 02:00 and 15 min after logon (so a machine that is off at 02:00 still gets swept),StartWhenAvailablefor catch-up. Runs as the current user with no administrator rights, deliberately: an automation that needs an elevated prompt gets skipped once and then forever. - After every guarded Android build — a build is the moment artifacts are created, so it is the moment worth sweeping at. Best-effort; it never fails the build.
- Escalation on pressure, not on a calendar (
--auto-escalate, used by the scheduled task) — the deep tier runs only when a drive is below the 15 GB floor. A fixed weekly deep sweep either throws away warm caches for nothing or misses the week the drive actually fills; tying it to measured free space makes the schedule self-adjusting.
npm run check:disk verifies the task is registered, so a machine where the automation was never installed — or was removed — fails the check rather than looking healthy.
Gotcha for anyone editing
tools/setup-disk-automation.ps1: keep it ASCII-only. Windows PowerShell 5.1 reads a BOM-less UTF-8.ps1as CP1252, and an em dash (E2 80 94) decodes with byte0x94= U+201D, a smart closing quote — which PS accepts as a string delimiter. One em dash in a comment producedThe string is missing the terminatorpointing at a line 50 lines away.
Troubleshooting quick reference
| Symptom | Cause | Fix |
|---|---|---|
ninja: … Filename longer than 260 characters | Project and/or Gradle-home path too deep | Repo on short D: path + GRADLE_USER_HOME=D:\DevCache\gradle; delete stale .cxx; rebuild |
| Same error for one package only | That package's .cxx baked an old long Gradle-home | Delete all .cxx + android/{build,app/build,.gradle}; rebuild |
TreeFS: Failed to make parent directory entry for …legacy… | Metro watching the whole monorepo root | Narrow watchFolders to packages + node_modules |
| C: at ~0 bytes; tooling can't write temp files | Dev caches accumulated on C: | Run qrsetu-disk-cleanup.ps1; then qrsetu-dev-relocate.ps1 to move caches to D: |
| D: filling up even though nothing is on C: | Relocation bounds where artifacts go, not how many | npm run clean:dev → clean:dev:apply → clean:dev:deep; see retention |
| Disk fills again weeks after a cleanup | The scheduled sweep was never installed (or was removed) | npm run setup:disk-automation; npm run check:disk now fails when it is missing |
check:disk says an env var is unset that you already setx-ed | setx does not update already-running processes | Open a new terminal (or reboot) — the value is in the user registry |
Editing setup-disk-automation.ps1 → The string is missing the terminator | A non-ASCII char (em dash) in a BOM-less UTF-8 .ps1 decodes as a smart quote under CP1252 | Keep that file ASCII-only |
| C: fills during builds even though caches are on D: | TEMP/TMP still default to C:\Users\…\AppData\Local\Temp — Metro/Hermes/Gradle scratch lands on C: | Set TEMP/TMP → D:\DevCache\temp (env table); open a new terminal |
Release build OOMs: hs_err_pid*.log / bundle exit value -1073740791/-2147483645 (0xC0000409) | Commit-limit exhaustion — C:-only page file capped by a full C:, worsened by Metro's per-core workers | TEMP/TMP on D: + METRO_MAX_WORKERS=1 + serialized single-ABI build; durable = page file on D: (admin+reboot) or EAS/CI — see Memory / commit limit |
| Build leaked to C: again despite the env fix | A shell (or agent) opened before setx still inherits TEMP/TMP=C: | Build via npm run build:android — the guarded script forces scratch onto D: regardless of the inherited shell env |
gradlew build "succeeded" but the APK is stale/old-dated | The command was piped (` | tail`), so the exit code was the pipe's, not Gradle's |
APK installs on the emulator then dies instantly: SoLoaderDSONotFoundError: couldn't find DSO to load: libreactnative.so | ABI mismatch, not a code fault. The shipped local build is arm64-only (commit limit + size budget), and the standard emulator is x86_64 — the log shows Native lib dir: …/lib/arm64 beside base.apk!/lib/x86_64 | npm run build:android:emulator (= --abi=x86_64). Use a physical arm64 device for anything you intend to ship; the x86_64 APK is a verification artifact only |
expo run:android says Port 8081 is being used and skips the dev server | An orphaned Metro from a prior session | Kill the node PID on 8081 (Get-NetTCPConnection -LocalPort 8081), start Metro from the current repo |
Maestro assertVisible "QRSETU" fails but the screen shows QRSETU seconds later | Dev-client bundle-load race | Use extendedWaitUntil with a 30s timeout |
| Memory/history "empty" after moving the repo | New project path → new .claude/projects slug | Copy the old slug folder to the new slug name (see mapping above) |
Replicating on a new machine or new project
- New project: create it under
D:\WorkSpace\DevArea\<name>(short path, off OneDrive) from day one. Caches are already shared via theD:\DevCacheenv vars — nothing per-project to set. - New machine: install the toolchain (see prerequisites), run
qrsetu-dev-relocate.ps1to establishD:\DevCache+ env vars, put the Android SDK on D:, then clone projects underD:\WorkSpace\DevArea.