Off-main, non-privileged
The workhorse. Runs everyday reads and writes on a background actor, off the main thread — preferring array-arguments with no shell and no quoting for anything containing your input.
The safety model
Catalyst's whole job is to run shell commands for you — so the execution layer is the most carefully guarded part of the app. Here's exactly how it protects you.
Three execution tiers
Every shell interaction is routed through exactly one of three tiers — each with its own guarantees.
The workhorse. Runs everyday reads and writes on a background actor, off the main thread — preferring array-arguments with no shell and no quoting for anything containing your input.
The most sensitive path. A native password dialog pipes to sudo in-memory — the password is never written to disk. Every destructive delete here is allowlist-gated first.
When you must watch or respond — chiefly the Homebrew installer — the command opens in your visible Terminal. Newlines and control characters are rejected as an injection guard.
Consent, not surprises
Modern system Pythons mark themselves “externally managed” (PEP 668) and refuse writes without a flag that can overwrite what the OS owns. Rather than scatter that flag around, Catalyst exposes a single, consented setting.
— none — The safe default. Respects system integrity; a risky install into system Python is simply refused. Nothing bad happens. --break-system-packages --user Installs into your personal user site instead of the system directory. Safer reach, still your call. --break-system-packages Writes directly into the OS-managed Python. Highest reach, highest risk — and always your explicit choice. Turning an override on requires an explicit confirmation that spells out the consequence. Reverting to Protected is safe and takes effect immediately — and while any override is active, a red integrity indicator stays visible in the app. Virtual environments are never externally managed, so they're never flagged and never gated.
The standing guarantees
Every outcome is decided on the process exit code — never by pattern-matching stdout, which lies.
Recoverable removal is preferred over permanent deletion, behind a confirmation dialog showing the count and total size.
Only caches, Cellar, virtualenv, and log directories are ever deletable. System, Library, and your Documents / Desktop / Downloads are blocked outright.
These paths are hard-skipped everywhere, in every scan and every delete.
A folder named node_modules or venv is only flagged as cruft when a sibling project marker confirms it — so an app's bundled files are never mistaken for junk.
The port-process finder uses a strict allowlist of dev keywords and a blocklist of critical processes, so it never offers to end something dangerous.
SSH tooling shows and copies public keys only. Private keys are never displayed, copied, or exported.
The sudo password lives only in memory and stdin — never embedded in a script or a temp file.