Read your Apple Messages from any machine.
imsgd runs on your signed-in Mac and keeps a portable replica.db in sync. imsgctl reads that replica on any other macOS or Linux machine — no Apple ID required on the reading end. Works locally too.
- List recent chats.
- Read message history for a chat.
- Filter history by start and end time.
- Include attachment metadata.
- Watch new message activity, including reactions.
- Emit JSON output for scripts and agents.
Source Mac:
brew install jpreagan/tap/imsgd
brew install jpreagan/tap/imsgctlRemote machine:
- Install
imsgctl. - Install
sqlite3_rsyncif the source Mac will publish a replica here.
This repo includes an agent skill for imsgctl at skills/imsgctl.
Install it from this public repo with:
npx skills add jpreagan/imsgkitThe installed skill helps an agent use imsgctl to check access, list chats, inspect message history, include attachment metadata, and watch new activity.
Some agents load new skills only when a session starts. If the skill does not appear immediately, start a new session or refresh skills in the agent runtime.
imsgctl starts imsgd locally as needed for live reads.
imsgctl health
imsgctl chats
imsgctl history --chat-id 42 --limit 20
imsgctl watch --chat-id 42 --reactionsBy default, imsgctl prefers ~/Library/Application Support/imsgkit/replica.db when a valid replica is present, otherwise falls back to ~/Library/Messages/chat.db.
You can always point to a specific database explicitly:
imsgctl chats --db ~/Library/Messages/chat.db
imsgctl history --db ~/Library/Application\ Support/imsgkit/replica.db --chat-id 42Many users will run imsgd sync on a signed-in Mac and imsgctl on a different machine.
- Create source-side sync config at
~/Library/Application Support/imsgkit/config.toml:
[replica]
publish = "user@remote:~/Library/Application Support/imsgkit/replica.db"
publish_interval_seconds = 5
remote_executable = "/opt/homebrew/bin/sqlite3_rsync"Use an explicit remote path in publish.
- macOS remote:
user@remote:~/Library/Application Support/imsgkit/replica.db - Linux remote:
user@remote:~/.local/share/imsgkit/replica.db
-
Prepare the remote path, ensure
sqlite3_rsyncis installed on the remote machine, and confirm the source Mac has SSH access to it. -
Start sync on the source Mac:
brew services start imsgdOr run it in the foreground:
imsgd sync- Read from the replica on the remote machine:
imsgctl chats
imsgctl history --chat-id 42 --limit 20
imsgctl watch --chat-id 42 --reactionsOn Linux, imsgctl reads ~/.local/share/imsgkit/replica.db by default, or $XDG_DATA_HOME/imsgkit/replica.db when XDG_DATA_HOME is set to an absolute path.
imsgd sync also maintains a sibling attachments/ directory next to replica.db, so replica-backed attachment paths reported by imsgctl point to files on the consuming machine rather than paths on the source Mac.
On the source Mac, imsgkit reads:
~/Library/Messages/chat.db- Apple Contacts data through
Contacts.framework
For Messages access on macOS, grant Full Disk Access to whatever is doing the reading:
- If you run
imsgctlorimsgdmanually in Terminal, Terminal needs Full Disk Access. - If you run
imsgdwithbrew services, grant Full Disk Access to the exact Homebrew service binary path, for example/opt/homebrew/opt/imsgd/bin/imsgdon Apple Silicon or/usr/local/opt/imsgd/bin/imsgdon Intel Macs. - In
System Settings > Privacy & Security > Full Disk Access, if/optis hard to browse in the file picker, pressShift+Command+Gand enter the path directly.
If Contacts permission is unavailable, imsgkit still works, but falls back to raw identifiers where necessary.
swift build
swift test
cd imsgctl
go build ./...
go test ./...