Spawn child processes that disclaim the parent's macOS TCC responsibility, so each child is judged under its own code-signing identity.
On macOS, a process spawned the ordinary way inherits its parent's responsibility: the system attributes the child's privacy-permission checks (Accessibility, Input Monitoring, Full Disk Access, …) to the parent app's identity, not the child's. For a helper with its own bundle identity and its own granted permissions — a menu-bar agent, a login item, an updater — that's the wrong identity: the child's permissions look missing because they were granted to it, not to whoever launched it.
disclaim spawns the child with the private libSystem
responsibility_spawnattrs_setdisclaim attribute, so macOS evaluates it against its
own code signature — the same identity it gets when launchd starts it directly. This
is the technique browsers use for their helper processes.
The API mirrors the relevant subset of std::process::Command:
let mut child = disclaim::Command::new("/Applications/My.app/Contents/Helpers/agent")
.arg("--background")
.env("RUST_LOG", "info")
.spawn()?;
println!("spawned agent pid {}", child.id());Command supports arg/args, env/envs/env_remove/env_clear, and
spawn() -> io::Result<Child>; Child exposes id() and wait(). stdio is
inherited.
The crate compiles and runs everywhere, so cross-platform code needs no cfg.
Disclaiming is a macOS concept; on every other platform Command is a thin
pass-through to std::process::Command (there is no responsibility to disclaim).
This crate exists for the disclaim case, typically a detached helper. It does not
expose stdio redirection (pipes/null) — for a fully-managed child with redirected
I/O, std::process::Command remains the right tool.
MIT OR Apache-2.0.