BareGit
Commits
Clone:
Name Latest commit Last update
📂 designs
📄 README.md Add readme file 12 hours ago
📄 doctor-boring-test.el Implement Doctor Boring 13 hours ago
📄 doctor-boring.el Implement Doctor Boring 13 hours ago
📄 prd.md Initial PRD and design 13 hours ago

Doctor Boring

Doctor Boring is a playful, LLM-backed relative of Emacs's classic M-x doctor. It gives you the same simple conversation-buffer experience, but sends each turn to an OpenAI-compatible Chat Completions API.

It is meant as a fun side activity, not as a medical tool or serious assistant.

Requirements

Doctor Boring does not require third-party packages or external executables. When markdown-mode is unavailable, it uses text-mode automatically.

Installation

Install the package file directly with:

M-x package-install-file RET /path/to/doctor-boring.el RET

For development or a manual installation, add the repository to your load path:

(add-to-list 'load-path "/path/to/emacs-doctor")
(require 'doctor-boring)

Configuration

Run:

M-x customize-group RET doctor-boring RET

At minimum, set doctor-boring-endpoint. It is the base URL ending at the API version, not the complete Chat Completions URL. Doctor Boring appends /chat/completions itself.

For example:

(setq doctor-boring-endpoint "https://api.example.com/v1"
      doctor-boring-api-key "your-api-key"
      doctor-boring-model "your-model")

The available options are:

Option Default Purpose
doctor-boring-endpoint "" Base URL for the API
doctor-boring-api-key "" Optional bearer token
doctor-boring-model "" Model sent in each request
doctor-boring-temperature 1.0 Sampling temperature
doctor-boring-system-prompt Built in Conversation personality
doctor-boring-greeting Built in Initial visible greeting
doctor-boring-request-timeout 300 Request timeout in seconds

An empty API key omits the Authorization header. An empty model is allowed for compatible local servers that ignore it. The endpoint cannot be empty when submitting a message.

Be aware that saving the API key through Customize writes it to your Emacs customization file.

Usage

Start or return to the conversation with:

M-x doctor-boring

Type at the bottom of the *doctor-boring* buffer, then either:

Whitespace-only messages are ignored. While a request is running, the conversation buffer is read-only and another message cannot be queued.

The default personality uses subtle, classic ELIZA-style reflection. It briefly mirrors the user's wording and is instructed to end every response with a natural question.

Editing the conversation

Previous user and assistant messages remain editable. Doctor Boring rebuilds the complete history from the visible message text before every request, so an edit affects the next response.

The initial greeting is only part of the presentation. It is not sent to the API, even if you edit it.

To begin a new conversation, kill the *doctor-boring* buffer and run M-x doctor-boring again. Invoking the command while the buffer exists returns to the same conversation without resetting it.

Errors and retries

Network, timeout, HTTP, and malformed-response failures display a short local error above the message that failed. The original input is restored at the bottom of the buffer so you can edit it or submit it again.

Local errors are never included in the API conversation history. More detailed diagnostics are written to the *Messages* buffer, and the API key is redacted.

Privacy

Every submitted conversation turn sends the current recorded conversation and system prompt to the configured endpoint. Doctor Boring does not persist the conversation separately from its Emacs buffer and disables URL-library cookies for API requests.

Development

Run the test suite without contacting a real API:

emacs -Q --batch -L . -l doctor-boring-test.el \
    -f ert-run-tests-batch-and-exit

Run the static checks with:

emacs -Q --batch -L . \
    --eval '(byte-compile-file "doctor-boring.el")'

emacs -Q --batch -L . -l doctor-boring.el \
    --eval '(checkdoc-file "doctor-boring.el")'

License

Doctor Boring is released under the WTFPL.