Greger is a Claude chat interface with tool use. It can read and edit code, download web pages, run shell commands, etc.
- Installation
- Usage
- Features
- Included tools
- Build your own tool
- Customization
- Examples
- Why "Greger"?
- License
Greger is available from MELPA. To install it, first add MELPA to your package archives by adding this to your init file:
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)
Then refresh your package list and install Greger:
M-x package-refresh-contents
M-x package-install RET greger
Once installed, just add to your configuration:
(require 'greger)
If you use use-package, you can install and configure Greger with:
(use-package greger
:ensure t
:bind ("C-M-;" . greger))
This will automatically install Greger from MELPA and set up the recommended keybinding.
There are two ways to authenticate Greger:
- Set the
ANTHROPIC_API_KEY
environment variable, or - Set
greger-anthropic-key-fn
to a function that returns an API key
You can set the environment variable in your Emacs configuration:
(setenv "ANTHROPIC_API_KEY" "your-claude-api-key")
If you use greger-anthropic-key-fn
, you can for example use auth-source:
(setq greger-anthropic-key-fn
(lambda () (cadr (auth-source-user-and-password "api.anthropic.com" "emacs"))))
Or in use-package:
(use-package greger
:ensure t
:bind ("C-M-;" . greger)
:custom
(greger-anthropic-key-fn
(lambda () (cadr (auth-source-user-and-password "api.anthropic.com" "emacs")))))
To start a new Greger session:
M-x greger
Or start a session with a reference to a particular point in a file:
C-u M-x greger
The recommended key binding for greger
is C-M-;
(global-set-key (kbd "C-M-;") 'greger)
In Greger buffers:
M-<return>
- Run agent (greger-buffer
)C-M-<return>
orC-u M-<return>
- Run without tools or thinking (greger-buffer-no-tools
)C-g
- Interrupt tool execution or text generation (greger-interrupt
)C-; u
- Insert# USER
tag (greger-insert-user-tag
)C-; a
- Insert# ASSISTANT
tag (greger-insert-assistant-tag
)C-; s
- Insert# SYSTEM
tag (greger-insert-system-tag
)C-; m
- Choose Claude model (greger-set-model
)C-; b
- Select a buffer and insert its file path (greger-mention-buffer-file
)C-; c
- Copy code block at point (greger-ui-copy-code
)C-; t
- Toggle thinking off and on (greger-toggle-thinking
)C-; f
- Toggle follow mode (greger-toggle-follow-mode
)C-; C-f
- Toggle folding and invisibility (greger-ui-toggle-folding
)TAB
- When inside a folded code block or citation: toggle folding
The full chat history is an editable Emacs buffer.
Greger uses a markdown-inspired syntax:
# SYSTEM
You're a helpful agent.
# USER
Do something
# THINKING
The user wants me to do something.
# ASSISTANT
I'll do something for you.
# TOOL USE
Name: read-file
## path
test.txt
# TOOL RESULT
Hello, world!
# ASSISTANT
The file contains: Hello, world!
Font-lock is used to hide a few things (e.g. thinking signatures) but they're still there in the file, and you can reveal all hidden text with C-; C-f
or M-x greger-ui-toggle-folding
.
This means that anything in the chat can be edited as text. You can yank any part of the conversation, undo steps, modify assistant responses, etc. And you can save chats as regular files.
It also means that you can share and let others continue or modify it.
Greger is able to use tools to edit files, run shell commands, search the web, etc. The full set of bundled tools is documented below. You can also give Greger your own custom tools (also documented below).
It's easy to get lost when an agent is editing multiple files in quick succession. Or if you're afk while the agent does your work for you.
Therefore Greger commits every change to Git. It means that the Git history can contain lots of commits for relatively minor changes, but it does give you the ability to revert to any previous state.
If the Greger chat is a file that's added to the Git repository, the Greger file will also be committed along with the changes, so you have lineage of the prompts and agent decisions that resulted in each change.
Branching is your friend here -- create a new branch for every new Greger session and keep your pieces of work separate. GitHub lets you squash PRs automatically, which also helps declutter the history.
Magit is magic, and makes it really easy to navigate through agent commits.
Assistant text and thinking is streamed to output. Tool use and tool responses are currently not streamed, but will be in the future
Greger automatically uses prompt caching. In agentic settings this can save tons of money.
Greger supports the latest Claude models:
- claude-sonnet-4-20250514
- claude-opus-4-20250514
Claude is the only supported model provider at the moment. Others could be added, but right now Claude is the best code LLM.
Greger should work out of the box on most UNIX systems without having to install external depdencies. The standard curl
command is used to communicate with the Anthropic API.
The Greger test suite has over 200 (unit/integration/end-to-end) tests and >90% test coverage. Not to say there aren't bugs, but it's fairly solid.
Greger comes with a "standard library" of tools. These are the included tools:
Read the contents of a file from the filesystem.
Parameters:
path
(required): Path to the file to readinclude-line-numbers
(optional): Whether to include line numbers in the output. Useful when you plan to modify the filestart-line
(optional): Starting line number (1-based) to begin reading fromend-line
(optional): Ending line number (1-based) to stop reading at (inclusive)
Write a new file with the given contents. Fails if the file already exists.
Parameters:
path
(required): Absolute path to the new filecontents
(required): Contents to write to the new filegit-commit-message
(required): Git commit message for this change
Replace the entire contents of an existing file. Slow but reliable - replaces the complete file contents. Use str-replace
for targeted changes in larger files.
Parameters:
path
(required): Path to the file to replacecontents
(required): New contents to replace the entire filegit-commit-message
(required): Git commit message for this change
This is the real work horse of agentic editing.
Replace a specific string or content block in a file with new content. Finds the exact original content and replaces it with new content. Be extra careful to format the original-content exactly correctly, taking extra care with whitespace and newlines. In addition to replacing strings, str-replace can also be used to prepend, append, or delete contents from a file.
Parameters:
path
(required): Path to the file to modifyoriginal-content
(required): The exact content to find and replacenew-content
(required): The new content to replace the original content withgit-commit-message
(required): Git commit message for this changereplace-all
(optional): If true, replace all instances of original-content. If false (default), replace only the first instance
Recursively create a directory and all parent directories if they don't exist.
Parameters:
path
(required): Path to the directory to creategit-commit-message
(required): Git commit message for this change
Rename or move a file from one path to another.
Parameters:
old-path
(required): Current path of the filenew-path
(required): New path for the filegit-commit-message
(required): Git commit message for this change
Delete files and if they're tracked in git, stage the deletion and commit.
Parameters:
paths
(required): List of file paths to deletegit-commit-message
(required): Git commit message for this change
List files and directories in a given directory.
Parameters:
path
(optional): Path to the directory to list. Defaults to current directoryexclude-directories-recursive
(optional): List of directory names to exclude when recursively listing files. Defaults to [".git", "pycache"]recursive
(optional): Whether to list files recursively
Search for patterns in files using ripgrep (rg) command line tool. Note that ripgrep only matches on single lines, so you can't search across multiple lines.
If Ripgrep isn't installed, just tell Greger to install it.
Parameters:
pattern
(required): The search pattern (regex or literal string). Uses regular expression syntax by default. Meta characters like .(){}*+?[]^$|\ have special meaning and should be escaped with backslash if you want to match them literallypath
(optional): Directory or file path to search in. Directories are searched recursively. Supports glob patterns and respects .gitignore rules by default. Use '.' for current directorycase-sensitive
(optional): Whether the search should be case-sensitivefile-type
(optional): Restrict search to specific file types using predefined type names. Examples: 'py', 'js', 'md', 'cpp', 'elisp', 'java', 'rust', 'go', 'html', 'css', 'json', 'xml', 'yaml', 'sh', 'sql', 'tex', 'dockerfile'context-lines
(optional): Number of context lines to show around matches (default: 0)fixed-strings
(optional): Treat the pattern as a literal string instead of a regular expressionword-regexp
(optional): Only show matches surrounded by word boundariesline-regexp
(optional): Only show matches where the entire line participates in the matchmax-results
(optional): Maximum number of results to return (default: 50)
Execute an arbitrary shell command and return the output.
Parameters:
command
(required): The shell command to executeworking-directory
(optional): Directory to run the command in (default: ".")timeout
(optional): Timeout in seconds for command execution (default: 600)enable-environment
(optional): Whether to source shell initialization files (.bashrc, .bash_profile) which may contain secrets and environment variables
If greger-allow-all-shell-commands
is nil, shell-command
will prompt for permission before running the command for security.
You can allow-list "safe shell commands" using <safe-shell-commands>
in the # SYSTEM
section. For example:
# SYSTEM
You are a helpful agent
<safe-shell-commands>
ls -al
</safe-shell-commands>
# USER
List all files in this directory.
Search the internet and return up-to-date information from web sources. This is a server-side tool with usage limits.
Hit TAB
or click on underlined text to see the cited URLs.
Parameters:
query
(required): Search query
Read webpage content from a URL. Can return either extracted text or raw HTML.
Parameters:
url
(required): The URL to read content fromextract-text
(optional): Whether to extract text content or return raw HTML (default: true)use-highest-readability
(optional): Whether to use eww's aggressive highest readability setting for better text extraction
Greger can use any custom tool you want. It takes three simple steps:
- Write an emacs lisp function that returns some text
- Register the tool
- Add the tool to
greger-tools
For example, let's say we want a file-count-lines
tool. First we write our line counting function (naming doesn't matter):
(defun count-lines-in-file (filename)
(with-temp-buffer
(insert-file-contents filename)
(count-lines (point-min) (point-max))))
Then we register the tool with greger-register-tool
:
(greger-register-tool "file-count-lines"
:description "Count the number of lines in a file"
:properties '((path . ((type . "string")
(description . "Path to file"))))
:required '("path")
:function count-lines-in-file)
There are lots of tool examples in greger-stdlib.el.
Finally, add the tool to 'greger-tools:
(add-to-list 'greger-tools "file-count-lines")
The following customization options are available:
- Type: choice (from available models)
- Default:
claude-sonnet-4-20250514
- Description: The currently used model.
- Type: string
- Default:
"You are an expert coding agent."
- Description: Default system prompt used for AI interactions.
- Type: integer
- Default:
32000
- Description: Maximum number of tokens to generate.
- Type: integer
- Default:
4096
- Description: Default budget for thinking (internal reasoning) content, in tokens. Set to 0 to disable thinking entirely.
- Type: boolean
- Default:
nil
- Description: Allow all shell commands to run without permission. May order 4,000 pounds of meat.
- Type: repeat symbol
- Default:
'("read-file" "write-new-file" "replace-file" "str-replace" "make-directory" "rename-file" "delete-files" "list-directory" "ripgrep" "shell-command" "read-webpage")
- Description: List of tools available to the agent.
- Type: repeat symbol
- Default:
'("web_search")
- Description: List of server tools available to the agent (e.g., web_search).
- Type: integer
- Default:
100
- Description: Maximum number of agent iterations before stopping.
You can customize all these plus all the colors and fonts with:
M-x customize-group
greger
There are a few examples of Greger chats in the ./examples directory.
Greger Tragg is a secret cold war agent in The Messenger Must Die by Kjell-Olof Bornemark. He's like a Swedish George Smiley, but he somehow manages to be even more mundane and melancholic and svårmodig. The book is a masterpiece.
MIT