macbackup: operational guide and backup project
Document updated on November 2, 2026.
Version 0.9.5. Available commands include init, check, explain, layout, preview --local, check --remote, preview --target, run --target, status, restore-icon, forget, versions, single-file restore, and verify for the current copy. Remote operations use rclone for transfers, encryption, and archiving older versions. Destinations are disabled in the initial setup. Whole-tree restoration and disk mounting are not yet available. restore-icon retrieves an icon from a local file.
Native Zsh completion of commands, options and paths is also available, integrated into dotfiles.
The transfer was tested with real rclone commands on local remotes and synthetic crypts, and then on Google Drive with only dummy files in separate test folders. On Google, a readable copy, recovery of the encrypted file, exclusion of the unauthorized file and recovery of an encrypted historical version were successful. The first real Google backup was started and then stopped at the user's request: it is not complete. Proton is not configured yet. The immediately following check revealed 216 plain files for 429,002,179 bytes and no files in the private area. status did not record a completed run. The sections indicated as future are not features already present.
Starting the local version
All commands require Python 3.11 or later, with no additional packages. Python 3.14.0 in /opt/homebrew/bin/python3 has been verified on the Mac. The executable file uses python3 available in the PATH; future automations will require explicit configuration of the interpreter.
macbackup --version
macbackup --help
macbackup initinit creates four lists and settings.toml: the three path lists are empty except for commented examples, while explicit-only contains .env and .env.*; both destinations are disabled. It does not overwrite an existing configuration, even partial. The new files have permissions 600 and the new directory 700. If the initialization has already been performed, there is no need to repeat it: the update to version 0.2 only adds the settings.toml if absent, without changing the lists.
To edit lists you use your editor, so:
macbackup check
macbackup explain "/Users/kevinmuka/Desktop/progetto/.env"
macbackup layout # nella cartella del progetto
macbackup layout "/Users/kevinmuka/Desktop/progetto"
macbackup preview --localcheck scans selected sources using names and metadata; does not read the contents of the files to be saved. Instead, it reads the contents of the four configuration lists. explain checks only one path, even hypothetical or currently absent; does not certify that the entire selection is valid. For example, if no directories are yet included, a .env may simply be "not selected".
preview --local shows local classifications and reasons for rejections. It doesn't compare to the cloud or estimate how many bytes you'll need to transfer. If it finds errors, it does not present the partial scan as a usable plan. For excluded directories, show an entry for the subtree without visiting all of its files: the number of skipped entries is not an exact count of all excluded files.
layout uses the current directory if you don't pass it a path; for example, inside ~/Desktop/project it may show PRIVATE /Users/kevinmuka/Desktop/project/.git. Takes a local directory selected in plain and shows the parts within it that are routed in private. For each it shows only the root of the subtree, the number of selected elements and the local bytes; does not list the names of each private file. With --json it adds the logical path private/current/... for use in other tools. Performs a full local scan, without access to the cloud. It does not show old copies in the clear or in the history, nor empty private directories, which the backup does not store as separate objects. If the scan finds errors, it does not show a partial result as valid.
The four read commands support --json. --config-dir replaces ~/.config/macbackup for the four lists and settings.toml; it does not change the data sources, the state file under ~/.local/state/macbackup, or the rclone credential configuration. The alternative directory is specified before the subcommand:
macbackup --config-dir "/percorso/assoluto/configurazione" check --jsonExit codes: 0 for completing the requested check, 1 for detected source errors or conflicts, 2 for syntax, configuration, or usage errors. A control with empty lists returns 0 with a warning: This is not a backup taken.
Symbolic links are identified as items to preserve, without traversing their destination directories. Special files discovered during scanning are skipped with warning; if selected as exact sources they produce errors. The scan blocks identity conflicts between normal and private files, and observed aliases of protected files that would bypass their exact inclusion. It does not recognize independent copies of the same content.
The selector protects the standard locations of the rclone configuration, even when connected to a different real path, and the standard operating state of macbackup. Using a custom rclone path requires you to explicitly include it in your protections - it is not yet automatically detected by the selector. Expected identity checking of external volumes is not implemented; currently a missing source produces error, but a bad mount is not certified.
To run tests from the dotfiles repository, without creating Python cache:
python3 -B -m unittest discover -s /Users/kevinmuka/.dotfiles/tests -p 'test_macbackup*.py' -vConfiguring transfers
/Users/kevinmuka/.config/macbackup/settings.toml does not contain passwords:
schema_version = 1
max_delete = 25
[policy]
private_directory_names = [".git"]
ignored_file_names = [".DS_Store", " ← ", ".localized"]
[targets.google]
enabled = true
plain = "gdrive:MacBackup/plain"
private = "gdrive-private:"
[targets.proton]
enabled = false
plain = "pdrive:MacBackup/plain"
private = "pdrive-private:"The gdrive remote must use the drive backend and use your OAuth client. For dedicated backup, drive.file scope is used: files that already exist and are created by other apps will not be automatically accessible. The remote gdrive-private must be of type crypt and wrap gdrive:MacBackup/private, with standard encryption of names and directories. Store the crypt password and any salt in your password manager, recoverable without this Mac.
What gdrive and gdrive-private represent
The two names are two ways of accessing the same Google account: they are not two services or two independent copies. gdrive: is the link to Drive; it doesn't inherently point to the plain folder. It is macbackup, through settings.toml, that chooses gdrive:MacBackup/plain as the destination of the files that can be consulted. gdrive-private: instead applies rclone encryption to the physical folder gdrive:MacBackup/private.
| Path used by macbackup | Location on Google Drive | What you see from your phone or from the site |
|---|---|---|
gdrive:MacBackup/plain/current |
My Drive/MacBackup/plain/current |
Searchable files with original paths under Users/... |
gdrive:MacBackup/plain/history/RUN_ID |
My Drive/MacBackup/plain/history/RUN_ID |
Old versions available, organized by execution |
gdrive-private:current |
Inside My Drive/MacBackup/private |
Encrypted names and contents; the current name is also encrypted |
gdrive-private:history/RUN_ID |
Inside My Drive/MacBackup/private |
Old encrypted versions, with encrypted directory names |
gdrive:MacBackup/plain/macos-icons/current |
My Drive/MacBackup/plain/macos-icons/current |
icon.json file with the data necessary to recover icons on Mac |
gdrive-private:macos-icons/current |
Inside My Drive/MacBackup/private |
The same icon data for private folders, encrypted |
The external folder private keeps this name readable; the encryption applies to what is written via the remote crypt inside it. Using gdrive:MacBackup/private/... directly for an upload would bypass the encryption: for private data, gdrive-private: should always be used. In the Google Drive app on your phone you can open plain files supported by the app; private files require an rclone crypt compatible client and the correct keys.
Both areas consume the same Google space. The future copy on Proton will require separate links, pdrive and pdrive-private, and will be a second independent destination.
For Proton Pass, the suggested recovery entry is called MacBackup — Google Drive — Crypt key. Create it as a custom item via More → Start from scratch. The Encryption password and Salt / password2 fields are hidden and contain the two original strings generated by rclone, not their obfuscation in the configuration. The text fields are Remote name = gdrive-private, Storage path = gdrive:MacBackup/private, Filename encryption = standard and Directory name encryption = true. Store Client ID and Client secret separately in the MacBackup — Google OAuth entry; the second is a hidden field. No TOTP codes are needed to represent these two static passwords.
Enable a destination only after you have configured the two remotes, reviewed the lists and completed the recovery test with synthetic files. Subsequent example operations become executable after that enablement. --target all requires both targets enabled: does not silently skip Proton if missing.
macbackup check --remote --target google
macbackup preview --target google
macbackup run --target google
macbackup statuscheck --remote reads inventories and checks needed types and capacities; it doesn't write to the cloud and doesn't try a recovery. preview --target also reads local content needed for integrity comparisons and dry-runs rclone: it does not modify the cloud. Shows how many files are selected and how many would be archived because deleted; does not yet show a complete list of all replacements.
run transfers only the permitted routes, stores the replaced or deleted copies under history/RUN_ID and records the distinct outcomes of the areas. It does not perform history cleanups. max_delete is the limit of archiving due to deletions by area and by destination: it is checked before transfers and also passed to rclone. The initial value 25 must be reviewed before automation; it is not a conservation policy.
A singly included path must exist: if a mandatory source is missing, the run stops before transfers. Automatic archiving by deletion, on the other hand, concerns missing files within a selected folder that still exists. For example, deleting .ssh/config can archive its copy if .ssh is selected and exists; the disappearance of the entire .ssh blocks the backup. Removing an entry from the lists stops future management of that entry and preserves cloud copies.
Remote operations share a local lock to prevent concurrent executions. Temporary lists and status are protected and remain out of the repository. No file contents are stored in the logs. status describes the last requested run, even partial: it does not always certify each destination, does not verify current reachability and does not imply a complete check of the history. During run, rclone shows the progress of the current phase in the terminal; status updates only at the end of the run. An interruption during the planning phase may still not produce a new state.
In normal areas you require hashes available on the backend. For crypt areas the comparison is carried out with cryptcheck: in this way a content modification of the same size and with the same time is not lost. Only private files that are new, different, or to be removed from current are transferred and stored; an unchanged run should not generate new historical copies. If the encrypted comparison is not complete, the operation on the area is blocked.
The transfer saves files, shortcut representations, and Finder icon data in dedicated areas. It does not yet preserve empty directories without icons or the entire set of macOS metadata: ACLs, extended attributes and resource forks of other files are not covered by this feature. Do not trigger a real backup of open databases yet without an appropriate export or shutdown procedure.
Custom macOS folder icons
The agreed choice is to keep the icons, without excluding the Icon\r files. In this name \r indicates a true carriage return character. The selector recognizes this specific case; other names with control characters remain blocked.
The ordinary contents of Icon\r may be empty: the image often resides in the resource fork. For each selected icon, a small JSON snapshot is then generated that contains the file data, the com.apple.ResourceFork and com.apple.FinderInfo attributes of the file, and the FinderInfo of the folder. The source path appears in the JSON only as information, without being used as a destination by the fetch command. The other documents in the folder are not read or packaged: an unauthorized .env remains excluded.
The icons are recovered on macOS; the Google Drive app on your phone uses its own folder presentation. A test with a valid icon generated via AppKit compared the rendered image before and after recovery, finding them the same. A visual check was not performed within a Finder window.
A snapshot for the /Users/kevinmuka/Desktop/Photography folder is saved in plain/macos-icons/current/Users/kevinmuka/Desktop/Photography/icon.json. Previous versions are in plain/macos-icons/history/RUN_ID/.../icon.json. For a private folder the same structure is under remote crypt, so the icon data is also encrypted.
Snapshots follow inclusions and exclusions like ordinary files. A new exclusion preserves the existing remote copy. Locally removing an icon within a still-selected folder archives the old copy; an unchanged icon must not create new historical versions. The max_delete limit includes files and icon snapshots for each area. Temporary snapshots are in the protected state directory and are removed at the end of the operation. A file or single icon attribute over 64 MiB blocks its area with error, without silently omitting it.
check counts icons using only ordinary names and metadata; does not read the resource fork. Reading the necessary contents occurs during remote preview or transfer. The local scan byte estimate does not include resource forks or the increase in size due to JSON encoding.
To test a recovery, after the first load download a snapshot and apply it to an existing test folder. Example for a normal folder:
mkdir -p "$HOME/Downloads/macbackup-restore/Photography"
rclone copyto \
"gdrive:MacBackup/plain/macos-icons/current/Users/kevinmuka/Desktop/Photography/icon.json" \
"$HOME/Downloads/macbackup-restore/icon.json"
macbackup restore-icon \
--file "$HOME/Downloads/macbackup-restore/icon.json" \
--folder "$HOME/Downloads/macbackup-restore/Photography"For private icons, download is done from gdrive-private:macos-icons/current/.../icon.json. The restore-icon command does not access the cloud, read lists, or write to the source path recorded in the snapshot. The destination is just the folder indicated with --folder, which must exist and not be a symbolic link. Restores the Icon\r file and the Finder bit that activates the custom icon, preserving the folder's other Finder indicators. The documents in the folder remain intact.
If an icon is already present, the command stops. To explicitly replace just that icon, add --replace. The command supports --json and autocompletion of all options. Like other filesystem operations, recovery does not promise an atomic transaction between files and metadata: an error while applying metadata must be checked and may require retrying with --replace.
Google login and OAuth issues
Configure Google in your terminal with rclone config, entering Client ID and Client secret. Do not share the configuration summary; it may contain tokens. The client must be Desktop app, the remote is called gdrive and the scope is drive.file. A "client_secret is missing" error requires you to edit the remote and fill in the Client secret field, not to recreate the Google project.
If your app is in Testing, your account must be added in Google Auth Platform → Audience → Test users. For a long-lasting automatic backup, it is necessary to resolve the weekly expiration limit of app access in Testing, evaluating the transition to Production for personal use; it is not an automatic change performed by the script. In the Audience screen shown on October 30, the status was still Testing: the message Google confirmed that Production requires a valid name, support email, homepage and privacy policy. The first two were already present; you need two real, public URLs, without inventing addresses or expanding Drive permissions. Logo and terms of service were not requested by that message. References: consent configuration, expiration of refresh tokens in Testing, switching to Production in the rclone guide.
Public pages for Google consent
With the user's permission, the gh-pages of kevinmuka/dotfiles branch was created directly on GitHub. GitHub Pages publishes that branch from its root. The site was verified with HTTP 200 responses and comparison of public content with prepared files. The branch includes the macbackup, Neovim, symlink and theme pages, along with manuals, graphic resources and files for site discovery by search engines.
The root dotfiles.kevinmuka.dev/ also documents the other dotfiles tools. To update Google Auth Platform to your custom domain, use these URLs:
| Field in Google Auth Platform → Branding | Value |
|---|---|
| Application home page | https://dotfiles.kevinmuka.dev/macbackup/ |
| Application privacy policy link | https://dotfiles.kevinmuka.dev/macbackup/privacy/ |
| Authorized domains | kevinmuka.dev |
After saving you return to Audience → Publish app. If you change URLs in the future, you will need to update Branding; if the domain changes, also Authorized domains. The move to Production concerns the availability of the OAuth client and the Testing limit: it does not share backup folders and does not publish tokens or keys.
The branch was created remotely via API, without changing the local checkout /Users/kevinmuka/.dotfiles and without publishing the local program changes to main. A branch is a version of the repository, not a new directory on the Mac. To see the reference in the local copy you can run git -C /Users/kevinmuka/.dotfiles fetch origin; this does not change the currently open branch. To edit gh-pages on the Mac it is advisable to use a copy or a separate worktree: changing branches in the checkout that feeds the dotfiles links would also change those active configurations. Public pages include the agreed upon support email, not the backup setup.
After confirming the In production status, you need to reconnect the remote in your terminal with rclone config reconnect gdrive: to obtain a new authorization in the new status. Client ID, Client secret and crypt keys remain as configured; they do not need to be regenerated. The user confirmed that they published the app and reconnected again. Soon after rclone about gdrive: and macbackup check --remote --target google succeeded in read-only. These controls verify access, they do not read publishing status from Google Auth Platform.
On October 30, 2026, reading the remote gdrive quota was successful with scope drive.file; the local configuration was protected with 600 permissions. This test did not list or download the account files.
An end-to-end test was then completed in the same account, limited to synthetic files under connection-tests namespaces distinct from the actual backup locations. Changes of the same size with the same time were also verified in both areas. The 0.2 trial namespaces have been removed from the Drive active area; the trash has not been emptied. No deletion of your files has been performed. The operational report is stored outside the repository. Before the first real backup, the preview review and enabling of the Google destination remain to be completed. Proton remains to be configured for the second copy.
Google's testing of version 0.3 also recovered plain and encrypted icons, preserved files after re-exclusion, and archived files and icons removed from still-selected folders. Blocking for a missing exact source was also checked. The local suite includes 122 successful tests, plus the icon rendering test via AppKit. In cleanup 0.3 the synthetic files were moved to the trash; removing some residual folders again returned errors, recorded separately from the success of the backup. The cleanup report is out of the repository and is not confused with the outcome of the recovery tests.
After explicit user consent, the cleanup of the two authorized 0.3 namespaces was completed by deleting individual items from bottom to top via their Google Drive IDs. All descendants, including those in the trash, were tested before removal: 155 items total, with nine test files, all owned by the account and authorized by the app. The two root IDs were then checked absent and the remaining empty test folders were removed. The scope remained drive.file and the overall trash was not emptied; the old 0.2 tests already in the bin were not part of this final authorization. Synthetic local fixtures have also been removed. This targeted cleanup preceded the general implementation of the forget command and was not evidence of it.
Deletion permissions and limit observed
drive.file is a read and write permission for files authorized to the application, not a read-only permission. A separate test, on new synthetic folders, both plain and crypt, successfully verified: creation and removal of an empty folder; moving a tree containing a file to the trash; removal of the file followed by removal of the remaining empty folders. Full scope drive was not requested.
Cleaning old test folders initially returned 403 appNotAuthorizedToChild for some deep trees. The normal area metadata check found isAppAuthorized=true in all visible items, including descendants already in the trash. Final checks then confirmed the absence of both test namespaces from the active area. The exact cause of intermediate waste has not been isolated; do not consider final success as a guarantee of clearing any tree. It was not necessary to request the full scope.
With the settings used in the first tests, rclone moved items to the Google trash; it was not a permanent deletion and the account trash was not emptied. Version 0.4 of forget distinguishes trash from permanent and also searches for historical backup copies; It doesn't automatically explore native revisions or items already in the trash.
The read-only mount, when added, will prevent changes through that mount. It will not change the OAuth permissions used by backup commands. Switching to full scope drive would allow access to all Drive files - setting MacBackup as the rclone root folder would not limit the Google token to that folder.
References: rclone scope, Google Drive trash and deletion, isAppAuthorized metadata.
Autocomplete Zsh
The integration is automatically loaded by normal Zsh startup in your dotfiles. After installation open a new terminal; to activate it also in an already open terminal, where Zsh completion is already initialized:
source "$HOME/.zsh/integrations/macbackup.zsh"Examples of what you can type before pressing the Tab key:
macbackup ch → macbackup check
macbackup check --j → macbackup check --json
macbackup lay → macbackup layout
macbackup preview --lo → macbackup preview --local
macbackup run --progress-d → macbackup run --progress-depth=
macbackup restore --lin → macbackup restore --links
macbackup --conf → macbackup --config-dir=…
macbackup explain /Users/kevinmuka/… → completa file e directory
Completion is contextual: --config-dir is proposed before the subcommand; --local for preview only; --target for the relevant remote commands. Also complete the google, proton and all values where allowed, the options of forget, --links for restore and the values 1 to 5 of --progress-depth. --json is proposed for commands that support it. For --config-dir a complete directory; for original paths, a complete file or directory. If you start an empty path value, it proposes /, because the selector requires absolute paths. --config-dir=PATH format and --config-dir PATH format are supported, and native name escaping with spaces is supported.
Completion does not run macbackup or rclone, does not read lists, and does not access the cloud. Complete routes using the normal Zsh completion system. The configuration of your keys and terminal styles remains as it already exists.
The versioned files are:
/Users/kevinmuka/.dotfiles/home/.zsh/completions/_macbackup
/Users/kevinmuka/.dotfiles/home/.zsh/integrations/macbackup.zsh
/Users/kevinmuka/.dotfiles/tests/test_macbackup_completion.py
The integration adds the completion directory to fpath before compinit. If it is reloaded after compinit, directly register the command via compdef. It does not require changes to .zshrc, which already loads the integration files. The definitions must be kept consistent with the parser when adding new commands or options.
1. Objective and limits
Save your Mac's chosen files and folders to two independent destinations: Google Drive and Proton Drive. Ordinary data must remain accessible from the service apps, even on a phone. Credentials and other sensitive data must be encrypted before uploading with rclone crypt. Each area must retain replaced and deleted copies.
It is not a bootable backup of your Mac and is not the same as Time Machine. Reading files while an application modifies them is not a consistent snapshot of the entire application: databases, photo libraries, and other active file sets may require an app shutdown or a dedicated export.
The availability of a copy on Google does not certify the one on Proton. Readability from the phone also depends on the formats supported by the apps: a file can be downloadable without being directly viewable.
2. Location on the Mac and relationship with Git
Location chosen for the executable file:
/Users/kevinmuka/.config/scripts/macbackup
The scripts folder is already a symbolic link to:
/Users/kevinmuka/.dotfiles/home/.config/scripts/
Consequently the real source of the command will be:
/Users/kevinmuka/.dotfiles/home/.config/scripts/macbackup
The documentation is stored in the repository in:
/Users/kevinmuka/.dotfiles/docs/macbackup.md
In the inspected terminal environment the scripts folder already appears in the PATH. This will also need to be verified from a new terminal; any automation must use explicit paths for the script and for rclone, without depending on the PATH of the interactive shell.
Proposed arrangement for other elements:
| Element | Location |
|---|---|
| Lists and settings | /Users/kevinmuka/.config/macbackup/ |
| Plans, status and records | /Users/kevinmuka/.local/state/macbackup/ |
| RClone configuration | /Users/kevinmuka/.config/rclone/rclone.conf on this Mac |
| Recovery folder in the examples | /Users/kevinmuka/Restore/ |
The rclone location was obtained with rclone config file; on another Mac you need to check it again. Remote operations use configuration through rclone; the script does not print the secrets.
The repository must contain code, documentation, tests and configuration examples only without secrets. Operational settings and personal lists initially remain outside the repository: even path names can reveal personal information. Adding lists to dotfiles must be a separate choice.
Passwords, OAuth tokens, rclone configuration, keys, plans, and logs should not be added to Git. The state local folder must have limited user access; logs can also contain sensitive file names. They must not contain file contents or credentials.
The installation does not include commits, pushes, shell profile changes, or enabling automatic executions.
Autocompletion adds two files to the Zsh integration system already provided by dotfiles; does not modify profiles or the .zshrc file.
3. Configuration: four lists and a settings file
Three files describe absolute paths to include or exclude. The fourth, explicit-only-patterns.txt, describes file and directory names that require exact inclusion and cannot make it into the backup just because you have included a parent directory. settings.toml contains destinations, deletion limits and directory names to be automatically encrypted.
/Users/kevinmuka/.config/macbackup/
plain-paths.txt
private-paths.txt
exclude-paths.txt
explicit-only-patterns.txt
settings.toml
plain means consultable through the normal apps of the service, with the permissions of your account. Does not enable public shares. On Proton the native encryption of the service remains active; private also adds rclone crypt encryption.
3.1 Syntax of the three path lists
- A line contains an absolute and literal path.
- Empty lines and lines starting with
#are ignored. - Quotation marks are not used in lists, even for names with spaces.
~,$HOME, variables, commands, or wildcards do not expand.- We don't support comments at the end of a line that contains a path.
- A file selects that file; a directory recursively selects descendants, including hidden files, but without implicitly authorizing files or directories subject to the explicit-only rule.
- The trailing slash can indicate a directory; it does not change the precedence of the rules.
- The program rejects relative paths and
..components, instead interpreting them in a terminal position-dependent manner. - Selection of the root
/as the entire source is rejected./is only the reference to reconstruct the paths. - Names that cannot be represented unambiguously in line format, for example containing a carriage return, must produce an explicit error. The program should not skip them silently.
The rules are literal: a path containing [ or * in the name must not accidentally become a filter. rclone rule generation must handle these characters correctly.
3.2 Precedence
- An absolute exclusion prevails over everything: the path is not saved, even if listed directly in plain or private.
- A file with a name in
[policy].ignored_file_namesis skipped everywhere, even if included exactly. The rule applies to files, not a directory of the same name. - If a file or directory name matches explicit-only, the item is not saved unless its full path appears directly in
plain-paths.txtorprivate-paths.txt. Listing only a parent directory does not satisfy this requirement, even in the private area. A skipped directory is not traversed. Deliberate exception: a directory that also matchesprivate_directory_namesis automatically traversed and encrypted; other protections within it continue to apply. - After passing the two checks, a private inclusion or match with
private_directory_namesis saved encrypted. Belonging to a private directory keeps the copy private: an exact inclusion in plain does not make it readable in plain storage. - A normal non-private include is saved in the
plainarea. - An unselected route is not saved.
You are not allowed to re-include a descendant of an excluded directory. You are not allowed to make a descendant of a private directory normal. These choices keep the rules predictable regardless of the order of the lines.
A path indicates itself and its descendants, not similar names: /a/karabiner/ does not include /a/karabiner-old/.
To ignore other file names throughout the selection, add them as string literals to ignored_file_names in settings.toml, for example ignored_file_names = [".DS_Store", "Thumbs.db"]. The comparison is case insensitive; no routes or wildcards are allowed. Spaces within TOML strings are significant: " ← " indicates exactly one name with one space before and one after the arrow. The active configuration ignores .DS_Store, ← and .localized. A new rule blocks future uploads, but leaves copies already present in current and history intact, which can be removed with forget. The rule does not delete local files.
3.2.1 Names permitted only by exact inclusion
Initial setup of explicit-only-patterns.txt:
.env
.env.*
Names are described here, not absolute paths. The .env rule matches that name in any directory; .env.* includes for example .env.local, .env.production and also .env.example. A possibly harmless example file should be included directly if desired: it is not assumed to be free of secrets. node_modules, .venv, venv and myenv have been added to the active configuration: a directory with one of these names is skipped wherever it is found, even if it is created after this revision.
The syntax accepts names and the * wildcard, limited to the final name of the file or directory; does not accept /, **, regular expressions, or signed rules + or -. Empty lines and comments at the beginning of the line work as in other lists. To be conservative, these name checks alone are case insensitive: .ENV also requires exact inclusion. The other paths retain their own semantics and do not become globally case insensitive.
The rule affects files, directories, and symbolic elements with those names. To explicitly whitelist a protected directory, you add its full path to an include list; the files inside it still follow the other rules, so a .env remains protected. Selecting a link saves the link according to the policy described below and does not automatically authorize copying of the destination.
Example with /Users/kevinmuka/Desktop/progetto/ in plain:
| Additional configuration | Outcome for /Users/kevinmuka/Desktop/progetto/.env |
|---|---|
| None | Skipped: Included only through directory |
| Exact plain route | Saved in the regular area, with a warning to explicitly include a protected name |
| Exact route in private | Saved encrypted and absent from the normal copy |
| Project directory in private, without the exact file path | Skipped: Private inclusion is also only inherited |
| Exact path in both lists | Saved encrypted: private prevails |
| Path to the file or its ancestor in exclude | Skipped anyway |
Authorization is for the written path only: listing progetto/.env exactly does not authorize progetto/subdir/.env, altro-progetto/.env, or progetto/.env.local.
This rule must be active both in the preview calculation and in the transfer execution, not just in the pre-check. A new .env created inside a directory during run does not have to go through a simple recursive directory inclusion.
Removing the exact path from the list, or adding a new protection pattern, stops future loads but preserves the copies already present in current and history. To remove them, forget remains necessary. preview --local shows blocked names; versions and forget allow you to find previous cloud copies. run and status do not yet produce an automatic alert linking these two pieces of information.
This protection applies to backup uploads to clouds. It does not configure Git, does not create .gitignore rules, and does not prevent a Git push done with other tools. It does not recognize a secret copied into a file with another name or an archive. The selected .git directories are now automatically encrypted; this does not delete any previous plaintext copies, which can be searched for and removed with versions and forget.
The rules file must be created explicitly at initialization. If it is missing or not readable in an active configuration, check, preview and run must stop: do not interpret the problem as an empty protection list. No temporary flags should globally bypass explicit-only.
3.3 Actual selection agreed on 30 October 2026
These routes have been entered into the local configuration. Google is now enabled in the local configuration to allow the user to launch the first copy; Proton remains disabled. Filling out the lists alone does not initiate a transfer.
plain-paths.txt:
/Users/kevinmuka/Desktop/
/Users/kevinmuka/Documents/
/Users/kevinmuka/.config/
/Users/kevinmuka/.dotfiles/
/Users/kevinmuka/.gitconfig
/Users/kevinmuka/.zshrc
/Users/kevinmuka/.zprofile
/Users/kevinmuka/.zshenv
/Users/kevinmuka/.zsh
private-paths.txt:
/Users/kevinmuka/.ssh/
/Users/kevinmuka/.config/rclone/
exclude-paths.txt:
/Users/kevinmuka/.config/gh/
/Users/kevinmuka/.config/github-copilot/
/Users/kevinmuka/.config/configstore/
/Users/kevinmuka/.config/opencode/
/Users/kevinmuka/.config/joplin-desktop/
explicit-only-patterns.txt contains .env, .env.*, node_modules, .venv, venv and myenv. No .env has been authorized individually: including Desktop, Documents or .config is not enough to load it. The four added entries stop files or directories with these names throughout the selection; directories are not traversed. The 42 temporary hard exclusions used for the review have been removed from exclude-paths.txt, which only retains the five .config exclusions listed above. The protected directory classification also applies when macbackup encounters an old copy already present in the cloud: it stops updates without archiving it as deletion. Existing history remains preserved until an explicit removal is performed.
On November 1st the user chose to encrypt all .git directories. In the active configuration settings.toml contains [policy] private_directory_names = [".git"]: every directory with this name, present or future, and its descendants enter the encrypted area if they are located under an included path. The entry .git also remains in explicit-only-patterns.txt: if the encryption by name rule is removed, an exact inclusion is required again. 68 .git directories were discovered for approximately 0.72 GiB. Project work files remain consultable; .env and other protected names inside .git still require exact inclusion. Absolute exclusion continues to prevail. The new classification does not delete any old plaintext .git copies, including those in the history.
If Desktop/progetto is in plain, a working file like README.md goes to plain/current/Users/kevinmuka/Desktop/progetto/README.md, while a Git object goes to private/current/Users/kevinmuka/Desktop/progetto/.git/objects/... via rclone crypt. On the Drive site, the searchable project directory does not contain .git; in the private area names and contents are encrypted. The original path is preserved in both areas, so the two trees can be recomposed during recovery. The current version of restore recovers one file at a time: automatic recomposition of an entire project is not yet implemented.
Karabiner is included: the exclusion discussed initially was just an example. .config/karabiner is a link; the actual content is saved through .dotfiles/home/.config/karabiner, included in the selected repository. Other .zsh links are preserved as links and their contents in the dotfiles are covered separately. An exclusion of one location does not automatically exclude an independent copy located elsewhere.
The first scan of names and metadata alone had counted approximately 182.5 decimal GB of selected files and approximately 488 thousand plain elements. The review identified 42 directories node_modules, .venv, venv and myenv under Desktop and Documents: approximately 8.6 GiB and 426 thousand files, recreateable from the respective projects. The Desktop/backup 25U3 0312-1112 folder contains photographs and remained included. With exclusions by name, the local selection was around 174.4 GB and 61.7 thousand plain elements; the numbers remain a snapshot of the moment, not a successful backup run. Version 0.2 reported 50 errors related to Icon\r files. The choice to also preserve the metadata was implemented in version 0.3, rather than adding exclusions. No real data loaded.
The full rescan with selector 0.3 succeeded without errors. The count during testing also included some small summary files in the workspace under Documents – the numbers are a snapshot of that moment, not an immutable inventory. Warnings about excluded links and sockets remain distinct from errors.
After the user switched the OAuth app to Production and reconnected, the Google remote check succeeded. The October 30 Google preview with the six explicit-only rules completed without errors: 61,664 ordinary files, 6 private and 50 selected icons, no archive for deletion expected. It was a dry-run: it neither loaded nor deleted files. A subsequent fix extended the classification of protected directories to old cloud copies as well; Local synthetic evidence has confirmed that these copies remain in current. The real Google target remains disabled in settings.toml and a personal data run has not been performed.
The November 1 preview with .git temporarily excluded had counted 35,526 ordinary files, 6 private and 50 icons, zero archives for deletion, approximately 173.7 GB local. It was a dry run. After the encrypted rule was activated, the local scan counted 35,576 plain items, 26,154 private items, 50 icons, and approximately 174.4 GB selected. The subsequent Google preview included 35,526 plain files, 26,154 private ones and 50 icons, without archiving for deletion. The difference of 50 in the plain count is due to the Finder icons, counted separately in the preview. This was also a preview; later Google was enabled and the first real transfer was stopped at the user's request after a few files. It is not a full backup.
Before leaving the user to manually launch, policy has been added to ignore the names .DS_Store, ← (with spaces), and .localized. The new Google preview was successful: 34,656 plain files, 26,078 private, 50 icons; only one file scheduled for archiving. The file was Desktop/modern-download-upload-web-symbol-cloud-storage_1017-59711.xmp, present in the partial copy but now absent on the Mac: the run will move it to the history, preserving it. No removals were proposed because of the newly ignored names. The counts are a snapshot of November 1st, not a guarantee for a subsequent run.
3.4 Credentials and symbolic links
We cannot promise to automatically recognize every secret in Desktop, Documents, repositories or .config. Before the first upload you need to review your selections. The actual path of the rclone configuration, when selected, must be protected by private classification; an inconsistent configuration must be blocked.
Symbolic links should not be followed automatically. They can be stored using --links, which rclone represents on the cloud with files with the suffix .rclonelink. The content of the link is the path to the destination, not the content of the destination.
For this reason, selecting .config/ is not enough to save the contents of a repository reached only through a link: the actual path must also be included. This is the case of the scripts folder in dotfiles.
Link preservation and collision checking with real .rclonelink files must be tested. If the same reserved source is also reached from a path selected as normal, the control must explicitly block or resolve the conflict; you do not have to proceed with a clear copy. It is not a system for recognizing independent copies with the same content.
4. Destination structure
Each service contains an area dedicated to this backup:
MacBackup/
plain/
current/
Users/kevinmuka/...
etc/hosts
Volumes/Archivio/...
history/
RUN_ID/...
private/
[nomi e contenuti cifrati]
The logical view of the private area, through the remote crypt, is:
current/Users/kevinmuka/.ssh/...
history/RUN_ID/Users/kevinmuka/.ssh/...
The remote crypt must include the entire private area, including the history. The private backup does not have to be performed directly on the underlying remote. Each service has its own crypt link; you don't need a copy from Google to Proton, because they both read local sources.
The structure reproduces the paths, but does not by itself certify the preservation of permissions, extended attributes or all properties of the macOS filesystem. Specific choices and tests are needed for the metadata necessary for recovery.
Store outside your Mac the parameters needed to recreate the remote crypt, including password and custom salt if used. It's not enough to know your Google or Proton password. The rclone configuration must also be protected locally: normal password obfuscation is not secure encryption of the configuration.
5. What happens during backup
| Event | Effect |
|---|---|
| New file selected and admitted by protections | Uploaded to the assigned area, under current |
New .env included via a directory only |
Skipped, with explicit-only reason |
| Exact path to a protected file removed from the lists | Already uploaded copies retained without updates |
| File modified | Previous copy in history; new copy in current |
| File deleted within a selected and available directory | Previous copy moved to history |
| Path added to exclusions | Already uploaded copies retained without updates |
| Route removed from lists | Already uploaded copies retained without updates |
| Path changed from normal to private | New encrypted backups; plain old copies maintained and reported |
| Path changed from private to normal | Explicit warning before uploading it can be consulted |
| Explicitly included source missing or illegible | Affected operation blocked; no interpretation as empty directory |
| Insufficient remote space | Error; no automatic cleaning of the history |
current means last copy of paths still managed, with any old copies left behind after an exclusion. It is not necessarily an exact mirror of the current selection. status and the preview must make these situations visible.
The disappearance of an explicitly listed source is ambiguous and blocks the backup: it could be a disconnected disk or an intentional deletion. The deletion of a child file within a selected and correctly available directory is instead a normal deletion to be archived.
For external volumes it is not enough to check that a directory exists: you need to verify that the expected volume is mounted and corresponds to the expected one.
There is no automatic expiration of our histories. The possible future introduction of a conservation policy requires a separate choice. Recycle bin and internal versions of services instead follow the respective provider rules.
Each attempt uses a unique identifier for the historian. A retry must not reuse a history folder where it might overwrite a retained version. An aborted execution may have already transferred or stored some files: it is not an atomic transaction, neither between files nor between services.
6. Proposed commands
They are subcommands of macbackup, not rclone. General restoration of a tree remains a future function.
| Command | Main effect |
|---|---|
init |
Create four lists and settings.toml locally, with no active inclusions |
check |
Check local sources; with --remote --target it also reads inventories and remotes |
explain PATH |
Explains the local classification of a single path |
layout [PATH] |
Show private parts inside a plain directory; without PATH use the current directory |
preview --local / preview --target |
Show local selection or simulate remote transfer without modification |
run --target |
Transfers to enabled areas, keeps versions and shows progress |
status |
He reads the local report of the last run, even if it was interrupted |
restore-icon |
Locally recreates a Finder icon from an already downloaded snapshot |
versions PATH |
List copies of a file or summarize those under a directory |
restore PATH |
Download a file to an explicit destination; with --links recreates a symlink |
verify --target |
Compare current sources with current, without modifications |
forget |
Prepare a removal plan and, with --plan ID --apply, apply it |
The global option --config-dir PATH goes before the subcommand and only changes the directory of the lists and settings.toml; does not change rclone sources, status or credentials. Read and execute commands involving --json return UTF-8 JSON.
Uniform values:
--target google|proton|all: destinations.--area plain|private|all: areas, when the command requires it.- Paths containing spaces must be quoted in the shell.
- An option that selects a private area must not require you to type encrypted names.
6.1 check: local and remote control
macbackup check
macbackup check --jsonCheck syntax, precedence, sources, read permissions, links, conflicts and presence of the explicit-only file. Highlights the exact inclusions that allow protected names in the plain area. check --remote --target google also reads inventories and controls remotes; the target is mandatory when you want a target other than the default Google target. It does not estimate provider quotas or costs.
It doesn't create a backup or prove that a recovery works. Reading sources may require macOS consent for Desktop or Documents: a refusal is an error to be resolved, not a silent exclusion.
6.2 preview: Show operations
macbackup preview --local
macbackup preview --local --jsonThe available mode shows routes and their local classification, reasons for exclusion and warnings. Exact inclusions of protected names in the normal area are highlighted. A file blocked by explicit-only also reports the responsible pattern in the JSON result and in the individual explanation.
The available preview --target google mode performs remote dry-run and reports selected files and archives due to deletions by destination and area. The complete presentation of individual differences and old copies that have become unmanaged remains to be completed.
Local mode does not access the cloud and does not write a report: it prints the result. Future version will be able to save a protected local report. Size and duration of the transfer, when estimated, should be indicated as estimates.
To understand the classification of a single path, without scanning all the sources:
macbackup explain "/Users/kevinmuka/Desktop/progetto/.env"
macbackup explain "/Users/kevinmuka/Desktop/progetto/.env" --jsonLocal explanations and previews do not prove that files are already saved or encrypted. The private folder on the cloud does not exist until the transfer part is configured.
Preview does not freeze files or destinations. A subsequent execution must revalidate the situation: it is not promised that it will execute exactly a list calculated hours before.
6.3 run: Back up
macbackup run --target all
macbackup run --target google
macbackup run --target protonThe program rechecks the configuration, acquires a lock against concurrent executions, and carries out operations in the assigned areas. A private path must never be uploaded to the plain area if encryption fails. During run, macbackup shows rclone reports every 5 seconds in a dedicated screen, if the terminal is interactive. ASCII bars distinguish progress in bytes from progress in files. Overall speed is prominent; for each active file, path and speed are on different lines. Elapsed time and estimate are rounded to the nearest second, no milliseconds. Press u to toggle between binary (KiB, MiB, GiB and their rates) and decimal (kB, MB, GB) units; press ? to show or hide the legend. It is a viewing choice during the current phase and does not change the files or the report. Ctrl-C stops the transfer as before; the terminal is reset. Without an interactive terminal, the same information is printed periodically as text and you cannot use the keys. Multiple files and folders can be transferred at the same time: there is not always a single "current directory". Each report summarizes the active file folders, grouping them by two levels under the home directory. You can choose from one to five levels with --progress-depth N, for example macbackup run --target google --progress-depth 3. Active file paths are not truncated. The statistics are for the plain, icon or private phase in progress, not for the entire backup. status is written at the end; after Ctrl+C during the transfer records the interrupted phase. At the next run the already complete files are compared; macbackup does not keep partial bytes to resume the interrupted file, which is transferred back from the beginning.
run --json does the same real backup and only changes the final summary to stdout. The progress remains on the terminal via stderr. Without --json, the final summary distinguishes selected from transferred and controlled; status keeps the same counts for each completed or interrupted phase.
Before an abnormal amount of removals from current, the program stops. The threshold is max_delete in settings.toml, initially 25 for area and destination; must be reviewed before enabling automation.
The outcome is separate for Google/Proton and plain/private. One target can succeed while the other fails: the summary and exit code must indicate the partial result. A success requires completing all required operations.
The single execution does not guarantee the same temporal snapshot on the two services: if the local files change between readings, the copies may refer to different moments. The backup should not be presented as a simultaneous snapshot.
6.4 status: know the stored result
macbackup statusShows the report of the last run, with the results for destination and area requested in that run. For each phase it distinguishes selected (expected items), transferred_files (transfers completed according to rclone), transferred_bytes (bytes accounted for by rclone in the phase), checked_files (rclone checks) and listed_items (files and folders encountered during exploration, not the total already present in the cloud). renamed_files, server_side_moves and server_side_move_bytes report the movements made on the cloud: with --backup-dir they include the previous copies moved in the history. They do not add to files loaded from the Mac. counts_complete: true indicates final statistics received after a successful phase. After Ctrl+C, if rclone has already output periodic statistics, show the latest count with counts_complete: false: it may be less than the files actually completed before the signal, and the bytes may include part of the broken file. If no report has arrived, the values are null instead of zero. Version 0.9.1 showed progress in the terminal but did not capture periodic reports during Ctrl+C: its nulls cannot be reconstructed from local state. From 0.9.2 the periodic summary is both shown and recorded as the last available photograph. JSON texts are printed in readable UTF-8, without \u2019 sequences for apostrophes. The historical view of the last success for each destination and the verification date are not yet implemented. The stored local state does not certify that the cloud is reachable at that moment, that all histories are intact, or that a recovery attempt was successful.
6.5 versions: Find copies of a file or directory
macbackup versions "/Users/kevinmuka/Documents/tesi.docx" --target google
macbackup versions "/Users/kevinmuka/.ssh/config" --target google --area private
macbackup versions ~/.dotfiles --target google
macbackup versions ~/.dotfiles --target google --filesThe command reads current and all the histories of the requested areas, even if the path has been removed from the lists or the local file no longer exists. --target is required; --area is all if omitted, because the search is read only. For a file you need the exact original path; the output shows area, service, size, available modification date and version identifier: current or the directory ID under history. The modification date is not the archive date.
For an existing directory on your Mac, just its path (~/.dotfiles is expanded by the shell). If the local directory no longer exists, add / to the end of the absolute path to ask for recursive search. Normal output shows, by region and target, a group current with the current item count, and a group for each run that has historical items under that directory, with count and bytes. --files adds original paths, size and type (files or macos-icons) for history groups only; of the current group, the count and bytes remain visible, without the list of current files. --json returns the same groups and details of each item, including the remote path. --files is only valid for one directory. The search includes both plain and private areas except for explicit --area: for .dotfiles, the encrypted .git directory appears under private, while searchable files appear under plain.
Each history/RUN_ID contains only the items moved in that run, not a complete snapshot of the directory at that date. Changing a file on the Mac does not immediately create a history: you need a previous copy already loaded and a subsequent run to replace it. versions does not restore an entire directory; restore continues working on one file at a time.
Destinations can be disabled in settings.toml, as long as the respective remote rclone exists. The command does not require the local state of old runs: it rebuilds the list from the cloud. --json also returns the exact remote path for each copy and preserves the details of the current items. Since version 0.9.5 versions uses its own read-only search: searches for the required path in current, lists the run IDs in history and searches for the same path within each run. For a single file look in its parent directory. It does not compute hashes or original IDs; forget continues to do its own inventory and verification prior to any removal. The limited search should be faster especially for small routes and few runs; with many runs it may result in multiple separate requests. It was not measured on the actual Drive.
6.6 restore: Recover a single file
After reading the identifier with versions, you explicitly choose a local destination:
macbackup restore "/Users/kevinmuka/Documents/tesi.docx" \
--target google --area plain --version current \
--to "/Users/kevinmuka/Restore/tesi-recuperata.docx"For a link, choose a different test path than the original and add --links:
macbackup restore "/Users/kevinmuka/.zprofile" \
--target google --area plain --version current \
--to "/Users/kevinmuka/Downloads/macbackup-restore/.zprofile" --linksThe Downloads/macbackup-restore directory must already exist. The recreated link points to the original recorded path, /Users/kevinmuka/.dotfiles/home/.zprofile; the destination must be retrieved separately. An absolute shortcut may not work on a Mac with a different home name.
For an older version, the ID of the relevant directory history shown by versions is used as the value of --version. The command requires only one service and one area. The destination directory must exist and not cross symlinks. The program rejects the original path as a destination and does not overwrite an already present file, except explicitly --replace; even then it refuses a symbolic or non-regular destination. First download to a temporary file with 600 permissions, check size, and when the backend exposes usable hashes, compare the hashes. Rereads the inventory before making the recovered file visible. If a hash is not available, declare it: size and metadata do not alone certify the integrity of the content.
A symbolic link can be recovered with restore --links: without the flag, the command stops and does not create a normal .rclonelink. Download and check the small destination file, then recreate a link with the same target, even if absolute or containing ..; does not create the file that the link points to. Restoring just the symlink in a test folder does not automatically reassemble the contents of the dotfiles. --links is rejected for normal files. The command does not restore entire directories, directory permissions, ACLs, macOS attributes, or original dates. For a .ssh key the recovered file has permissions 600, but you need to separately prepare the destination directory with appropriate permissions, normally 700. Finder icons follow the restore-icon procedure described above. A file downloaded into a still selected source can be included in the next run.
Isolated testing on November 1 found two synthetic versions on Google: one in plain/history and one in private/current. Both were downloaded and compared with the starting dummy files. The hash of the normal copy has been verified; the remote crypt did not expose a usable hash, and the result stated so. The two cloud files and test folders were removed and checked absent. No personal files were recovered or modified.
History Limit: Each history/RUN_ID directory contains only the files archived in that attempt. The program does not promise restoration of an entire tree to an arbitrary date. To offer this requires comprehensive inventories and proven reconstruction, or a snapshot-based tool.
6.7 verify: Compare local selection with current
macbackup verify --target google
macbackup verify --target google --area private --downloadThe command scans the selected local sources and compares the files allowed with current in the requested service. It does not modify sources or clouds. Ordinary mode uses rclone check for the normal area and rclone cryptcheck for the encrypted area; both require a full match in the rclone report. --download uses rclone check --download and reads remote content to compare with local content - this can generate a lot of traffic and take a long time. For the regular folder Google rclone uses common hashes when available; encrypted verification uses the appropriate cryptcheck method. The verification also includes the current snapshots of Finder icons that macbackup generates from the selected sources.
The result separates matching, mismatched, missing files, and read errors by service, region, and type. A difference between current and the current local file does not prove that the backup is corrupt: the file may have been modified after copying. The command does not check histories, copies retained after an exclusion, the full set of macOS metadata, or native provider revisions. Without a content manifest recorded at run time, it does not certify the contents of an old file by comparing it to the current original. Destinations can be disabled in settings.toml, as long as rclone remotes exist.
In the isolated test on Google on November 1st, verify found a normal file and an encrypted file corresponding both with the ordinary method and with --download. A dummy local change that preserved size and time was reported as a difference. The two test files and namespaces were removed and checked absent; personal files were not touched.
6.8 forget: Remove retained copies
forget uses two passes. The first reads the cloud and only creates a plan; the second applies that plan after a new check. Area, destination and mode are always explicit. For a file, the exact original path is indicated; for a directory you add trailing /, even if the local directory no longer exists:
macbackup forget "/Users/kevinmuka/Desktop/old-project/" \
--area plain --target google --mode trashTo also remove the plain histories of a file that has become private, you can create a Google plan with --mode permanent instead of trash, after checking the path and the printed plan:
macbackup forget "/Users/kevinmuka/Desktop/progetto/segreto.txt" \
--area plain --target google --mode permanentThis example does not apply removal yet: only the next forget --plan ID --apply uses the plan. --area private searches for the encrypted copy instead; --area all searches for both.
The plan lists each matching file in current and all directories under history, with known area, service, location, number, and bytes. For a directory also includes macos-icons snapshots of the folder and descendants. Comparison uses path boundaries: old-project/ does not include old-project-other/. The search does not apply current selection rules, so it also finds copies uploaded before a new exclusion or private classification. Destinations can be disabled in settings.toml, as long as their rclone remotes are configured. A plan of more than 10,000 files is rejected: narrow the path and create more plans.
If there are no matches, a plan is not created. Otherwise macbackup generates a random ID and saves the plan in a local file with permissions 600, under ~/.local/state/macbackup/forget-plans. The plan expires after one hour and can only be used once. The output shows the precise command to apply it:
macbackup forget --plan F0123456789ab --applyBefore applying macbackup re-reads the inventories and compares the complete set of matches, remote paths, sizes, times, IDs and hashes returned by the backend. If one copy changes or another appears, it blocks the entire plan. Some backends do not expose content hashes: modifications of the same file with identical size and identical time may not be detected. For this reason the plan expires and should not be used while other clients modify the backup.
The application removes files one at a time, then rereads the inventory. In case of error there may be a partial result, recorded under the same ID; a new plan is created for the remaining elements. The command does not modify local sources or lists. If the path is still included, a subsequent run may load it again: first change the classification and then use forget. Empty directories can remain in the cloud after files are removed.
--area plain allows for example to remove old copies that can be consulted after moving a file to the private area. --area all searches both areas. --target all requires both services to be configured; does not assume that a disabled target is absent.
6.9 Recycle Bin, Permanent Removal, and Provider Revisions
--mode trash removes the identified copies from the backup folders and sends them to the service recycle bin. It does not mean permanent deletion and may not free up space.
--mode permanent is only accepted for --target google when the normal remote is really Google Drive type. The November 1 isolated test created four small dummy files (plain and private, current and history), generated a four-match plan, applied permanent, verified zero remaining active files, and removed the two remaining empty test directories. No personal files were touched. Cannot be combined with --target all; an unsupported capacity is rejected before any removal and is not silently transformed to trash.
On Google, rclone supports permanent deletion of files identified via --drive-use-trash=false. The inspection of native revisions and copies already present in the trash is distinct from the inspection of our folders: it should not be declared complete without a dedicated and verified functionality. Removing a path does not automatically find duplicates under another name or in other folders.
In the Proton backend of rclone 1.75.2, Remove moves the file to the trash and CleanUp empties the entire trash. There is no rclone command exposed by this selective tombstone backend: macbackup rejects permanent on Proton. trash will be tested on the Proton account when the remote is configured. Selective permanent removal of items already in the Proton Recycle Bin remains manual; macbackup does not yet provide a verified map of the encrypted names in the recycle bin.
The result distinguishes the removal from active folders and the requested mode. trash leaves recoverable copies in the service recycle bin; permanent asks the Google provider to permanently delete the selected active files. The program does not certify the absence of copies previously in the trash, native Drive revisions or duplicates with other names.
7. Operational safety and recoverability
- The program must check the sources before any archiving due to deletion. Should not use
--ignore-errorsto force backup beyond a read error. - It must not start two runs at the same time, nor run and forget at the same time.
- Encryption must fail in a closed manner: no fallback on a plaintext upload.
- All paths should be passed to rclone as arguments, without building shell commands from untrusted text.
- Local state files, credentials, and recovery folders must have adequate protections. Operational state must be excluded from routine backup to avoid recursion and accidental loading of plans or logs.
- The configuration necessary to reconstruct the backup must be exportable in protected form; recovery keys must be available without depending on the only Mac saved.
- Backup cloud files should be viewed as copies. Changes or deletions from the phone are not propagated to the Mac and can be overwritten or recreated by the next run.
- Logs do not contain file contents. Any remote inventory of private routes must also be encrypted.
- A simple backup with access to the same account is not an immutable archive: compromised access can put even remote copies at risk.
8. What rclone already does and what macbackup needs to do
| Task | Responsibility |
|---|---|
| Access to providers and transfers | rclone |
| Encryption of private content and names | rclone crypt |
| Retention of replaced/deleted files | rclone sync with backup-dir, tested on the provider |
| Translation of the four lists into exact area lists, distinguishing exact inclusions from inherited ones | macbackup |
| Local source controls and classification | macbackup; the identity of an external mount is not yet verified |
| Blocking concurrent executions | macbackup |
| Separate summary of results | macbackup |
| Version inventory and guided recovery | macbackup with rclone operations |
| Selective forget plans and outcome control | macbackup with rclone operations supported |
You should not naively combine files-from with exclude filters: rclone ignores other filters when files-from is used. User lists should not be presented as a native rclone format.
Explicit-only is not a native rclone option. The selector applies Python precedences to both local files and copies under current. The transport only passes an exact NUL-separated list to rclone via files-from0, without combining it with exclude filters that would be ignored. The list includes admitted files and old copies still managed to archive; the excluded or become copies of the other area do not enter it and remain preserved. A new file appearing after list preparation waits for the next run. You do not pass a recursive directory inclusion to rclone that would bypass the choice of individual protected files.
The use of the rclone commands remains possible even without the program, as long as the remotes are known and the crypt command is used for the private area. Document the actual names of the remotes after configuration. Do not provide generic destructive commands to be executed from memory.
9. Checks already carried out and necessary checks
The current local suite includes 126 tests with synthetic data and real rclone commands on local and crypt remotes. Covers selection and precedence, .env and other protected names, automatic directory encryption .git, skipped files with spaces in the name, symbolic links, Finder icons, transfers, history, plans forget, versions, restore of files and symlinks with --links, verify, aborted run report, transferred counts, and Zsh autocompletion. The rendering of Finder icons was also tested via AppKit.
Isolated tests were performed on Google Drive with dummy files: plain and crypt copy, recovery of current and historical versions, permanent forget on test copies and ordinary verify and with download. Authorized test namespaces have been removed and checked absent. These tests are not the same as verifying your entire personal copy.
The first transfer of personal data to Google has been interrupted and does not yet have an outcome ok: true for all areas. Before calling it a successful backup you need a full run, macbackup verify --target google and at least three recovery attempts in a separate directory: a plain file, a private file and a symlink with restore --links. verify compares the current copy with the current local files; any local changes after the backup should be interpreted before concluding that the cloud copy is incorrect.
Proton is not yet configured or tested with your user account. Removing forget --mode trash on Proton, a second run without changes, retrieving keys from a new Mac, read-only mounting, and periodic automation remain to be verified or implemented as described in the respective sections. Verifying the identity of external mounts, automatically restoring an entire tree, native revisions, and items already in the provider bin are not covered by the current commands.
10. Operational decisions and remaining work
The location of the script in the dotfiles, the absolute paths that reflect the Mac, the plain/private areas, the encryption of .ssh, .config/rclone and all .git directories, the protection of .env, the agreed exclusions and the names ignored in settings.toml. A new exclusion or reclassification does not automatically delete previous copies; to remove them from current and history an explicit forget plan is used. Google is enabled, Proton is still disabled.
The next milestone is to complete and verify the user-initiated Google copy. Then you configure Proton Drive, repeat backup and recovery on that service and evaluate the read-only consultation setup. Automation is enabled only after a successful backup and recovery trial; There is no automatic expiration of the history.
If it becomes necessary to restore entire folders to exactly one date, a snapshot tool such as restic should be evaluated. macbackup now keeps files moved in the history per run, not complete photographs of the selection at each date.
11. Official sources
Consult during the design and checks from 30 October to 2 November 2026:
- Rclone: filters and files-from
- Rclone: sync
- Rclone: backup-dir
- Rclone: crypt and configuration protection
- Rclone: Google Drive, revisions and trash
- Rclone: Proton Drive and limitations
- Rclone 1.75.2: Proton Drive backend code
- Rclone: delete and filters
- Rclone: purge ignores filters
- Rclone: symbolic links
- Rclone: cryptcheck
- Google: native revision management
- Proton: Selective deletion from trash in the app
- Proton: Deletion and recovery of synchronized files
- Restic: snapshot and recovery
- Zsh: completion system, fpath, compinit and compdef
- Proton Pass: Custom Items
- Proton Pass: Hidden Fields