Skip to main content

Background Daemon

Matcha includes an optional background daemon that keeps email connections alive, syncs mail, and sends desktop notifications — even when the TUI is closed.

Features

  • Always-On IMAP IDLE: Maintains persistent connections to detect new mail instantly.
  • Periodic Sync: Fetches new emails every 5 minutes for all accounts.
  • Desktop Notifications: Sends notifications when new mail arrives and the TUI is not running.
  • Instant TUI Startup: When the TUI connects to a running daemon, email data is immediately available.
  • Automatic Fallback: If the daemon is not running, the TUI works exactly as before (direct mode).

Commands

matcha daemon start # Start the daemon in the background
matcha daemon stop # Stop the running daemon
matcha daemon status # Show daemon status (PID, uptime, accounts)
matcha daemon run # Run the daemon in the foreground (for systemd/launchd)

How It Works

The daemon runs as a separate background process. It communicates with the TUI over a Unix domain socket using a JSON-based protocol.

┌─────────────┐ Unix Socket ┌──────────────────┐
│ TUI Client │◄──── JSON-RPC ─────►│ Daemon │
│ (matcha) │ bidirectional │ (matcha daemon) │
└─────────────┘ └──────────────────┘

When you open the TUI:

  1. It tries to connect to the daemon socket.
  2. If the daemon is running, the TUI subscribes to folder updates and receives real-time push events.
  3. If the daemon is not running, the TUI falls back to direct mode — identical to previous behavior.

Status

$ matcha daemon status
Daemon running (PID 12345)
Uptime: 2h 15m
Accounts: 2
- alice@gmail.com
- bob@outlook.com

Running as a System Service

systemd (Linux)

Create ~/.config/systemd/user/matcha-daemon.service:

[Unit]
Description=Matcha Email Daemon
After=network-online.target

[Service]
ExecStart=/usr/bin/matcha daemon run
Restart=on-failure
RestartSec=5

[Install]
WantedBy=default.target
systemctl --user enable matcha-daemon
systemctl --user start matcha-daemon

launchd (macOS)

Create ~/Library/LaunchAgents/com.matcha.daemon.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.matcha.daemon</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/matcha</string>
<string>daemon</string>
<string>run</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>
launchctl load ~/Library/LaunchAgents/com.matcha.daemon.plist

File Paths

FilePlatformPurpose
$XDG_RUNTIME_DIR/matcha/daemon.sockLinuxUnix domain socket
$XDG_RUNTIME_DIR/matcha/daemon.pidLinuxPID file
~/Library/Caches/matcha/daemon.sockmacOSUnix domain socket
~/Library/Caches/matcha/daemon.pidmacOSPID file

Architecture

The daemon is split across three packages:

  • daemonrpc/ — Shared protocol definitions (request/response types, event types, transport layer). Used by both daemon and client.
  • daemon/ — The daemon process itself: lifecycle management, RPC handlers, IDLE watchers, periodic sync, PID file management, signal handling.
  • daemonclient/ — Client library with a Service interface that abstracts daemon mode vs direct mode. The TUI uses this interface transparently.