LocalCode Studio's core promise is that your code doesn't leave your machine unless you explicitly configure a remote provider AND enable code upload. Everything else here is defence in depth on top of that promise.
| Layer | Trust | Notes |
|---|---|---|
| The user | Fully trusted | This is a single-user desktop app. |
| The React UI | Trusted (in-process) | Runs in the Tauri webview. |
| The Tauri IPC boundary | Enforced | Only #[tauri::command] fns are callable. |
| The Rust core | Enforced | Every filesystem/shell op runs the policy first. |
| The LLM | Untrusted | Treated as a stranger who sends suggestions. Never writes files directly, never runs commands directly. |
| Any remote provider | Untrusted + no code by default | Must be explicitly enabled + allow_code_upload: true. |
Every path crossing the Tauri boundary is canonicalised (Path::canonicalize) and then checked:
- Path must be inside
allowed_roots. Default is the currently open workspace. No sneaking../../../etc/passwd. - Path must not match any glob in
blocked_paths. Defaults block~/.ssh,~/.aws,~/.gcp,~/.kube,/etc. - Files over the configured size limit (default 5 MB for
read_file) returnfile_too_largeinstead of reading. - Binary detection — first 8 KiB is scanned for
\0. Binaries are refused (not silently returned as garbage UTF-8).
Overriding defaults is done in localcode.config.yaml. Any override is a conscious act; the app's built-in defaults are aimed at safe-by-default.
Every command hits the policy before spawning:
- Blocked — hard fail. Examples:
rm -rf /,sudo rm,mkfs,dd if=,chmod -R 777 /, fork bomb. No approval flow can override. - Needs confirmation — the UI shows a yellow banner requiring click-through. Examples:
git push,git reset --hard,npm publish,pnpm publish,pip publish,twine upload,docker system prune,kubectl apply,terraform apply,gcloud,aws. - Allowed — anything else. Runs with a 60-second default timeout, streams stdout+stderr, captures exit code.
Comparison is whitespace-normalised: "git push" still matches "git push".
Every AI-proposed change goes through:
- Validate. File paths must resolve;
modifypatches must have a body; target files must exist for modify/delete. - Snapshot. Original content saved to
.localcode/snapshots/<uuid>/before touching. - Diff apply. Uses
diffy(line-ending aware, refuses ambiguous hunks). - Atomic write. Content is written to a temp sibling then renamed — no half-written files if the process dies mid-write.
- Per-file rollback. If any file in a multi-file patch fails, all previously touched files are restored from the snapshot before returning an error.
- Async execution via tokio.
kill_on_drop(true)guarantees the child dies when the request is cancelled. - Every command runs with a bounded timeout. Default 60s; agent tools override to 120s for tests; user manual runs can go up to 600s.
- stdout+stderr are streamed line-by-line, so a runaway process doesn't OOM the app with buffered output.
- The LLM is not trusted to know what's safe. It suggests; the user (or the agent framework with a bounded iteration budget) decides what to apply.
- Every patch proposal is validated against the same schema (
PatchProposalSchemainpackages/shared). A malformed patch never reaches the engine. - Tool inputs are validated against Zod schemas before tool execution.
- Secret redaction runs on any text sent to a remote provider (never on local Ollama, since the data isn't leaving the machine anyway).
- A malicious user with terminal access. LocalCode Studio can't stop you from running
rm -rf ~in your own terminal. It just prevents its own agent from doing so. - Someone copying
.localcode/snapshotsor your source folder. That's the same threat model as any repo on your laptop — enable FileVault / BitLocker / LUKS if you care. - A malicious dependency in your own repo. LocalCode Studio operates on the files you have. If your
package.jsonhas a malicious postinstall, runningpnpm installfrom our terminal panel will run it — same as any other terminal.
Open a private security advisory on GitHub. Don't publish exploit paths publicly before we've had a chance to fix them. In practice we aim for a 7-day acknowledgement and 30 days to fix for high-severity.