Claude
Skills
Sign in
Back

package-conventions

Included with Lifetime
$97 forever

Emacs Lisp package development standards and conventions

General

What this skill does


# Emacs Package Conventions

Comprehensive guide to Emacs Lisp package development standards, covering naming, structure, metadata, and distribution requirements.

## Overview

Emacs packages follow strict conventions to ensure compatibility, discoverability, and quality. These conventions cover file structure, naming, metadata, documentation, and distribution through package archives like MELPA and GNU ELPA.

## Package Types

### Simple Package

Single `.el` file with header metadata.

```elisp
;;; mypackage.el --- Brief description  -*- lexical-binding: t; -*-

;; Copyright (C) 2025 Your Name

;; Author: Your Name <[email protected]>
;; Version: 1.0.0
;; Package-Requires: ((emacs "25.1"))
;; Keywords: convenience, tools
;; URL: https://github.com/user/mypackage

;;; Commentary:

;; Longer description of what the package does.

;;; Code:

(defun mypackage-hello ()
  "Say hello."
  (interactive)
  (message "Hello from mypackage!"))

(provide 'mypackage)
;;; mypackage.el ends here
```

### Multi-File Package

Directory with `-pkg.el` descriptor file.

Structure:
```
mypackage/
├── mypackage.el
├── mypackage-utils.el
├── mypackage-pkg.el
└── README.md
```

`mypackage-pkg.el`:
```elisp
(define-package "mypackage" "1.0.0"
  "Brief description"
  '((emacs "25.1")
    (dash "2.19.1"))
  :keywords '("convenience" "tools")
  :url "https://github.com/user/mypackage")
```

## File Header Conventions

### Required Headers

**Simple package** (single `.el`):
- `;;; filename.el --- description`
- `;; Author:`
- `;; Version:` or `;; Package-Version:`
- `;;; Commentary:`
- `;;; Code:`
- `(provide 'feature-name)`
- `;;; filename.el ends here`

### Standard Headers

```elisp
;;; mypackage.el --- Brief one-line description  -*- lexical-binding: t; -*-

;; Copyright (C) 2025 Author Name

;; Author: Author Name <[email protected]>
;; Maintainer: Maintainer Name <[email protected]>
;; Version: 1.0.0
;; Package-Requires: ((emacs "25.1") (dash "2.19.1"))
;; Keywords: convenience tools
;; URL: https://github.com/user/mypackage
;; SPDX-License-Identifier: GPL-3.0-or-later

;;; License:

;; 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.

;;; Commentary:

;; Detailed description spanning multiple lines.
;; Explain what the package does, how to use it.

;;; Code:
```

### Lexical Binding

Always enable lexical binding:
```elisp
;;; mypackage.el --- Description  -*- lexical-binding: t; -*-
```

Required for modern Emacs development and MELPA acceptance.

## Naming Conventions

### Package Prefix

Choose short, unique prefix. All public symbols must use this prefix.

```elisp
;; Package: super-mode
;; Prefix: super-

(defun super-activate ()          ; ✓ Public function
  ...)

(defvar super-default-value nil)  ; ✓ Public variable

(defun super--internal-helper ()  ; ✓ Private function (double dash)
  ...)

(defvar super--state nil)         ; ✓ Private variable
```

### Symbol Naming Rules

**Public vs Private:**
- Public: `prefix-name`
- Private: `prefix--name` (double dash)

**Variable types:**
- Function variable: `prefix-hook-function`
- Hook: `prefix-mode-hook`
- Option: `prefix-enable-feature`
- Local variable: `prefix--internal-state`

**Special cases:**
- Commands can omit prefix if memorable: `list-frobs` in `frob` package
- Major modes: `prefix-mode`
- Minor modes: `prefix-minor-mode`

### Case Convention

Use lowercase with hyphens (lisp-case):
```elisp
(defun my-package-do-something ()  ; ✓
  ...)

(defun myPackageDoSomething ()     ; ✗ Wrong
  ...)
```

## Package Metadata

### Version Format

Semantic versioning: `MAJOR.MINOR.PATCH`

```elisp
;; Version: 1.2.3
```

For snapshot builds:
```elisp
;; Package-Version: 1.2.3-snapshot
;; Version: 1.2.3
```

### Dependencies

Specify minimum Emacs version and package dependencies:

```elisp
;; Package-Requires: ((emacs "26.1") (dash "2.19.1") (s "1.12.0"))
```

Each dependency: `(package-name "version")`

### Keywords

Use standard keywords from `finder-known-keywords`:

```elisp
;; Keywords: convenience tools matching
```

Common keywords:
- `convenience` - Convenience features
- `tools` - Programming tools
- `extensions` - Emacs extensions
- `languages` - Language support
- `comm` - Communication
- `files` - File handling
- `data` - Data structures

Check available: `M-x describe-variable RET finder-known-keywords`

## Code Organization

### Feature Provision

Always end with `provide`:

```elisp
(provide 'mypackage)
;;; mypackage.el ends here
```

Feature name must match file name (without `.el`).

### Loading Behavior

**Don't modify Emacs on load:**
```elisp
;; ✗ Bad - changes behavior on load
(global-set-key (kbd "C-c m") #'my-command)

;; ✓ Good - user explicitly enables
(defun my-mode-setup ()
  "Set up keybindings for my-mode."
  (local-set-key (kbd "C-c m") #'my-command))
```

### Autoload Cookies

Mark interactive commands for autoloading:

```elisp
;;;###autoload
(defun my-package-start ()
  "Start my-package."
  (interactive)
  ...)

;;;###autoload
(define-minor-mode my-mode
  "Toggle My Mode."
  ...)
```

### Group and Custom Variables

Define customization group:

```elisp
(defgroup my-package nil
  "Settings for my-package."
  :group 'applications
  :prefix "my-package-")

(defcustom my-package-option t
  "Description of option."
  :type 'boolean
  :group 'my-package)
```

## Documentation Standards

### Docstrings

**Functions:**
```elisp
(defun my-package-process (input &optional format)
  "Process INPUT according to FORMAT.

INPUT should be a string or buffer.
FORMAT, if non-nil, specifies output format (symbol).

Return processed result as string."
  ...)
```

First line: brief description ending with period.
Following lines: detailed explanation.
Document arguments in CAPS.
Document return value.

**Variables:**
```elisp
(defvar my-package-cache nil
  "Cache for processed results.
Each entry is (KEY . VALUE) where KEY is input and VALUE is result.")
```

**User options:**
```elisp
(defcustom my-package-auto-save t
  "Non-nil means automatically save results.
When enabled, results are saved to `my-package-save-file'."
  :type 'boolean
  :group 'my-package)
```

### Checkdoc Compliance

Verify documentation:
```elisp
M-x checkdoc RET
```

Requirements:
- First line ends with period
- First line fits in 80 columns
- Argument names in CAPS
- References to symbols quoted with `symbol'
- No spelling errors

## Code Quality

### Required Tools

**package-lint:**
```elisp
M-x package-lint-current-buffer
```

Checks:
- Header format
- Dependency declarations
- Symbol naming
- Autoload cookies

**flycheck-package:**
```elisp
(require 'flycheck-package)
(flycheck-package-setup)
```

Real-time package.el validation.

### Common Issues

**Missing lexical binding:**
```elisp
;;; package.el --- Description  -*- lexical-binding: t; -*-
```

**Wrong provide:**
```elisp
;; File: my-utils.el
(provide 'my-utils)  ; ✓ Matches filename

;; File: my-package.el
(provide 'my-pkg)    ; ✗ Doesn't match filename
```

**Namespace pollution:**
```elisp
;; ✗ Bad
(defun format-string (s)  ; Collides with other packages
  ...)

;; ✓ Good
(defun my-package-format-string (s)
  ...)
```

**Global state on load:**
```elisp
;; ✗ Bad
(setq some-global-var t)  ; Changes Emacs on load

;; ✓ Good
(defcustom my-package-feature-enabled nil
  "Enable my-package feature."
  :type 'boolean
  :set (lambda (sym val)
         (set-default sym val)
         (when val (my-package-activate))))
```

## MELPA Submission

### Repository Requirements

**Source control:**
- Git or Mercurial only
- Official repository (no forks)
- Contains LICENSE file

**Structure:**
```
mypackage/
├── mypackage.el
├── LICENSE
└── README.md
```

### Recipe Format

Create `recipes/mypackage` in MELPA repository:

```elisp
(mypackage :fetcher github
           :repo "user/mypac

Related in General