This package provides integration between Emacs and Linear.app, allowing you to view and manage your Linear issues without leaving Emacs. I was just sick of leaving Emacs for the uncomfortable world of some corporation's UI. I hope this simple integration helps you, too.
- List, view, and create Linear issues directly from Emacs
- Bi-directional synchronization between Linear.app and org-mode
- Map Linear workflow states to org-mode TODO states
- Update issue details from either Linear or Emacs
- Track issue priorities, labels, and assignments
- Support for issue filtering and organization
- Automatically sync changes between systems
Ensure you have MELPA configured in your Emacs:
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)
Once accepted to MELPA, you'll be able to install with:
M-x package-install RET linear-emacs RET
- Clone this repository:
git clone ssh://[email protected]/gyamtso/linear-emacs.git
or, if you really have to:
git clone https://github.com/anegg0/linear-emacs.git
-
Add the following to your Emacs configuration:
(add-to-list 'load-path "/path/to/linear-emacs") (require 'linear-emacs)
-
Install the required dependencies:
M-x package-install RET request RET M-x package-install RET dash RET M-x package-install RET s RET
(package! linear-emacs
:recipe (:host github :repo "anegg0/linear-emacs" :files ("*.el")))
There are several ways to set your Linear API key:
(setq linear-emacs-api-key "your-api-key-here")
Set the LINEAR_API_KEY
environment variable and load it with:
(linear-emacs-load-api-key-from-env)
For secure credential storage, use Emacs' built-in auth-source package:
(defun my/linear-load-api-key-from-auth-source ()
"Load Linear API key from auth-source."
(interactive)
(require 'auth-source)
(let* ((auth-info (auth-source-search :host "api.linear.app" :user "apikey" :max 1))
(secret (when auth-info
(funcall (plist-get (car auth-info) :secret)))))
(if secret
(progn
(setq linear-emacs-api-key secret)
(message "Successfully loaded Linear API key from auth-source"))
(message "Failed to retrieve Linear API key from auth-source"))))
;; Call this function when linear loads
(after! linear-emacs
(my/linear-load-api-key-from-auth-source))
To set up your auth-source entry:
-
For macOS Keychain users, run:
security add-generic-password -a apikey -s api.linear.app -w YOUR_API_KEY
-
For
~/.authinfo.gpg
users, add this line to your file:machine api.linear.app login apikey password YOUR_API_KEY
Note: The hostname (api.linear.app
) and username (apikey
) in your auth-source entry must match exactly what you're using in the auth-source-search
function.
You can get your API key from Linear.app under Settings > Account > API > Personal API Keys.
Optionally, set a default team ID to streamline issue creation:
(setq linear-emacs-default-team-id "your-team-id")
By default, Linear issues are saved to gtd/linear.org
in your org-directory
. You can customize this location:
;; Change the output file location
(setq linear-emacs-org-file-path "/path/to/your/linear-issues.org")
;; Or use a different subdirectory in your org-directory
(setq linear-emacs-org-file-path (expand-file-name "projects/linear.org" org-directory))
To enable bidirectional synchronization with org-mode in Doom Emacs:
;; In your config.el
(after! linear-emacs
(linear-emacs-load-api-key-from-env)
;; Automatically enable two-way sync when linear.org is opened
(defun my/enable-linear-org-sync ()
"Enable Linear-org synchronization when linear.org is opened."
(when (and buffer-file-name
(string-match-p "linear\\.org$" buffer-file-name))
(when (fboundp 'linear-enable-org-sync)
(linear-emacs-enable-org-sync)
(message "Linear-org synchronization enabled for this buffer"))))
;; Add hook to auto-enable sync when linear.org is opened
(add-hook 'find-file-hook #'my/enable-linear-org-sync)
;; Enable sync for org-after-todo-state-change-hook
(add-hook 'org-after-todo-state-change-hook
(lambda ()
(when (and buffer-file-name
(string-match-p "linear\\.org$" buffer-file-name)
(fboundp 'linear-emacs-sync-org-to-linear))
(linear-emacs-sync-org-to-linear)))))
When you run M-x linear-emacs-list-issues
, the package will create a file with all your assigned issues at the location specified by linear-org-file-path
(see "Customizing the Output Path" above).
The org file will have the following structure:
:PROPERTIES:
:ID: a12acb12-8a69-4d15-a846-21e20ed2f3ae
#+title: Linear issues assigned to me
#+TAGS: :
#+filetags: :twai:b:
#+STARTUP: overview
#+TODO: TODO IN-PROGRESS IN-REVIEW BACKLOG BLOCKED | DONE
:END:
*** TODO [#B] Issue Title
:PROPERTIES:
:ID: issue-unique-id
:ID-LINEAR: TEAM-123
:TEAM: Team Name
:DESCRIPTION: |
Issue description goes here
:PRIORITY: High
:LABELS: [label1, label2]
:PROJECT: Project Name
:LINK: https://linear.app/issue/TEAM-123
:END:
When you change the TODO state of an issue in the org file, it will automatically synchronize with Linear.
Map Linear priorities to org priorities:
(setq linear-emacs-org-priority-mapping
'((0 . nil) ; No priority
(1 . "A") ; Urgent
(2 . "B") ; High
(3 . "C") ; Medium
(4 . "D"))) ; Low
M-x linear-emacs-list-issues
- Display your assigned issuesM-x linear-emacs-new-issue
- Create a new issueM-x linear-emacs-test-connection
- Test your Linear API connectionM-x linear-emacs-toggle-debug
- Toggle debug mode for troubleshootingM-x linear-emacs-check-setup
- Verify your API key is loaded correctly
M-x linear-emacs-list-issues
- Pull issues from Linear into org-modeM-x linear-emacs-sync-org-to-linear
- Sync the current org entry to LinearM-x linear-emacs-enable-org-sync
- Enable automatic synchronizationM-x linear-emacs-disable-org-sync
- Disable automatic synchronization
The following commands are available in the optimized configuration:
M-x my/linear-sync-single-issue-at-point
- Sync only the current issue at pointM-x my/toggle-linear-auto-sync
- Toggle automatic syncing before showing todo list
For Doom Emacs, you can set up convenient keybindings:
(map! :leader
(:prefix ("l" . "Linear")
:desc "Sync all Linear issues" "s" #'linear-emacs-list-issues
:desc "New issue" "n" #'linear-emacs-new-issue
:desc "Toggle Linear auto-sync" "t" #'my/toggle-linear-auto-sync
:desc "Test connection" "c" #'linear-emacs-test-connection
:desc "Toggle debug" "d" #'linear-emacs-toggle-debug))
In the optimized configuration, these keybindings are already set up for you:
(map! :leader
:prefix "l"
:desc "Sync all Linear issues" "s" #'linear-emacs-list-issues
:desc "Toggle Linear auto-sync" "t" #'my/toggle-linear-auto-sync)
To avoid synchronization performance issues, the optimized configuration:
- Only synchronizes the current issue at point instead of all issues
- Makes automatic synchronization optional with a toggle
- Adds convenient keybindings for managing synchronization
;; In your config.el
(after! linear-emacs
;; Improved synchronization function that only updates the changed issue
(defun my/linear-sync-single-issue-at-point ()
"Sync only the current issue at point to Linear API."
(interactive)
(save-excursion
;; Move to the beginning of the current heading
(org-back-to-heading t)
;; Check if this is a Linear issue heading
(when (looking-at "^\\*\\*\\* \\(TODO\\|IN-PROGRESS\\|IN-REVIEW\\|BACKLOG\\|BLOCKED\\|DONE\\)")
;; [Implementation details omitted for brevity]
)))
;; Override linear-emacs-sync-org-to-linear to only sync the current issue
(defun linear-emacs-sync-org-to-linear ()
"Sync only the current issue to Linear API."
(interactive)
(my/linear-sync-single-issue-at-point))
;; Add convenient keybinding for manually syncing all issues
(map! :leader
:prefix "l"
:desc "Sync all Linear issues" "s" #'linear-emacs-list-issues
:desc "Toggle Linear auto-sync" "t" #'my/toggle-linear-auto-sync))
Enable debug logging to troubleshoot issues:
(setq linear-emacs-debug t)
-
Check your connection:
M-x linear-emacs-test-connection
-
Enable debug mode:
M-x linear-emacs-toggle-debug
-
Verify your API key is loaded correctly:
M-x linear-emacs-check-setup
-
Check the
*Messages*
buffer for detailed error information when debug mode is enabled
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the GPL-3.0 License - see the LICENSE file for details.