Nfd2nfc
macOS NFD/NFC filename converter with TUI, CLI, and background watcher
Install / Use
/learn @elgar328/Nfd2nfcREADME
nfd2nfc
[!NOTE] nfd2nfc is now on homebrew-core! If you previously installed via the tap, see Migration.
A macOS tool that watches directories and converts NFD filenames to NFC in real time, ensuring cross-platform compatibility.
What is NFD/NFC?
Unicode has two main ways to represent composed characters such as Korean Hangul, accented Latin (é, ü, ñ), Japanese kana (が, ぱ), and more:
- NFC (Composed): One codepoint per character —
가=U+AC00 - NFD (Decomposed): Base + combining marks —
가=U+1100 U+1161
macOS stores filenames in NFD, while Windows and Linux use NFC. This mismatch causes problems when sharing files across platforms:
- Hangul syllables appear as decomposed jamo (e.g., 한글 → ㅎㅏㄴㄱㅡㄹ)
- Accented characters may render or sort incorrectly
- Git sees identical files as untracked or modified
- Cloud sync and archive tools fail to match paths
nfd2nfc provides an interactive TUI, a scriptable CLI, and a background watcher service that handles conversion automatically.
Features
- Real-time monitoring — Converts NFD filenames to NFC as soon as they appear
- Flexible watch paths — Mix
watch/ignoreactions withrecursive/childrenmodes to control exactly which directories are monitored - Manual conversion — Convert filenames between NFD and NFC, individually or recursively
- Log viewer — Review past watcher logs or follow new entries live
- Intuitive TUI — Every keybinding is shown on screen, with full mouse support
- CLI mode — Script and AI-agent friendly, with
--jsonoutput and--dry-runpreviews
Home
<img src="https://github.com/elgar328/nfd2nfc/releases/download/assets/home.png" alt="Home" width="750" />The Home tab displays the current watcher service status and provides controls to start, stop, or restart it.
Config
<img src="https://github.com/elgar328/nfd2nfc/releases/download/assets/config.png" alt="Config" width="750" />The Config tab manages which directories the watcher monitors. Each path entry has an action (watch or ignore), mode (recursive or children), and validation status.
Logs
<img src="https://github.com/elgar328/nfd2nfc/releases/download/assets/logs.png" alt="Logs" width="750" />The Logs tab lets you browse past watcher logs and follow new entries in real time. Logs are stored in macOS system logs, and retention is managed by the OS.
Browser
<img src="https://github.com/elgar328/nfd2nfc/releases/download/assets/browser.png" alt="Browser" width="750" />The Browser tab lets you inspect files and directories for their Unicode normalization form and convert them directly. The watcher only picks up newly created or modified files, so use this tab to convert any existing NFD names.
CLI Mode
Running nfd2nfc without arguments launches the TUI. Add a command to use CLI mode. Run nfd2nfc <command> --help for detailed options.
nfd2nfc status [--json]
nfd2nfc watcher start|stop|restart
nfd2nfc config list [--json]
nfd2nfc config add <path> [--action watch|ignore] [--mode recursive|children] [--dry-run] [--json]
nfd2nfc config remove <index> [--dry-run] [--json]
nfd2nfc config sort
nfd2nfc convert <path> [--mode name|children|recursive] [--target nfc|nfd] [--dry-run] [--json]
nfd2nfc log show [--last 30m] [--json]
nfd2nfc log stream [--json]
Example:
$ nfd2nfc status
Watcher: running
Version: 2.1.0
Binary: /opt/homebrew/Cellar/nfd2nfc/2.1.0/bin/nfd2nfc
Watcher binary: /opt/homebrew/Cellar/nfd2nfc/2.1.0/bin/nfd2nfc-watcher
Config: ~/.config/nfd2nfc/config.toml
Plist: ~/Library/LaunchAgents/io.github.elgar328.nfd2nfc.plist
Registered paths: 6 total (4 active, 1 overridden, 1 not found)
Full Disk Access: granted
Update: up to date
Limitations
nfd2nfc solves the root cause of filenames breaking across operating systems — macOS storing them in NFD. However, other software (browsers, email services, cloud storage, messaging apps, archive tools, etc.) may independently convert filenames to NFD when transferring files. This is application-level behavior outside the scope of nfd2nfc.
Installation
Requires Homebrew.
brew install nfd2nfc
Then run it:
nfd2nfc
On first launch, the watcher service is automatically registered as a LaunchAgent. After that, you can start and stop it from the TUI or CLI.
Permissions
If macOS repeatedly prompts for folder access when the watcher converts files, grant Full Disk Access to the watcher binary:
- Run
which nfd2nfc-watcherto find the binary path - Open System Settings → Privacy & Security → Full Disk Access
- If
nfd2nfc-watcheris already listed, remove it completely (click-, not just toggle off) - Click
+, pressCmd+Shift+G, paste the path from step 1, and add it - Run
nfd2nfc statusand verify that Full Disk Access showsgranted
After upgrading to a new version, you must re-do the steps above to grant Full Disk Access again.
Note: On macOS Tahoe 26.1–26.2, Full Disk Access does not take effect for command-line binaries due to a system bug. This is resolved in macOS 26.3.
Migration
Starting with v2.0.7, nfd2nfc moved from the personal tap to homebrew-core. If you are using v2.0.6 or earlier, migrate with:
brew uninstall nfd2nfc
brew untap elgar328/nfd2nfc
brew install nfd2nfc
Upgrading
brew upgrade nfd2nfc
If you have granted Full Disk Access, you must reconfigure it after upgrading.
Uninstallation
brew uninstall nfd2nfc
