Splice Shell runs a Windows ConPTY process and manages clipboard images in %TEMP%. This document describes how the application protects the host machine from resource leaks.
| Problem | Symptom | Fix |
|---|---|---|
| Blocking Tauri commands | UI thread freeze, PC unresponsive | All Tauri commands marked async fn |
| PTY output flooding | CPU spike, IPC saturation | 16 ms output throttle buffer |
| Clipboard PNG accumulation | Unbounded disk usage in %TEMP% |
Age-based sweeper + lifecycle hooks |
| Orphan PTY processes on crash | Ghost processes after app close | Windows Job objects + tree walk fallback |
Every Tauri backend command runs on a background worker thread. None execute on the main UI thread.
// All commands are declared as async fn.
// Tauri schedules them on its async runtime.
#[tauri::command]
async fn pty_spawn(...) -> Result<...> { ... }Why it matters: a blocking call on the main thread (e.g. ConPTY creation, pipe write) would freeze the WebView2 event loop and make the app appear hung.
The ConPTY reader pushes output into an mpsc channel. A background flusher wakes every 16 ms, drains the channel, and emits one batched IPC event to the frontend.
ConPTY reader → mpsc::channel → flusher (16 ms) → tauri::emit → xterm.js
At 60 FPS the budget per frame is ~16 ms, so this groups high-frequency output into at most one IPC call per frame. CPU and JSON serialization overhead drop significantly under heavy output (e.g. cargo build logs).
Clipboard previews are written to %TEMP%\splice-shell\clipboard\splice-clipboard-*.png.
| Event | Action |
|---|---|
| App startup | Delete entire %TEMP%\splice-shell\clipboard\ directory |
| PTY session close | Delete the image for that session immediately |
| App shutdown | Delete entire %TEMP%\splice-shell\clipboard\ directory |
| Background sweep | Delete any .png older than 5 minutes |
Files are matched by metadata.modified() time (falling back to metadata.created() on filesystems that do not track modification time). Access errors (locked files, permission denied) are ignored silently.
When a PTY session is closed, Splice Shell terminates the full process tree — not just the immediate child — to prevent orphan processes.
Primary path — Windows Job object:
The ConPTY process is assigned to a Job object with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE. When the Job handle is dropped, Windows terminates every process in the job.
The process is spawned with CREATE_BREAKAWAY_FROM_JOB to allow nested jobs (required when the parent process already owns a job, for example inside some CI environments or IDE wrappers).
Fallback path — process tree walk:
If job assignment fails (e.g. nested job limit reached on older Windows versions), Splice Shell walks the process tree from the leaf processes upward and terminates each one with TerminateProcess. This prevents orphans even when Job objects are unavailable.
All safety behaviours are covered by the test suite:
cargo test --workspace # 74 tests, 0 failures
cargo clippy --workspace --all-targets -- -D warnings # 0 warningsKey test names:
test_flusher_aggregates_high_frequency_outputtest_flusher_idle_flushes_immediatelytest_startup_cleanup_deletes_all_temp_filestest_session_close_deletes_specific_image_immediatelytest_shutdown_cleanup_deletes_temp_directorytest_fallback_tree_termination_when_job_is_nonelive_pty_session_kills_grandchild_process_tree_on_closepty_spawn_close_cycles_do_not_leak_process_handles