| name | syncthing-setup |
| description | Install and configure Syncthing for folder sync between macOS and Android devices. Covers brew install, service setup, web UI automation for folder creation, device ID extraction, and cross-device pairing instructions. Use when user needs to sync folders between Mac and phone/tablet. |
| version | 1.0.0 |
| author | Hermes Agent (for Adit) |
| license | MIT |
| metadata | {"hermes":{"tags":["Syncthing","Sync","macOS","Android","Obsidian","File Sync","P2P"]}} |
Syncthing Setup
Install and configure Syncthing to sync folders between macOS and Android devices. Common use case: syncing Obsidian vaults.
When to Use
- User wants to sync a folder from Mac to Android (or vice versa)
- Setting up Obsidian vault sync between devices
- Need real-time, encrypted, no-cloud file sync
- User asks "how to sync files between Mac and phone"
Installation
brew install syncthing
brew services start syncthing
sleep 4
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8384
Web UI Access
Open http://127.0.0.1:8384 and use browser tools to interact. The REST API has CSRF protection, so browser automation is more reliable than curl-based API calls.
Device ID Extraction
curl -s http://127.0.0.1:8384/rest/system/status 2>/dev/null | python3 -c "import sys,json; print(json.load(sys.stdin).get('myID',''))"
This returns the full Device ID like: TIST2PB-54H2NQC-KHI5B3G-5OLLMZM-IGU7LC2-ARRMEIA-46VI6ST-AZFCPAJ
Adding a Folder via Browser Automation
- Navigate to
http://127.0.0.1:8384
- Dismiss setup dialogs (click through: Yes for usage reporting, OK for crash reporting, OK for auth warnings)
- Click "Add Folder" button
- In the modal:
- Set Folder Label (e.g., "CPNS-2026")
- Set Folder ID (e.g., "cpns-2026") — must match on all devices
- Set Folder Path (e.g.,
/Users/adityahimawan/Documents/Obsidian/CPNS-2026)
- Click "Save"
Adding a Remote Device
- Click "Add Remote Device" in the Devices section
- Enter the remote device's full Device ID (from their Syncthing app)
- Give it a friendly name (e.g., "Adit's Android")
- Click "Save"
Folder Sharing Setup
After devices are paired:
- Click on the shared folder in the Folders section
- Go to the "Sharing" tab
- Check the remote device
- Click "Save"
Android Setup Instructions (tell the user)
- Install Syncthing from Play Store (or Syncthing-Fork from F-Droid)
- Open app → accept TOS
- Note the Device ID (menu → ID & Alamat Jarak Jauh)
- Exchange Device IDs between Mac and Android
- Accept folder share on Android and set sync path to:
/storage/emulated/0/Documents/Obsidian/CPNS-2026
Obsidian Android Setup
- Open Obsidian Android → "Open folder as vault"
- Navigate to the Syncthing sync folder
- Notes will auto-sync both directions
Multi-Vault Configuration
When syncing multiple folders (e.g., CPNS-2026 + Notes vaults), you need one <folder> element per vault in config.xml. Each folder must have:
- Unique
id attribute
- Correct
path attribute
- A
<device> child with the paired device ID
Example config structure (2 folders):
<folder id="cpns-2026" label="CPNS-2026" path="/Users/adityahimawan/Documents/Obsidian/CPNS-2026" ...>
<device id="DEVICE_ID" introducedBy=""><encryptionPassword /></device>
...
</folder>
<folder id="notes" label="Notes" path="/Users/adityahimawan/Documents/Obsidian/Notes" ...>
<device id="DEVICE_ID" introducedBy=""><encryptionPassword /></device>
...
</folder>
Config Editing Patterns
ALWAYS backup before editing:
cp ~/Library/Application\ Support/Syncthing/config.xml ~/Library/Application\ Support/Syncthing/config.xml.bak
Safe Python XML edit pattern (avoid list.remove errors):
import xml.etree.ElementTree as ET
tree = ET.parse(config_path)
root = tree.getroot()
for la in list(options.findall('listenAddress')):
options.remove(la)
Quick text fix (when XML editing is overkill):
brew services stop syncthing
brew services start syncthing
lsof -i :22000
lsof -i :8384
grep -c "tcp://default" config.xml
Renaming a Vault
When renaming a vault folder on macOS:
- Rename the folder on disk:
mv OldName NewName
- Stop syncthing:
brew services stop syncthing
- Update config.xml
path and label attributes to match
- Also update folder
id if you want consistency
- Restart syncthing:
brew services start syncthing
- On Android: delete old folder entry in Syncthing app, add new one with matching folder ID
The folder ID must match between Mac and Android — if you change it on one side, the other side will reject the sync.
Troubleshooting
| Problem | Fix |
|---|
| Devices "Disconnected (Inactive)" — CRITICAL BUG | Check if port 22000 is listening: lsof -i :22000. If empty, config has <listenAddress>tcp://default</listenAddress> which means "resolve hostname 'default'" — not a keyword! Fix: Stop syncthing → edit config.xml → replace <listenAddress>tcp://default</listenAddress> with <listenAddress>tcp://0.0.0.0:22000</listenAddress> AND add <listenAddress>quic://0.0.0.0:22000</listenAddress> → restart syncthing. Also check <defaults><device> section for stale <listenAddress> entries and remove them. |
| CSRF errors on API calls | Use browser automation instead of curl/API |
| Devices not discovering each other | Make sure both are on same WiFi or enable global discovery |
| Folder not syncing | Check folder is shared with the device in both directions |
| Permission denied on Android | Grant "All files access" or specific folder permission to Syncthing app |
| Syncthing service won't start | Check brew services list, try brew services restart syncthing |
| Log shows "lookup default: no such host" | This confirms the tcp://default hostname resolution bug — see fix above |
| Port 22000 not listening after restart | Check for ALL <listenAddress> elements in config.xml (both <options> AND <defaults><folder> sections). Replace any with tcp://default to tcp://0.0.0.0:22000 |
| Python XML tree.remove(x) error | ValueError: list.remove(x): x not in list happens when trying to remove elements while iterating. Always use list(element.findall('tag')) to create a copy before removing |
| Syncthing says "lookup default: no such host" | This is NOT a DNS issue — it means <listenAddress>tcp://default</listenAddress> in config.xml. Syncthing treats "default" as a literal hostname to resolve, not a keyword. Search for ALL occurrences: grep -n "tcp://default|quic://default|default:22000" config.xml. This can appear in BOTH <options> AND <defaults><folder> sections. The <defaults><folder><listenAddress> variant is easy to miss and is a common cause of persistent failures even after "fixing" the <options> section |
Pitfalls
tcp://default is NOT a keyword — Syncthing interprets this as "resolve the hostname 'default'" which fails with "no such host". This is a common issue on first-time macOS setup where brew pours a bad default config. Always verify port 22000 is listening with lsof -i :22000 after setup.
- Don't use the REST API for configuration — CSRF protection makes it unreliable. Browser automation (browser_click, browser_type) works consistently.
- Editing config.xml is sometimes necessary — normally use GUI, but the
tcp://default bug requires direct XML edit. Only modify <listenAddress> elements in both <options> and <defaults> sections.
- Device IDs must be exchanged in BOTH directions — Mac adds Android AND Android adds Mac, otherwise they can't connect.
- Folder path on Android uses different conventions —
/storage/emulated/0/ is the standard internal storage root, not ~ or /Users/.
- "Listeners 0/1" in GUI = broken connection — If the GUI shows 0/1 listeners, port binding failed and devices will never connect.
.stfolder/ marker required — Every Syncthing folder MUST have a .stfolder/ directory in its root, or Syncthing shows "folder marker missing" error and shows "Out of Sync" with 0 inSyncFiles even when files exist. Fix: mkdir -p /path/to/vault/.stfolder && touch /path/to/vault/.stfolder/.syncthingignore then force rescan with API.
- Force rescan fixes out-of-sync — When local ≠ global state, after fixing the root cause (e.g., adding
.stfolder), rescan: curl -s -X POST "http://127.0.0.1:8384/rest/db/scan?folder=<id>" -H "X-API-Key: <key>"