* Noise Noise is a Signal Messenger client in Elisp for Emacs powered by https://github.com/AsamK/signal-cli Its ultimate goal is to provide a fast and efficient user interface for Signal chats. ** Tech stack The tech stack is Elisp and SQLite (for storing conversations) ** Setup The project assumes a working installation of signal-cli and interfaces with that via JSON-RPC. Noise uses Server-Sent Events (SSE) to receive messages in real-time. ** Dependencies For SQLite access we use this library - https://github.com/pekingduck/emacs-sqlite3-api We communicate with signal-cli via JSON-RPC over HTTP on localhost port 8080 by default but this can be configured by specifying =noise-signal-cli-address= ** User Experience We follow Emacs conventions for keybindings with the addition of evil support out of the box. When evil compatibility is enabled then we provide a modal interface for searching conversations/contacts, creating conversations, sending messages, etc. ** User Interface See the file signal-emacs-ui.html for user interface mockups we're targeting. ** Installation *** signal-cli Install =signal-cli= and start the daemon in JSON-RPC mode: #+begin_src shell # Install signal-cli (example using the official tarball) wget https://github.com/AsamK/signal-cli/releases/latest/download/signal-cli.tar.gz tar xf signal-cli.tar.gz # Register or link your device signal-cli link -n "emacs-noise" # Start the daemon on default port 9128 signal-cli daemon --receive-mode=manual #+end_src *** emacs-sqlite3-api Noise requires the =emacs-sqlite3-api= library for SQLite access. Install it with your package manager of choice, then set up Noise itself. *** Noise Package Below are recipes for several popular Emacs package managers. **** elpaca #+begin_src elisp (use-package noise :ensure (noise :host github :repo "git.roo.lol/jbrechtel/noise" :protocol https) :config ;; Optional: set a custom signal-cli address ;; (setq noise-signal-cli-address "http://localhost:8080") ;; Required when signal-cli has multiple accounts registered: ;; (setq noise-account "+15551234567") ;; Start Noise automatically (noise-mode 1)) #+end_src Or, if you prefer the =elpaca= recipe directly without =use-package=: #+begin_src elisp (elpaca (noise :host github :repo "git.roo.lol/jbrechtel/noise" :protocol https)) (require 'noise) (noise-mode 1) #+end_src **** straight.el #+begin_src elisp (straight-use-package '(noise :type git :host github :repo "git.roo.lol/jbrechtel/noise" :protocol https)) (require 'noise) (noise-mode 1) #+end_src **** Quelpa #+begin_src elisp (quelpa '(noise :fetcher github :repo "git.roo.lol/jbrechtel/noise")) (require 'noise) (noise-mode 1) #+end_src **** Manual / package-vc-install (Emacs 29+) #+begin_src elisp (package-vc-install "https://git.roo.lol/jbrechtel/noise") (require 'noise) (noise-mode 1) #+end_src **** Manual clone #+begin_src shell git clone https://git.roo.lol/jbrechtel/noise ~/.emacs.d/manual-packages/noise #+end_src Then in your init file: #+begin_src elisp (add-to-list 'load-path "~/.emacs.d/manual-packages/noise") (require 'noise) (noise-mode 1) #+end_src ** Usage Once signal-cli is running and Noise is installed: - =M-x noise-mode= — toggle the Noise client (opens the chat list) - =M-x noise-check-connection= — test connectivity to signal-cli - =M-x noise-select-account= — pick which registered signal-cli account to use (sets =noise-account=) - =M-x noise-new-chat= — start a new conversation by searching contacts - =M-x noise-new-chat-sync-contacts= — re-sync contacts from signal-cli - =M-x noise-receive= — fetch new messages from signal-cli once While =noise-mode= is enabled, Noise connects to signal-cli's SSE endpoint at =/api/v1/events= for real-time message reception. Incoming messages, delivery/read receipts, typing indicators, and messages sent from your other linked devices are all stored locally and reflected in open buffers automatically. The SSE connection automatically reconnects with exponential backoff if the connection is lost. You can configure the maximum reconnect delay via =noise-sse-max-reconnect-delay= (default 60 seconds). If signal-cli has more than one account registered, set =noise-account= to the phone number you want to use (E.164 format), or run =M-x noise-select-account= to choose interactively. With a single account it can stay nil. *** Keybindings **** Chat list (*signal* buffer) | Key | Action | |-------+---------------------------| | =n= | Next chat | | =p= | Previous chat | | =RET= | Open selected chat | | =c= | New chat (search contacts) | | =m= | Mark chat as read | | =g= | Refresh chat list | | =/= | Filter chats | | =q= | Quit chat list window | | =C-x b= | Switch conversation (minibuffer) | **** Conversation buffer (*signal:NAME*) Compose inline at the =>= prompt at the bottom of the buffer. Message history above the prompt is read-only. | Key | Action | |-----------+---------------------------------| | =RET= | Send the composed message | | =M-RET= | Insert a newline (multi-line) | | =C-c C-g= | Refresh conversation from store | Sent messages show a =✓= once sent and =✓✓= once delivered or read. When the contact is typing, the modeline shows =NAME is typing…=. **** Minibuffer switcher =M-x noise-switcher= (or =C-x b= from the chat list) opens a fuzzy completion interface showing all conversations and contacts. Start typing to narrow, then press =RET= to open the selected conversation.