msg
A terminal iMessage client for macOS.
Read, send, and monitor your iMessage conversations without leaving the terminal.
Quick Start
1. Install Go
brew install go
2. Grant Full Disk Access
Your terminal needs permission to read ~/Library/Messages/chat.db:
System Settings > Privacy & Security > Full Disk Access > add your terminal app (Ghostty, iTerm2, Terminal, etc.)
Restart your terminal after granting access.
3. Build and Install
git clone https://github.com/jdubba1/imsg-tui.git
cd imsg-tui
sudo make install
This builds the binary and installs it to /usr/local/bin/msg.
4. Set Up Your Favorites
On first run, msg opens to the Favorites view which will be empty. The fastest way to get started: tell your preferred CLI agent (Claude Code, Cursor, etc.) to look at your contacts.json and build a favorites list with your most-texted contacts. Or edit the config manually:
msg # first run: creates ~/.config/imsg-tui/
Then edit ~/.config/imsg-tui/config.json:
{
"favorites": ["Alex", "Jordan", "Sam"]
}
You can also press 2 for all known contacts or 3 for all conversations without configuring favorites.
contacts.json is auto-generated from your macOS Contacts.app. Edit it to add nicknames or fix names:
{
"+15551234567": "Alex",
"jordan@icloud.com": "Jordan"
}
5. Run
msg # opens to most recent conversation
msg alex # opens directly to Alex
msg jordan # opens directly to Jordan
Demo Mode
Try it out without Full Disk Access or a real Messages database:
msg --demo
This launches with seeded conversations and fake contacts so you can explore the UI.
Keybindings
| Key |
Action |
↑↓←→ |
Navigate conversations |
tab |
Toggle chat list / input focus |
1 2 3 |
Favorites / Contacts / All |
enter |
Send message (from input) |
scroll |
Mouse scroll on either pane |
click |
Click a chat to open |
h |
Toggle help bar |
q |
Quit (from chat list) |
ctrl+c |
Force quit |
How It Works
- Reading: queries
~/Library/Messages/chat.db directly (read-only)
- Sending: shells out to
osascript which tells Messages.app to send
- Polling: checks for new messages every 3 seconds
- Contacts: reads macOS Contacts.app database, overlays with your
contacts.json
- Drafts: unsent message text is preserved per-conversation when switching chats
Config Options
All options go in ~/.config/imsg-tui/config.json:
{
"favorites": ["Alex", "Jordan"],
"sidebar_width": 22,
"sent_color": "#79b8ff",
"recv_color": "#f8f8f8",
"placeholder": "message",
"poll_seconds": 3,
"show_help": true
}
Known Limitations
- 1:1 only — group chats are filtered out
- Can't start new conversations — you can only reply to existing chats. To message someone new, send them a message from Messages.app first, then it'll appear in
msg
- No typing indicators — Apple doesn't persist typing status to the database
- No read receipts sending — opening a chat in
msg won't mark it as read in Messages.app (see Experimental: Mark Read to opt in)
- No message effects — invisible ink, slam, confetti, echo, etc. display as plain text (the text content is still readable)
- No image/attachment viewing — attachments show as
[image], [video], etc.
- Reactions are read-only — you can see reactions but can't add them
- macOS only — depends on
chat.db and osascript
Experimental: Mark Read
Opt in to syncing read status back to Messages.app when you open a chat in msg. This writes directly to chat.db.
{
"experimental_mark_read": true
}
Warnings:
- May conflict with Messages.app's own write operations
- Messages.app may overwrite changes on next sync
- If anything goes wrong, set
"experimental_mark_read": false and restart Messages.app
- WAL journaling means writes are relatively safe but not guaranteed conflict-free
When enabled, a warning is printed to stderr on startup: experimental_mark_read enabled
Uninstall
sudo rm /usr/local/bin/msg
rm -rf ~/.config/imsg-tui
License
MIT