Metadata-Version: 2.5
Name: mackup-ng
Version: 3.1.0
Summary: Backup and keep your application settings in sync (maintained fork of mackup).
Project-URL: Repository, https://github.com/grigorii-horos/mackup-ng.git
Project-URL: Issues, https://github.com/grigorii-horos/mackup-ng/issues
Project-URL: Changelog, https://github.com/grigorii-horos/mackup-ng/releases
Author-email: Grigorii Horos <horosgrisa@gmail.com>, Laurent Raufaste <analogue@glop.org>
License-Expression: GPL-3.0-or-later
License-File: LICENSE
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: System :: Archiving :: Backup
Classifier: Topic :: Utilities
Requires-Python: >=3.12
Requires-Dist: docopt-ng>=0.9.0
Description-Content-Type: text/markdown

# mackup-ng

[![Tests](https://github.com/grigorii-horos/mackup-ng/actions/workflows/test.yaml/badge.svg)](https://github.com/grigorii-horos/mackup-ng/actions/workflows/test.yaml)
[![PyPI version](https://badge.fury.io/py/mackup-ng.svg)](https://badge.fury.io/py/mackup-ng)
[![Python Versions](https://img.shields.io/pypi/pyversions/mackup-ng.svg)](https://pypi.org/project/mackup-ng/)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
[![mypy](https://img.shields.io/badge/mypy-checked-blue)](http://mypy-lang.org/)
[![License](https://img.shields.io/github/license/grigorii-horos/mackup-ng.svg)](https://github.com/grigorii-horos/mackup-ng/blob/master/LICENSE)

Backup and keep your application settings in sync.

> **mackup-ng** is a maintained fork of [mackup](https://github.com/lra/mackup)
> by Laurent Raufaste. It replaces the backup/restore/link commands with a
> single two-way `sync` plus an `rm` command, while keeping the same on-disk
> conventions (`config.toml`, the `Mackup` storage folder).
>
> ⚠️ **Incompatible with the original `mackup`.** This package installs a
> `mackup` command (and a `mackup-ng` alias) that **shadows the upstream
> `mackup`** — do not install both in the same environment, or the last one
> installed wins. The on-disk format also diverges: mackup-ng records deletion
> tombstones (`.mackup-deletions`) and syncs by modification time, so a folder
> written by mackup-ng is not meant to be managed by the original mackup.

## Table of contents

- [mackup-ng](#mackup-ng)
  - [Table of contents](#table-of-contents)
  - [Quickstart](#quickstart)
  - [Usage](#usage)
  - [What does it do](#what-does-it-do)
    - [Sync mode](#sync-mode)
    - [Ignored files](#ignored-files)
  - [Storage](#storage)
  - [Supported Applications](#supported-applications)
  - [Can you support application X](#can-you-support-application-x)
  - [Personalization \& configuration](#personalization--configuration)
  - [Fork Additions](#fork-additions)
  - [Why this fork exists](#why-this-fork-exists)
  - [What platforms are supported](#what-platforms-are-supported)
  - [What's up with the weird name](#whats-up-with-the-weird-name)
  - [Architecture](#architecture)
  - [Where can I find more information](#where-can-i-find-more-information)

## Quickstart

Install it with [pip](https://pip.pypa.io/en/stable/) (or
[uv](https://docs.astral.sh/uv/)):

```bash
# Install mackup-ng with pip
pip install --upgrade mackup-ng

# ...or as an isolated tool with uv
uv tool install mackup-ng

# Launch it and sync your files
mackup-ng sync
```

You're all set and can back up from now on.

Next, on any new workstation, do:

```bash
# Install mackup-ng
pip install --upgrade mackup-ng

# Launch it and sync your files
mackup-ng sync
```

Done!

You can find more detailed instructions in [INSTALL.md](INSTALL.md).

## Usage

`mackup-ng init <path>`

Set up this machine: write the config pointing at `<path>` as the backup
folder, then run the first sync.

That first sync is not an ordinary one. The backup side wins every contest,
whatever the timestamps say, because on a fresh machine the applications you
have just installed have already written their default configs — with today's
timestamp. Under the ordinary newest-wins rule those defaults would beat the
real settings in the backup folder, and the next sync would spread them to
every other machine.

A path inside your home folder is recorded relative to it, so the config stays
correct on a machine whose home lives elsewhere. `init` refuses if a config
already exists; it sets up a new machine rather than repointing a working one.

`mackup-ng sync`

Synchronize your application files between your home folder and the Mackup folder.

`mackup-ng rm <path>`

Remove a managed config path locally and from the Mackup folder, and record the
deletion so future syncs remove it on other machines too.

`mackup-ng info <path>...`

Report how a path relates to the backup: the config that manages it, whether it
is synced (and why not, when it isn't), both copies with their size and mtime,
what the last sync on this machine did to it, and whether the two sides still
agree. Exits with status 1 when a path is managed by no config.

```console
$ mackup-ng info ~/.zshrc
Path: .zshrc
Config: zsh (Zsh)
Sync: yes
Local: /home/you/.zshrc — 8.9 KiB, 2026-08-17 13:33
Backup: /home/you/Sync/Configs/Mackup/.zshrc — 8.5 KiB, 2026-08-14 09:02
Last sync: 2026-08-14 09:02 (Backed up)
State: diverged — local is newer; next sync backs it up
```

The "Last sync" line comes from a machine-local log that `mackup-ng sync`
writes to `$XDG_STATE_HOME/mackup/sync-log.json`; it reads `never recorded on
this machine` until the first sync after upgrading.

`mackup-ng list`

Display the list of applications supported by mackup-ng.

`mackup-ng mark <marker>` / `mackup-ng unmark <marker>` / `mackup-ng markers`

Set / remove / list machine-local markers (e.g. `backup`, `low-resource`,
`no-linger`, `no-apikey`, `no-dconf`). See "Machine-local extras" below.

`mackup-ng dconf-add <path>...`

Track and dump dconf path(s), e.g. `/org/gnome/terminal/` (Linux/GNOME).

`mackup-ng apply`

Run every config's action blocks (without syncing files); blocks also run
automatically during `sync`.

`mackup-ng -h`

Get some help, obviously...

## What does it do

By only tracking pure configuration files, it keeps the crap out of your
freshly new installed workstation (no cache, temporary and locally specific
files are transferred).

mackup-ng makes setting up the environment easy and simple.

mackup-ng uses sync mode.

### Sync mode

Sync mode is used to synchronize your files.
The files are stored in the one folder you set as `storage.backup_dir`.

It is covered by the commands:

- `mackup-ng sync`
- `mackup-ng rm <path>`

`sync` reconciles every managed file in both directions by modification time.
To drop a single managed path everywhere, use `mackup-ng rm <path>`: it removes
the file locally and from the Mackup folder, and records a deletion tombstone so
future syncs remove it on your other machines too.

### Ignored files

Storage backends drop their own bookkeeping inside the folders they sync.
Syncthing is the loud one: each concurrent edit leaves a `*.sync-conflict-*`
copy next to the file. mackup-ng carries none of it in either direction, and
deletes none of it either — those files belong to the tool that made them. A
fresh conflict copy is skipped when picking the newer side too, so it cannot
beat a real edit on another machine.

Patterns live in `<name>.toml` files with an `[ignore]` table, read from the
package, then `$XDG_CONFIG_HOME/mackup/ignores/`:

```toml
# ~/.config/mackup/ignores/mine.toml
[ignore]
name = "My junk"
patterns = ["*.bak", "*.orig"]
```

The built-in `syncthing.toml` covers `*.sync-conflict-*`, `~syncthing~*.tmp`,
`.syncthing.*.tmp`, `.stfolder`, `.stversions` and `.stignore`. A local file of
the same name replaces the built-in outright, so this turns the whole set off:

```toml
# ~/.config/mackup/ignores/syncthing.toml
[ignore]
patterns = []
```

A single application config can add patterns that apply to its own paths only:

```toml
# ~/.config/mackup/applications/notes.toml
name = "notes"
files = [".notes"]
ignore = ["*.bak"]
```

### Update check

At the end of `mackup sync`, mackup-ng checks whether a newer release is on
PyPI and prints one line if there is:

```text
mackup-ng 2.1.0 -> 2.2.0 available. Upgrade: uv tool upgrade mackup-ng
```

The upgrade command is guessed from where the running executable lives (snap,
uv tool, pipx, or plain pip). The result is cached under
`$XDG_CACHE_HOME/mackup/update-check.json` for a day, so at most one request a
day leaves the machine, and a dry run (`-n`) never checks at all. Any failure —
offline, timeout, a bad answer — is silent.

The request goes to `https://pypi.org/pypi/mackup-ng/json`. It carries nothing
but the package name, though like any request it discloses the machine's IP
address and the fact that mackup-ng is in use. To switch it off for good on a
machine:

```bash
mackup-ng mark no-update-check
```

## Storage

mackup-ng has no storage backends. It backs up into one folder, set as
`storage.backup_dir` in `config.toml`, and that is the whole of it:

```toml
[storage]
backup_dir = "Sync/Configs/Mackup"
```

Point it at whatever already syncs on your machine — a
[Syncthing](https://syncthing.net/) share, a mounted drive, a cloud
provider's local folder, a [Git](https://git-scm.com/) working copy, or a
plain second directory you copy elsewhere yourself. mackup-ng never talks to
a sync service; it only reads and writes that folder, so anything that can
replicate a directory works.

Earlier versions detected Dropbox, Google Drive and iCloud folders for you.
That is gone: the detection was three code paths that guessed a location, and
naming the folder yourself is both shorter and unambiguous.

## Supported Applications

- [1Password 4](https://agilebits.com/onepassword)
- [2Do](http://www.2doapp.com/)
- [Ack](http://beyondgrep.com/)
- [act](https://github.com/nektos/act)
- [ActivityWatch](http://activitywatch.net/)
- [Adium](https://adium.im/)
- [Adobe Camera Raw](http://www.adobe.com/products/photoshop/extend.html)
- [Adobe Illustrator CC](https://www.adobe.com/products/illustrator.html)
- [Adobe Photoshop CC](http://www.adobe.com/products/photoshop.html)
- [Adobe Photoshop Lightroom CC](https://www.adobe.com/products/photoshop-lightroom.html)
- [Adobe Photoshop Lightroom Classic](https://www.adobe.com/de/products/photoshop-lightroom-classic.html)
- [aerc](https://aerc-mail.org/)
- [AeroSpace](https://github.com/nikitabobko/AeroSpace)
- [Affinity Designer](https://affinity.serif.com/designer)
- [Affinity Photo](https://affinity.serif.com/photo)
- [Affinity Publisher](https://affinity.serif.com/publisher)
- [Airflow](https://airflowapp.com/)
- [Airmail](http://airmailapp.com/)
- [Akamai-CLI](https://developer.akamai.com/cli)
- [Alacritty](https://github.com/jwilm/alacritty)
- [AlDente](https://apphousekitchen.com/)
- [AltTab](https://alt-tab-macos.netlify.app/)
- [Amethyst](https://ianyh.com/amethyst/)
- [Ancient Domains of Mystery](http://www.adom.de/home/index.html)
- [Android Studio](https://developer.android.com/sdk/)
- [Ansible](http://www.ansible.com/)
- [AppCleaner](http://freemacsoft.net/appcleaner/)
- [AppCode](http://www.jetbrains.com/objc/)
- [Apple Music](https://www.apple.com/apple-music/)
- [Apptivate](http://www.apptivateapp.com/)
- [Arara](https://github.com/cereda/arara)
- [aria2c](http://aria2.sourceforge.net/)
- [Arm](https://www.atagar.com/arm/)
- [Artistic Style](http://astyle.sourceforge.net)
- [asciinema](https://asciinema.org/)
- [asdf version manager](https://github.com/asdf-vm/asdf)
- [Aspell](http://aspell.net/)
- [Atlantis](http://www.riverdark.net/atlantis/)
- [Atom](https://atom.io/)
- [Audacious](http://audacious-media-player.org/)
- [AusKey](https://abr.gov.au/AUSkey/)
- [Autokey](https://code.google.com/p/autokey/)
- [Awareness](http://iamfutureproof.com/tools/awareness/)
- [AWS Command Line Interface](https://aws.amazon.com/cli/)
- [Bartender](http://www.macbartender.com/)
- [Base](https://menial.co.uk/base/)
- [Bash it](https://github.com/Bash-it/bash-it)
- [Bash](http://www.gnu.org/software/bash/)
- [Bat](https://github.com/sharkdp/bat)
- [Bc](https://www.gnu.org/software/bc/)
- [Beatport Pro](https://www.beatport.com/desktop)
- [Beets](http://beets.io/)
- [BetterSnapTool](http://www.boastr.net/)
- [BetterTouchTool](http://www.boastr.net/)
- [Beyond Compare](https://scootersoftware.com/)
- [BibDesk](http://bibdesk.sourceforge.net/)
- [Billings Pro Server Admin](https://www.marketcircle.com/billingspro/download/billingspro-server/)
- [BitBar](https://getbitbar.com/)
- [Bitchx](http://www.bitchx.org/)
- [Blackfire](https://blackfire.io/)
- [ble.sh](https://github.com/akinomyoga/ble.sh)
- [Blender](https://blender.org/)
- [Boto](https://github.com/boto/boto)
- [Boxer](http://boxerapp.com)
- [Brackets](http://brackets.io/)
- [Brave](https://brave.com/)
- [Btop](https://github.com/aristocratos/btop)
- [Bump](https://github.com/fabiospampinato/bump)
- [Bundler](http://bundler.io)
- [Byobu](http://byobu.co/)
- [Caffeine](http://lightheadsw.com/caffeine/)
- [Calibre](https://calibre-ebook.com/)
- [Capture One](http://www.phaseone.com/Imaging-Software/Capture-One.aspx)
- [Cartographica](https://www.macgis.com/)
- [Cerebro](https://cerebroapp.com/)
- [Charles](http://www.charlesproxy.com)
- [Cheat](https://github.com/chrisallenlane/cheat)
- [Chef](https://www.chef.io/chef/)
- [Chicken](http://sourceforge.net/projects/chicken/)
- [Choosy](https://www.choosyosx.com/)
- [chunkwm](https://github.com/koekeishiya/chunkwm)
- [Cider](https://github.com/msanders/cider)
- [ClashX](https://github.com/yichengchen/clashX)
- [Clasp](https://github.com/google/clasp)
- [Claude Code](https://www.claude.com/product/claude-code)
- [CleanShot](https://cleanshot.com/)
- [Clementine](https://www.clementine-player.org/)
- [CLion](https://www.jetbrains.com/clion/)
- [ClipMenu](http://www.clipmenu.com/)
- [Clipy](https://clipy-app.com/)
- [CloudApp](http://getcloudapp.com/)
- [Coda 2](http://panic.com/coda/)
- [Codex](https://openai.com/codex/)
- [Colloquy](http://colloquy.info/)
- [ColorSchemer Studio 2](http://www.colorschemer.com/osx_info.php)
- [ColorSlurp](http://colorslurp.com/)
- [ColorSync](https://en.wikipedia.org/wiki/ColorSync)
- [Composer](https://getcomposer.org/)
- [Concentrate](http://www.getconcentrating.com/)
- [Conky](https://github.com/brndnmtthws/conky)
- [Consular](https://github.com/achiu/consular)
- [Context7](https://context7.com/)
- [Contexts](https://contexts.co)
- [ControlPlane](http://www.controlplaneapp.com/)
- [CopyQ](https://github.com/hluk/CopyQ)
- [CoRD](http://cord.sourceforge.net/)
- [CotEditor](http://coteditor.com/)
- [Ctags](http://ctags.sourceforge.net/)
- [Cursor](https://cursor.sh/)
- [cVim](https://github.com/1995eaton/chromium-vim)
- [Cyberduck](https://cyberduck.io/)
- [DaisyDisk](https://daisydiskapp.com)
- [Dash](https://kapeli.com/dash)
- [DataGrip](https://www.jetbrains.com/datagrip/)
- [Day-O](http://www.shauninman.com/archive/2011/10/20/day_o_mac_menu_bar_clock)
- [DBeaver](https://dbeaver.io/)
- [DbVisualizer](https://www.dbvis.com/)
- [Deal Alert](http://dealalertapp.com/)
- [Deepin-dde-dock](https://github.com/linuxdeepin/dde-dock)
- [Deepin-dde-file-manager](https://www.deepin.org/en/original/dde-file-manager/)
- [Deepin-Terminal](https://github.com/linuxdeepin/deepin-terminal)
- [Default Folder X](http://www.stclairsoft.com/DefaultFolderX/)
- [Devil's Pie 2](http://www.gusnan.se/devilspie2/)
- [Devil's Pie](<https://en.wikipedia.org/wiki/Devil's_Pie_(software)>)
- [dig](<http://en.wikipedia.org/wiki/Dig_(command)>)
- [Divvy](http://mizage.com/divvy/)
- [Docker](https://www.docker.com/)
- [Dolphin](https://dolphin-emu.org/)
- [Doom Emacs](https://github.com/hlissner/doom-emacs)
- [Double Commander](http://doublecmd.sourceforge.net/)
- [Doxie](http://www.getdoxie.com/)
- [Dozer](https://github.com/Mortennn/Dozer)
- [Draft](https://draft.sh/)
- [Droplr](https://droplr.com/)
- [Dropzone 3](https://aptonic.com/dropzone3/)
- [Drush](http://www.drush.org/)
- [Eagle (ogdesign)](https://eagle.cool/)
- [EditorConfig](http://editorconfig.org/)
- [Electrum](https://electrum.org/#home)
- [Elgato StreamDeck](https://www.elgato.com/en/welcome-to-stream-deck)
- [Emacs](http://www.gnu.org/software/emacs/)
- [Enjoyable](https://yukkurigames.com/enjoyable/)
- [Environmental Station Alpha](http://www.hempuli.com/esa/)
- [eqMac2](https://bitgapp.com/eqmac/)
- [ESLint](https://eslint.org/)
- [espanso](https://espanso.org)
- [Exercism](http://exercism.io/)
- [ExpanDrive](http://www.expandrive.com/)
- [Factorio](https://www.factorio.com)
- [Factory Droid](https://factory.ai/)
- [Fantastical](http://flexibits.com/fantastical)
- [fasd](https://github.com/clvv/fasd)
- [fastlane](https://fastlane.tools)
- [FastScripts](https://redsweater.com/fastscripts/)
- [Feeds](http://www.feedsapp.com/)
- [FileZilla](https://filezilla-project.org/)
- [Finicky](https://github.com/johnste/finicky)
- [Fish](http://fishshell.com/)
- [Fisher](https://github.com/jorgebucaran/fisher)
- [Flake8](https://flake8.pycqa.org/)
- [Flameshot](https://flameshot.org)
- [FlexGet](http://flexget.com/)
- [Flux](https://justgetflux.com/)
- [Focus](https://heyfocus.com)
- [Fontconfig](https://www.freedesktop.org/wiki/Software/fontconfig/)
- [FontExplorer X](http://www.fontexplorerx.com/)
- [Forge](http://www.slightlymagic.net/wiki/Forge)
- [Fork](https://git-fork.com/)
- [ForkLift](http://www.binarynights.com/forklift/)
- [Franz](https://meetfranz.com)
- [Gas Mask](https://github.com/2ndalpha/gasmask/)
- [gdb](https://www.gnu.org/software/gdb/)
- [Gear Player](https://www.gearmusicplayer.com/)
- [GeekTool](http://projects.tynsoe.org/en/geektool/)
- [GHCi](https://wiki.haskell.org/GHC/GHCi)
- [Ghidra](https://ghidra-sre.org)
- [Ghostty](https://ghostty.org/)
- [Ghostwriter](https://wereturtle.github.io/ghostwriter/)
- [Gimp](https://www.gimp.org/)
- [Git Hooks](https://github.com/git-hooks/git-hooks)
- [Git](http://git-scm.com/)
- [Gitbox](http://gitboxapp.com/)
- [GitFox](https://www.gitfox.app)
- [GitHub CLI](https://cli.github.com/)
- [GitKraken](https://www.gitkraken.com)
- [GitUp](http://gitup.co/)
- [Gmail Notifr](http://ashchan.com/projects/gmail-notifr)
- [gmailctl](https://github.com/mbrt/gmailctl)
- [GMVault](http://gmvault.org/)
- [Gnome SSH Tunnel Manager](http://sourceforge.net/projects/gstm/)
- [GNU Stow](https://www.gnu.org/software/stow/)
- [GnuPG](https://www.gnupg.org/)
- [Go2Shell](http://zipzapmac.com/Go2Shell)
- [Goku](https://github.com/yqrashawn/GokuRakuJoudo)
- [GoLand](https://www.jetbrains.com/go/)
- [Goldendict](http://goldendict.org/)
- [GoodSync](https://goodsync.com/)
- [GoShare](https://github.com/dictget/goshare)
- [Gradle](http://gradle.org)
- [GrandTotal 3](http://www.mediaatelier.com/GrandTotal4/)
- [grsync](http://www.opbyte.it/grsync/)
- [Hammerspoon](http://www.hammerspoon.org/)
- [HandBrake](https://handbrake.fr/)
- [Hands Off!](http://www.oneperiodic.com/products/handsoff/)
- [Hazel](http://www.noodlesoft.com/hazel.php)
- [Helix](https://helix-editor.com/)
- [Hero Lab](http://www.wolflair.com/index.php?context=hero_lab)
- [Heroku](https://www.heroku.com/)
- [HexChat](https://hexchat.github.io/)
- [Hexels](http://hexraystudios.com/hexels/)
- [Hocus Focus](http://hocusfoc.us/)
- [Homebrew](https://brew.sh)
- [Homebridge](https://github.com/nfarina/homebridge)
- [Houdini](http://uglyapps.co.uk/houdini/)
- [Hstr](https://github.com/dvorka/hstr)
- [HTML Tidy](https://www.html-tidy.org/)
- [Htop](http://htop.sourceforge.net/)
- [HTTPie](https://httpie.org/)
- [hub](https://hub.github.com)
- [Hyper.app](https://hyper.is/)
- [HyperDock](https://bahoom.com/hyperdock)
- [HyperSwitch](https://bahoom.com/hyperswitch)
- [i2cssh](https://github.com/wouterdebie/i2cssh)
- [i3](https://i3wm.org/)
- [IDA Pro](https://www.hex-rays.com/products/ida/)
- [IdeaVim](https://github.com/JetBrains/ideavim)
- [IINA](https://iina.io)
- [Inkscape](https://inkscape.org/)
- [Insomnia](https://insomnia.rest/)
- [IntelliJIDEA](http://www.jetbrains.com/idea/)
- [IPython](http://ipython.org/)
- [Irssi](http://www.irssi.org/)
- [iStat Menus](https://bjango.com/mac/istatmenus/)
- [iTerm2](https://www.iterm2.com/)
- [iTermocil](https://github.com/TomAnthony/itermocil)
- [Itsycal](https://github.com/sfsam/Itsycal)
- [iTunes Scripts](https://www.apple.com/)
- [JankyBorders](https://github.com/FelixKratz/JankyBorders)
- [Janus](https://github.com/carlhuda/janus)
- [Jitouch](http://www.jitouch.com/)
- [Joplin](https://joplinapp.org/)
- [jrnl](https://jrnl.sh)
- [JS Beautifier](https://github.com/beautify-web/js-beautify)
- [JSHint](http://jshint.com/)
- [Julia](http://julialang.org)
- [Jumpcut](http://jumpcut.sourceforge.net/)
- [Jupyter](http://jupyter.org/)
- [k9s](https://k9scli.io/)
- [Kaggle](https://kaggle.com/)
- [Kaleidoscope](http://www.kaleidoscopeapp.com/)
- [Karabiner Elements](https://github.com/tekezo/Karabiner-Elements)
- [Karabiner](https://pqrs.org/osx/karabiner/)
- [Kdenlive](https://kdenlive.org/)
- [KeePassX](http://www.keepassx.org/)
- [KeePassXC](https://keepassxc.org/)
- [KeepingYouAwake](https://github.com/newmarcel/KeepingYouAwake)
- [Keka](http://www.kekaosx.com/en/)
- [Keybase](https://keybase.io/)
- [Keyboard Maestro](http://www.keyboardmaestro.com)
- [Keymo](http://manytricks.com/keymo/)
- [KeyRemap4MacBook](https://pqrs.org/osx/karabiner/)
- [Khd](https://github.com/koekeishiya/khd/)
- [Kiro](https://kiro.dev/)
- [kitty](https://sw.kovidgoyal.net/kitty/)
- [Krew](https://github.com/kubernetes-sigs/krew)
- [Kubectl](https://kubernetes.io/docs/reference/kubectl/overview/)
- [Kwm](https://koekeishiya.github.io/kwm/)
- [LaTeXiT](http://www.chachatelier.fr/latexit/latexit-home.php?lang=en)
- [LaunchBar](https://www.obdev.at/products/launchbar/index.html)
- [lazydocker](https://github.com/jesseduffield/lazydocker)
- [lazygit](https://github.com/jesseduffield/lazygit)
- [Ledger](http://ledger-cli.org)
- [Leiningen](http://leiningen.org/)
- [lf](https://github.com/gokcehan/lf)
- [LibreOffice](https://www.libreoffice.org/)
- [Liftoff](https://github.com/thoughtbot/liftoff)
- [Light Table](http://lighttable.com/)
- [LightPaper](https://getlightpaper.com/)
- [LimeChat](http://limechat.net/mac/)
- [Liquid Prompt](https://github.com/nojhan/liquidprompt)
- [LittleSnitch](http://www.obdev.at/products/littlesnitch/)
- [Livestreamer](http://livestreamer.tanuki.se/)
- [Logitech Options](https://www.logitech.com/en-us/product/options)
- [Logseq](https://logseq.com/)
- [Lollypop](https://gnumdk.github.io/lollypop-web/)
- [Loopback](https://rogueamoeba.com/loopback/)
- [Luftrausers](http://luftrausers.com)
- [LunarVim](https://www.lunarvim.org/)
- [MacDive](http://www.mac-dive.com/)
- [MacDown](http://macdown.uranusjr.com/)
- [MacOSX](http://www.apple.com/osx/)
- [MacVim](https://github.com/macvim-dev/macvim)
- [Magic Launch](https://www.oneperiodic.com/products/magiclaunch/)
- [MagicPrefs](http://magicprefs.com/)
- [Magnet](https://magnet.crowdcafe.com/)
- [Maid](https://github.com/benjaminoakes/maid/)
- [Mail](https://support.apple.com/guide/mail/welcome/mac)
- [Mailmate](http://freron.com/)
- [Mailplane](http://mailplaneapp.com/)
- [mako](https://wayland.emersion.fr/mako/)
- [Marked 2](http://marked2app.com)
- [Marta](https://marta.yanex.org/)
- [MATLAB](http://www.mathworks.com/products/matlab/)
- [Maven](http://maven.apache.org)
- [Max](http://sbooth.org/Max/)
- [Mendeley Desktop](https://www.mendeley.com)
- [MenuMeters](http://www.ragingmenace.com/software/menumeters/)
- [Mercurial](https://www.mercurial-scm.org/)
- [MercuryMover](http://www.heliumfoot.com/mercurymover/)
- [Messages](http://www.apple.com/osx/apps/#messages)
- [Micro](https://github.com/zyedidia/micro)
- [Microsoft Azure CLI](https://github.com/Azure/azure-xplat-cli)
- [Microsoft Remote Desktop](https://itunes.apple.com/us/app/microsoft-remote-desktop-10/id1295203466)
- [mise-en-place](https://github.com/jdx/mise)
- [mitmproxy](https://mitmproxy.org/)
- [mkcert](https://github.com/FiloSottile/mkcert)
- [Mole](https://github.com/tw93/Mole)
- [MonoDevelop](http://www.monodevelop.com)
- [Moom](http://manytricks.com/moom/)
- [Mosaic](https://lightpillar.com/mosaic.html)
- [Mou](http://25.io/mou/)
- [mpd](http://www.musicpd.org)
- [MPlayerX](http://mplayerx.org)
- [MPS Youtube](https://github.com/mps-youtube/mps-youtube)
- [MPV](https://mpv.io/)
- [MTMR](https://github.com/Toxblh/MTMR)
- [Multitouch](https://multitouch.app/)
- [Mumu](https://getmumu.com)
- [MusicBrainz Picard](https://picard.musicbrainz.org/)
- [MuteSpotifyAds](https://github.com/simonmeusel/MuteSpotifyAds)
- [mycli](https://www.mycli.net/)
- [myrepos](https://github.com/joeyh/myrepos)
- [MySQL Workbench](https://www.mysql.com/products/workbench/)
- [MySQL](http://www.mysql.com/)
- [Name Mangler](http://manytricks.com/namemangler/)
- [Nano](http://www.nano-editor.org/)
- [Navicat](http://navicat.com/)
- [ncmpcpp](http://rybczak.net/ncmpcpp/)
- [Neofetch](https://github.com/dylanaraps/neofetch)
- [neovim](https://github.com/neovim/neovim)
- [Nethack](http://www.nethack.org)
- [Netlify](https://www.netlify.com/)
- [newsbeuter](http://newsbeuter.org/)
- [ngrok](https://ngrok.com/)
- [ni](https://github.com/antfu/ni/)
- [Nomacs](http://nomacs.org/)
- [NoSQLBooster for MongoDB](https://www.nosqlbooster.com/)
- [notion-enhancer](https://notion-enhancer.github.io/)
- [Nova](https://www.nova.app/)
- [npm](https://www.npmjs.com/)
- [npmrc](https://github.com/deoxxa/npmrc/)
- [NSLogger](https://github.com/fpillet/NSLogger)
- [nuget](https://www.nuget.org/)
- [Nushell](https://www.nushell.sh/)
- [nvALT](http://brettterpstra.com/projects/nvalt/)
- [nvm](https://github.com/nvm-sh/nvm)
- [nvpy](https://github.com/cpbotha/nvpy)
- [OBS](https://obsproject.com)
- [OfflineIMAP](https://www.offlineimap.org/)
- [Oh My Fish](https://github.com/bpinto/oh-my-fish)
- [Oh My Tmux](https://github.com/gpakosz/.tmux)
- [okta-awscli](https://github.com/okta-awscli/okta-awscli)
- [OmniFocus](https://www.omnigroup.com/omnifocus/)
- [OmniGraffle](https://www.omnigroup.com/omnigraffle/)
- [Openbox](http://openbox.org)
- [OpenCode](https://opencode.ai)
- [OpenEmu](http://openemu.org)
- [OpenSSH](http://www.openssh.com/)
- [Opera](http://www.opera.com)
- [Oracle Cloud Infrastructure CLI](https://docs.oracle.com/en-us/iaas/Content/API/Concepts/cliconcepts.htm)
- [Paintbrush](http://paintbrush.sourceforge.net/)
- [Pandoc](http://pandoc.org)
- [Pass](http://www.passwordstore.org/)
- [Pastebot](http://tapbots.com/software/pastebot/)
- [Path Finder](http://www.cocoatech.com/pathfinder/)
- [PDFjam](https://warwick.ac.uk/fac/sci/statistics/staff/academic-research/firth/software/pdfjam/)
- [Pear](http://pear.php.net/)
- [Pentadactyl](http://5digits.org/pentadactyl/)
- [Perl](https://www.perl.org/)
- [Phoenix](https://github.com/kasper/phoenix)
- [PhoneView](https://www.ecamm.com/mac/phoneview/)
- [PhpStorm](http://www.jetbrains.com/phpstorm/)
- [PicGo](https://github.com/Molunerfinn/PicGo)
- [Pidgin](https://www.pidgin.im)
- [PIP](http://www.pip-installer.org/)
- [PixelSnap 2](https://getpixelsnap.com/)
- [PixelSnap](https://getpixelsnap.com/)
- [Planner](https://useplanner.com/)
- [Plover](http://www.openstenoproject.org/plover/)
- [Pnpm](https://pnpm.js.org/)
- [Pock](https://pock.pigigaldi.com)
- [Podman](https://podman.io/)
- [Poedit](http://poedit.net/)
- [Poetry](https://python-poetry.org)
- [PokerStars](https://www.pokerstars.com/)
- [Polybar](https://polybar.github.io/)
- [PopClip](http://pilotmoon.com/popclip/)
- [Popcorn-Time](https://popcorntime.io/)
- [PostgreSQL](http://www.postgresql.org/)
- [Postico](https://eggerapps.at/postico/)
- [Pow](http://pow.cx/)
- [Powerlevel10k](https://github.com/romkatv/powerlevel10k)
- [Powerline-shell](https://github.com/b-ryan/powerline-shell)
- [Powerline](https://github.com/powerline/powerline)
- [Prezto](https://github.com/sorin-ionescu/prezto)
- [Processing](https://processing.org/)
- [Proselint](https://github.com/amperser/proselint)
- [ProxyChains NG](http://sourceforge.net/projects/proxychains-ng/)
- [ProxyChains](http://proxychains.sourceforge.net)
- [Proxyman](https://proxyman.io)
- [PrusaSlicer](https://www.prusa3d.com/prusaslicer/)
- [PsySH](https://psysh.org/)
- [Punto Switcher](https://punto.yandex.ru/)
- [PyCharm](https://www.jetbrains.com/pycharm/)
- [PyPI](https://pypi.python.org/pypi)
- [PyRadio](http://www.coderholic.com/pyradio/)
- [Querious](http://www.araelium.com/querious/)
- [Quicksilver](http://qsapp.com/)
- [Quitter](https://marco.org/apps)
- [Qutebrowser](http://qutebrowser.org/)
- [Qv2ray](https://qv2ray.net/)
- [R](http://www.r-project.org/)
- [Rails](http://rubyonrails.org/)
- [Ranger](https://ranger.github.io/)
- [Rbenv](https://www.github.com/rbenv/rbenv)
- [Rclone](https://rclone.org/)
- [Rectangle](https://rectangleapp.com/)
- [Redshift Scheduler](https://github.com/spantaleev/redshift-scheduler)
- [Redshift](http://jonls.dk/redshift/)
- [Remote Desktop Manager](https://remotedesktopmanager.com/)
- [Rhythmbox](https://wiki.gnome.org/Apps/Rhythmbox)
- [Rime](http://rime.im/)
- [ripgrep](https://github.com/BurntSushi/ripgrep)
- [Robo 3T](http://robomongo.org/)
- [Rocket](https://matthewpalmer.net/rocket/)
- [Rofi](https://github.com/DaveDavenport/rofi)
- [Royal TSX](http://www.royaltsx.com/ts/osx/features)
- [RStudio](https://www.rstudio.com/)
- [rTorrent](http://libtorrent.rakshasa.no/)
- [rtx](https://github.com/jdx/rtx)
- [rubiTrack 5](https://www.rubitrack.com)
- [Rubocop](https://github.com/bbatsov/rubocop)
- [Ruby Version Manager](https://rvm.io/)
- [Ruby Version](https://gist.github.com/fnichol/1912050)
- [Ruby](https://www.ruby-lang.org/)
- [RubyMine](http://www.jetbrains.com/ruby/)
- [Rust](https://www.rust-lang.org/)
- [RustRover](https://www.jetbrains.com/rust/)
- [S3cmd](http://s3tools.org/s3cmd)
- [SABnzbd](http://sabnzbd.org/)
- [SBCL](http://www.sbcl.org/)
- [SBT](http://www.scala-sbt.org/)
- [Scenario](http://www.lagentesoft.com/scenario/)
- [Screen](http://www.gnu.org/software/screen/)
- [Screenhero](https://screenhero.com)
- [Scrivener](http://www.literatureandlatte.com/scrivener.php)
- [Scroll Reverser](https://pilotmoon.com/scrollreverser/)
- [Secure Pipes](http://www.opoet.com/)
- [SecureCRT](https://www.vandyke.com/products/securecrt/)
- [Seil](https://pqrs.org/osx/karabiner/seil.html.en)
- [SelfControl](http://selfcontrolapp.com/)
- [Sequel Pro](http://www.sequelpro.com/)
- [ShadowsocksX-NG](https://github.com/shadowsocks/ShadowsocksX-NG)
- [ShiftIt](https://github.com/fikovnik/ShiftIt)
- [Shifty](https://shifty.natethompson.io/)
- [Shimo](https://www.feingeist.io/shimo/)
- [ShowyEdge](https://pqrs.org/osx/ShowyEdge/index.html.en)
- [SHSH Blobs](https://en.wikipedia.org/wiki/SHSH_blob)
- [Shuttle](http://fitztrev.github.io/shuttle/)
- [SizeUp](http://www.irradiatedsoftware.com/sizeup/)
- [Sizzy](https://sizzy.co/)
- [SketchyBar](https://felixkratz.github.io/SketchyBar/)
- [skhd](https://github.com/koekeishiya/skhd/)
- [Skim](http://skim-app.sourceforge.net/)
- [Skitch](https://evernote.com/skitch/)
- [Slate](https://github.com/jigish/slate)
- [Slic3r](http://slic3r.org)
- [Slogger](http://brettterpstra.com/projects/slogger/)
- [SmartGit](http://www.syntevo.com/smartgit/)
- [Smooth Mouse](http://smoothmouse.com/)
- [Soulver](http://www.acqualia.com/soulver/)
- [SourceTree](https://www.sourcetreeapp.com/)
- [SpaceLauncher](https://spacelauncherapp.com)
- [Spacemacs](https://github.com/syl20bnr/spacemacs)
- [SpaceVim](https://github.com/SpaceVim/SpaceVim)
- [SpamSieve](https://c-command.com/spamsieve)
- [Spark](http://www.shadowlab.org/softwares/spark.php)
- [Spectacle](https://www.spectacleapp.com/)
- [Spectrwm](https://github.com/conformal/spectrwm/wiki)
- [Splice](https://splice.com/)
- [Spotify Notifications](http://spotify-notifications.citruspi.io/)
- [Spotify](https://www.spotify.com/)
- [Sqitch](https://sqitch.org/)
- [Starship](https://starship.rs/)
- [Startupizer2](http://appledoc.gentlebytes.com/startupizer/)
- [Stata](http://www.stata.com/)
- [Stats](https://github.com/exelban/stats)
- [Stay](https://cordlessdog.com/stay/)
- [Storyist](http://storyist.com/)
- [Subler](https://subler.org)
- [Sublime Merge](https://www.sublimemerge.com/)
- [Sublime Text](http://www.sublimetext.com/)
- [Subversion](http://subversion.apache.org/)
- [SuperDuper!](http://www.shirt-pocket.com/SuperDuper/SuperDuperDescription.html)
- [Surge](http://surge.run/manual/)
- [Sway](https://swaywm.org/)
- [Swinsian](http://swinsian.com/)
- [Swish](https://highlyopinionated.co/swish/)
- [SwitchHosts](https://github.com/oldj/SwitchHosts)
- [T](http://sferik.github.io/t/)
- [TablePlus](https://tableplus.io)
- [TaskPaper](https://www.taskpaper.com)
- [Taskwarrior](http://taskwarrior.org/)
- [Teamocil](https://github.com/remi/teamocil)
- [Telegram for macOS](https://macos.telegram.org)
- [Terminal](http://www.apple.com/osx/apps/)
- [Terminator](https://launchpad.net/terminator/)
- [termite](https://github.com/thestinger/termite)
- [Termux](https://termux.dev/)
- [Terraform](https://developer.hashicorp.com/terraform)
- [TextExpander](https://smilesoftware.com/textexpander)
- [TextMate](http://macromates.com/)
- [Textual](http://www.codeux.com/textual/)
- [Things](https://culturedcode.com/things/)
- [Tig](https://github.com/jonas/tig)
- [Tiles](https://www.sempliva.com/tiles/)
- [Tilix](https://github.com/gnunn1/tilix)
- [Timeout](https://www.dejal.com/timeout/)
- [tint2](https://code.google.com/p/tint2/)
- [TinyFugue](http://tinyfugue.sourceforge.net)
- [Tmux](http://tmux.sourceforge.net/)
- [Tmuxinator](https://github.com/tmuxinator/tmuxinator)
- [Tmuxp](https://github.com/tony/tmuxp)
- [Todo.txt CLI](http://todotxt.com/)
- [ToothFairy](https://c-command.com/toothfairy/)
- [TotalSpaces2](http://totalspaces.binaryage.com/)
- [Tower](http://www.git-tower.com/)
- [Transmission](http://www.transmissionbt.com/)
- [Transmit](http://panic.com/transmit/)
- [TripMode](https://www.tripmode.ch)
- [Trizen](https://github.com/trizen/trizen)
- [Tunnelblick](https://tunnelblick.net)
- [tvnamer](https://github.com/dbr/tvnamer)
- [Twitterrific](http://twitterrific.com/)
- [Typinator](http://www.ergonis.com/products/typinator/)
- [Typora](https://typora.io)
- [Übersicht](http://tracesof.net/uebersicht/)
- [ulauncher](https://ulauncher.io/)
- [uTorrent](http://www.utorrent.com/)
- [Ventrilo](http://www.ventrilo.com/)
- [Verdaccio](https://verdaccio.org/)
- [Versions](http://www.versionsapp.com)
- [Vim](http://www.vim.org/)
- [Vimperator](http://www.vimperator.org/vimperator)
- [Vimwiki](https://vimwiki.github.io/)
- [Viscosity](http://www.sparklabs.com/viscosity/)
- [Visual Studio Code - Insiders](https://code.visualstudio.com/insiders)
- [Visual Studio Code - OSS](https://github.com/Microsoft/vscode)
- [Visual Studio Code](https://code.visualstudio.com/)
- [Visual Studio for Mac](https://www.visualstudio.com/vs/visual-studio-mac/)
- [VLC](http://www.videolan.org/)
- [Volt](https://github.com/vim-volt/volt)
- [VSCodium](https://vscodium.com/)
- [Wakatime](https://wakatime.com/)
- [Warp](https://www.warp.dev)
- [waybar](https://github.com/Alexays/Waybar)
- [WebStorm](https://www.jetbrains.com/webstorm/)
- [WezTerm](https://wezfurlong.org/wezterm/)
- [Wget](https://www.gnu.org/software/wget/)
- [WhatsApp Web](https://web.whatsapp.com/)
- [Windsurf](https://www.codeium.com)
- [Wireshark 2](https://www.wireshark.org)
- [Witch](http://manytricks.com/witch/)
- [WordGrinder](https://cowlark.com/wordgrinder/)
- [WordPress WP-CLI](http://wp-cli.org/)
- [Workrave](http://www.workrave.org/)
- [X11](http://www.x.org/)
- [Xamarin Studio](https://xamarin.com/studio)
- [xbar](https://xbarapp.com/)
- [XBindKeys](http://www.nongnu.org/xbindkeys/)
- [Xchat](http://xchat.org/)
- [Xcode](https://developer.apple.com/xcode/)
- [Xee](https://theunarchiver.com/xee)
- [XEmacs](http://www.xemacs.org/)
- [XLD](http://tmkk.undo.jp/xld/)
- [Xonsh](https://xon.sh)
- [XtraFinder](http://www.trankynam.com/xtrafinder/)
- [yabai](https://github.com/koekeishiya/yabai)
- [yarn](https://yarnpkg.com)
- [yazi](https://github.com/sxyazi/yazi)
- [youtube-dl](https://ytdl-org.github.io/youtube-dl/)
- [Yummy FTP](http://www.yummysoftware.com/)
- [zabbix-cli](https://github.com/usit-gd/zabbix-cli)
- [zathura](https://pwmt.org/projects/zathura/)
- [zed](https://zed.dev/)
- [Zoom](http://zoom.com/)
- [zoxide](https://github.com/ajeetdsouza/zoxide)
- [Zsh](http://zsh.sourceforge.net/)

## Can you support application X

We can [with your help](doc#get-official-support-for-an-application) ;)

## Personalization & configuration

Have an application that shouldn't be generally supported but that you use?
Or some personal files you want to sync, e.g. various config files in a `~/.config/`
directory or your personal `~/.gitignore`?

- Create files under `~/.config/mackup/applications/` to [sync an application or any file or directory](doc#add-support-for-an-application-or-any-file-or-directory)

## Fork Additions

This fork adds path templating for application config definitions (`*.toml` in
`src/mackup_ng/applications`) to reduce duplication and simplify cross-platform
entries. App definitions are **flat TOML** (no `[application]` wrapper):
top-level `name` and a `files` array (plus an optional
`[mapped_files]` table and action blocks). A legacy `[application]` table is
still accepted.

### 1. Brace expansion (`{...}`)

You can define multiple paths in one line:

```toml
name = "Code"
files = [
    "${MACKUP_XDG_CONFIG}/Code/User/{snippets,keybindings.json,settings.json}",
]
```

This expands to one entry per item (cartesian product if multiple brace groups
are used).

### 2. Platform selector (`[...]`)

You can choose different path fragments per platform:

```toml
files = [
    "${MACKUP_XDG_CONFIG}/[mac:Blender,blender]",
]
```

Another example with a full-path fallback:

```toml
files = [
    "[linux:${MACKUP_XDG_CONFIG}/myapp/linux.conf,mac:${MACKUP_XDG_CONFIG}/MyApp/mac.conf,windows:${MACKUP_XDG_CONFIG}/MyApp/windows.conf,${MACKUP_XDG_CONFIG}/myapp/other.conf]",
]
```

- `linux:`, `mac:`, `windows:` are supported keys
- the last unkeyed item is the fallback
- in this fork, the fallback also acts as the canonical backup path

This means the selector can map different local paths to one shared backup path.
Example:

```toml
files = [
    "[mac:${MACKUP_XDG_CONFIG}/MyApp/config.json,linux:${MACKUP_XDG_CONFIG}/myapp/config.json,${MACKUP_XDG_CONFIG}/shared/myapp-config.json]",
]
```

Behavior:

- macOS local path: `${MACKUP_XDG_CONFIG}/MyApp/config.json`
- Linux local path: `${MACKUP_XDG_CONFIG}/myapp/config.json`
- backup path (all platforms): canonical Linux path for the fallback, i.e. `.config/shared/myapp-config.json`

### 3. Built-in XDG variables

These reserved Mackup-owned aliases (not OS environment variables) mimic the XDG
base directories on **every** OS, even ones that don't set the `XDG_*` env vars.
The `MACKUP_` prefix keeps them distinct from real `${VAR}` env references; `XDG`
marks the semantics:

- `${MACKUP_XDG_CONFIG}` -> `.config` (Linux) / `Library/Application Support` (macOS) / `AppData/Roaming` (Windows)
- `${MACKUP_XDG_DATA}` -> `.local/share` (Linux) / `Library/Application Support` (macOS) / `AppData/Local` (Windows)
- `${MACKUP_XDG_STATE}` -> `.local/state` (Linux) / `Library/Application Support` (macOS) / `AppData/Local` (Windows)
- `${MACKUP_XDG_CACHE}` -> `.cache` (Linux) / `Library/Caches` (macOS) / `AppData/Local` (Windows)

Important in this fork:

- built-in variables in local paths are resolved for the current OS
- built-in variables in backup paths are always resolved to Linux canonical paths
  (e.g. `${MACKUP_XDG_CONFIG}` in backup becomes `.config`)

### 4. Environment variables (`${VAR}` + `source_env`)

Any `${VAR}` that is not a reserved `MACKUP_*` built-in is resolved as a real
environment variable, falling back to `KEY=VALUE` lines in the app's
`source_env` files. It expands to the same value on both the local and backup
side, so use it for relative, machine-specific fragments (a profile dir name,
a hostname). Unresolved or absolute results skip just that entry.

```toml
name = "Firefox"
source_env = ["~/.config/mackup-env"]   # KEY=VALUE lines; env takes priority
files = [
    "${MACKUP_XDG_CONFIG}/firefox/${FF_PROFILE}/prefs.js",
]
```

### 5. Processing order

Path templates are resolved in this order:

1. Platform selector `[...]` (produces local path + canonical backup path)
2. Built-in variables (`${MACKUP_XDG_CONFIG}`, `${MACKUP_XDG_DATA}`, `${MACKUP_XDG_STATE}`, `${MACKUP_XDG_CACHE}`)
3. Environment variables (any other `${VAR}`, from env / `source_env`)
4. Brace expansion `{...}`

### 6. Config style in this fork

- Upstream-style `xdg_configuration_files` is not used in this fork; express entries directly in
  `files` using `${MACKUP_XDG_CONFIG}/...`
- many app definitions in this fork were normalized to use `${MACKUP_XDG_CONFIG}`,
  `${MACKUP_XDG_DATA}`, and selectors to avoid macOS/Linux duplicates
  (for example VS Code-family configs)

### 7. Explicit local → backup mapping (`[mapped_files]`)

`files` keeps the local path and storage layout identical. To
decouple them, add a `[mapped_files]` table with `LOCAL = BACKUP` pairs:

```toml
[mapped_files]
".config/app/grisa.profile/user.js" = ".config/app/profile/user.js"
```

Paths are quoted TOML strings, so spaces, dashes and even `->` are safe inside
them. Both sides honor selectors, built-in vars and braces (brace groups zip
pairwise). Handy when a machine-specific local path (e.g. a per-machine Firefox
profile dir) should share one canonical path in the backup folder.

One backup file can feed several local files — repeat the value:

```toml
[mapped_files]
".config/app/work.profile/user.js"     = ".config/app/profile/user.js"
".config/app/personal.profile/user.js" = ".config/app/profile/user.js"
```

All members of such a group are peers: whichever copy you edited last wins and
is propagated to the others on the next `mackup sync`.

Destinations are unique. If a later config maps the same local path to a
different backup file, the earlier mapping is dropped — that is how you
overwrite a stock config with your own. Configs are read stock first, then
`$XDG_CONFIG_HOME/mackup/applications`, so your own files always win. Run
`mackup sync -v` to see which mappings were overridden and which backup files
are left without a destination.

An orphaned backup file (no destination maps to it) is left untouched; it is
only reported by `mackup sync -v`, never deleted on its own. `mackup rm <path>`
removes one destination and tombstones it — the shared backup source survives
as long as another destination still feeds from it, and is only deleted once
the last destination is removed. Re-declaring a destination with the *same*
backup file is not an override and is not reported.

`mackup rm` also accepts a path *inside* a managed directory. Because the
members of a group mirror each other, such a removal is applied to the whole
group: the file goes from the backup source and from every destination, and
the tombstone keeps it from coming back on the next sync.

### 8. Units of work (action blocks)

A config file is not a file list with hooks bolted on either end — it is an
**ordered sequence of units of work**. A config whose top-level `[when]`
holds executes, in this order:

1. its `[[block]]` entries with `phase = "pre"`, in declaration order
2. the **top-level unit** — the config's own `files` and `[mapped_files]`,
   then its action if the top level carries one
3. its `[[block]]` entries with `phase = "during"` — **the default phase**
4. its `[[block]]` entries with `phase = "post"`, in declaration order

Units are numbered by `slot` across that whole final order, not per phase.
Within one unit, **files sync first, then its action runs**. A block has an
optional `[when]` conditions sub-table, optional `files`, and at most one
action sub-table; there is no `type` key. A block may carry `files`, an
action, or both — `files` on a block work exactly like top-level `files`;
only the top level also takes `[mapped_files]`. `[when]` on a block gates
**both** its files and its action. Actions: `[copy]`, `[chmod]`, `[run]`,
`[xml]` (edit XML), `[systemd]` (user drop-in).

```toml
name = "SSH"
files = [".ssh"]

# top-level unit: chmod runs right after .ssh syncs, in the same unit
[when]
os = ["linux", "macos"]
[chmod]
path = "~/.ssh"
recursive = true
dir_mode = "700"
file_mode = "600"
```

`[when]` keys (any-of lists): `os`, `not_os`, `arch`, `marker`, `not_marker`,
`command`, `gui`, `exists`, `not_exists`, `env`. For more than one block per
file use a `[[block]]` array with `[block.when]` / `[block.<action>]`; an
array entry defaults to `phase = "during"` unless it says otherwise. Configs
run sorted by filename; `mackup apply` runs every unit's action without
syncing files. A block-only file (no top-level `files`) is a pure hook.

The old `<app>-macos` split — a whole second TOML config file, with its own
application id, gated by a top-level `[when] os = "macos"` — is gone. Put
both variants in one config instead, as two blocks:

```toml
name = "AppCode 3.1"

[[block]]
files = [
    "${MACKUP_XDG_CONFIG}/appCode31",
]
[block.when]
not_os = "macos"

[[block]]
files = [
    "Library/Preferences/appCode31",
]
[block.when]
os = "macos"
```

Use `not_os = "macos"` rather than `os = ["linux", "windows"]` for
"everywhere but macOS": `hooks.os_kind()` reports `android` as its own value
(distinct from `linux`), so a hardcoded OS list silently drops an Android
machine's XDG paths, while `not_os` only excludes what it names.

`mackup-ng show <app>` prints the resolved file mappings and then a `Units:`
section listing every `[[block]]` the config declares, whether or not it ran
— `slot N: <action>` naming its action, or `slot N: files only` when it has
none, with a trailing `— conditions not met (...)` when its `[when]` didn't
hold. The implicit top-level unit is different: it shows up in `Units:` only
when the top level itself carries an action — a bare top-level `files` (and
`[mapped_files]`) with no action never appears there, even though its
mappings already showed up under `Configuration files:` above. This is how a
block dropped by `[when]` is named instead of silently vanishing.

Conditions written at the top level of a config gate the **whole** config —
its synced files as well as its units' actions. A config whose conditions do
not hold on this machine declares nothing, so a mapping from another config
keeps the destination. That is how one machine can take a different source
for the same local file:

```toml
# ~/.config/mackup/applications/zz-termux-colors-eink.toml
[when]
os = ["android"]
marker = ["eink"]

[mapped_files]
".termux/colors.properties" = ".termux/colors-eink.properties"
```

Run `mackup show <app>` to see whether a config's conditions hold here, and
`mackup sync -v` to list the configs skipped for that reason. To gate a
single unit's files and/or action instead of the whole config, put the
condition inside `[[block]]` as `[block.when]`.

Top-level keys (`files`, `mapped_files`, etc.) must come **before** the
`[when]` header in the file. TOML assigns a bare `key = value` line to
whichever table opened above it — write `files = [...]` after `[when]` and it
becomes `when.files` instead of the config's own file list, so the config
silently syncs nothing. Loading a config warns about this: an unrecognized
key inside `[when]` or a `[when]` that isn't a table at all both print a
`Warning:` line naming the config and the problem.

### 9. Machine-local extras

Beyond custom app configs, mackup-ng splits its own state across the three
XDG base directories:

```text
$XDG_CONFIG_HOME/mackup/     (~/.config/mackup)       synced
    config.toml               main config
    applications/*.toml       config *.toml files: sync lists AND action blocks
    ignores/*.toml            ignore definitions
    markers/*.toml            LOCAL marker DEFINITIONS (same format as apps)
$XDG_DATA_HOME/mackup/       (~/.local/share/mackup)  synced
    dconf-backup/*.dconf      dconf dumps
$XDG_STATE_HOME/mackup/      (~/.local/state/mackup)  NOT synced
    markers/                  marker STATE flags, machine-local
    sync-log.json             per-machine record of the last sync
```

Marker *state* (which markers are on) is the only part of this that is
machine-local and never synced; it lives under
`$XDG_STATE_HOME/mackup/markers/` (default `~/.local/state/mackup/markers/`).

Marker state is not the only machine-local state: `sync` also records what it
did to each destination in `$XDG_STATE_HOME/mackup/sync-log.json`, which is what
`mackup-ng info` reports as "Last sync". Both stay out of the synced backup
folder, since they describe this machine only.

mackup-ng backs up its own configuration through the same mechanism, via the
built-in `Mackup` profile (`applications/mackup.toml`): its file list is the
literal, home-relative paths `.config/mackup` and `.local/share/mackup`, not
`dirs.config_dir()` / `dirs.data_dir()`. If you point `$XDG_CONFIG_HOME` (or
`$XDG_DATA_HOME`) somewhere other than its default, mackup-ng itself keeps
working from the new location, but this profile keeps watching the old one —
so it silently stops syncing mackup's own configuration.

- **Markers** (`mark`/`unmark`/`markers`) are empty flag files gating behavior on
  one machine only. `backup` marks the source machine.
- **dconf** (Linux/GNOME): the backup-role machine dumps tracked paths before the
  file sync; other machines load them after. Opt out with the `no-dconf` marker;
  register paths with `dconf-add`.
- **Units of work** (in `applications/*.toml`, applied during `sync` / via
  `apply`): a config is an ordered sequence of units — `pre` blocks, the
  top-level unit (its `files`/`[mapped_files]`, then its action), `during`
  blocks (the **default** phase), `post` blocks — numbered by `slot` across
  that final order. A block = base scalars, a `[when]` conditions sub-table,
  optional `files`, and at most one **action sub-table** whose name is the
  action (`[copy]` / `[chmod]` / `[run]` / `[xml]` / `[systemd]`); no `type`
  key. Within a unit, files sync first, then its action runs. Base scalars:
  `phase` (`pre`/`during`/`post`, default `during`) and optional
  `restart_service`. `[when]` gates both a block's files and its action, with
  short-keyed conditions (`os`, `not_os`, `arch`, `marker`, `not_marker`,
  `command`, `gui`, `exists`, `not_exists`, `env`). In a `[[block]]` array the
  sub-tables are `[block.when]` / `[block.<action>]`; at the top level
  `[when]` / `[<action>]` (plus `files` / `[mapped_files]`, top-level only).
  Configs apply sorted by filename — cross-cutting hooks use numeric prefixes
  (`10-`, `40-`).
- **Environment contract**: `[run]` blocks receive a `MACKUP_*` environment
  (`MACKUP_PHASE`, `MACKUP_ROLE`, `MACKUP_OS`, `MACKUP_ARCH`, `MACKUP_HAS_GUI`,
  `MACKUP_CONFIG_DIR`, `MACKUP_DATA_DIR`, `MACKUP_STATE_DIR`,
  `MACKUP_BACKUP_DIR`, `MACKUP_MARKERS_DIR`, `MACKUP_DCONF_BACKUP_DIR`). A
  pre-sync executable is a `[run]` block with `phase = "pre"`.

Requires Python 3.12+.

## Why this fork exists

[Mackup](https://github.com/lra/mackup) was written by Laurent Raufaste on a
premise worth keeping: application config files are small, portable, and the
most annoying thing to lose when you reinstall a machine. A tool that moves
them between a workstation and a folder saves hours every time.

mackup-ng keeps that premise and rebuilds nearly everything around it.

**One two-way sync instead of three one-way commands.** Upstream has `backup`,
`restore` and `uninstall`, each moving files in one direction, and it links
the originals into place with symlinks. mackup-ng has a single `sync` that
reconciles both sides by modification time and **copies** — no symlinks, so a
broken link cannot silently detach your home directory from the folder. `rm`
records a tombstone, so deleting a managed file removes it from both sides and
stays deleted instead of reappearing on the next run.

**Application definitions are a small language, not just a file list.** They
are flat TOML with brace expansion (`{settings.json,keybindings.json}`),
platform selectors (`[mac:Blender,blender]`), XDG variables, and a
`[mapped_files]` table for paths that differ between machines.

**Configs can do things, not only be copied.** A definition may carry action
blocks — `[run]`, `[copy]`, `[chmod]`, `[xml]`, `[systemd]` — gated by a
`[when]` table on OS, architecture, GUI presence, an installed command, or a
machine-local marker. `mackup apply` runs them without touching any files.

**Machines differ, and the tool knows it.** Markers such as `backup`,
`low-resource`, `no-dconf` or `no-linger` are set per machine, never synced,
and decide which side is the source of truth and which behaviour is skipped.

**Linux is the first-class target.** dconf paths are dumped on the backup
machine and loaded on the others; systemd units get drop-ins; the layout
follows the XDG base directory spec; and a built-in ignore definition keeps
Syncthing's in-flight files out of your backups.

**No storage backends.** Upstream detects Dropbox, Google Drive and iCloud
folders. mackup-ng backs up into the one folder you name in `backup_dir`, and
leaves replication to whatever you already use for it.

The two are **not compatible on disk or on the command line**, which is why
this is a fork with a different name rather than a set of patches.

It remains [GPL](http://www.gnu.org/licenses/gpl.html), of course.

## What platforms are supported

- macOS
- GNU/Linux

## What's up with the weird name

Mackup is a portmanteau of Mac and Backup. It is simple, short, and easy to
remember, and it corresponds with the whole idea: the simpler – the better!
The `-ng` suffix ("next generation") marks this maintained fork, which
streamlines Mackup down to a single two-way `sync` plus `rm`.

## Architecture

Want to understand how Mackup works internally? Check out the
[Architecture Guide](doc/ARCHITECTURE.md) which includes:

- Visual architecture diagram
- Component breakdown
- Data flow diagrams
- Design decisions
- Extension points for contributors

Perfect for contributors who want to understand the codebase or users
curious about how their configs are managed.

## Where can I find more information

In the [doc](doc) directory.
