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
|
;;; claude-code-context.el --- Share Emacs context with Claude Code -*- lexical-binding: t; -*-
;; Copyright (C) 2025 Luke Hoersten
;; Author: Luke Hoersten <[email protected]>
;; URL: https://github.com/lhoersten/claude-code-context
;; Version: 0.1.0
;; Package-Requires: ((emacs "27.1"))
;; Keywords: tools, ai, convenience
;; This file is not part of GNU Emacs.
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; This package automatically shares your current Emacs buffer context
;; (file, line, column, selection, and diagnostics) with Claude Code
;; via a context file that Claude Code hooks can read.
;;
;; Setup:
;; 1. Add to your init.el:
;; (require 'claude-code-context)
;; (claude-code-context-mode 1)
;;
;; 2. Add this hook to your ~/.claude/settings.json:
;; {
;; "hooks": {
;; "UserPromptSubmit": [
;; {
;; "hooks": [
;; {
;; "type": "command",
;; "command": "CONTEXT_FILE=\"$HOME/.emacs.d/claude-context.txt\"; if [ -f \"$CONTEXT_FILE\" ]; then echo \"\\n---\\n## Emacs Context\\n\"; cat \"$CONTEXT_FILE\"; echo \"\\n---\"; fi"
;; }
;; ]
;; }
;; ]
;; }
;; }
;;
;; Usage:
;; - C-c C-l u : Manually update context
;; - C-c C-l d : Add flymake diagnostics to context
;; - C-c C-l c : Clear context
;; - C-c C-l m : Toggle automatic context mode
;;; Code:
(defgroup claude-code-context nil
"Share Emacs context with Claude Code."
:group 'tools
:prefix "claude-code-context-")
(defcustom claude-code-context-file
(expand-file-name "claude-context.txt" user-emacs-directory)
"File where Claude Code context is written."
:type 'file
:group 'claude-code-context)
(defcustom claude-code-context-update-interval 2
"Seconds between context updates (to avoid excessive writes)."
:type 'integer
:group 'claude-code-context)
(defvar claude-code-context-timer nil
"Timer for updating Claude Code context.")
(defun claude-code--get-current-context ()
"Get current buffer context as a string."
(when (buffer-file-name)
(let* ((file (buffer-file-name))
(line (line-number-at-pos))
(col (current-column))
(selection (when (use-region-p)
(buffer-substring-no-properties (region-beginning) (region-end)))))
(concat
(format "File: %s\n" file)
(format "Line: %d, Column: %d\n" line col)
(when selection
(format "Selection:\n```\n%s\n```\n" selection))))))
(defun claude-code--get-flymake-diagnostics ()
"Get flymake diagnostics for current buffer."
(when (and (bound-and-true-p flymake-mode)
(buffer-file-name))
(let ((diags (flymake-diagnostics)))
(when diags
(concat
"\nFlymake Diagnostics:\n"
(mapconcat
(lambda (diag)
(format " %4d %8s %-8s %s"
(line-number-at-pos (flymake-diagnostic-beg diag))
(flymake-diagnostic-type diag)
(flymake-diagnostic-backend diag)
(flymake-diagnostic-text diag)))
diags
"\n"))))))
(defun claude-code-update-context ()
"Update Claude Code context file with current buffer state."
(interactive)
(let ((context (claude-code--get-current-context)))
(when context
(with-temp-file claude-code-context-file
(insert "# Emacs Context for Claude Code\n")
(insert "# This file is automatically updated by Emacs\n\n")
(insert context))
(message "Claude Code context updated"))))
(defun claude-code-add-diagnostics ()
"Add flymake diagnostics to Claude Code context file."
(interactive)
(let ((context (claude-code--get-current-context))
(diags (claude-code--get-flymake-diagnostics)))
(when context
(with-temp-file claude-code-context-file
(insert "# Emacs Context for Claude Code\n")
(insert "# This file is automatically updated by Emacs\n\n")
(insert context)
(when diags
(insert diags)))
(message "Claude Code context updated with diagnostics"))))
(defun claude-code-clear-context ()
"Clear the Claude Code context file."
(interactive)
(when (file-exists-p claude-code-context-file)
(delete-file claude-code-context-file)
(message "Claude Code context cleared")))
(defun claude-code--update-context-timer ()
"Timer function to update context periodically."
(when (and (buffer-file-name)
(not (minibufferp)))
(claude-code-update-context)))
(defun claude-code-context-mode-enable ()
"Enable automatic context updates."
(unless claude-code-context-timer
(setq claude-code-context-timer
(run-with-idle-timer claude-code-context-update-interval t
#'claude-code--update-context-timer))
(message "Claude Code context mode enabled")))
(defun claude-code-context-mode-disable ()
"Disable automatic context updates."
(when claude-code-context-timer
(cancel-timer claude-code-context-timer)
(setq claude-code-context-timer nil)
(message "Claude Code context mode disabled")))
;;;###autoload
(define-minor-mode claude-code-context-mode
"Minor mode for automatic Claude Code context updates."
:global t
:lighter " CC"
:group 'claude-code-context
(if claude-code-context-mode
(claude-code-context-mode-enable)
(claude-code-context-mode-disable)))
;; Keybindings
(defvar claude-code-context-command-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "u") 'claude-code-update-context)
(define-key map (kbd "d") 'claude-code-add-diagnostics)
(define-key map (kbd "c") 'claude-code-clear-context)
(define-key map (kbd "m") 'claude-code-context-mode)
map)
"Keymap for claude-code-context commands.")
(global-set-key (kbd "C-c C-l") claude-code-context-command-map)
(provide 'claude-code-context)
;;; claude-code-context.el ends here
|