llm stuff?

This commit is contained in:
Joe Frikker
2026-10-07 14:26:39 -04:00
parent 402002e6e6
commit 55c2311bd7
2 changed files with 265 additions and 169 deletions
Generated
+15 -15
View File
@@ -8,11 +8,11 @@
"systems": "systems" "systems": "systems"
}, },
"locked": { "locked": {
"lastModified": 1790280108, "lastModified": 1791071338,
"narHash": "sha256-bApGLOF5XDhf3UCM1/e1yIQCoY5wW1+B88lHkcYlp2U=", "narHash": "sha256-YBAFoulgm9qEavWtmb2gHwk7lgpVZL7vtr4+yi6H3UU=",
"owner": "sadjow", "owner": "sadjow",
"repo": "claude-code-nix", "repo": "claude-code-nix",
"rev": "f10421316cc6df045497f5aa0009adce648e89ee", "rev": "b17e42820330bd34ab890632c2f6f80daf4e517f",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -28,11 +28,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1790215976, "lastModified": 1790996401,
"narHash": "sha256-VkR1rMGyjU9jtw8ISFx5uqR9e+LEaOlhHwrseFkiIVk=", "narHash": "sha256-f+kOxEmOUnQazVAmGg0i8hzwgd1kX/geY+k/Dpheye8=",
"owner": "nix-community", "owner": "nix-community",
"repo": "home-manager", "repo": "home-manager",
"rev": "a6631107a83ceab5872f298a2ea710859c80c4cb", "rev": "db7d5e2332710f5abb088f6b5de927d7f9511b35",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -49,11 +49,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1789892076, "lastModified": 1791105314,
"narHash": "sha256-Dkg4VKPmDPqTwaiw2WH5br73tXoL1qrOO0xJnR4TlcA=", "narHash": "sha256-oTM7QFgRQ+vxBpMBMc7hEYpqBtpXAzXu2xuB/tru84U=",
"owner": "nix-community", "owner": "nix-community",
"repo": "nix-index-database", "repo": "nix-index-database",
"rev": "9ad722673ab3b3f91f02135e53775825b240b869", "rev": "e740bc4e9d8918d7819a51486d5099930c65c72e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -64,11 +64,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1790218706, "lastModified": 1791143449,
"narHash": "sha256-6e4Na3z008XpdVyOXgfasXIn1aN+z8AXFG+jXdQSyuI=", "narHash": "sha256-9+n3ReS2y9xS199LoJjKUWHwZrISGHWgkD/LUZTDZyA=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "c508844df6c28fa6dabc1b6af70f3ccbd65c5201", "rev": "0d9e9b832d03ac387417e16ce1febf73b2e631e1",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -94,11 +94,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1788678358, "lastModified": 1790708379,
"narHash": "sha256-xFu9deElkBd81tRYo2yRSZQ40LDXMnVd/gO1/uELxhI=", "narHash": "sha256-UShpDPmypGviorjBWDwRtKWUTdVik7Zp6bt1t875jV4=",
"owner": "~rycee", "owner": "~rycee",
"repo": "nur-expressions", "repo": "nur-expressions",
"rev": "2554c0e25259c6ab3e71dac5177f8d38f76a6e1c", "rev": "b549e36268fa8c975535d0405f66e013b234a0a4",
"type": "sourcehut" "type": "sourcehut"
}, },
"original": { "original": {
+184 -88
View File
@@ -801,20 +801,13 @@ Actually, nix *really* requires ~bash~. This is a plugin that allows using zsh f
} }
#+END_SRC #+END_SRC
** Claude Code ** LLM
:PROPERTIES: :PROPERTIES:
:header-args:elisp: :tangle target/emacs.el :header-args:elisp: :tangle target/emacs.el
:END: :END:
#+BEGIN_SRC nix #+BEGIN_SRC nix
{ (let gptel = (epkgs: epkgs.melpaBuild {
programs.claude-code = {
enable = true;
};
programs.emacs = {
extraPackages = epkgs: with epkgs;
let gptel = (epkgs.melpaBuild {
pname = "gptel"; pname = "gptel";
version = "0.9.9.6"; version = "0.9.9.6";
src = pkgs.fetchFromGitHub { src = pkgs.fetchFromGitHub {
@@ -828,8 +821,16 @@ Actually, nix *really* requires ~bash~. This is a plugin that allows using zsh f
''; '';
packageRequires = [ epkgs.transient ]; packageRequires = [ epkgs.transient ];
}); });
in [ in
(epkgs.trivialBuild { {
programs.claude-code = {
enable = true;
};
programs.emacs.init.usePackage = {
claude-code = {
enable = true;
package = (epkgs: epkgs.trivialBuild {
pname = "claude-code"; pname = "claude-code";
version = "0.4.5"; version = "0.4.5";
src = pkgs.fetchFromGitHub { src = pkgs.fetchFromGitHub {
@@ -839,8 +840,30 @@ Actually, nix *really* requires ~bash~. This is a plugin that allows using zsh f
sha256 = "sha256-5QJrWIu4EgnHcOqMwlrs2JBBx7aI9OaSJswesr6Apfk="; sha256 = "sha256-5QJrWIu4EgnHcOqMwlrs2JBBx7aI9OaSJswesr6Apfk=";
}; };
packageRequires = [ epkgs.inheritenv ]; packageRequires = [ epkgs.inheritenv ];
}) });
(epkgs.melpaBuild { bindKeyMap."C-c c" = "claude-code-command-map";
custom.claude-code-optimize-window-resize = false;
};
gptel = {
enable = true;
package = gptel;
command = ["gptel"];
bind."C-c g" = "gptel-menu";
custom = {
gptel-default-mode = "'org-mode";
gptel-model = "'claude-sonnet-5";
gptel-org-branching-context = true;
gptel-include-reasoning = false;
};
config = ''
<<emacs-gptel-config>>
'';
};
gptel-agent = {
enable = true;
package = (epkgs: epkgs.melpaBuild {
pname = "gptel-agent"; pname = "gptel-agent";
version = "20260823"; version = "20260823";
src = pkgs.fetchFromGitHub { src = pkgs.fetchFromGitHub {
@@ -852,30 +875,57 @@ Actually, nix *really* requires ~bash~. This is a plugin that allows using zsh f
recipe = pkgs.writeText "gptel-agent-recipe" '' recipe = pkgs.writeText "gptel-agent-recipe" ''
(gptel-agent :fetcher github :repo "karthink/gptel-agent" :files (:defaults "agents")) (gptel-agent :fetcher github :repo "karthink/gptel-agent" :files (:defaults "agents"))
''; '';
packageRequires = [ gptel ]; packageRequires = [ (gptel epkgs) ];
}) });
gptel after = ["gptel"];
]; config = ''
<<emacs-gptel-agent-config>>
'';
}; };
} };
})
#+END_SRC #+END_SRC
#+BEGIN_SRC elisp #+BEGIN_SRC elisp :tangle no :noweb-ref emacs-gptel-config
(use-package claude-code (setf (alist-get 'org-mode gptel-prompt-prefix-alist) "@user\n")
:bind-keymap ("C-c c" . claude-code-command-map) (setf (alist-get 'org-mode gptel-response-prefix-alist) "@assistant\n")
:custom (claude-code-optimize-window-resize nil)) (gptel-make-tool
:name "git_uncommitted_diff"
:function (lambda ()
(magit-git-output "diff" "HEAD"))
:description "Return a unified diff of all uncommitted changes (staged and
unstaged) in the current git repository, relative to HEAD. Note: this does
not include brand-new untracked files that have never been added to the
index."
:args nil
:category "git")
(use-package gptel (gptel-make-tool
:commands "gptel" :name "git_head_commit_diff"
:bind (("C-c g" . gptel-menu)) :function (lambda ()
:custom (magit-git-output "show" "HEAD"))
(require 'org) :description "Return the diff (including commit message) introduced by the
(gptel-default-mode 'org-mode) HEAD commit in the current git repository, i.e. =git show HEAD=."
(gptel-model 'claude-sonnet-5)) :args nil
:category "git")
(use-package gptel-agent (gptel-make-tool
:after gptel :name "git_branch_diff"
:config :function (lambda ()
(let* ((upstream (magit-get-upstream-branch))
(merge-base (and upstream (magit-git-string "merge-base" "HEAD" upstream))))
(if (not merge-base)
"Could not determine upstream branch / merge base for the current branch."
(magit-git-output "diff" merge-base))))
:description "Return a unified diff of all committed changes on the current
branch relative to its upstream tracking branch's merge base. This shows
everything this branch has added since it diverged from upstream."
:args nil
:category "git")
#+END_SRC
#+BEGIN_SRC elisp :tangle no :noweb-ref emacs-gptel-agent-config
(require 'gptel-agent-tools-introspection) (require 'gptel-agent-tools-introspection)
(gptel-agent-update) (gptel-agent-update)
(gptel-make-preset 'coding (gptel-make-preset 'coding
@@ -883,13 +933,16 @@ Actually, nix *really* requires ~bash~. This is a plugin that allows using zsh f
:backend "Claude" :backend "Claude"
:model 'claude-sonnet-5 :model 'claude-sonnet-5
:use-tools t :use-tools t
:tools '("Agent" "Skill" "TodoWrite" "Grep" "Read" "Glob" "Write" "Insert" :max-tokens 128000
"Edit" "Mkdir" "Diagnostics" "WebFetch" "WebSearch" "Bash")) :tools '("Grep" "Read" "Glob" "Write" "Insert"
"Edit" "Mkdir" "Diagnostics" "WebFetch" "WebSearch" "Bash" "git_uncommitted_diff" "git_head_commit_diff"
"git_branch_diff"))
(gptel-make-preset 'research (gptel-make-preset 'research
:description "Preset for answering questions with web results" :description "Preset for answering questions with web results"
:backend "Claude" :backend "Claude"
:model 'claude-sonnet-5 :model 'claude-sonnet-5
:use-tools t :use-tools t
:max-tokens 128000
:confirm-tool-calls nil :confirm-tool-calls nil
:tools '("WebFetch" "WebSearch")) :tools '("WebFetch" "WebSearch"))
(gptel-make-preset 'emacs-research (gptel-make-preset 'emacs-research
@@ -897,13 +950,14 @@ Actually, nix *really* requires ~bash~. This is a plugin that allows using zsh f
:backend "Claude" :backend "Claude"
:model 'claude-sonnet-5 :model 'claude-sonnet-5
:use-tools t :use-tools t
:max-tokens 128000
:confirm-tool-calls nil :confirm-tool-calls nil
:tools '("WebFetch" "WebSearch" :tools '("WebFetch" "WebSearch"
"variable_completions" "command_completions" "function_completions" "variable_completions" "command_completions" "function_completions"
"variable_documentation" "function_documentation" "variable_value" "variable_documentation" "function_documentation" "variable_value"
"variable_source" "function_source" "symbol_manual_section" "variable_source" "function_source" "symbol_manual_section"
"library_source" "manual_node_contents" "manual_nodes" "manual_names" "library_source" "manual_node_contents" "manual_nodes" "manual_names"
"features" "load_paths" "symbol_exists"))) "features" "load_paths" "symbol_exists"))
#+END_SRC #+END_SRC
** Age ** Age
@@ -992,14 +1046,12 @@ These are just some general settings that apply everywhere. First, a few package
{ {
programs.emacs = { programs.emacs = {
extraPackages = epkgs: with epkgs; [ extraPackages = epkgs: with epkgs; [
ace-window
doom-modeline doom-modeline
free-keys free-keys
ligature
mixed-pitch
popper
]; ];
}; };
programs.emacs.init.usePackage.emacs.enable = true;
} }
#+END_SRC #+END_SRC
@@ -1106,36 +1158,52 @@ especially on monitors with a lot of vertical space.
From the docs: "If ‘complete’, TAB first tries to indent the current line, and if the line was From the docs: "If ‘complete’, TAB first tries to indent the current line, and if the line was
already indented, then try to complete the thing at point." Recommended by [[https://github.com/minad/corfu][the ~corfu~ readme]]. already indented, then try to complete the thing at point." Recommended by [[https://github.com/minad/corfu][the ~corfu~ readme]].
#+BEGIN_SRC elisp #+BEGIN_SRC nix
(setopt tab-always-indent 'complete) {
programs.emacs.init.usePackage.emacs.custom.tab-always-indent = "'complete";
}
#+END_SRC #+END_SRC
Set the cursor to be a bar. I'm not sure what the benefit would be of a block cursor, since the Set the cursor to be a bar. I'm not sure what the benefit would be of a block cursor, since the
current character isn't really "selected" like it would be in Helix. I switch this to a box when in current character isn't really "selected" like it would be in Helix. I switch this to a box when in
god mode / read-only buffers, like vim would. god mode / read-only buffers, like vim would.
#+BEGIN_SRC elisp #+BEGIN_SRC nix
{
programs.emacs.init.usePackage.emacs.config = ''
(setq-default cursor-type 'bar) (setq-default cursor-type 'bar)
'';
}
#+END_SRC #+END_SRC
Repeat-mode takes care of eliminating some annoying duplicate keypresses. I mostly use repeat-mode Repeat-mode takes care of eliminating some annoying duplicate keypresses. I mostly use repeat-mode
for two-character commands that need to be repeated; ~devil~ also has some single-key-with-modifier for two-character commands that need to be repeated; ~devil~ also has some single-key-with-modifier
repeats set up that only apply in that mode. repeats set up that only apply in that mode.
#+BEGIN_SRC elisp #+BEGIN_SRC nix
(add-hook 'after-init-hook 'repeat-mode) {
programs.emacs.init.usePackage.repeat = {
enable = true;
hook = ["after-init"];
};
}
#+END_SRC #+END_SRC
Save the minibuffer history to disk, so recently-used options show up at the top of the picker Save the minibuffer history to disk, so recently-used options show up at the top of the picker
across restarts. across restarts.
#+BEGIN_SRC elisp #+BEGIN_SRC nix
(add-hook 'after-init-hook 'savehist-mode) {
programs.emacs.init.usePackage.savehist = {
enable = true;
hook = ["after-init"];
};
}
#+END_SRC #+END_SRC
Let's unbind some builtin keys that I don't use. I'm not sure if I'll replace them with anything or not, but at a minimum it'll avoid accidental keypresses and clean up which-key output. Let's unbind some builtin keys that I don't use. I'm not sure if I'll replace them with anything or not, but at a minimum it'll avoid accidental keypresses and clean up which-key output.
#+begin_src elisp #+begin_src elisp :tangle no
(require 'bind-key) (require 'bind-key)
(unbind-key "C-x RET") (unbind-key "C-x RET")
(unbind-key "C-x #") (unbind-key "C-x #")
@@ -1161,22 +1229,34 @@ it would update after every command, slowing down everything). I don't need the
I have the tab bar at the top of the window. The other settings just clear up some space, and make I have the tab bar at the top of the window. The other settings just clear up some space, and make
things look at little nicer. things look at little nicer.
#+BEGIN_SRC elisp #+BEGIN_SRC nix
(require 'doom-modeline) {
(setopt doom-modeline-irc nil) programs.emacs.init.usePackage.doom-modeline = {
(setopt doom-modeline-workspace-name nil) enable = true;
(setopt doom-modeline-buffer-encoding nil) hook = ["after-init"];
(setopt doom-modeline-buffer-file-name-style 'relative-to-project) custom = {
; (setopt doom-modeline-vcs-max-length 30) doom-modeline-irc = false;
doom-modeline-workspace-name = false;
doom-modeline-buffer-encoding = false;
doom-modeline-buffer-file-name-style = "'relative-to-project";
};
config = ''
(doom-modeline-remove-segment 'vcs 'main) (doom-modeline-remove-segment 'vcs 'main)
(doom-modeline-mode) '';
};
}
#+END_SRC #+END_SRC
Ligature mode combines character sequences like <= into a single on-screen glyph. It looks kind of Ligature mode combines character sequences like <= into a single on-screen glyph. It looks kind of
cool, so I'm turning it on in prog mode. The enabled ligatures are font-specific, taken from [[https://github.com/mickeynp/ligature.el/wiki#jetbrains-mono][the cool, so I'm turning it on in prog mode. The enabled ligatures are font-specific, taken from [[https://github.com/mickeynp/ligature.el/wiki#jetbrains-mono][the
ligature wiki]]. ligature wiki]].
#+BEGIN_SRC elisp :noweb no #+BEGIN_SRC nix :noweb no
{
programs.emacs.init.usePackage.ligature = {
enable = true;
hook = ["(after-init . global-ligature-mode)"];
config = ''
(ligature-set-ligatures 'prog-mode (ligature-set-ligatures 'prog-mode
'("--" "---" "==" "===" "!=" "!==" "=!=" '("--" "---" "==" "===" "!=" "!==" "=!="
"=:=" "=/=" "<=" ">=" "&&" "&&&" "&=" "++" "+++" "***" ";;" "!!" "=:=" "=/=" "<=" ">=" "&&" "&&&" "&=" "++" "+++" "***" ";;" "!!"
@@ -1191,30 +1271,48 @@ ligature wiki]].
"|||>" "<|||" "<|>" "..." ".." ".=" "..<" ".?" "::" ":::" ":=" "::=" "|||>" "<|||" "<|>" "..." ".." ".=" "..<" ".?" "::" ":::" ":=" "::="
":?" ":?>" "//" "///" "/*" "*/" "/=" "//=" "/==" "@_" "__" "???" ":?" ":?>" "//" "///" "/*" "*/" "/=" "//=" "/==" "@_" "__" "???"
"<:<" ";;;")) "<:<" ";;;"))
(global-ligature-mode t) '';
};
}
#+END_SRC #+END_SRC
Use variable-width fonts in text buffers. ~mixed-pitch-mode~ keeps most code blocks as monospace. Use variable-width fonts in text buffers. ~mixed-pitch-mode~ keeps most code blocks as monospace.
#+BEGIN_SRC elisp #+BEGIN_SRC nix
(add-hook 'text-mode-hook 'mixed-pitch-mode) {
programs.emacs.init.usePackage.mixed-pitch = {
enable = true;
command = ["mixed-pitch-mode"];
hook = ["text-mode"];
init = ''
(defun no-mixed-pitch () (defun no-mixed-pitch ()
(mixed-pitch-mode -1)) (mixed-pitch-mode -1))
(add-hook 'yaml-ts-mode-hook 'no-mixed-pitch) (add-hook 'yaml-ts-mode-hook 'no-mixed-pitch)
(add-hook 'mhtml-mode 'no-mixed-pitch) (add-hook 'mhtml-mode 'no-mixed-pitch)
(add-hook 'nxml-mode 'no-mixed-pitch) (add-hook 'nxml-mode 'no-mixed-pitch)
'';
};
}
#+END_SRC #+END_SRC
A basic ace-window setup. Allows switching between windows quickly (although avy can do the same...). A basic ace-window setup. Allows switching between windows quickly (although avy can do the same...).
#+BEGIN_SRC elisp #+BEGIN_SRC nix
(bind-keys ("M-o" . ace-window) {
("s-o" . ace-window) programs.emacs.init.usePackage.ace-window = {
("C-c o" . ace-window)) enable = true;
(setopt aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)) bind = {
(setopt aw-dispatch-always t) "M-o" = "ace-window";
"s-o" = "ace-window";
"C-c o" = "ace-window";
};
custom = {
aw-keys = "'(?a ?s ?d ?f ?g ?h ?j ?k ?l)";
aw-dispatch-always = true;
};
};
}
#+END_SRC #+END_SRC
Set up a few project- / workspace-related key bindings. Set up a few project- / workspace-related key bindings.
@@ -1239,23 +1337,13 @@ Set up a few project- / workspace-related key bindings.
} }
#+END_SRC #+END_SRC
Don't run a server. I'm not using this, I can always turn it back on if I need to.
#+BEGIN_SRC elisp
(server-mode -1)
#+END_SRC
All the beeping is annoying. This flashes a huge icon over the screen, which is still annoying, but All the beeping is annoying. This flashes a huge icon over the screen, which is still annoying, but
less so? less so?
#+BEGIN_SRC elisp #+BEGIN_SRC nix
(setopt visible-bell t) {
#+END_SRC programs.emacs.init.usePackage.emacs.custom.visible-bell = true;
}
I'm trying this out. This disables visual selections. It's bold, which is why I like it :)
#+BEGIN_SRC elisp
(transient-mark-mode -1)
#+END_SRC #+END_SRC
I use tabs to manage multiple "workspaces". I don't tie a project to a tab or anything; often fixing I use tabs to manage multiple "workspaces". I don't tie a project to a tab or anything; often fixing
@@ -1266,18 +1354,27 @@ fix / issue, and leave it open until I'm done with that issue.
change when drilling into a help page or something. I've set up repeat mode to make it easier to change when drilling into a help page or something. I've set up repeat mode to make it easier to
move backward / forward through history. move backward / forward through history.
#+BEGIN_SRC elisp #+BEGIN_SRC nix
{
programs.emacs.init.usePackage.tab-bar = {
enable = true;
hook = ["(after-init . tab-bar-history-mode)"];
config = ''
(bind-keys :repeat-map tab-bar-repeat-map (bind-keys :repeat-map tab-bar-repeat-map
("<left>" . tab-bar-history-back) ("<left>" . tab-bar-history-back)
("<right>" . tab-bar-history-forward)) ("<right>" . tab-bar-history-forward))
'';
(tab-bar-history-mode) };
}
#+END_SRC #+END_SRC
Make compilation mode buffers auto-scroll to the first error: Make compilation mode buffers auto-scroll to the first error:
#+BEGIN_SRC elisp #+BEGIN_SRC nix
(setopt compilation-scroll-output 'first-error) {
programs.emacs.init.usePackage.compile.enable = true;
programs.emacs.init.usePackage.compile.custom.compilation-scroll-output = true;
}
#+END_SRC #+END_SRC
#+begin_src nix #+begin_src nix
@@ -1331,7 +1428,7 @@ content to be.
}; };
custom = { custom = {
popper-display-control = false; popper-display-control = false;
popper-reference-buffers = ''(concat my/bottom-popups my/right-popups)''; popper-reference-buffers = ''(append jf/bottom-popups jf/right-popups)'';
}; };
}; };
}; };
@@ -1367,7 +1464,6 @@ content to be.
"\\*claude:.*" "\\*claude:.*"
"\\*Man .*" "\\*Man .*"
"\\*List .*" "\\*List .*"
"\\*Embark Actions\\*"
"\\*eldoc\\*")) "\\*eldoc\\*"))
#+end_src #+end_src
@@ -1768,7 +1864,7 @@ I don't like UI elements that insert fake text into the file. They mess up the s
programs.emacs.init.usePackage.eglot = { programs.emacs.init.usePackage.eglot = {
custom = { custom = {
eglot-ignored-server-capabilities = "'(:inlayHintProvider :semanticTokensProvider)"; eglot-ignored-server-capabilities = "'(:inlayHintProvider :semanticTokensProvider)";
eglot-code-actions-indications = false; eglot-code-action-indications = false;
eglot-events-buffer-config = "'(:size 300000 :format full)"; eglot-events-buffer-config = "'(:size 300000 :format full)";
}; };
config = "(add-hook 'eglot-managed-mode-hook (lambda () (eglot-inlay-hints-mode -1)) nil t)"; config = "(add-hook 'eglot-managed-mode-hook (lambda () (eglot-inlay-hints-mode -1)) nil t)";