Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

87 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Go Bubble Tea Docs

keyboard-first terminal client for imessage, backed by a bluebubbles-compatible server.

== features ==

  real-time updates over socket.io/websocket, with api polling as a reconciliation path
  multi-pane chat layout with horizontal/vertical splits, up to 4 panes per-pane focus
  unread msg indicators, layout + message-cache persistence chat list with activity
   ordering, unread markers, timestamps, previews, search, resizable width
  chat delete + rename, with local alias fallback for unsupported server-side renames
  optional timestamps, line numbers, sender labels, pane dividers, chat previews
  image attachment labels + /img #N, click-to-open, selected-row Enter open
  youtube / spotify / instagram / news-site link previews via oembed, html metadata,
   or a configurable preview proxy.
  tapbacks render as compact emoji on the original message
  optimistic outgoing messages with timeout reconciliation
  mouse support: focus, chat-list resize, pane-divider resize, image open, scroll
== requirements ==

  go 1.24+
  a running bluebubbles-compatible server
  network access from this client to the bluebubbles http + websocket endpoints
== configuration ==

  read from env vars and ~/.config/imessage-tui/imessage.yaml; env overrides the file.
  credentials prefer the os keyring and fall back to the config file.
  ui/layout state, message cache, and chat aliases live under ~/.config/imessage-tui/

  server_url                BB_SERVER_URL               required  bluebubbles url
  password                  BB_PASSWORD                 required  api password
  message_limit             BB_MESSAGE_LIMIT            50        messages per chat
  chat_limit                BB_CHAT_LIMIT               50        chats in the sidebar
  poll_interval_sec         BB_POLL_INTERVAL_SEC        10        refresh; 0 disables
  enable_link_previews      BB_ENABLE_LINK_PREVIEWS     true      preview metadata
  max_previews_per_message  BB_MAX_PREVIEWS_PER_MESSAGE 2         previews per message
  preview_proxy_url         BB_PREVIEW_PROXY_URL        empty     optional json proxy
  oembed_endpoint           BB_OEMBED_ENDPOINT          noembed   oembed endpoint
  (env only)                BB_INSECURE_TLS             unset     skip tls verify (self-signed; insecure)
  theme                     BB_THEME                    auto      auto|light|dark terminal background

  theme: only sets what lipgloss reports for the terminal background. the
  palette no longer branches on it — every colour is chosen to stay readable
  on light and dark alike, and message text carries no colour at all so it
  inherits the terminal's own foreground. leave it on auto unless a plugin or
  future style needs it pinned.
# ~/.config/imessage-tui/imessage.yaml
server_url: "https://your-server:1234"
password: "your-api-password"
message_limit: 50
chat_limit: 50
poll_interval_sec: 10
enable_link_previews: true
max_previews_per_message: 2
# build and run -- runtime logs go to ~/.imessage-tui.log
go test ./...
go build -o imessage-tui .
./imessage-tui
== keybindings ==

single-letter shortcuts (? q d r g G /) and the plain arrow keys only act when
you are not typing. with the message composer or chat search focused they edit
text instead — `?` writes a question mark, `←/→` move the cursor. shortcuts
that use ctrl/alt/shift work everywhere, including mid-message.

`tab`
  toggle focus between chat list and current window
`esc`
  return to the chat list
`← / →`
  move the cursor while writing; move between windows otherwise
`shift+← / shift+→`
  move between windows, also while writing
`ctrl+↑ / ctrl+↓`
  move to the window above or below
`↑ / ↓` or `k / j`
  move the cursor while writing; navigate chats or scroll messages otherwise
`g`
  jump to top of chat list
`G`
  jump to bottom of chat list
`enter`
  open selected chat or send from the input
`shift+enter`
  insert a newline in the input

== window management ==

`ctrl+f`
 split the focused window horizontally
`ctrl+g`
 split the focused window vertically
`ctrl+w`
 close the focused window

`ctrl+S`
  toggle chat list visibility
`ctrl+T`
  toggle message timestamps
`ctrl+N`
  toggle message line numbers
`ctrl+B`
  toggle sender names (show text only when off)
`alt+M`
  toggle sender names (alternative binding)
`q` / `ctrl+C`
  quit

there is no persistent status bar. prompts you have to act on — delete/rename confirmations, errors, toasts — appear on the bottom row while they are live and disappear again; unread chats are marked in the chat list and with a ● on pane headers.

== emoticons ==

the composer rewrites text emoticons as emojis. an emoticon has to stand as its
own whitespace-delimited word, so "hej :)" converts and "http://x" does not.

  <3 </3 :) :-) =) :( ;) :| :* 8) :'( \o/   convert the moment you type them
  :D :P :p :O :o xD XD :/ :\ B) o/          convert on the next space, or on send

the second group waits for a word boundary so ":Down" and "xDrive" survive and
urls keep their "://". a rewrite is skipped while the cursor sits behind the end
of the text, so editing earlier in a draft never moves you to the end.

== chat management ==

delete uses the bluebubbles private api (DELETE /api/v1/chat/{guid}/delete) and clears local cachet only after the server confirms: press d on a chat, then D to confirm, Esc to cancel. rename uses the group-rename api when available; if rejected, the tui saves an alias in ~/.config/imessage-tui/chat_overrides.json and applies it on refresh.


== link previews ==

supported media urls render a compact preview line, e.g.

[YouTube] video title [Spotify] track/playlist title [Instagram] post/reel [Aftonbladet] article title

hosts: youtube.com m.youtube.com youtu.be spotify.com open.spotify.com instagram.com m.instagram.com aftonbladet.se expressen.se dn.se svd.se svt.se omni.se gp.se sydsvenskan.se di.se. fetches are async (fallback label first, then metadata) prefer html metadata so generic titles like "search" are ignored and refetched.


== bluebubbles setup ==

bluebubbles must run on a mac signed into icloud with messages enabled; grant full disk access, accessibility, and automation to the server app.

verify connectivity; curl -k "https://your-server/api/v1/server/info?password=YOUR_PASSWORD" use the same url + password as BB_SERVER_URL and BB_PASSWORD.


```text
== architecture ==

main.go    bubble tea program startup
api/       bluebubbles http client, contacts, attachments, link previews
config/    config loading, credentials, ui/layout/message-cache state
models/    chat, message, attachment, link-preview, websocket event types
tui/       bubble tea models, split layout, rendering, input, persistence
ws/        socket.io/websocket client with reconnect + overflow signals
== tests + release checks ==

go test ./...        # api shape, de-dup, ordering, tapbacks, layout, previews
gofmt -w $(git ls-files '*.go')
go build ./...
git diff --check
== troubleshooting ==
* tls errors: verify server url, certificate trust, and password.
  certs are verified by default; for a self-signed server set BB_INSECURE_TLS=1 (insecure).
* missing names: ensure contacts are available to bluebubbles.
* stale chats: verify websocket connectivity;
  polling reconciles open chats when enabled.
* build errors on modern stdlib packages: ensure go 1.24+ is first on PATH.

About

Keyboard-first iMessage TUI with split panes, real-time updates, local cache, and session restore. Built in Go with Bubble Tea.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages