Table of Contents

1. Introduction

Configuration for Org-mode and knowledge management tools including org-roam, org-gcal, and related packages.

2. Org Mode Core Configuration

Core Org-mode settings including babel languages, templates, and basic customization.

;;; doc-org-conf.el --- Org-mode and knowledge management configuration  -*- lexical-binding: t; -*-
;;; Commentary:
;;; Code:

;; Configure browser for opening URLs (fixes LaTeXiT issue on macOS)
(setq browse-url-browser-function 'browse-url-default-macosx-browser)

;; Required packages for org extensions
(use-package org-contrib)
(use-package ob-typescript)
(use-package ob-powershell)
(use-package ob-http)
(use-package ob-restclient)

(use-package org
  :pin org
  :commands (org-capture org-agenda)
  :custom
  ;; Agenda and logging
  (org-agenda-start-with-log-mode t)
  (org-log-done 'time)
  (org-log-into-drawer t)

  ;; Editing behavior
  (org-catch-invisible-edits 'show)
  (org-edit-timestamp-down-means-later t)
  (org-fast-tag-selection-single-key 'expert)
  (org-src-window-setup 'current-window)

  ;; Export settings
  (org-export-coding-system 'utf-8)
  (org-export-kill-product-buffer-when-displayed t)
  (org-html-validation-link nil)

  ;; LaTeX export
  (org-latex-compiler "xelatex")
  (org-latex-pdf-process '("latexmk -xelatex -synctex=1 -f -interaction=nonstopmode -output-directory=%o %f"))

  ;; Display and appearance
  (org-hide-emphasis-markers t)
  (org-pretty-entities nil)
  (org-startup-indented nil)
  (org-startup-with-inline-images t)
  (org-display-remote-inline-images 'download)
  (org-image-actual-width '(450))
  (org-tags-column 80)
  :hook
  ((org-mode-hook . olivetti-mode))
  :config
  ;; Load org-tempo for easy template expansion
  (require 'org-tempo)

  ;; Load babel language support
  (require 'ob-js)
  (require 'ob-typescript)
  (require 'ob-ruby)
  (require 'ob-lua nil t)  ; 'nil t' means don't error if not found

  ;; Add custom structure templates
  (add-to-list 'org-structure-template-alist '("txt"  . "src text"))
  (add-to-list 'org-structure-template-alist '("cc"   . "src C"))
  (add-to-list 'org-structure-template-alist '("sh"   . "src shell"))
  (add-to-list 'org-structure-template-alist '("zsh"  . "src zsh"))
  (add-to-list 'org-structure-template-alist '("bash" . "src bash"))
  (add-to-list 'org-structure-template-alist '("posh" . "src powershell"))
  (add-to-list 'org-structure-template-alist '("el"   . "src emacs-lisp"))
  (add-to-list 'org-structure-template-alist '("py"   . "src python"))
  (add-to-list 'org-structure-template-alist '("js"   . "src js"))
  (add-to-list 'org-structure-template-alist '("ts"   . "src typescript"))
  (add-to-list 'org-structure-template-alist '("java" . "src java"))
  (add-to-list 'org-structure-template-alist '("scm"  . "src scheme"))
  (add-to-list 'org-structure-template-alist '("sql"  . "src sql"))
  (add-to-list 'org-structure-template-alist '("rust" . "src rust"))
  (add-to-list 'org-structure-template-alist '("rb"   . "src ruby"))
  (add-to-list 'org-structure-template-alist '("lua"  . "src lua"))

  ;; Enable babel languages - only load those that are available
  (org-babel-do-load-languages
   'org-babel-load-languages
   (seq-filter
    (lambda (pair)
      (locate-library (concat "ob-" (symbol-name (car pair)))))
    '((dot        . t)
      (C          . t)
      (gnuplot    . t)
      (latex      . t)
      (python     . t)
      (js         . t)
      (typescript . t)
      (lua        . t)
      (shell      . t)
      (zsh        . t)
      (bash       . t)
      (posh       . t)
      (powershell . t)
      (scheme     . t)
      (sql        . t)
      (sqlite     . t)
      (ruby       . t)
      (emacs-lisp . t)
      (http       . t)
      (restclient . t))))

  ;; Fix electric-pair-mode for org-mode angle brackets
  (defun handle-electric-pair-inhibit (c)
    (if (char-equal c ?<) t (,electric-pair-inhibit-predicate c)))

  (defun handle-org-mode-hook()
    (setq-local electric-pair-inhibit-predicate #'handle-electric-pair-inhibit))

  (add-hook 'org-mode-hook #'handle-org-mode-hook)

  )

3. Org Download

Drag-and-drop images and screenshots into org buffers. Automatically skipped on server/headless environments (requires GUI for screenshots).

(use-package org-download
    :after org
    :custom
    ;; Store images in a local "images" directory
    (org-download-image-dir "images")

    ;; Don't create heading-based subdirectories
    (org-download-heading-lvl nil)

    ;; Screenshot method based on OS
    (org-download-screenshot-method
     (cond ((eq system-type 'darwin) "screencapture -i %s")
           ((eq system-type 'gnu/linux) "scrot -s %s")))

    :config
    ;; Enable inline display of remote images
    (setq org-download-display-inline-images 'posframe))

4. Org Appear (Disabled)

Shows hidden emphasis markers and links when cursor is on them. Currently disabled.

(use-package org-appear
  :hook
  (org-mode . org-appear-mode)
  :custom
  (org-appear-autoemphasis t)
  (org-appear-autolinks t)
  (org-appear-autosubmarkers t)
  (org-appear-autoentities t)
  (org-appear-autokeywords t)
  (org-appear-inside-latex t)
  (org-appear-delay 0.0)
  (org-appear-trigger 'always))

5. Pretty Org - Visual Enhancements

Modern, beautiful styling for Org-mode with enhanced typography, icons, and visual elements.

5.1. Org Modern

The org-modern package provides a clean, modern appearance for Org-mode with better typography, styling, and visual hierarchy.

Features:

  • Modern table styling with proper borders
  • Beautiful heading styles with custom fonts
  • Enhanced todo keywords and priorities
  • Styled tags, timestamps, and statistics
  • Better block delimiters
  • Improved checkbox appearance
  • Clean list bullets
;; Modern Org-mode styling
(use-package org-modern
  :hook
  (org-mode . org-modern-mode)
  (org-agenda-finalize . org-modern-agenda)
  :custom
  ;; Heading styles
  (org-modern-star 'replace)
  (org-modern-hide-stars t)
  (org-modern-table t)
  (org-modern-table-vertical 1)
  (org-modern-table-horizontal 0.2)

  ;; List bullets
  (org-modern-list '((43 . "➤")   ; +
                     (45 . "–")   ; -
                     (42 . "•"))) ; *

  ;; Block delimiters
  (org-modern-block-name '(("src" "»" "«")
                           ("example" "»–" "–«")
                           ("quote" "❝" "❞")
                           ("export" "⏩" "⏪")))

  ;; Keywords styling
  (org-modern-keyword t)
  (org-modern-checkbox nil)
  (org-modern-horizontal-rule t)

  ;; Timestamps
  (org-modern-timestamp t)
  (org-modern-statistics t)

  ;; Tags
  (org-modern-tag t)
  (org-modern-priority t)

  ;; Todo keywords
  (org-modern-todo t)
  (org-modern-todo-faces
   '(("TODO" :background "#ff6c6b" :foreground "#282c34" :weight bold)
     ("DOING" :background "#51afef" :foreground "#282c34" :weight bold)
     ("REVIEW" :background "#ecbe7b" :foreground "#282c34" :weight bold)
     ("DONE" :background "#98be65" :foreground "#282c34" :weight bold)
     ("CANCEL" :background "#5B6268" :foreground "#282c34" :weight bold))))

6. Org Google Calendar

Bidirectional sync between Org-mode and Google Calendar. Disabled for now.

(use-package org-gcal
  :after org
  :custom
  ;; IMPORTANT: Set these variables in your private.el or custom-vars.el:
  ;; (setq org-gcal-client-id "your-client-id-from-google-console.apps.googleusercontent.com")
  ;; (setq org-gcal-client-secret "your-client-secret-from-google-console")
  ;; (setq org-gcal-file-alist '(("your-email@gmail.com" . "~/org/gcal.org")
  ;;                              ("another-calendar@gmail.com" . "~/org/work-gcal.org")))

  ;; Directory to store OAuth token and sync metadata
  (org-gcal-dir (expand-file-name ".org-gcal/" user-emacs-directory))

  ;; Token storage - use plain text file (no .gpg extension) to avoid encryption
  ;; The token file will have restricted file permissions (600) for security
  (org-gcal-token-file (expand-file-name ".org-gcal/token" user-emacs-directory))

  ;; Automatically fetch events when opening org-agenda
  (org-gcal-auto-archive nil)

  ;; Notify on sync
  (org-gcal-notify-p t)

  ;; Update events if they already exist (bidirectional sync)
  (org-gcal-update-cancelled-events-with-todo t)

  :init
  ;; CRITICAL: Disable plstore encryption BEFORE org-gcal loads
  ;; This must be in :init, not :config
  (setq plstore-cache-passphrase-for-symmetric-encryption t)
  (setq plstore-encrypt-to nil)

  ;; Ensure EPG context doesn't prompt for passphrase
  (setq epg-pinentry-mode 'loopback)

  ;; Auto-provide a passphrase if encryption can't be disabled
  ;; This prevents repeated prompts
  (defvar my/org-gcal-passphrase "emacs-gcal-token")
  (defun my/org-gcal-passphrase-callback (context key-id handback)
    "Automatically provide passphrase for org-gcal token encryption."
    my/org-gcal-passphrase)

  ;; Override EPG passphrase callback
  (setq epg-passphrase-callback-function #'my/org-gcal-passphrase-callback)

  :config
  ;; Additional workaround: advice plstore to disable encryption
  (when (fboundp 'plstore-open)
    (advice-add 'plstore-open :around
                (lambda (orig-fun file)
                  (let ((plstore-encrypt-to nil))
                    (funcall orig-fun file)))))

  ;; Add org-gcal files to org-agenda-files if configured
  (when (and (boundp 'org-gcal-file-alist) org-gcal-file-alist)
    (dolist (calendar org-gcal-file-alist)
      (let ((gcal-file (cdr calendar)))
        ;; Create the file if it doesn't exist
        (unless (file-exists-p gcal-file)
          (make-directory (file-name-directory gcal-file) t)
          (write-region "" nil gcal-file))
        ;; Add to org-agenda-files if not already there
        (when (and (boundp 'org-agenda-files)
                   (not (member gcal-file org-agenda-files)))
          (add-to-list 'org-agenda-files gcal-file)))))

  :bind
  (("C-c g p" . org-gcal-post-at-point)
   ("C-c g d" . org-gcal-delete-at-point)
   ("C-c g r" . org-gcal-refresh-token)))

7. Org Image Preview

Display remote HTTP/HTTPS images inline in org buffers with automatic caching. Uses the org-image-preview package from GitHub.

(use-package org-image-preview
  :vc (:url "https://github.com/mandoo180/org-image-preview"
       :branch "main")
  :after org
  :custom
  ;; Enable caching for better performance
  ;; Options: 'skip (disable), 'download (no cache), 'cache (recommended)
  (org-display-remote-inline-images 'cache))

8. Org HTML Preview

Live HTML preview for Org-mode buffers in browser. Auto-refreshes on save.

(use-package org-html-preview
  :vc (:url "https://github.com/mandoo180/org-html-preview"
       :branch "main")
  :after org)

9. Org-Roam Configuration

Org-roam is a powerful Zettelkasten-style note-taking system built on top of Org-mode. It enables networked thought through bidirectional linking and provides tools for knowledge management inspired by Roam Research.

9.1. Core Setup

(use-package org-roam
  :after org
  :demand t
  :init
  ;; Ensure org-roam directory exists before package loads
  (let ((roam-dir (file-truename "~/org-roam/")))
    (unless (file-directory-p roam-dir)
      (make-directory roam-dir t)))
  :custom
  ;; Directory where all your notes will be stored
  (org-roam-directory (file-truename "~/org-roam/"))

  ;; Better database location (avoid cluttering org-roam directory)
  (org-roam-db-location (expand-file-name "org-roam.db" user-emacs-directory))

  ;; Enable completion everywhere (for inserting links)
  (org-roam-completion-everywhere t)

  ;; Configure how nodes are displayed in completion
  (org-roam-node-display-template
   (concat "${title:*} " (propertize "${tags:10}" 'face 'org-tag)))

  :bind
  (("C-c n l" . org-roam-buffer-toggle)         ;; Show backlinks sidebar
   ("C-c n f" . org-roam-node-find)             ;; Find or create a note
   ("C-c n i" . org-roam-node-insert)           ;; Insert a link to a note
   ("C-c n c" . org-roam-capture)               ;; Quick capture
   ("C-c n j" . org-roam-dailies-capture-today) ;; Daily note
   ("C-c n g" . org-roam-graph)                 ;; Visualize the graph
   :map org-mode-map
   ("C-M-i"   . completion-at-point))           ;; Complete link at point

  :config
  ;; Initialize org-roam database and sync on startup
  (org-roam-db-autosync-mode 1))

9.2. Capture Templates

Define templates for different types of notes. This follows the best practice of having different note types (fleeting, permanent, literature, etc.).

(use-package org-roam
  :custom
  ;; Capture templates for different note types
  (org-roam-capture-templates
   '(("d" "default" plain
      "%?"
      :target (file+head "%<%Y%m%dT%H%M%S>--${slug}.org"
                         "#+title: ${title}\n#+date: %U\n#+filetags: \n\n")
      :unnarrowed t)

     ("p" "permanent" plain
      "* Source\n\n%?\n\n* Content\n\n\n* Links\n"
      :target (file+head "permanent/%<%Y%m%dT%H%M%S>--${slug}.org"
                         "#+title: ${title}\n#+date: %U\n#+filetags: :permanent:\n\n")
      :unnarrowed t)

     ("l" "literature" plain
      "* Source\n\nAuthor: %^{Author}\nTitle: ${title}\nYear: %^{Year}\n\n%?\n\n* Summary\n\n\n* Key Points\n\n\n* Quotes\n\n\n* Related\n"
      :target (file+head "literature/%<%Y%m%dT%H%M%S>--${slug}.org"
                         "#+title: ${title}\n#+date: %U\n#+filetags: :literature:\n\n")
      :unnarrowed t)

     ("c" "concept" plain
      "* Definition\n\n%?\n\n* Examples\n\n\n* Related Concepts\n"
      :target (file+head "concepts/%<%Y%m%dT%H%M%S>--${slug}.org"
                         "#+title: ${title}\n#+date: %U\n#+filetags: :concept:\n\n")
      :unnarrowed t)

     ("r" "reference" plain
      "* %?\n"
      :target (file+head "reference/%<%Y%m%dT%H%M%S>--${slug}.org"
                         "#+title: ${title}\n#+date: %U\n#+filetags: :reference:\n\n")
      :unnarrowed t))))

9.3. Daily Notes Configuration

Daily notes are essential for journaling and capturing fleeting thoughts. This configuration follows best practices for daily note organization.

(use-package org-roam
  :custom
  ;; Store daily notes in a dedicated subdirectory
  (org-roam-dailies-directory "daily/")

  ;; Capture templates for daily notes
  (org-roam-dailies-capture-templates
   '(("d" "default" entry
      "* %?"
      :target (file+head "%<%Y-%m-%d>.org"
                         "#+title: %<%Y-%m-%d (%A)>\n#+filetags: :daily:\n\n"))

     ("m" "meeting" entry
      "* %<%H:%M> Meeting: %^{Meeting Title}\n\n** Attendees\n%?\n\n** Notes\n\n\n** Action Items\n"
      :target (file+head "%<%Y-%m-%d>.org"
                         "#+title: %<%Y-%m-%d (%A)>\n#+filetags: :daily:\n\n"))

     ("j" "journal" entry
      "* %<%H:%M> Journal\n\n%?"
      :target (file+head "%<%Y-%m-%d>.org"
                         "#+title: %<%Y-%m-%d (%A)>\n#+filetags: :daily:journal:\n\n"))

     ("t" "task" entry
      "* TODO %?\n  SCHEDULED: %t\n"
      :target (file+head "%<%Y-%m-%d>.org"
                         "#+title: %<%Y-%m-%d (%A)>\n#+filetags: :daily:\n\n"))))

  :bind
  (("C-c n t" . org-roam-dailies-goto-today)
   ("C-c n y" . org-roam-dailies-goto-yesterday)
   ("C-c n d" . org-roam-dailies-goto-date)
   ("C-c n n" . org-roam-dailies-goto-next-note)
   ("C-c n p" . org-roam-dailies-goto-previous-note)))

9.4. Enhanced Node Display

Customize how nodes appear in completion and searches for better usability.

(use-package org-roam
  :config
  ;; Custom function to display nodes with more context
  (setq org-roam-node-display-template
        (concat "${type:15} ${title:*} " (propertize "${tags:20}" 'face 'org-tag)))

  ;; Add custom properties to node display
  (cl-defmethod org-roam-node-type ((node org-roam-node))
    "Return the TYPE of NODE based on tags or directory."
    (let ((tags (org-roam-node-tags node))
          (file (org-roam-node-file node)))
      (cond
       ((member "permanent" tags) "📝 Permanent")
       ((member "literature" tags) "📚 Literature")
       ((member "concept" tags) "💡 Concept")
       ((member "reference" tags) "📖 Reference")
       ((member "daily" tags) "📅 Daily")
       ((string-match-p "/daily/" file) "📅 Daily")
       ((string-match-p "/literature/" file) "📚 Literature")
       ((string-match-p "/permanent/" file) "📝 Permanent")
       ((string-match-p "/concepts/" file) "💡 Concept")
       (t "📄 Note")))))

9.5. Graph Visualization

Configure org-roam's graph visualization for better insights into your knowledge network.

(use-package org-roam
  :custom
  ;; Graphviz executable for generating graphs
  (org-roam-graph-executable (executable-find "dot"))

  ;; Exclude certain tags from the graph for cleaner visualization
  ;; (org-roam-graph-exclude-matcher '("daily" "fleeting"))
  (org-roam-graph-exclude-matcher '())
  ;; Use specific program for graph generation
  (org-roam-graph-viewer (executable-find "open"))  ;; macOS
  ;; For Linux: (org-roam-graph-viewer "xdg-open")
  ;; For Windows: (org-roam-graph-viewer "start")

  ;; Additional graph settings
  (org-roam-graph-extra-config
   '(("overlap" . "false")
     ("splines" . "true")
     ("rankdir" . "LR"))))  ;; Left to Right layout

9.6. UI Enhancement with org-roam-ui

Optional web-based graph visualization interface (requires separate package). Automatically skipped on server/headless environments.

;; Skip org-roam-ui on server (requires browser/GUI)
(unless emacs-server-mode
  (use-package org-roam-ui
    :after org-roam
    :custom
    (org-roam-ui-sync-theme t)              ;; Sync with Emacs theme
    (org-roam-ui-follow t)                  ;; Follow current note in UI
    (org-roam-ui-update-on-save t)          ;; Update graph on save
    (org-roam-ui-open-on-start t)           ;; Open browser when activated
    (org-roam-ui-browser-function #'browse-url-default-browser)  ;; Use default browser
    :bind
    ("C-c n u" . org-roam-ui-mode)))

9.7. Performance Optimizations

Best practices for maintaining good performance with large note collections.

  (use-package org-roam
    :custom
    ;; Increase cache size for better performance
    (org-roam-db-gc-threshold most-positive-fixnum)

    ;; Update database asynchronously
    (org-roam-db-update-method 'immediate)

    :config
    ;; Auto-save database periodically
    (run-with-idle-timer 300 t #'org-roam-db-sync))

  ;; Helper function for safe note deletion
  (defun fu/org-roam-node-delete (&optional node)
    "Delete an org-roam NODE after showing backlinks warning.
If NODE is not provided, prompt to select a note from minibuffer.
If called from within a note, can use current note."
    (interactive)
    (let* ((node (or node
                     (if (derived-mode-p 'org-mode)
                         ;; Try current node first, fall back to selection
                         (or (org-roam-node-at-point)
                             (org-roam-node-read))
                       ;; Not in org-mode, always prompt
                       (org-roam-node-read))))
           (file (org-roam-node-file node))
           (title (org-roam-node-title node))
           (backlinks (org-roam-backlinks-get node))
           (buffer (find-buffer-visiting file)))
      (if backlinks
          (progn
            ;; Open the file if not already open
            (unless buffer
              (find-file file))
            (org-roam-buffer-toggle)
            (message "WARNING: %d notes link to '%s'! Check backlinks first."
                     (length backlinks) title))
        (when (yes-or-no-p (format "Delete '%s'? " title))
          (when buffer (kill-buffer buffer))
          (delete-file file)
          (org-roam-db-sync)
          (message "Note '%s' deleted and database synced." title)))))

  (provide 'org-conf)
  ;;; org-conf.el ends here

9.8. Best Practices Summary

Key principles to follow when using org-roam:

  1. Atomic Notes: One idea per note - keeps notes focused and linkable
  2. Consistent Tagging: Use tags systematically (e.g., :permanent:, :literature:, :concept:)
  3. Regular Capturing: Use daily notes to capture fleeting thoughts immediately
  4. Link Liberally: Create connections between notes to build your knowledge graph
  5. Regular Reviews: Periodically review and refactor notes to strengthen connections
  6. Structured Templates: Use capture templates to maintain consistency
  7. Hierarchical Organization: Use subdirectories (daily/, literature/, etc.) for better organization
  8. Database Maintenance: Let org-roam-db-autosync-mode handle synchronization automatically
  9. Safe Deletion: Always check backlinks before deleting notes to avoid orphaned links

9.9. Common Workflows

9.9.1. Creating a New Note

  1. C-c n f (org-roam-node-find)
  2. Type the note title
  3. Select template (or use default)
  4. Write your note with [[links]] to other notes

9.9.2. Linking Notes

  1. C-c n i (org-roam-node-insert) while writing
  2. Search for existing note or create new one
  3. Link is created bidirectionally

9.9.3. Daily Journaling

  1. C-c n j (org-roam-dailies-capture-today)
  2. Select template (journal, meeting, task, etc.)
  3. Write entry - automatically timestamped

9.9.4. Reviewing Connections

  1. C-c n l (org-roam-buffer-toggle) to see backlinks
  2. C-c n g (org-roam-graph) for visual exploration
  3. C-c n u (org-roam-ui-mode) for interactive web interface

9.9.5. Deleting Notes Safely

Method 1: Delete from anywhere (recommended)

  1. M-x fu/org-roam-node-delete from any buffer
  2. Select the note to delete from minibuffer (with completion)
  3. If backlinks exist, the note opens and backlinks sidebar shows warning
  4. Check each linking note and update/remove links
  5. Run the command again to confirm deletion
  6. Database automatically syncs after deletion

Method 2: Delete current note

  1. Open the note you want to delete
  2. M-x fu/org-roam-node-delete (automatically uses current note)
  3. Follow steps 3-6 from Method 1

Alternative manual method:

  1. C-c n l to check backlinks first
  2. Update all linking notes
  3. Delete the file normally
  4. M-x org-roam-db-sync to clean up the database

10. Org-Jira

org-jira provides a seamless integration between Emacs Org-mode and Atlassian Jira. It allows you to sync, create, update, and manage Jira issues directly from Org-mode buffers, bringing the power of Org's task management to your Jira workflow.

10.1. Key Features

  • Bidirectional Sync: Pull issues from Jira into Org files and push updates back
  • Issue Management: Create, update, and transition issues without leaving Emacs
  • Worklog Tracking: Log time spent on issues directly from Org-mode
  • Comment Support: Add and view comments on Jira issues
  • Custom JQL Queries: Define custom queries to fetch specific sets of issues
  • Org Integration: Issues are stored as standard Org headings with properties

10.2. Configuration

(use-package org-jira
  :after org
  :custom
  ;; Directory to store org-jira files
  (org-jira-working-dir (expand-file-name "jira/" org-directory))

  ;; Default JQL query for fetching issues
  (org-jira-default-jql
   "assignee = currentUser() AND resolution = Unresolved ORDER BY priority DESC, updated DESC")

  ;; How to handle issue priority in Org
  (org-jira-priority-to-org-priority-alist
   '(("Highest" . ?A)
     ("High"    . ?B)
     ("Medium"  . ?C)
     ("Low"     . ?D)
     ("Lowest"  . ?E)))

  ;; Map Jira status to Org TODO keywords
  (org-jira-jira-status-to-org-keyword-alist
   '(("To Do"       . "TODO")
     ("In Progress" . "DOING")
     ("In Review"   . "REVIEW")
     ("Done"        . "DONE")
     ("Closed"      . "DONE")))

  :config
  ;; Ensure jira working directory exists
  (unless (file-directory-p org-jira-working-dir)
    (make-directory org-jira-working-dir t))

  :bind
  (("C-c j g" . org-jira-get-issues)                      ;; Fetch issues with default JQL
   ("C-c j q" . org-jira-get-issues-from-custom-jql)      ;; Fetch from custom JQL
   ("C-c j c" . org-jira-create-issue)                    ;; Create a new issue
   ("C-c j u" . org-jira-update-issue)                    ;; Update current issue
   ("C-c j p" . org-jira-progress-issue)                  ;; Transition issue status
   ("C-c j a" . org-jira-assign-issue)                    ;; Assign issue to someone
   ("C-c j r" . org-jira-refresh-issue)                   ;; Refresh current issue
   ("C-c j w" . org-jira-update-worklogs-from-org-clocks) ;; Sync worklogs
   ("C-c j t" . org-jira-todo-to-jira)                    ;; Create Jira issue from TODO
   ("C-c j b" . org-jira-browse-issue)))                  ;; Open issue in browser

10.3. Authentication Setup

For Jira Cloud, you need to use Basic Auth with your email and an API token.

10.3.1. Getting an API Token

  1. Go to https://id.atlassian.com/manage-profile/security/api-tokens
  2. Click "Create API token"
  3. Give it a label (e.g., "Emacs org-jira")
  4. Copy the generated token

10.3.2. Configuring Authentication

Set these in your private configuration (private.el or similar - DO NOT commit!):

;; Jira Cloud authentication
(setq jiralib-url "https://your-company.atlassian.net")

;; For Jira Cloud, use Basic Auth with email:token
(setq jiralib-token
      (cons "Authorization"
            (concat "Basic "
                    (base64-encode-string
                     "your-email@company.com:your-api-token-here"
                     t))))  ; 't' prevents newlines in base64

10.4. JQL Query Language

JQL (Jira Query Language) is used to filter and sort issues. Use it with C-c j g or in custom queries.

10.4.1. Common JQL Examples

# My open issues, sorted by priority
assignee = currentUser() AND resolution = Unresolved ORDER BY priority DESC

# Issues in current sprint
project = PROJ AND sprint in openSprints() ORDER BY rank

# Recently updated issues (last 7 days)
assignee = currentUser() AND updated >= -7d ORDER BY updated DESC

# Filter by status
status IN ("To Do", "In Progress") AND assignee = currentUser()

# Filter by label
labels = "backend" AND resolution = Unresolved

# Specific project, exclude done
project = MYPROJ AND status != Done ORDER BY created DESC

# Issues I'm watching
watcher = currentUser()

# Issues I reported
reporter = currentUser() AND created >= -30d ORDER BY created DESC

10.4.2. ORDER BY Options

Field Description
priority Issue priority
created Creation date
updated Last update date
duedate Due date
rank Sprint board order
status Issue status
summary Issue title (alphabetical)

Use DESC (descending) or ASC (ascending) after the field name.

10.5. Custom JQL Queries

Define saved queries for quick access via C-c j q (org-jira-get-issues-from-custom-jql):

;; Custom JQL queries - add to your config
(setq org-jira-custom-jqls
      '(;; Current sprint issues
        (:jql "project = PROJ AND sprint in openSprints() ORDER BY rank"
         :filename "current-sprint")

        ;; My in-progress work
        (:jql "assignee = currentUser() AND status = 'In Progress' ORDER BY updated DESC"
         :filename "in-progress")

        ;; Issues I reported
        (:jql "reporter = currentUser() AND created >= -30d ORDER BY created DESC"
         :filename "my-reported")

        ;; High priority unresolved
        (:jql "assignee = currentUser() AND priority IN (Highest, High) AND resolution = Unresolved"
         :filename "high-priority")

        ;; Recently updated across team
        (:jql "project = PROJ AND updated >= -1d ORDER BY updated DESC"
         :filename "team-recent")))

10.6. Common Workflows

10.6.1. Syncing Issues from Jira

  1. C-c j g - Fetch issues using default JQL
  2. C-c j q - Select from custom saved queries
  3. Issues are saved to org-jira-working-dir

10.6.2. Creating an Issue

  1. C-c j c (org-jira-create-issue)
  2. Select project and issue type
  3. Fill in summary and description
  4. Issue is created in Jira and synced locally

10.6.3. Updating an Issue

  1. Position cursor on issue heading
  2. Make changes to summary, description, or properties
  3. C-c j u (org-jira-update-issue)

10.6.4. Transitioning Issue Status

  1. Position cursor on issue heading
  2. C-c j p (org-jira-progress-issue)
  3. Select new status from available transitions

10.6.5. Logging Work Time

  1. Use org-clock-in and org-clock-out on issue headings
  2. C-c j w (org-jira-update-worklogs-from-org-clocks)
  3. Clock entries are synced to Jira worklogs

11. End of File

(provide 'doc-org-conf)
;;; doc-org-conf.el ends here