中文 | English
A Windows symbolic-link manager. TempDirector redirects the cache and temp directories
of desktop applications to a RAM disk with directory junctions, then rebuilds that
directory tree on the RAM disk at every logon — cutting SSD writes while hot cache I/O
stays in memory. Junctions don't need SeCreateSymbolicLinkPrivilege, so the normal case
runs with zero UAC prompts; elevation happens on demand only when a source path sits under
Program Files / ProgramData or another protected location.
The UI speaks 中文 / English — switch from the dropdown at the top right (follows the system language on first launch; the choice is remembered).
Main window:
- Rule list: status badges (✅ OK /
⚠️ broken link or empty target / ❌ not linked / 🚫 foreign reparse point), source → target paths side by side, wanted/boot-rebuild flags; search, category filter and "needs attention only" narrow the list; checked rows drive batch actions (apply / restore / enable / disable / relink / delete). - Detail panel: full info per rule (source template and expanded path, link type, warnings, last applied time and size) plus single-rule actions.
- Add / edit rule: live validation (path expansion, protected location, target state), system folder picker for the source, and a presets dropdown with cache-dir templates for common apps.
- Also: batch progress overlay, activity log, settings (autostart / scheduled cleaning / target roots), and a tray menu.
Prebuilt binaries (NSIS installer + portable zip) are on the Releases page.
scripts\cargo.cmd build -p td-gui --release # output: target\release\tempdirector-gui.exeThe interface is static files embedded into the exe — no npm, no bundler. To preview it
without Tauri, open crates/td-gui/ui/index.html?mock=1 in a browser (add &progress=1 /
&modal=1 / &settings=1 / &ops=1 for the overlays and dialogs).
Register a per-user logon task (no admin rights needed) to rebuild the RAM-disk tree automatically at every logon:
tempdirector autostart enable # afterwards every logon rebuilds automatically
tempdirector autostart status # inspect: registered? running what?
tempdirector autostart run # trigger one run now, to verify
tempdirector autostart disable # removeThe task action is <GUI path> boot-rebuild; portable setups also get --data-dir baked
into the task, because scheduled tasks don't inherit your shell's environment variables.
Failures are never silent: the report is stored in the database and written to
logs/boot-rebuild.log, and the UI shows a banner on next open.
Directory junctions themselves need no privileges, but writing caches under
C:\Program Files / C:\ProgramData / C:\Windows needs admin rights. Such rules are
marked in the UI, and a batch apply offers to elevate through a one-shot worker: a job
file containing rule ids only — no paths, required to live inside <data dir>\jobs\,
relaunching itself via ShellExecuteExW(runas) and re-running the exact same safety checks
as the GUI/CLI (blacklist, self-loop, occupancy detection). A job placed anywhere else is
rejected with exit code 1.
# 1) Build (the script fills in the MSVC + Rust toolchain environment itself)
scripts\cargo.cmd build --release
# output: target\release\tempdirector.exe
# 2) Register the RAM disk as a target root
tempdirector roots add RAMDisk "R:"
# 3) Add a rule (source paths support %VAR% templates, expanded per user on import)
tempdirector rules add "Chrome cache" `
"%LOCALAPPDATA%\Google\Chrome\User Data\Default\Cache" `
"browsers\chrome-cache" --category browser --enable
# 4) Inspect first: health check + occupancy + dry run
tempdirector status --all
tempdirector locks "<rule id of the Chrome cache rule>"
tempdirector apply --all --dry-run
# 5) Run for real (checks occupancy first; aborts without touching anything when occupied)
tempdirector apply --all
# 6) Boot rebuild
tempdirector boot-rebuild
# 7) Undo by restoring
tempdirector restore --allThe data directory defaults to
%PROGRAMDATA%\TempDirector. Override it with theTEMPDIRECTOR_DATA_DIRenvironment variable or the--data-dirargument.
overview
doctor environment self-check: data dir, link capability, target volumes, rule states, pending fixes
version
target roots (RAM disk)
roots list
roots add <name> <path> [--timeout ms] [--hdd]
roots rm <id>
volume <R: or R:\Dir> [--timeout ms] probe / wait for the volume to be ready
rules
rules list [--enabled] [--category cat] [--search term] [--json]
rules add <name> <source template> <target subpath> [--root id] [--category cat]
[--link-type junction|symlink_dir] [--enable] [--no-boot] [--notes note]
rules rm <id...>
rules enable|disable <id...|--all>
inspection and operations
status [--enabled|--all] [--category cat] [--search term] [--no-persist] [--json]
locks <rule id|directory path> [--json] check occupancy and name the process holding it
apply <id...|--all> [--dry-run] [--merge] [--sha256] [--skip-lock-check]
restore <id...|--all> [--dry-run] [--sha256]
relink <id> rebuild the link only (data untouched)
boot rebuild
boot-rebuild [--json]
autostart status whether the "rebuild at logon" task is registered
autostart enable [--exe <path>] register (per-user, no admin rights needed)
autostart disable
autostart run trigger one run manually, to verify
elevation worker (normally not needed manually)
elevated <job.json> run a job as administrator (rule ids only, no paths)
config migration
export <file.json>
import <file.json> [--dry-run] [--ram-root R:]
audit
events [--limit N]
ops [--limit N] operation history (including pending fixes)
Category values: browser / design / dev / system / media / office / game / other
- Never delete source content before the data check passes. Cross-volume moves always go enumerate → copy → verify (file count + bytes, optional SHA-256) → delete source.
- Deleting a link removes only the link — never recurse into a reparse point; doing so would wipe the real data on the RAM disk.
- Never touch what you don't understand. Foreign reparse points (OneDrive placeholders,
AppExecLink, mount points) are reported, not processed; when a software update replaces a link with a real directory, the boot guardian only warns and leaves it to a human.
See docs/ARCHITECTURE.md (Chinese) for 20+ edge cases.
crates/
td-core/ engine library (no GUI dependencies)
src/util.rs path normalization, \\?\ long paths, env var expansion, volume detection
src/safety.rs rule blacklist (volume roots / system dirs / self-loops)
src/link/ reparse point identification, Junction create/remove
src/fsops/ occupancy detection (+Restart Manager), safe moving, merging, verification
src/engine.rs orchestration: decision tree → move → link → rollback → persist
src/store/ SQLite schema / migrations / DAO / operation history
src/boot/ waiting for volume readiness, batch rebuild at boot, DACL re-apply
src/autostart.rs logon task register / query / remove (schtasks + task XML)
src/elevate.rs elevation state detection, launching a process as admin and waiting
src/worker.rs the elevation worker's job protocol and executor (the trust anchor)
src/portable.rs config import / export
presets.json built-in preset list (cache dirs of common apps, embedded at compile time)
td-cli/ tempdirector.exe (management / elevation worker / boot rebuild)
td-gui/ tempdirector-gui.exe (Tauri 2 UI)
src/api.rs business layer: takes &Store, emits serde structs (unit-testable without a window)
src/commands.rs thin #[tauri::command] forwarding + progress events + folder dialog
src/submode.rs headless submodes: boot-rebuild / elevated (intercepted before Tauri)
src/lib.rs entry: submodes → in-memory store fallback → mark_stale_ops → register commands
src/tray.rs tray menu (show window / rebuild now / quit)
ui/ index.html / style.css / app.js (static files, embedded at compile time)
docs/ARCHITECTURE.md architecture and edge cases (Chinese)
docs/screenshots/ UI screenshots (one Chinese set + one English set: main-window / add-rule / settings / progress)
scripts/cargo.cmd dev build wrapper (fills in MSVC + Rust environment)
scripts/make_icon.py app icon generation (pure PIL, re-runnable)
scripts/take-screens.cjs UI screenshot generation (mock data + headless browser, Chinese and English sets, re-runnable)
rebuild.bat one-click full rebuild (clean + release) and desktop shortcut refresh
The "Add rule" dialog offers a preset dropdown with cache-directory templates for common apps, merged from two layers:
- Built-in —
crates/td-core/presets.json, embedded at compile time (editing it requires a rebuild). - User-external —
presets.jsonin the data directory (%PROGRAMDATA%\TempDirector, or theTEMPDIRECTOR_DATA_DIRdirectory in portable mode). Same format, no rebuild:
[
{
"name": "My app cache",
"category": "dev",
"source_template": "%LOCALAPPDATA%\\MyApp\\Cache",
"target_subpath": "dev\\myapp-cache",
"note": "optional hint"
}
]A user entry whose source_template matches a built-in one (case-insensitive)
overrides it; the rest are appended. Only entries whose source directory actually
exists on this machine are shown. The chain is covered by the integration test
crates/td-gui/tests/preset_override.rs.
scripts\cargo.cmd check --workspace --all-targets
scripts\cargo.cmd test --workspace # 104 unit tests (td-core 88 + td-gui 16)
scripts\cargo.cmd build --release # both exes at once
rebuild.bat # full rebuild: clean + release + refresh the desktop shortcut
python scripts\make_icon.py # regenerate the app iconscripts/cargo.cmd wraps cargo to fill in the MSVC + Rust toolchain environment
(vcvars64.bat, PATH, RUSTUP_HOME / CARGO_HOME); keep it pure ASCII — cmd.exe
reads batch files with an OEM code page. rebuild.bat also refreshes the desktop shortcut
after a clean rebuild, since cargo clean wipes target\ and any earlier .lnk would
dangle.
Retaking the UI screenshots for this README (mock data + headless browser, no Tauri):
# requires playwright (npm i playwright); uses the Edge / Chrome already installed
node scripts\take-screens.cjs --lang en # English set
node scripts\take-screens.cjs --lang zh # Chinese set
node scripts\take-screens.cjs --lang en --check # scan for missing translations onlyPin the whole family together — tauri 2.11.5 / tauri-build 2.6.3 / tauri-codegen 2.6.3 / tauri-macros 2.6.3 / tauri-plugin 2.6.3 / tauri-utils 2.9.3 / tauri-runtime 2.11.3 / tauri-runtime-wry 2.11.4 / wry 0.55.1. The transitive crates are range dependencies, so
bumping only the main crate breaks the build with errors like
no variant named UnexpectedMenuKind; move the whole set with cargo update -p <crate> --precise <ver>.



