aboutsummaryrefslogtreecommitdiff
path: root/README.org
blob: 3606b865222e28a3ae3f21f2d117557baa7a11f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
* CHIME Heralds Imminent Modeline Events

[[#features][Features]] | [[#installation][Installation]] | [[#quick-start][Quick Start]] | [[#documentation][Documentation]] | [[#development--testing][Development & Testing]] | [[#history][History]]

[[https://www.gnu.org/software/emacs/][file:assets/made-for-emacs-badge.svg]]

" /I love deadlines. I love the whooshing noise they make as they go by./ "
— /Douglas Adams/

CHIME (backronym: *CHIME Heralds Imminent Modeline Events*) makes sure your org-agenda events don't whoosh by unnoticed. You get desktop notifications, an audible chime, and your next event shows up in the modeline.

** Features
:PROPERTIES:
:CUSTOM_ID: features
:END:

- Desktop notifications with configurable alert intervals and urgency
- Optional audible chime sound, using the bundled WAV or a custom file
- Interactive modeline display for the next timed event
- Hover tooltip with upcoming events grouped by day
- Left-click calendar URL and right-click jump-to-org-entry actions
- SCHEDULED, DEADLINE, plain timestamp, and repeating timestamp support
- 12-hour and 24-hour org timestamp parsing
- All-day event notifications for birthdays, holidays, and multi-day events
- Filtering by TODO keywords, tags, and custom predicates
- Async agenda checks so Emacs stays responsive
- [[https://github.com/cjennings/chime/tree/main/tests][Well-tested]], including with org-gcal

** Installation
:PROPERTIES:
:CUSTOM_ID: installation
:END:

Not on MELPA yet, but coming soon.

*Requirements:* Emacs 27.1+, org-mode 9.0+, and the =alert=, =dash=, and =async= packages. Package managers pull these automatically.

*** package-vc-install (Emacs 29+)

#+BEGIN_SRC elisp
(unless (package-installed-p 'chime)
  (package-vc-install "https://github.com/cjennings/chime"))
#+END_SRC

*** use-package with :vc (Emacs 29+)

#+BEGIN_SRC elisp
(use-package chime
  :vc (:url "https://github.com/cjennings/chime" :rev :newest)
  :after alert
  :commands (chime-mode chime-check chime-refresh-modeline)
  :bind ("C-c A" . chime-check)
  :config
  ;; Notify 5 minutes before and at event time.
  (setq chime-alert-intervals '((5 . medium) (0 . high)))

  ;; Keep the modeline focused on imminent events.
  (setq chime-modeline-lookahead-minutes 120)
  (setq chime-tooltip-lookahead-hours 168)

  ;; Default exclude rules skip done items and declined invitations.
  (setq chime-exclude-filters
        '((predicates . (chime-done-keywords-predicate
                         chime-declined-events-predicate))))

  (chime-mode 1))
#+END_SRC

*** straight.el

#+BEGIN_SRC elisp
(straight-use-package
 '(chime :type git :host github :repo "cjennings/chime"))
#+END_SRC

*** quelpa

#+BEGIN_SRC elisp
(quelpa '(chime :fetcher github :repo "cjennings/chime"))
#+END_SRC

*** Manual installation

#+BEGIN_SRC bash
git clone https://github.com/cjennings/chime.git ~/path/to/chime
#+END_SRC

#+BEGIN_SRC elisp
(add-to-list 'load-path "~/path/to/chime")
(require 'chime)
(chime-mode 1)
#+END_SRC

** Quick Start
:PROPERTIES:
:CUSTOM_ID: quick-start
:END:

Once you've installed chime, the only thing you actually need is:

#+BEGIN_SRC elisp
(chime-mode 1)
#+END_SRC

The defaults are intentionally usable: chime checks =org-agenda-files= every 60 seconds, notifies 10 minutes before events and again at event time, plays the bundled chime sound, and shows the next timed event in the modeline. Make sure your calendar org files are in =org-agenda-files=.

Modeline interaction:

- *Hover* to see upcoming events grouped by day
- *Left-click* to open =chime-calendar-url=, when configured
- *Right-click* to jump to the next event's org entry

Manual commands:

#+BEGIN_SRC elisp
M-x chime-check             ; refresh and send due notifications
M-x chime-refresh-modeline  ; refresh modeline only, without notifications
M-x chime-validate-configuration
#+END_SRC

** Documentation
:PROPERTIES:
:CUSTOM_ID: documentation
:END:

- [[file:docs/CONFIGURATION.org][Configuration]] — alert intervals, modeline, tooltip, filtering, all-day events, and advanced settings
- [[file:docs/ARCHITECTURE.org][Architecture]] — state flow, async retrieval, event data structures, and subsystem boundaries
- [[file:docs/INTEGRATIONS.org][Integrations]] — org-gcal and org-contacts setup notes
- [[file:docs/TROUBLESHOOTING.org][Troubleshooting]] — debug mode, missing notifications, sound issues, event detection, and duplicate notifications
- [[file:TESTING.org][Testing]] — running and writing the ERT test suite

*** Minimal Configuration Examples

Notify at event time only:

#+BEGIN_SRC elisp
(setq chime-alert-intervals '((0 . high)))
#+END_SRC

Use a compact modeline:

#+BEGIN_SRC elisp
(setq chime-modeline-format " ⏰ %s")
(setq chime-notification-text-format "%t (%u)")
(setq chime-time-left-formats
      '((at-event . "now")
        (short    . "%mm")
        (long     . "%hh%mm")))
#+END_SRC

Disable sound:

#+BEGIN_SRC elisp
(setq chime-sound-file nil)
#+END_SRC

Filter out done items and declined invitations:

#+BEGIN_SRC elisp
(setq chime-exclude-filters
      '((predicates . (chime-done-keywords-predicate
                       chime-declined-events-predicate))))
#+END_SRC

** Development & Testing
:PROPERTIES:
:CUSTOM_ID: development--testing
:END:

Clone the repo and load from source:

#+BEGIN_SRC bash
git clone https://github.com/cjennings/chime.git
#+END_SRC

#+BEGIN_SRC elisp
(add-to-list 'load-path "~/path/to/chime")
(require 'chime)
#+END_SRC

Quick test commands:

#+BEGIN_SRC bash
make test
make test-file FILE=modeline
make coverage
#+END_SRC

See [[file:TESTING.org][TESTING.org]] for the full test guide.

** History
:PROPERTIES:
:CUSTOM_ID: history
:END:

CHIME started life as [[https://github.com/akhramov/org-wild-notifier.el][org-wild-notifier]], written by Artem Khramov. I relied on it daily for years, so when Artem archived the repo and stopped responding to issues in August 2025, I adopted it rather than let it rot. One bug fix led to another, features crept in, and eventually it had changed enough to deserve its own name.

Org-wild-notifier itself has since been picked back up under the [[https://github.com/emacsorphanage/org-wild-notifier][Emacs Orphanage]]. Chime continues on its own line because it has materially diverged — see the [[#features][Features]] list for what it adds.

All credit for the original idea and architecture goes to Artem. I'm just the person who couldn't let it go.

Bug reports, feature requests, and PRs are welcome — consider this repo CHIME's permanent home.

*** Migration from org-wild-notifier

If you're migrating from org-wild-notifier, update your configuration:

1. Change package name:
   - =(require 'org-wild-notifier)= → =(require 'chime)=

2. Update all configured variable names:
   - =org-wild-notifier-*= → =chime-*=

3. Update configured function names:
   - =org-wild-notifier-mode= → =chime-mode=
   - =org-wild-notifier-check= → =chime-check=

4. The per-event reminder property is back. =:CHIME_NOTIFY_BEFORE: N= on a heading (N = a non-negative integer number of minutes) overrides =chime-alert-intervals= for that heading. The old =:WILD_NOTIFIER_NOTIFY_BEFORE:= name still works as a deprecated alias (chime warns once per session). See [[file:docs/CONFIGURATION.org][Configuration]] → "Per-Event Override".

** License
:PROPERTIES:
:CUSTOM_ID: license
:END:

[[file:LICENSE][GPL-3.0]]