From 0772736d2bca36472f623d5258784f41db9b4f9a Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sun, 10 May 2026 16:36:31 -0500 Subject: docs: split detailed user docs out of readme --- docs/ARCHITECTURE.org | 259 +++++++++++++++++++++++++++++ docs/CONFIGURATION.org | 420 +++++++++++++++++++++++++++++++++++++++++++++++ docs/INTEGRATIONS.org | 109 ++++++++++++ docs/TROUBLESHOOTING.org | 180 ++++++++++++++++++++ 4 files changed, 968 insertions(+) create mode 100644 docs/ARCHITECTURE.org create mode 100644 docs/CONFIGURATION.org create mode 100644 docs/INTEGRATIONS.org create mode 100644 docs/TROUBLESHOOTING.org (limited to 'docs') diff --git a/docs/ARCHITECTURE.org b/docs/ARCHITECTURE.org new file mode 100644 index 0000000..f05f36c --- /dev/null +++ b/docs/ARCHITECTURE.org @@ -0,0 +1,259 @@ +#+TITLE: Chime Architecture +#+AUTHOR: Craig Jennings + +Architecture notes for contributors and reviewers. + +[[file:../README.org][README]] | [[file:CONFIGURATION.org][Configuration]] | [[file:INTEGRATIONS.org][Integrations]] | [[file:TROUBLESHOOTING.org][Troubleshooting]] | [[file:../TESTING.org][Testing]] + +* Overview + +Chime is a small event pipeline around =org-agenda=. It periodically asks org for upcoming entries, converts those entries into serializable event alists, then uses that event list for notifications, modeline text, tooltip content, and jump-to-source actions. + +The central design constraint is responsiveness: agenda scanning can be slow for large org collections, so Chime does that work in an async Emacs subprocess and keeps the interactive Emacs session limited to scheduling, callbacks, rendering, and notification dispatch. + +* Runtime Flow + +#+BEGIN_EXAMPLE +chime-mode + | + v +chime--start + | + v +timer -> chime-check + | + v + chime--maybe-validate + | + v + chime--fetch-and-process + | + v + async child process + | + v + chime--retrieve-events + | + v + org-agenda-list -> markers -> filters -> chime--gather-info + | + v + event alists returned to parent process + | + v + chime--handle-async-success + | + v + callback + | | + v v +chime--process-events chime--update-modeline + | | + v v +chime--notify chime-modeline-string +#+END_EXAMPLE + +Manual refresh uses the same validation and async retrieval path, but supplies a modeline-only callback so it does not send notifications: + +#+BEGIN_EXAMPLE +M-x chime-refresh-modeline + -> chime--maybe-validate + -> chime--fetch-and-process + -> chime--update-modeline +#+END_EXAMPLE + +* Major Components + +** Lifecycle + +=chime-mode= controls the package lifecycle. Enabling the mode calls =chime--start=, which installs a timer. Disabling the mode calls =chime--stop=, which cancels the timer, interrupts any active async process, and resets validation state. + +Key state: + +- =chime--timer= — active polling timer +- =chime--process= — currently running async process, if any +- =chime--last-check-time= — last event check time +- =chime--validation-done= — whether startup validation has succeeded +- =chime--validation-retry-count= — retry counter for startup validation + +** Validation + +=chime--maybe-validate= gates event retrieval. It gives startup configuration a chance to populate =org-agenda-files= before Chime starts checking. + +=chime-validate-configuration= is also interactive. Interactively, it prints a checklist to =*Messages*=. Programmatically, it returns issue pairs so callers can decide whether to continue. + +** Async Retrieval + +=chime--retrieve-events= returns the child-process form used by async.el. The child process: + +1. Receives selected parent variables through =async-inject-variables=. +2. Initializes package.el. +3. Requires =chime=. +4. Runs =org-agenda-list= for the required lookahead span. +5. Extracts org markers from agenda line text properties. +6. Applies include/exclude filters. +7. Converts markers to event alists with =chime--gather-info=. + +The parent process receives only plain Lisp data. This is why event source identity is stored as file path and buffer position rather than as live marker objects. + +** Event Processing + +=chime--process-events= handles notification dispatch. It combines: + +- timed notifications from =chime--check-event= +- day-wide notifications from =chime--day-wide-notifications= + +Timed notifications compare event timestamps against current time plus each configured alert interval. Day-wide notifications are handled separately because all-day timestamps have no clock component. + +** Modeline and Tooltip + +=chime--update-modeline= computes two related views: + +- =chime-modeline-string= — rendered text for the soonest timed event inside =chime-modeline-lookahead-minutes= +- =chime--upcoming-events= — sorted tooltip tuples inside =chime-tooltip-lookahead-hours= + +All-day events are never shown in the modeline itself because the modeline is clock-relative. They can appear in the tooltip and in day-wide notifications. + +The tooltip uses =chime--upcoming-events=, grouping entries by day and limiting display with =chime-modeline-tooltip-max-events=. + +* Data Structures + +** Event Alist + +The internal event shape is an alist created by =chime--make-event= and validated by =chime--valid-event-p=: + +#+BEGIN_SRC elisp +((times . (("<2026-05-10 Sun 09:30>" . (26760 32460)))) + (title . "Planning") + (intervals . ((10 . medium) (0 . high))) + (marker-file . "/path/to/agenda.org") + (marker-pos . 1234)) +#+END_SRC + +Keys: + +- =times= — list of timestamp entries +- =title= — sanitized display title +- =intervals= — alert intervals from =chime-alert-intervals= +- =marker-file= — source org file path, or nil for synthesized test events +- =marker-pos= — source buffer position, or nil for synthesized test events + +Use the accessors instead of open-coded =assoc= in production code: + +- =chime--event-times= +- =chime--event-title= +- =chime--event-intervals= +- =chime--event-marker-file= +- =chime--event-marker-pos= + +** Time Entry + +Each entry in =times= is: + +#+BEGIN_SRC elisp +(TIMESTAMP-STRING . PARSED-TIME) +#+END_SRC + +=TIMESTAMP-STRING= is the original org timestamp string. =PARSED-TIME= is a serialized Emacs time value for timed events, or nil for all-day events. + +Examples: + +#+BEGIN_SRC elisp +("<2026-05-10 Sun 09:30>" . (26760 32460)) +("<2026-05-10 Sun>" . nil) +#+END_SRC + +** Upcoming Event Tuple + +Tooltip state uses tuples derived from event alists: + +#+BEGIN_SRC elisp +(EVENT TIME-INFO MINUTES-UNTIL) +#+END_SRC + +Example: + +#+BEGIN_SRC elisp +(((times . ...) + (title . "Planning") + (intervals . ...) + (marker-file . "/path/to/agenda.org") + (marker-pos . 1234)) + ("<2026-05-10 Sun 09:30>" . (26760 32460)) + 15.0) +#+END_SRC + +These tuples are stored in =chime--upcoming-events= and are also passed through tooltip grouping and deduplication helpers. + +* Filtering + +Filtering happens in the async child before event alists are created: + +#+BEGIN_EXAMPLE +markers + -> chime--apply-include-filters + -> chime--apply-exclude-filters + -> chime--gather-info +#+END_EXAMPLE + +Filters operate on org markers, not event alists, so predicates can inspect org properties, tags, TODO state, and source files directly. + +=chime-include-filters= and =chime-exclude-filters= share the same shape: + +#+BEGIN_SRC elisp +((keywords . ("TODO" "NEXT")) + (tags . ("work")) + (predicates . (my-marker-predicate))) +#+END_SRC + +If include filters are configured, a marker must match at least one include predicate. Exclude filters then remove any matching marker. + +* org-gcal Handling + +Regular org entries use SCHEDULED and DEADLINE timestamps first, then plain timestamps in the entry body. + +org-gcal entries are different: Chime detects them by the =entry-id= property and extracts timestamps only from the =:org-gcal:= drawer. That drawer is the authoritative source after calendar syncs; planning lines or body timestamps can lag behind after remote edits. + +* Error Handling + +Async failures are tracked with =chime--consecutive-async-failures=. Repeated failures can trigger a warning controlled by =chime-max-consecutive-failures=. + +=chime--fetch-and-process= records failures from two places: + +- errors returned by the async process +- errors raised while the parent callback handles returned data + +Successful async processing resets the consecutive failure counter. + +* Navigation + +Modeline right-click uses the first item in =chime--upcoming-events=. Chime reconstructs source location from =marker-file= and =marker-pos=: + +#+BEGIN_EXAMPLE +chime--jump-to-first-event + -> chime--jump-to-event + -> find-file + -> goto-char + -> org-fold-show-entry / org-show-entry +#+END_EXAMPLE + +This works across the async boundary because the child returns file path and numeric position, not marker objects. + +* Testing Notes + +Tests build event alists through shared helpers in =tests/testutil-events.el= so fixtures stay aligned with the production event contract. + +Useful focused test files: + +- =tests/test-chime-event-contract.el= +- =tests/test-chime-gather-info.el= +- =tests/test-chime-check-event.el= +- =tests/test-chime-update-modeline.el= +- =tests/test-chime-update-modeline-helpers.el= +- =tests/test-chime-process-notifications.el= + +Run the full suite with: + +#+BEGIN_SRC sh +make test +#+END_SRC diff --git a/docs/CONFIGURATION.org b/docs/CONFIGURATION.org new file mode 100644 index 0000000..ae73071 --- /dev/null +++ b/docs/CONFIGURATION.org @@ -0,0 +1,420 @@ +#+TITLE: Chime Configuration +#+AUTHOR: Craig Jennings + +Reference for Chime's user-facing configuration. + +[[file:../README.org][README]] | [[file:ARCHITECTURE.org][Architecture]] | [[file:INTEGRATIONS.org][Integrations]] | [[file:TROUBLESHOOTING.org][Troubleshooting]] | [[file:../TESTING.org][Testing]] + +* Polling Interval + +Control how often chime checks for upcoming events: + +#+BEGIN_SRC elisp +;; Default: check every 60 seconds +(setq chime-check-interval 60) + +;; More responsive +(setq chime-check-interval 30) +#+END_SRC + +Lower values make notifications more responsive but increase system load. Higher values reduce polling overhead but may delay notifications slightly. + +Changes take effect after restarting =chime-mode=. + +* Alert Intervals + +Set when to receive notifications and their urgency levels using =(minutes . severity)= pairs: + +#+BEGIN_SRC elisp +;; Default: 10 minutes before and at event time +(setq chime-alert-intervals '((10 . medium) (0 . high))) + +;; Single notification at event time +(setq chime-alert-intervals '((0 . high))) + +;; Multiple notifications with escalating urgency +(setq chime-alert-intervals + '((10 . low) + (5 . medium) + (0 . high))) +#+END_SRC + +Severity levels are =high=, =medium=, and =low=. They are passed to [[https://github.com/jwiegley/alert][alert.el]], which maps them to your notification style or daemon. + +* Chime Sound + +#+BEGIN_SRC elisp +;; Disable sound entirely +(setq chime-sound-file nil) + +;; Use a custom WAV or AU file +(setq chime-sound-file "/path/to/chime.wav") +#+END_SRC + +Chime uses Emacs's built-in =play-sound-file=. WAV and AU are the safest formats. + +* Notification Icon + +#+BEGIN_SRC elisp +;; Use a custom icon +(setq chime-notification-icon "/path/to/icon.png") + +;; Use the system/default alert icon +(setq chime-notification-icon nil) +#+END_SRC + +The icon is passed through to alert.el. PNG is the safest cross-platform choice. + +* Startup Delay + +Chime waits before the first check after enabling =chime-mode= so =org-agenda-files= and related config can finish loading. + +#+BEGIN_SRC elisp +;; Default +(setq chime-startup-delay 10) + +;; Increase if startup checks run before org-agenda-files is populated +(setq chime-startup-delay 20) +#+END_SRC + +* Modeline Display + +#+BEGIN_SRC elisp +;; Enable modeline display +(setq chime-enable-modeline t) + +;; Show events up to 2 hours ahead +(setq chime-modeline-lookahead-minutes 120) + +;; Customize the modeline prefix +(setq chime-modeline-format " ⏰ %s") +#+END_SRC + +The modeline displays the soonest timed event within the lookahead window and updates automatically on each check. + +** Minor Mode Lighter + +By default, the minor mode lighter is empty because the event display already indicates chime is running. + +#+BEGIN_SRC elisp +(setq chime-modeline-lighter " Chime") +#+END_SRC + +** No-Events Text + +Control what appears when no events are within the modeline lookahead window: + +#+BEGIN_SRC elisp +;; Default icon +(setq chime-modeline-no-events-text " ⏰") + +;; Show nothing +(setq chime-modeline-no-events-text nil) + +;; Custom text +(setq chime-modeline-no-events-text " No events") +#+END_SRC + +** Tooltip + +Hover over the modeline text to see upcoming events grouped by day. Configure the tooltip event limit: + +#+BEGIN_SRC elisp +;; Show up to 10 events +(setq chime-modeline-tooltip-max-events 10) + +;; Show all events in the lookahead window +(setq chime-modeline-tooltip-max-events nil) +#+END_SRC + +Customize the tooltip header: + +#+BEGIN_SRC elisp +(setq chime-tooltip-header-format + "Upcoming Events as of %a %b %d %Y @ %I:%M %p") +#+END_SRC + +Tooltip display strings are customizable for localization and plain-text +accessibility: + +#+BEGIN_SRC elisp +;; Section labels +(setq chime-tooltip-today-label "Today") +(setq chime-tooltip-tomorrow-label "Tomorrow") +(setq chime-tooltip-relative-day-format "%s, %b %d") +(setq chime-tooltip-future-day-format "%A, %b %d") + +;; Event lines and overflow +(setq chime-tooltip-event-format "%t at %T %u") +(setq chime-tooltip-more-events-format "... and %d more event%s") +(setq chime-tooltip-section-separator "─────────────") +(setq chime-tooltip-no-events-separator "─────────────────────") + +;; Tooltip-specific day/hour countdown words +(setq chime-tooltip-countdown-prefix "in") +(setq chime-tooltip-day-unit-labels '("day" . "days")) +(setq chime-tooltip-hour-unit-labels '("hour" . "hours")) + +;; No-events tooltip guidance +(setq chime-tooltip-no-events-format + "No calendar events in\nthe next %s.") +(setq chime-tooltip-increase-lookahead-format + "Increase `%s`\nto expand scope.") +(setq chime-tooltip-left-click-label "Left-click: Open calendar") +#+END_SRC + +** Tooltip Lookahead + +The tooltip can show events beyond the modeline lookahead window: + +#+BEGIN_SRC elisp +;; Modeline shows events within 2 hours +(setq chime-modeline-lookahead-minutes 120) + +;; Tooltip shows events within 1 week +(setq chime-tooltip-lookahead-hours 168) +#+END_SRC + +Larger values increase the agenda span fetched by the async subprocess and can slow checks for large org collections. + +** Click Actions + +- Left-click opens =chime-calendar-url= in a browser. +- Right-click jumps to the next event's org entry. + +#+BEGIN_SRC elisp +(setq chime-calendar-url "https://calendar.google.com") +#+END_SRC + +* Notification Text + +Control what appears in notifications and the modeline event text: + +#+BEGIN_SRC elisp +;; Default: title, event time, countdown +(setq chime-notification-text-format "%t at %T (%u)") + +;; Title and countdown only +(setq chime-notification-text-format "%t (%u)") +#+END_SRC + +Placeholders: + +- =%t= — event title +- =%T= — event time formatted by =chime-display-time-format-string= +- =%u= — time until event formatted by =chime-time-left-formats= + +* Time Formats + +#+BEGIN_SRC elisp +;; 12-hour with AM/PM +(setq chime-display-time-format-string "%I:%M %p") + +;; 24-hour +(setq chime-display-time-format-string "%H:%M") +#+END_SRC + +Countdown formatting uses =chime-time-left-formats=: + +#+BEGIN_SRC elisp +(setq chime-time-left-formats + '((at-event . "right now") + (short . "in %M") + (long . "in %H %M"))) +#+END_SRC + +* Title Truncation + +#+BEGIN_SRC elisp +;; No truncation +(setq chime-max-title-length nil) + +;; Limit title text +(setq chime-max-title-length 25) +#+END_SRC + +This affects only the event title placeholder =%t=, not the icon, time, or countdown. + +* Filtering + +Two alists control which events trigger notifications: + +- =chime-include-filters= — event must match at least one configured include rule +- =chime-exclude-filters= — event is dropped if it matches any configured exclude rule + +Both use this shape: + +#+BEGIN_SRC elisp +'((keywords . ("TODO" "NEXT")) + (tags . ("work" "urgent")) + (predicates . (my-predicate-fn))) +#+END_SRC + +Example: + +#+BEGIN_SRC elisp +(setq chime-include-filters + '((keywords . ("TODO" "NEXT")) + (tags . ("important")))) + +(setq chime-exclude-filters + '((keywords . ("DONE" "CANCELLED")) + (tags . ("someday")) + (predicates . (chime-done-keywords-predicate + chime-declined-events-predicate)))) +#+END_SRC + +If the same keyword or tag appears in both include and exclude filters, exclude wins. + +** Custom Predicates + +Predicates receive an org marker and return non-nil to match. + +#+BEGIN_SRC elisp +(defun my-no-notify-predicate (marker) + "Match events with a NO_NOTIFY property set." + (org-entry-get marker "NO_NOTIFY")) + +(setq chime-exclude-filters + '((predicates . (chime-done-keywords-predicate + chime-declined-events-predicate + my-no-notify-predicate)))) +#+END_SRC + +* All-Day Events + +Chime distinguishes timed events from all-day events. + +Timed: + +#+BEGIN_SRC org +* Meeting +<2026-05-10 Sun 14:30> +#+END_SRC + +All-day: + +#+BEGIN_SRC org +* Birthday +<2026-05-10 Sun> +#+END_SRC + +All-day events are never shown in the modeline itself. They can appear in tooltip and day-wide notifications. + +** Day-Wide Notification Times + +#+BEGIN_SRC elisp +;; Default: notify at 8:00 AM +(setq chime-day-wide-alert-times '("08:00")) + +;; Multiple times +(setq chime-day-wide-alert-times '("08:00" "17:00")) + +;; 12-hour Org time strings are accepted +(setq chime-day-wide-alert-times '("8:00am" "5:00pm")) + +;; Disable all-day notifications +(setq chime-day-wide-alert-times nil) +#+END_SRC + +** Overdue and Past All-Day Events + +#+BEGIN_SRC elisp +;; Show overdue items with all-day notifications +(setq chime-show-any-overdue-with-day-wide-alerts t) + +;; Show only today's all-day events +(setq chime-show-any-overdue-with-day-wide-alerts nil) +#+END_SRC + +Today's events always show if you launch Emacs after the alert time. This setting controls whether previous-day all-day events are included. + +** Advance Notice + +#+BEGIN_SRC elisp +;; Only notify on the day of the event +(setq chime-day-wide-advance-notice nil) + +;; Also notify one day before +(setq chime-day-wide-advance-notice 1) +#+END_SRC + +** Tooltip Display + +#+BEGIN_SRC elisp +;; Show all-day events in tooltip +(setq chime-tooltip-show-all-day-events t) + +;; Hide all-day events from tooltip +(setq chime-tooltip-show-all-day-events nil) +#+END_SRC + +* Advanced Settings + +** Failure Warnings + +#+BEGIN_SRC elisp +;; Warn after 5 consecutive async failures +(setq chime-max-consecutive-failures 5) + +;; Disable failure warnings +(setq chime-max-consecutive-failures 0) +#+END_SRC + +** Extra Alert Arguments + +#+BEGIN_SRC elisp +(setq chime-extra-alert-plist '(:style libnotify)) +#+END_SRC + +** Async Environment Variables + +If custom predicates need additional variables in the async subprocess, add regexes for their names: + +#+BEGIN_SRC elisp +(setq chime-additional-environment-regexes '("my-custom-var")) +#+END_SRC + +* Full Example + +#+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) + :config + (setq chime-check-interval 60) + (setq chime-alert-intervals '((5 . medium) (0 . high))) + (setq chime-enable-modeline t) + (setq chime-modeline-lookahead-minutes 180) + (setq chime-tooltip-lookahead-hours 168) + (setq chime-modeline-format " ⏰ %s") + (setq chime-notification-text-format "%t (%u)") + (setq chime-display-time-format-string "%H:%M") + (setq chime-time-left-formats + '((at-event . "NOW!") + (short . "in %mm") + (long . "%hh%mm"))) + (setq chime-exclude-filters + '((predicates . (chime-done-keywords-predicate + chime-declined-events-predicate)))) + (chime-mode 1)) +#+END_SRC + +* Supported Org Timestamp Shapes + +#+BEGIN_SRC org +* Scheduled event +SCHEDULED: <2026-05-10 Sun 10:00> + +* Deadline +DEADLINE: <2026-05-10 Sun 17:00> + +* Plain timestamp +<2026-05-10 Sun 14:30> + +* Repeating timestamp +SCHEDULED: <2026-05-10 Sun 09:00 +1w> +#+END_SRC + +Diary sexp timestamps such as =<%%(...)>= are not supported. Use standard org timestamps or repeating timestamps instead. diff --git a/docs/INTEGRATIONS.org b/docs/INTEGRATIONS.org new file mode 100644 index 0000000..dd8fea8 --- /dev/null +++ b/docs/INTEGRATIONS.org @@ -0,0 +1,109 @@ +#+TITLE: Chime Integrations +#+AUTHOR: Craig Jennings + +Setup notes for related org-mode packages. + +[[file:../README.org][README]] | [[file:CONFIGURATION.org][Configuration]] | [[file:ARCHITECTURE.org][Architecture]] | [[file:TROUBLESHOOTING.org][Troubleshooting]] | [[file:../TESTING.org][Testing]] + +* org-gcal +:PROPERTIES: +:CUSTOM_ID: org-gcal +:END: + +[[https://github.com/kidd/org-gcal.el][org-gcal]] syncs Google Calendar events into org files, which is exactly what chime reads. They work well together with no special configuration as long as the org files that org-gcal writes to are in =org-agenda-files=. + +Typical setup: + +#+BEGIN_SRC elisp +(use-package org-gcal + :after org + :config + (setq org-gcal-client-id "your-client-id" + org-gcal-client-secret "your-client-secret" + org-gcal-fetch-file-alist + '(("you@gmail.com" . "~/org/gcal.org")))) + +;; Make sure chime can see those events +(add-to-list 'org-agenda-files "~/org/gcal.org") +#+END_SRC + +After org-gcal syncs, run: + +#+BEGIN_SRC elisp +M-x chime-refresh-modeline +#+END_SRC + +That refreshes the modeline without sending notifications. Otherwise chime will pick up synced events on the next polling cycle. + +org-gcal commonly writes plain timestamps like: + +#+BEGIN_SRC org +* Team Sync +<2026-05-10 Sun 14:00> +#+END_SRC + +Chime handles plain timestamps, SCHEDULED timestamps, and DEADLINE timestamps. If you filter by TODO keyword, remember that org-gcal events usually do not have TODO keywords unless you add them through your org-gcal templates. + +Chime also ships =chime-declined-events-predicate=, which filters out org-gcal entries with =:STATUS: declined=. This predicate is included in the default =chime-exclude-filters=. + +* org-contacts +:PROPERTIES: +:CUSTOM_ID: org-contacts +:END: + +org-contacts birthdays are often exposed through diary sexps such as: + +#+BEGIN_SRC org +%%(org-contacts-anniversaries) +#+END_SRC + +Chime does not support diary sexp timestamps as event timestamps. For birthday notifications, convert contacts to standard repeating org timestamps. + +** Convert Existing Contacts + +Load the conversion script: + +#+BEGIN_SRC elisp +(require 'convert-org-contacts-birthdays + (expand-file-name "convert-org-contacts-birthdays.el" + (file-name-directory (locate-library "chime")))) +#+END_SRC + +Then run: + +#+BEGIN_SRC elisp +M-x chime-convert-contacts-in-place RET ~/org/contacts.org RET +#+END_SRC + +The command creates a timestamped backup first, then adds yearly repeating timestamps below contacts with birthday properties. vCard export still works because the original =:BIRTHDAY:= property remains in place. + +After conversion, comment out the diary sexp from your schedule file: + +#+BEGIN_SRC org +# %%(org-contacts-anniversaries) +#+END_SRC + +** Capture Template for New Contacts + +The optional =chime-org-contacts= integration adds an org-capture template that prompts for contact details and inserts a yearly repeating timestamp when a birthday is provided. + +#+BEGIN_SRC elisp +(setq chime-org-contacts-file "~/org/contacts.org") + +;; Optional: customize capture key. Default is "C". +(setq chime-org-contacts-capture-key "C") + +(with-eval-after-load 'org-capture + (require 'chime-org-contacts)) +#+END_SRC + +With use-package: + +#+BEGIN_SRC elisp +(use-package chime-org-contacts + :after org-capture + :init + (setq chime-org-contacts-file "~/org/contacts.org")) +#+END_SRC + +Set =chime-org-contacts-file= to nil to disable the integration. diff --git a/docs/TROUBLESHOOTING.org b/docs/TROUBLESHOOTING.org new file mode 100644 index 0000000..5f28a5c --- /dev/null +++ b/docs/TROUBLESHOOTING.org @@ -0,0 +1,180 @@ +#+TITLE: Chime Troubleshooting +#+AUTHOR: Craig Jennings + +Debugging guide for common Chime setup issues. + +[[file:../README.org][README]] | [[file:CONFIGURATION.org][Configuration]] | [[file:ARCHITECTURE.org][Architecture]] | [[file:INTEGRATIONS.org][Integrations]] | [[file:../TESTING.org][Testing]] + +* Validate Configuration + +Start with: + +#+BEGIN_SRC elisp +M-x chime-validate-configuration +#+END_SRC + +Interactive validation prints a checklist in =*Messages*= showing whether =org-agenda-files= is set, whether files exist, whether org-agenda is loadable, and whether modeline support is available. + +* Enable Debug Mode +:PROPERTIES: +:CUSTOM_ID: enable-debug-mode +:END: + +Enable debug mode before loading chime: + +#+BEGIN_SRC elisp +(setq chime-debug t) +(require 'chime) +#+END_SRC + +This loads =chime-debug.el= and provides: + +- =M-x chime-debug-dump-events= — show stored upcoming events +- =M-x chime-debug-dump-tooltip= — show tooltip content +- =M-x chime-debug-config= — dump complete configuration +- =M-x chime-debug-show-async-stats= — show async success/failure stats +- =M-x chime-debug-force-check= — force an immediate diagnostic check + +Debug mode also logs event loading and async process timing to =*Messages*=. + +* No Notifications Appearing + +Check these in order: + +1. Verify a notification daemon is running on your system. + - Linux examples: =dunst=, =mako=, =swaync= + - macOS and Windows have built-in notification support. +2. Verify =chime-mode= is enabled: + #+BEGIN_SRC elisp + M-: chime-mode + #+END_SRC +3. Check alert.el style configuration: + #+BEGIN_SRC elisp + (setq alert-default-style 'libnotify) + #+END_SRC +4. Run =M-x chime-check= manually. +5. Check =*Messages*= for errors. +6. Enable [[#enable-debug-mode][debug mode]] for more detail. + +* No Sound Playing + +1. Verify a sound file is configured: + #+BEGIN_SRC elisp + M-: chime-sound-file + #+END_SRC +2. Check that the file exists: + #+BEGIN_SRC elisp + M-: (file-exists-p chime-sound-file) + #+END_SRC +3. Test sound directly: + #+BEGIN_SRC elisp + M-: (play-sound-file chime-sound-file) + #+END_SRC +4. Ensure your system has audio support configured. + +Set =chime-sound-file= to nil to disable sound. + +* Events Not Being Detected + +Common causes: + +1. The org file is not in =org-agenda-files=. +2. The timestamp is all-day and you expected it in the modeline. All-day events do not appear in the modeline. +3. The timestamp is a diary sexp such as =<%%(...)>=. Chime does not support those as event timestamps. +4. Filters are excluding the event. +5. The event is outside the modeline or tooltip lookahead window. + +Chime supports timed 24-hour and 12-hour timestamps: + +#+BEGIN_SRC org +* 24-hour event +<2026-05-10 Sun 14:00> + +* 12-hour event +<2026-05-10 Sun 2:00pm> +#+END_SRC + +* Modeline Is Empty + +Check: + +1. =chime-enable-modeline= is non-nil. +2. =chime-modeline-lookahead-minutes= is greater than zero. +3. There is a timed event inside the modeline lookahead. +4. Events are visible to =org-agenda-files=. + +All-day events may appear in the tooltip, but never in the modeline itself. + +* Tooltip Has Too Many or Too Few Events + +Relevant settings: + +#+BEGIN_SRC elisp +(setq chime-tooltip-lookahead-hours 168) +(setq chime-modeline-tooltip-max-events 5) +(setq chime-tooltip-show-all-day-events t) +#+END_SRC + +If you increase =chime-tooltip-lookahead-hours= a lot, async checks can take longer because chime fetches a wider agenda span. + +* Multiple Emacs Instances Produce Duplicate Notifications + +If you receive duplicate notifications for every event, you likely have multiple Emacs processes running with =chime-mode= enabled. + +Check running Emacs processes: + +#+BEGIN_SRC bash +ps aux | grep emacs +#+END_SRC + +Common scenario: + +#+BEGIN_SRC bash +emacs --daemon +emacsclient -c +emacs & +#+END_SRC + +The final command starts a second standalone Emacs process, so chime runs twice. + +Choose one approach: + +- Use daemon + emacsclient consistently. +- Use standalone Emacs processes only. + +To stop a daemon: + +#+BEGIN_SRC bash +emacsclient -e "(kill-emacs)" +#+END_SRC + +* Startup Validation Fails Before org-agenda-files Loads + +If your configuration populates =org-agenda-files= asynchronously, chime may validate before those files are ready. + +Options: + +#+BEGIN_SRC elisp +;; Give startup more time before first check. +(setq chime-startup-delay 20) +#+END_SRC + +or ensure =org-agenda-files= is set before enabling =chime-mode=. + +* Async Check Failures + +Chime warns after repeated async failures. Tune or disable those warnings: + +#+BEGIN_SRC elisp +;; Default +(setq chime-max-consecutive-failures 5) + +;; Disable warnings +(setq chime-max-consecutive-failures 0) +#+END_SRC + +For custom predicate functions, ensure any variables they depend on are available in the async subprocess: + +#+BEGIN_SRC elisp +(setq chime-additional-environment-regexes '("my-custom-var")) +#+END_SRC -- cgit v1.2.3