Update AGENTS.md
This commit is contained in:
parent
18a7d1f126
commit
81fbe9ed45
1 changed files with 86 additions and 44 deletions
130
AGENTS.md
130
AGENTS.md
|
|
@ -1,21 +1,29 @@
|
|||
# Agent Guidelines for nano-gpt
|
||||
# Agent Guidelines for AI (Emacs Lisp)
|
||||
|
||||
This is an Emacs Lisp project for a dashboard application. The codebase consists of:
|
||||
- `dashboard.el` - Main dashboard implementation (180 lines)
|
||||
This is an Emacs Lisp project providing dashboard packages for AI APIs. The codebase consists of:
|
||||
- `ai.el` - Main package that loads all dashboards
|
||||
- `ppq-status.el` - Dashboard for PayPerQ API (models, balance, topup)
|
||||
- `nano-gpt-status.el` - Dashboard for Nano-GPT API (models, usage, balance, deposit)
|
||||
|
||||
## Build/Load Commands
|
||||
|
||||
```elisp
|
||||
;; Load the dashboard in Emacs
|
||||
(load-file "dashboard.el")
|
||||
;; Load the package in Emacs
|
||||
(load-file "ai.el")
|
||||
|
||||
;; Or load individual dashboards
|
||||
(load-file "ppq-status.el")
|
||||
(load-file "nano-gpt-status.el")
|
||||
|
||||
;; Byte-compile for faster loading
|
||||
(byte-compile-file "dashboard.el")
|
||||
(byte-compile-file "ai.el")
|
||||
(byte-compile-file "ppq-status.el")
|
||||
(byte-compile-file "nano-gpt-status.el")
|
||||
```
|
||||
|
||||
## Running Tests
|
||||
|
||||
This project uses Emacs's built-in ERT testing framework. No external test framework is configured.
|
||||
This project uses Emacs's built-in ERT testing framework. No test files are currently present.
|
||||
|
||||
To run a single test in Emacs:
|
||||
```elisp
|
||||
|
|
@ -25,77 +33,79 @@ To run a single test in Emacs:
|
|||
|
||||
Or from command line:
|
||||
```bash
|
||||
emacs --batch --eval "(progn (load-file \"dashboard.el\") (ert \"^test-name$\"))"
|
||||
emacs --batch --eval "(progn (load-file \"ai.el\") (ert \"^test-name$\"))"
|
||||
```
|
||||
|
||||
Run all tests:
|
||||
```bash
|
||||
emacs --batch --eval "(progn (load-file \"dashboard.el\") (ert t))"
|
||||
emacs --batch --eval "(progn (load-file \"ai.el\") (ert t))"
|
||||
```
|
||||
|
||||
## Linting Commands
|
||||
|
||||
Emacs has built-in linting tools available:
|
||||
Emacs has built-in linting tools:
|
||||
|
||||
```elisp
|
||||
;; Check documentation strings
|
||||
(checkdoc "dashboard.el")
|
||||
(checkdoc "ppq-status.el")
|
||||
|
||||
;; Check for undefined variables (elint)
|
||||
(elint-file "dashboard.el")
|
||||
(elint-file "ppq-status.el")
|
||||
|
||||
;; Byte-compile to catch errors
|
||||
(byte-compile-file "dashboard.el")
|
||||
(byte-compile-file "ppq-status.el")
|
||||
```
|
||||
|
||||
Run linting from command line:
|
||||
```bash
|
||||
emacs --batch --eval "(progn (load-file \"dashboard.el\") (checkdoc \"dashboard.el\"))"
|
||||
emacs --batch --eval "(progn (load-file \"ppq-status.el\") (checkdoc \"ppq-status.el\"))"
|
||||
```
|
||||
|
||||
## Code Style Guidelines
|
||||
|
||||
### General Principles
|
||||
- Use CamelCase for function and variable names (Emacs Lisp convention)
|
||||
- Prefix all public functions/variables with a project-specific namespace: `my-dashboard-`
|
||||
- Use kebab-case for keymap names: `my-dashboard-mode-map`
|
||||
- Use kebab-case for function and variable names (Emacs Lisp convention)
|
||||
- Prefix all public functions/variables with project namespace: `ppq-` or `nano-gpt-`
|
||||
- Private functions/variables: prefix with `--` (e.g., `ppq--internal`)
|
||||
- Use `lexical-binding: t` in file header
|
||||
|
||||
### Naming Conventions
|
||||
- Functions: `my-dashboard-function-name`
|
||||
- Variables: `my-dashboard-variable-name`
|
||||
- Private functions/variables: prefix with `--` (e.g., `my-dashboard--internal`)
|
||||
- Modes: `my-dashboard-foo-mode`
|
||||
- Keymaps: `my-dashboard-foo-mode-map`
|
||||
- Functions: `ppq-function-name` or `nano-gpt-function-name`
|
||||
- Variables: `ppq-variable-name` or `nano-gpt-variable-name`
|
||||
- Private functions/variables: `ppq--function-name` (double dash)
|
||||
- Modes: `ppq-foo-mode`
|
||||
- Keymaps: `ppq-foo-mode-map`
|
||||
- Buffer names: `*Dashboard:Name*`
|
||||
- Custom groups: `ppq` or `nano-gpt`
|
||||
|
||||
### Formatting
|
||||
- Indent using 2 spaces (Emacs default for Elisp)
|
||||
- Maximum line length: 80 characters
|
||||
- Use `setq` for setting variables, `defvar` for defining variables with docstrings
|
||||
- Place docstrings on the line after `defun`/`defvar` opening paren
|
||||
- Use consistent spacing around operators: `(+ x y)` not `(+x y)`
|
||||
- Use `setq` for setting variables, `defvar` for defining with docstrings
|
||||
- Place docstrings on line after `defun`/`defvar` opening paren
|
||||
- Consistent spacing around operators: `(+ x y)` not `(+x y)`
|
||||
|
||||
### Imports and Dependencies
|
||||
- Use `(require 'module)` at the top of files
|
||||
- Common dependencies: `url`, `json`, `tabulated-list`, `org`
|
||||
- Use `use-package` for declarative package management if needed
|
||||
- Use `(require 'module)` at top of file after header
|
||||
- Common dependencies: `url`, `json`, `auth-source`, `org`, `tabulated-list`, `hl-line`
|
||||
- Use `(declare-function func "file")` for external functions (e.g., `qrencode-string`)
|
||||
|
||||
### Types
|
||||
- Use `:type` property in `defcustom` for customization types
|
||||
- Use type predicates: `numberp`, `stringp`, `listp`, `functionp`, `bufferp`
|
||||
- Use type predicates: `numberp`, `stringp`, `listp`, `functionp`, `bufferp`, `vectorp`
|
||||
- Check for nil explicitly: `(when var ...)` not `(if var ...)`
|
||||
- Use `eq` for symbol comparison, `equal` for lists/strings
|
||||
|
||||
### Error Handling
|
||||
- Use `condition-case` for error catching
|
||||
- Check API error status with `plist-get status :error`
|
||||
- For async URL operations, check status with `(plist-get status :error)`
|
||||
- Provide meaningful error messages in docstrings
|
||||
- Handle `:null` values from JSON parsing explicitly
|
||||
|
||||
### Keymap Conventions
|
||||
- Use `make-sparse-keymap` for mode keymaps
|
||||
- Set keymap parent to appropriate mode map (e.g., `tabulated-list-mode-map`)
|
||||
- Define keys using `define-key` with key sequences as strings (e.g., "q", "C-x C-f")
|
||||
- Set keymap parent: `(set-keymap-parent map tabulated-list-mode-map)`
|
||||
- Define keys using `define-key` with string sequences (e.g., "q", "C-x C-f")
|
||||
- Use `setq` with `let` for local keymap creation
|
||||
|
||||
### Mode Definition
|
||||
|
|
@ -103,18 +113,20 @@ emacs --batch --eval "(progn (load-file \"dashboard.el\") (checkdoc \"dashboard.
|
|||
- Set `tabulated-list-format` and `tabulated-list-entries`
|
||||
- Call `tabulated-list-init-header` and `tabulated-list-print`
|
||||
- Set `inhibit-read-only` before modifying read-only buffers
|
||||
- Enable `hl-line-mode` for highlighting current line
|
||||
|
||||
### Async Operations
|
||||
- Use `url-retrieve` for async HTTP requests
|
||||
- Define callback functions with `status` parameter
|
||||
- Check for errors with `plist-get status :error`
|
||||
- Use `goto-char (point-min)` before parsing buffer content
|
||||
- Use `re-search-forward` to skip HTTP headers in response
|
||||
- Check for errors: `(unless (plist-get status :error) ...)`
|
||||
- Use `(goto-char (point-min))` before parsing buffer content
|
||||
- Use `(re-search-forward "^$" nil t)` to skip HTTP headers
|
||||
|
||||
### Documentation
|
||||
- Every `defun` and `defvar` should have a docstring
|
||||
- Every `defun` and `defvar` must have a docstring
|
||||
- Docstrings start with descriptive verb ("Show", "Fetch", "Copy")
|
||||
- Document interactive commands with `(interactive)` and "Calling from program..."
|
||||
- Use `;;;###autoload` for user-facing commands
|
||||
|
||||
### Package Management
|
||||
- Use `defcustom` for user-configurable variables with `:type`, `:group`, `:default`
|
||||
|
|
@ -123,9 +135,9 @@ emacs --batch --eval "(progn (load-file \"dashboard.el\") (checkdoc \"dashboard.
|
|||
|
||||
## Project-Specific Patterns
|
||||
|
||||
### Safe List Access
|
||||
### Safe List Access (ALIST)
|
||||
```elisp
|
||||
(defun my-dashboard--aget (alist key)
|
||||
(defun ppq--aget (alist key)
|
||||
"Safely get value from ALIST for KEY, returns nil if null."
|
||||
(let ((val (cdr (assq key alist))))
|
||||
(unless (eq val :null) val)))
|
||||
|
|
@ -149,8 +161,8 @@ emacs --batch --eval "(progn (load-file \"dashboard.el\") (checkdoc \"dashboard.
|
|||
### Window Configuration
|
||||
```elisp
|
||||
;; Save/restore window config
|
||||
(setq my-dashboard--window-config (current-window-configuration))
|
||||
(set-window-configuration my-dashboard--window-config)
|
||||
(setq ppq--window-config (current-window-configuration))
|
||||
(set-window-configuration ppq--window-config)
|
||||
|
||||
;; Split windows
|
||||
(split-window-right) ; vertical split
|
||||
|
|
@ -163,7 +175,7 @@ emacs --batch --eval "(progn (load-file \"dashboard.el\") (checkdoc \"dashboard.
|
|||
;; Parse JSON with alist object type
|
||||
(let* ((json (json-parse-string (buffer-substring (point) (point-max))
|
||||
:object-type 'alist))
|
||||
(data (cdr (assq 'data json))))
|
||||
(data (ppq--aget json 'data)))
|
||||
...)
|
||||
```
|
||||
|
||||
|
|
@ -178,12 +190,42 @@ emacs --batch --eval "(progn (load-file \"dashboard.el\") (checkdoc \"dashboard.
|
|||
|
||||
;; Entries: (id [col1 col2 col3] ...)
|
||||
(setq tabulated-list-entries
|
||||
'((1 ["Apple" "Red" "Sweet"])
|
||||
(2 ["Banana" "Yellow" "Sweet"])))
|
||||
(mapcar
|
||||
(lambda (item)
|
||||
(list (get-id item)
|
||||
(vector (get-name item) (get-id item) ...)))
|
||||
data))
|
||||
```
|
||||
|
||||
### Properize Text with Faces
|
||||
```elisp
|
||||
(propertize text 'font-lock-face face)
|
||||
;; face can be: '(:foreground "green"), 'bold, etc.
|
||||
;; face can be: '(:foreground "green"), 'bold, nil, etc.
|
||||
```
|
||||
|
||||
### Auth-Source Integration
|
||||
```elisp
|
||||
(defun ppq--get-api-key ()
|
||||
"Get API key from auth-source for ppq.ai."
|
||||
(let ((secret (auth-source-search :host "ppq.ai" :secret t)))
|
||||
(when secret
|
||||
(funcall (plist-get (car secret) :secret)))))
|
||||
```
|
||||
|
||||
### URL Request Patterns
|
||||
```elisp
|
||||
;; GET request
|
||||
(url-retrieve url #'callback nil t t)
|
||||
|
||||
;; POST with JSON body
|
||||
(let ((url-request-method "POST")
|
||||
(url-request-extra-headers '(("Content-Type" . "application/json")))
|
||||
(url-request-data (json-encode data)))
|
||||
(url-retrieve url #'callback nil nil t))
|
||||
|
||||
;; POST with auth header
|
||||
(let ((url-request-method "POST")
|
||||
(url-request-extra-headers (list (cons "Authorization" (format "Bearer %s" key))))
|
||||
(url-request-data (json-encode data)))
|
||||
(url-retrieve url #'callback nil nil t))
|
||||
```
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue