paranco
paranco is a small macOS application whose only job is to hold Full Disk Access and copy files out of a folder macOS protects, along routes you write down, into an ordinary folder any program can read. It exists because macOS keeps some folders, the Voice Memos library among them, closed to any process without that permission, and because granting it to a script or an interpreter grants it to every package installed beside that runtime as well. paranco holds the permission itself and copies files one way, from one allowlisted source to one destination you choose, so whatever reads the destination reads an ordinary folder and is granted nothing.
What it does not do
Section titled “What it does not do”- It runs on macOS only. The permission and the protected folders it reads are macOS’s.
- It reads from one source today, the Voice Memos library, from a list compiled into the binary. Adding a source means editing the source file and rebuilding.
- It carries no Developer ID, so its bundle has an ad-hoc signature. Every
./build.shproduces a binary the privacy database treats as new, so Full Disk Access has to be granted to it again after each rebuild. - It offers no notarised download. It is built from the repository.
- It writes nothing back to the source: no marker, no ledger, nothing.
- The command line cannot install the launchd agent. The agent has to run the same bundle that was granted access, so only the window, which is that bundle, can install it.
Install
Section titled “Install”git clone https://github.com/nerln/parancocd paranco./build.shThat leaves Paranco.app in the repository folder, built for release; ./build.sh debug
builds the debug configuration instead. The first build also generates the icon through
make-icon.sh, which needs swiftc and iconutil. Then:
- Add
Paranco.appto Full Disk Access in System Settings > Privacy & Security. open Paranco.app.- Add a route: a source from the list and a destination folder, for example
~/Recordings. - Install the agent from the window.
paranco sources # the folders this build may readparanco routes # the routes on diskparanco add <source-id> <folder> [--name N] [--ext a,b]paranco remove <name> # removes every route with that nameparanco check [<folder>] # readable, refused or missingparanco lift [<name>] # run one route, or all of them, onceparanco watch [seconds] # run every route every N seconds (default 300)paranco agent status|remove # the launchd agentThe binary can also be produced with swift build -c release --product paranco, which leaves
it at .build/release/paranco. paranco add voice-memos ~/Recordings makes a route from
the command line. Run from a terminal, the CLI carries the terminal’s own permission, not
the application’s, so paranco check on a protected folder still says refused even after
Paranco.app has been granted access; use the application or the agent for routes out of
protected folders, and the command line for editing the route list or checking folders the
terminal can already read.
How it works
Section titled “How it works”A route names one source by identifier, never by path, and one destination. Running a route once is a lift: a file with the same name and size as one already at the destination is left alone; a different size means the copy is stale and is copied again; a file whose size changes between two checks two seconds apart is still being written and is skipped until the next run. The destination is the only bookkeeping there is.
A launchd agent runs every enabled route on a timer, every five minutes by default, and
once when it is loaded, at install and at every login. It runs the application bundle’s
own executable with --agent, the same binary the window uses, because Full Disk Access
is granted to that one bundle and has to be spent by it. It logs a line only when a route
is refused or something is copied or fails, to
~/Library/Application Support/paranco/agent.log.
Routes live in ~/Library/Application Support/paranco/routes.json, mode 0600 inside a
0700 folder, written through a rename so a reader never sees a half-written file.
paranco on GitHub, MIT licensed.