Let's evolve our skills with Claude Code help

This commit is contained in:
fenix 2026-03-16 12:28:01 +01:00
commit cfa64a51f0
19 changed files with 897 additions and 0 deletions

View File

@ -0,0 +1,33 @@
{
"name": "fenix-skills",
"owner": {
"name": "Fénix",
"email": "fenix@local"
},
"metadata": {
"description": "Fénix's Claude Code skills — Emacs integration (forked from xenodium/emacs-skills) + custom productivity tools",
"version": "1.0.0"
},
"plugins": [
{
"name": "fenix-tools",
"description": "Fénix's Emacs integration and productivity skills for Claude Code",
"source": "./",
"strict": false,
"skills": [
"./skills/d2",
"./skills/describe",
"./skills/dired",
"./skills/emacsclient",
"./skills/extract-pdf-pages",
"./skills/file-links",
"./skills/gnuplot",
"./skills/highlight",
"./skills/mermaid",
"./skills/open",
"./skills/plantuml",
"./skills/select"
]
}
]
}

79
README.md Normal file
View File

@ -0,0 +1,79 @@
# Fenix Skills — Claude Code Plugin
Custom Claude Code skills for Fénix's workflow.
Includes all [xenodium/emacs-skills](https://github.com/xenodium/emacs-skills) (forked & rebranded) plus Fénix's own productivity tools.
---
## Plugin Structure
```
~/Emacs/fenix-skills/
├── .claude-plugin/
│ └── marketplace.json # Plugin manifest
├── README.md
└── skills/
├── d2/ # /d2 — Create D2 diagrams
├── describe/ # /describe — Emacs describe-* lookups
├── dired/ # /dired — Open files in dired buffer
├── emacsclient/ # (auto) Always use emacsclient, not emacs
├── extract-pdf-pages/ # /extract-pdf-pages — Extract page ranges with pdftk
├── file-links/ # (auto) Format file refs as markdown #L links
├── gnuplot/ # /gnuplot — Plot data with gnuplot
├── highlight/ # /highlight — Highlight regions in Emacs
├── mermaid/ # /mermaid — Create Mermaid diagrams
├── open/ # /open — Open files in Emacs buffers
├── plantuml/ # /plantuml — Create PlantUML diagrams
└── select/ # /select — Select regions in Emacs
```
## Registration
Registered in `~/.claude/settings.json` as:
```json
"extraKnownMarketplaces": {
"fenix-skills": {
"source": {
"source": "directory",
"path": "/home/fenix/Emacs/fenix-skills"
}
}
}
```
```json
"enabledPlugins": {
"fenix-tools@fenix-skills": true
}
```
## Usage
All slash-command skills are available **system-wide** in any Claude Code session:
| Skill | Invocation | Description |
|:---|:---:|:---|
| **d2** | `/d2` | Create diagrams with D2 |
| **describe** | `/describe` | Look up Emacs docs (functions, variables, keys) |
| **dired** | `/dired` | Open recent files in Emacs dired buffer |
| **emacsclient** | _(auto)_ | Always prefer `emacsclient` over `emacs` |
| **extract-pdf-pages** | `/extract-pdf-pages` | Extract page range from PDF via `pdftk` |
| **file-links** | _(auto)_ | Format file references as `file.py#L42` links |
| **gnuplot** | `/gnuplot` | Plot data with gnuplot |
| **highlight** | `/highlight` | Highlight line regions in Emacs buffers |
| **mermaid** | `/mermaid` | Create Mermaid diagrams |
| **open** | `/open` | Open files in Emacs (with optional line jump) |
| **plantuml** | `/plantuml` | Create PlantUML diagrams |
| **select** | `/select` | Select (mark) regions in Emacs buffers |
## Origin
- **Emacs skills** (d2, describe, dired, emacsclient, file-links, gnuplot, highlight, mermaid, open, plantuml, select) — forked from [xenodium/emacs-skills](https://github.com/xenodium/emacs-skills) by Alvaro Ramirez
- **extract-pdf-pages** — original, requires `pdftk` (`apt install pdftk`)
## Requirements
- GNU Emacs with running server daemon (`emacsclient` accessible)
- `pdftk` for PDF extraction skill
- Claude Code with plugins enabled

65
skills/d2/SKILL.md Normal file
View File

@ -0,0 +1,65 @@
---
name: d2
description: 'This skill should be used when the user invokes "/d2" to create a diagram from the current context using D2 and output the resulting image path.'
tools: Bash
disable-model-invocation: true
---
# Create diagrams with D2
Create a diagram from the most recent interaction context using D2. Generate a PNG image and output it as a markdown image so it renders inline.
## How to create a diagram
1. Extract or derive diagrammable data from the current context.
2. If the Emacs foreground color and background mode are not already known from a previous diagram in this session, query them:
```sh
emacsclient --eval '(face-foreground (quote default))'
emacsclient --eval '(frame-parameter nil (quote background-mode))'
```
The first returns a hex color like `"#eeffff"`. The second returns `dark` or `light`. Reuse both for all subsequent diagrams.
3. Write a D2 file to a temporary file using the foreground color.
4. Run D2 with `--theme 200` if background mode is `dark`, or `--theme 0` if `light`.
5. Output the result as a markdown image on its own line:
```
![description](/tmp/agent-diagram-XXXX.png)
```
```sh
# Use --theme 200 for dark, --theme 0 for light
d2 --theme 200 --pad 40 /tmp/agent-diagram-XXXX.d2 /tmp/agent-diagram-XXXX.png
```
## D2 template
Use `--theme 200` for dark or `--theme 0` for light, based on the Emacs background mode. Apply the queried foreground color to `style.font-color` and `style.stroke` on nodes and edges.
```d2
direction: right
node1: Label {
style.font-color: "#eeffff"
style.fill: "#2d3748"
style.stroke: "#eeffff"
}
node2: Label {
style.font-color: "#eeffff"
style.fill: "#2d3748"
style.stroke: "#eeffff"
}
node1 -> node2: label {style.stroke: "#eeffff"; style.font-color: "#eeffff"}
```
## Rules
- Query the Emacs foreground color once per session and reuse it for all subsequent diagrams. Only query again if the color is not already known.
- Query the Emacs background mode once per session via `(frame-parameter nil 'background-mode)`. Use `--theme 200` for `dark` or `--theme 0` for `light`. Always use `--pad 40`.
- Always use a timestamp in the filename (e.g., `/tmp/agent-diagram-$(date +%s).png`). Never use descriptive names.
- Set the queried foreground color on `style.font-color` and `style.stroke` for all nodes and edges so the diagram is readable on the user's Emacs background.
- Use meaningful fill colors to distinguish different types of elements.
- After D2 runs successfully, output a markdown image (`![description](path)`) on its own line.
- Choose an appropriate layout direction and structure for the data.
- Include labels on edges when they add clarity.
- If no diagrammable data exists in the recent context, inform the user.

25
skills/describe/SKILL.md Normal file
View File

@ -0,0 +1,25 @@
---
name: describe
description: 'This skill should be used when the user invokes "/describe" to look up Emacs documentation via emacsclient.'
tools: Bash
disable-model-invocation: true
---
# Look up Emacs documentation
Look up Emacs documentation using `emacsclient --eval` and summarize the findings. The query is searched across multiple mechanisms (function, variable, face, key binding, and apropos) in one call, returning all findings as a single string.
First, locate `agent-skill-describe.el` which lives alongside this skill file at `skills/describe/agent-skill-describe.el` in the emacs-skills plugin directory.
```sh
emacsclient --eval '
(progn
(load "/path/to/skills/describe/agent-skill-describe.el" nil t)
(agent-skill-describe :query "dired-mark"))'
```
## Rules
- Summarize the returned documentation for the user in the conversation.
- Locate `agent-skill-describe.el` relative to this skill file's directory.
- Run the `emacsclient --eval` command via the Bash tool.

View File

@ -0,0 +1,76 @@
(require 'cl-lib)
(cl-defun agent-skill-describe (&key query)
"Look up QUERY across multiple Emacs documentation mechanisms.
Searches for QUERY as a function, variable, and via apropos,
returning all findings in a single string."
(let ((sym (intern-soft query))
(sections nil))
;; Function documentation
(when (and sym (fboundp sym))
(push (format "## Function: %s\n\n%s\n\nSignature: %s\n\n%s"
query
(cond ((subrp (symbol-function sym)) "Built-in function")
((macrop sym) "Macro")
((commandp sym) "Interactive command")
(t "Function"))
(or (help-function-arglist sym t) "()")
(or (documentation sym t) "No documentation available."))
sections))
;; Variable documentation
(when (and sym (boundp sym))
(let ((val (symbol-value sym)))
(push (format "## Variable: %s\n\nCurrent value: %s\n\n%s"
query
(let ((printed (format "%S" val)))
(if (> (length printed) 200)
(concat (substring printed 0 200) "...")
printed))
(or (documentation-property sym 'variable-documentation t)
"No documentation available."))
sections)))
;; Face documentation
(when (and sym (facep sym))
(push (format "## Face: %s\n\n%s"
query
(or (documentation-property sym 'face-documentation t)
"No documentation available."))
sections))
;; Key binding (if it looks like a key sequence)
(when (string-match-p "\\`[CMSs]-\\|\\`<" query)
(let* ((keyseq (ignore-errors (kbd query)))
(binding (and keyseq (key-binding keyseq))))
(when binding
(push (format "## Key binding: %s\n\n%s runs `%s'\n\n%s"
query query binding
(or (documentation binding t)
"No documentation available."))
sections))))
;; Apropos matches (up to 20)
(let ((matches nil))
(mapatoms
(lambda (s)
(when (and (string-match-p (regexp-quote query) (symbol-name s))
(not (eq s sym))
(or (fboundp s) (boundp s)))
(push (format " %s%s"
(symbol-name s)
(cond ((and (fboundp s) (boundp s))
" [function, variable]")
((fboundp s) " [function]")
(t " [variable]")))
matches))))
(when matches
(let ((sorted (sort matches #'string<)))
(push (format "## Related symbols\n\n%s%s"
(mapconcat #'identity (seq-take sorted 20) "\n")
(if (> (length sorted) 20)
(format "\n ... and %d more" (- (length sorted) 20))
""))
sections))))
(if sections
(mapconcat #'identity (nreverse sections) "\n\n")
(format "No documentation found for \"%s\"." query))))
(provide 'agent-skill-describe)

37
skills/dired/SKILL.md Normal file
View File

@ -0,0 +1,37 @@
---
name: dired
description: 'This skill should be used when the user invokes "/dired" to open files from the latest interaction in an Emacs dired buffer via emacsclient.'
tools: Bash
disable-model-invocation: true
---
# Open files in Emacs dired
Open files from the most recent interaction in an Emacs dired buffer using `emacsclient --eval`. Only include files relevant to the latest interaction (files just generated, edited, listed, or produced by the most recent tool output), not all files mentioned throughout the conversation.
## Strategy
Determine whether the relevant files all reside in the same directory or span multiple directories, then call `agent-skill-dired` accordingly.
- **Same directory**: `:dir` is the directory, `:files` are basenames. Opens dired at that directory with the files marked in context.
- **Multiple directories**: `:dir` is the common ancestor, `:files` are relative paths. Creates a curated `*agent-files*` buffer with all files marked.
First, locate `agent-skill-dired.el` which lives alongside this skill file at `skills/dired/agent-skill-dired.el` in the emacs-skills plugin directory.
```sh
emacsclient --eval '
(progn
(load "/path/to/skills/dired/agent-skill-dired.el" nil t)
(agent-skill-dired
:dir "/path/to/directory"
:files (quote ("file1.txt"
"file2.txt"
"file3.txt"))))'
```
## Rules
- Use relative paths in `:files` relative to `:dir`.
- Locate `agent-skill-dired.el` relative to this skill file's directory.
- If no relevant files exist in the recent interaction, inform the user.
- Run the `emacsclient --eval` command via the Bash tool.

View File

@ -0,0 +1,26 @@
(require 'cl-lib)
(require 'dired)
(cl-defun agent-skill-dired (&key dir files)
"Open a dired buffer at DIR with FILES marked.
When all files share the same parent directory, DIR is that
directory and FILES are basenames shown in context.
When files span multiple directories, DIR is the common ancestor
and FILES are relative paths. A curated `*agent-files*' buffer
is created instead."
(let ((same-dir-p (cl-every (lambda (f) (not (string-match-p "/" f))) files)))
(if same-dir-p
(progn
(dired dir)
(dired-unmark-all-marks)
(dolist (file files)
(dired-goto-file (expand-file-name file dir))
(dired-mark 1)))
(let ((default-directory (file-name-as-directory dir)))
(dired (cons "*agent-files*" files))
(dired-unmark-all-marks)
(dired-toggle-marks)))))
(provide 'agent-skill-dired)

View File

@ -0,0 +1,42 @@
---
name: emacsclient
description: 'Always use emacsclient instead of emacs. This applies to all Emacs operations: user requests, byte compilation, check-parens, running ERT tests, and any other elisp evaluation.'
tools: Bash
---
# Always use emacsclient
The user has an Emacs server running. **All** Emacs operations must go through `emacsclient`, never `emacs` or `emacs --batch`. This includes both user-requested actions and agent-initiated operations like byte compilation, syntax checking, or running tests.
## Examples
- Open a file: `emacsclient --no-wait "/path/to/file"`
- Evaluate elisp: `emacsclient --eval '(some-function)'`
- Open at a line: `emacsclient --no-wait +42 "/path/to/file"`
- Byte compile a file:
```sh
emacsclient --eval '
(byte-compile-file "/path/to/file.el")'
```
- Check parentheses:
```sh
emacsclient --eval '
(with-temp-buffer
(insert-file-contents "/path/to/file.el")
(check-parens))'
```
- Run ERT tests:
```sh
emacsclient --eval '
(progn
(load "/path/to/test-file.el" nil t)
(ert-run-tests-batch-and-exit "pattern"))'
```
## Rules
- Always use `emacsclient`, never `emacs` or `emacs --batch`.
- Use `--no-wait` when opening files so the command returns immediately.
- Use `--eval` when evaluating elisp.
- Always format `--eval` elisp across multiple lines with proper indentation.
- Run `emacsclient` commands via the Bash tool.

View File

@ -0,0 +1,32 @@
---
name: extract-pdf-pages
description: 'Use when the user invokes "/extract-pdf-pages" to extract a page range from a PDF file using pdftk.'
tools: Bash
disable-model-invocation: true
---
# Extract PDF Pages
Extract a page range from a PDF file into a new PDF using `pdftk`.
## Usage
When invoked, ask the user for (if not already provided):
1. **Source PDF** — absolute path to the input PDF file
2. **Page range** — start and end pages (e.g., `200-204`)
3. **Output filename** — name for the new PDF (defaults to current working directory)
## Command
```bash
pdftk "<source_pdf>" cat <start>-<end> output "<output_path>"
```
## Rules
- Always use absolute paths for both source and output files.
- If the user provides only a filename (no directory), place the output in the current working directory.
- If the output file already exists, warn the user before overwriting.
- Support multiple extractions in a single invocation (run them in parallel).
- After extraction, confirm with file size: `ls -lh "<output_path>"`
- Requires `pdftk` to be installed (`apt install pdftk`).

View File

@ -0,0 +1,48 @@
---
name: file-links
description: 'When referencing files, format them as markdown links with line numbers using GitHub-style #L syntax.'
---
# Format file references as markdown links
When referencing files in your output, always format them as markdown links. Use the GitHub-style `#L` fragment for line numbers.
## Format
With a line number:
```
[filename.el:42](relative/path/to/filename.el#L42)
```
With a line range:
```
[filename.el:42-50](relative/path/to/filename.el#L42-L50)
```
Without a line number:
```
[filename.el](relative/path/to/filename.el)
```
## Important
- The link text uses `:` for line numbers (e.g., `filename.el:42`).
- The URL uses `#L` for line numbers (e.g., `filename.el#L42`).
- For ranges, the link text uses `-` (e.g., `filename.el:42-50`) and the URL uses `-L` (e.g., `filename.el#L42-L50`).
- The range must appear in both the link text and the URL.
Do NOT do this:
```
[filename.el#L42-L50](filename.el#L42)
```
## Rules
- Use paths relative to the project root.
- Include line numbers when they are relevant (e.g., error locations, function definitions, modified lines).
- Use line ranges when referring to a block of code.
- The link text should be the filename (or relative path if needed for clarity) followed by the line number.

60
skills/gnuplot/SKILL.md Normal file
View File

@ -0,0 +1,60 @@
---
name: gnuplot
description: 'This skill should be used when the user invokes "/gnuplot" to plot data from the current context using gnuplot and output the resulting image path.'
tools: Bash
disable-model-invocation: true
---
# Plot data with gnuplot
Plot data from the most recent interaction context using gnuplot. Generate a PNG image with a transparent background and output it as a markdown image so it renders inline.
## How to plot
1. Extract or derive plottable data from the current context.
2. If the Emacs foreground color is not already known from a previous plot in this session, query it:
```sh
emacsclient --eval '
(face-foreground (quote default))'
```
This returns a hex color like `"#eeffff"`. Reuse it for all subsequent plots.
3. Write a gnuplot script to a temporary file using that color.
4. Run gnuplot on the script.
5. Output the result as a markdown image on its own line:
```
![description](/tmp/agent-plot-XXXX.png)
```
```sh
gnuplot /tmp/agent-plot-XXXX.gp
```
## Gnuplot script template
```gnuplot
set terminal pngcairo transparent enhanced size 800,500
set output "/tmp/agent-plot-XXXX.png"
FG = "#eeffff" # from emacsclient query
set border lc rgb FG
set key textcolor rgb FG
set xlabel textcolor rgb FG
set ylabel textcolor rgb FG
set title textcolor rgb FG
set xtics textcolor rgb FG
set ytics textcolor rgb FG
# ... plot commands using the data ...
```
## Rules
- Query the Emacs foreground color once per session and reuse it for all subsequent plots. Only query again if the color is not already known.
- Always use `pngcairo transparent` terminal for transparent background.
- Always use a timestamp in the filename (e.g., `/tmp/agent-plot-$(date +%s).png`). Never use descriptive names like `agent-plot-lorenz.png`.
- Use inline data (`$DATA << EOD ... EOD`) when practical. For large datasets, write a separate data file.
- After gnuplot runs successfully, output a markdown image (`![description](path)`) on its own line.
- Choose an appropriate plot type for the data (lines, bars, histogram, scatter, etc.).
- Include a title, axis labels, and a legend when they add clarity.
- Use `enhanced` text mode for subscripts/superscripts when needed.
- If no plottable data exists in the recent context, inform the user.

39
skills/highlight/SKILL.md Normal file
View File

@ -0,0 +1,39 @@
---
name: highlight
description: 'This skill should be used when the user invokes "/highlight" to highlight relevant regions in one or more files in Emacs via emacsclient.'
tools: Bash
disable-model-invocation: true
---
# Highlight regions in Emacs
Highlight relevant regions in one or more files in Emacs using `emacsclient --eval`. Files are opened in a temporary read-only minor mode with highlighted overlays. The user presses `q` to exit the mode and remove all highlights in that buffer.
Determine the relevant files and line ranges from the most recent interaction context.
## How to highlight
First, determine the path to `agent-skill-highlight.el`. It lives alongside this skill file at `skills/highlight/agent-skill-highlight.el` in the emacs-skills plugin directory.
```sh
emacsclient --eval '
(progn
(load "/path/to/skills/highlight/agent-skill-highlight.el" nil t)
(agent-skill-highlight
:files (quote (("/path/to/file1.el"
:regions ((:start 90 :lines 18)
(:start 114 :lines 49)))
("/path/to/file2.el"
:regions ((:start 94 :lines 18)))))))'
```
- `:start` is the 1-indexed line number.
- `:lines` is the number of lines to highlight from that start line.
- Add as many files and regions as needed.
## Rules
- Use absolute paths for files.
- Locate `agent-skill-highlight.el` relative to this skill file's directory.
- If no relevant files or regions exist in the recent interaction, inform the user.
- Run the `emacsclient --eval` command via the Bash tool.

View File

@ -0,0 +1,53 @@
(eval-when-compile
(require 'cl-lib))
(require 'hi-lock)
(defvar-local agent-skill-highlight--overlays nil)
(defvar-local agent-skill-highlight--was-read-only nil)
(defun agent-skill-highlight--remove-overlays ()
(mapc #'delete-overlay agent-skill-highlight--overlays)
(setq agent-skill-highlight--overlays nil))
(defun agent-skill-highlight-exit ()
(interactive)
(agent-skill-highlight-mode -1))
(define-minor-mode agent-skill-highlight-mode
"Temporary read-only mode with highlighted regions. Press q to exit."
:lighter " Highlight"
:keymap (let ((map (make-sparse-keymap)))
(define-key map (kbd "q") #'agent-skill-highlight-exit)
map)
(if agent-skill-highlight-mode
(progn
(setq agent-skill-highlight--was-read-only buffer-read-only)
(read-only-mode 1)
(message "Press q to exit highlights"))
(agent-skill-highlight--remove-overlays)
(unless agent-skill-highlight--was-read-only
(read-only-mode -1))))
(cl-defun agent-skill-highlight (&key files)
"Highlight regions in FILES.
FILES is a list of (FILE-PATH :regions REGIONS) where REGIONS is
a list of (:start LINE :lines COUNT)."
(dolist (file-spec files)
(let ((file-path (car file-spec))
(regions (plist-get (cdr file-spec) :regions)))
(find-file file-path)
(dolist (region regions)
(let* ((start-line (plist-get region :start))
(num-lines (plist-get region :lines))
(ov (make-overlay
(progn (goto-char (point-min))
(forward-line (1- start-line))
(point))
(progn (forward-line num-lines)
(point)))))
(overlay-put ov 'face 'hi-yellow)
(push ov agent-skill-highlight--overlays)))
(agent-skill-highlight-mode 1))))
(provide 'agent-skill-highlight)

86
skills/mermaid/SKILL.md Normal file
View File

@ -0,0 +1,86 @@
---
name: mermaid
description: 'This skill should be used when the user invokes "/mermaid" to create a diagram from the current context using Mermaid and output the resulting image path.'
tools: Bash
disable-model-invocation: true
---
# Create diagrams with Mermaid
Create a diagram from the most recent interaction context using Mermaid. Generate a PNG image with a transparent background and output it as a markdown image so it renders inline.
## How to create a diagram
1. Extract or derive diagrammable data from the current context.
2. If the Emacs foreground color and background mode are not already known from a previous diagram in this session, query them:
```sh
emacsclient --eval '(face-foreground (quote default))'
emacsclient --eval '(frame-parameter nil (quote background-mode))'
```
The first returns a hex color like `"#eeffff"`. The second returns `dark` or `light`. Reuse both for all subsequent diagrams.
3. Write a Mermaid file to a temporary file.
4. Write a JSON config file that overrides theme variables with the queried foreground color. Set `"theme"` to `"dark"` or `"default"` based on the background mode.
5. Run `mmdc` with `-t dark` if background mode is `dark`, or `-t default` if `light`.
6. Output the result as a markdown image on its own line:
```
![description](/tmp/agent-diagram-XXXX.png)
```
```sh
# Use -t dark for dark, -t default for light
PUPPETEER_EXECUTABLE_PATH=/opt/homebrew/bin/chromium mmdc \
-i /tmp/agent-diagram-XXXX.mmd \
-o /tmp/agent-diagram-XXXX.png \
-t dark -b transparent --scale 2 \
--configFile /tmp/agent-diagram-XXXX-config.json
```
## Mermaid config template
Write this JSON config file to apply the Emacs foreground color. Replace `#eeffff` with the queried color. Set `"theme"` to `"dark"` or `"default"` based on the Emacs background mode.
```json
{
"theme": "dark",
"themeVariables": {
"primaryTextColor": "#eeffff",
"secondaryTextColor": "#eeffff",
"tertiaryTextColor": "#eeffff",
"primaryBorderColor": "#eeffff",
"lineColor": "#eeffff",
"textColor": "#eeffff",
"actorTextColor": "#eeffff",
"actorBorder": "#eeffff",
"signalColor": "#eeffff",
"signalTextColor": "#eeffff",
"labelTextColor": "#eeffff",
"loopTextColor": "#eeffff",
"noteTextColor": "#eeffff",
"noteBorderColor": "#eeffff",
"sectionTextColor": "#eeffff",
"titleColor": "#eeffff"
}
}
```
## Mermaid diagram template
```mermaid
sequenceDiagram
participant a as Alice
participant b as Bob
a->>b: Hello
b-->>a: Hi back
```
## Rules
- Query the Emacs foreground color once per session and reuse it for all subsequent diagrams. Only query again if the color is not already known.
- Query the Emacs background mode once per session via `(frame-parameter nil 'background-mode)`. Use `-t dark` for `dark` or `-t default` for `light`. Always use `-b transparent --scale 2`.
- Always use `PUPPETEER_EXECUTABLE_PATH=/opt/homebrew/bin/chromium` when invoking `mmdc`.
- Always write a JSON config file with `themeVariables` set to the queried foreground color and pass it via `--configFile`.
- Always use a timestamp in the filename (e.g., `/tmp/agent-diagram-$(date +%s).png`). Never use descriptive names.
- After mmdc runs successfully, output a markdown image (`![description](path)`) on its own line.
- Choose an appropriate diagram type for the data (sequence, flowchart, class, state, er, gantt, etc.).
- Include a title when it adds clarity.
- If no diagrammable data exists in the recent context, inform the user.

35
skills/open/SKILL.md Normal file
View File

@ -0,0 +1,35 @@
---
name: open
description: 'This skill should be used when the user invokes "/open" to open files from the latest interaction in Emacs buffers via emacsclient.'
tools: Bash
disable-model-invocation: true
---
# Open files in Emacs
Open files from the most recent interaction in Emacs buffers using `emacsclient --eval`. Only include files relevant to the latest interaction (files just generated, edited, listed, or produced by the most recent tool output), not all files mentioned throughout the conversation.
## How to open
First, locate `agent-skill-open.el` which lives alongside this skill file at `skills/open/agent-skill-open.el` in the emacs-skills plugin directory.
Each file spec in `:files` is either a string (file path) or a plist with `:file` and optional `:line`.
```sh
emacsclient --eval '
(progn
(load "/path/to/skills/open/agent-skill-open.el" nil t)
(agent-skill-open
:files (quote ((:file "/path/to/file1.txt"
:line 42)
"/path/to/file2.txt"
"/path/to/file3.txt"))))'
```
## Rules
- Use absolute paths for files.
- Use `:line` when a specific line is relevant (e.g., an error location or a newly added function).
- Locate `agent-skill-open.el` relative to this skill file's directory.
- If no relevant files exist in the recent interaction, inform the user.
- Run the `emacsclient --eval` command via the Bash tool.

View File

@ -0,0 +1,18 @@
(require 'cl-lib)
(cl-defun agent-skill-open (&key files)
"Open FILES in Emacs buffers.
FILES is a list of file specs. Each spec is either a string
\(file path) or a plist (:file PATH :line LINE)."
(dolist (spec files)
(if (stringp spec)
(find-file spec)
(let ((file (plist-get spec :file))
(line (plist-get spec :line)))
(find-file file)
(when line
(goto-char (point-min))
(forward-line (1- line)))))))
(provide 'agent-skill-open)

82
skills/plantuml/SKILL.md Normal file
View File

@ -0,0 +1,82 @@
---
name: plantuml
description: 'This skill should be used when the user invokes "/plantuml" to create a diagram from the current context using PlantUML and output the resulting image path.'
tools: Bash
disable-model-invocation: true
---
# Create diagrams with PlantUML
Create a diagram from the most recent interaction context using PlantUML. Generate a PNG image with a transparent background and output it as a markdown image so it renders inline.
## How to create a diagram
1. Extract or derive diagrammable data from the current context.
2. If the Emacs foreground color is not already known from a previous diagram in this session, query it:
```sh
emacsclient --eval '
(face-foreground (quote default))'
```
This returns a hex color like `"#eeffff"`. Reuse it for all subsequent diagrams.
3. Write a PlantUML file to a temporary file using that color.
4. Run PlantUML on the file.
5. Output the result as a markdown image on its own line:
```
![description](/tmp/agent-diagram-XXXX.png)
```
```sh
plantuml -tpng /tmp/agent-diagram-XXXX.puml
```
## PlantUML template
```plantuml
@startuml
skinparam backgroundColor transparent
skinparam shadowing true
skinparam roundcorner 10
skinparam defaultFontName "Helvetica"
skinparam defaultFontColor #eeffff
' Set foreground color on all element types
skinparam titleFontColor #eeffff
skinparam sequenceLifeLineBorderColor #eeffff
skinparam sequenceArrowColor #eeffff
skinparam sequenceGroupHeaderFontColor #eeffff
skinparam sequenceGroupBorderColor #eeffff
skinparam sequenceDividerFontColor #eeffff
skinparam sequenceDividerBorderColor #eeffff
skinparam actorBorderColor #eeffff
skinparam actorFontColor #eeffff
skinparam participantFontColor #eeffff
skinparam participantBorderColor #eeffff
skinparam collectionsFontColor #eeffff
skinparam collectionsBorderColor #eeffff
skinparam noteFontColor #eeffff
skinparam noteBorderColor #eeffff
skinparam arrowFontColor #eeffff
skinparam classFontColor #eeffff
skinparam classBorderColor #eeffff
skinparam classAttributeFontColor #eeffff
skinparam packageFontColor #eeffff
skinparam packageBorderColor #eeffff
skinparam componentFontColor #eeffff
skinparam componentBorderColor #eeffff
skinparam interfaceFontColor #eeffff
skinparam interfaceBorderColor #eeffff
' ... diagram content ...
@enduml
```
## Rules
- Query the Emacs foreground color once per session and reuse it for all subsequent diagrams. Only query again if the color is not already known.
- Always use `skinparam backgroundColor transparent` for transparent background.
- Always use a timestamp in the filename (e.g., `/tmp/agent-diagram-$(date +%s).png`). Never use descriptive names.
- Set the queried foreground color on `defaultFontColor` and all relevant `skinparam` entries for borders, arrows, and text so the diagram is readable on the user's Emacs background.
- After PlantUML runs successfully, output a markdown image (`![description](path)`) on its own line.
- Choose an appropriate diagram type for the data (sequence, class, component, activity, state, etc.).
- Include a title when it adds clarity.
- If no diagrammable data exists in the recent context, inform the user.

42
skills/select/SKILL.md Normal file
View File

@ -0,0 +1,42 @@
---
name: select
description: 'This skill should be used when the user invokes "/select" to open one or more files in Emacs and select a region relevant to the current discussion via emacsclient.'
tools: Bash
disable-model-invocation: true
---
# Select region in Emacs
Open one or more files in Emacs and select (activate the region around) the code or text most relevant to the current discussion using `emacsclient --eval`. This allows the user to immediately act on the selection: narrow, copy, refactor, comment, etc.
Determine the relevant files and line ranges from the most recent interaction context.
## How to select
First, locate `agent-skill-select.el` which lives alongside this skill file at `skills/select/agent-skill-select.el` in the emacs-skills plugin directory.
```sh
emacsclient --eval '
(progn
(load "/path/to/skills/select/agent-skill-select.el" nil t)
(agent-skill-select
:selections (quote (("/path/to/file1.el"
:start 10
:end 25)
("/path/to/file2.el"
:start 5
:end 12)))))'
```
- `:start` is the 1-indexed start line.
- `:end` is the 1-indexed end line.
- The last file visited will have the visually active region. Other files have mark and point set (use `C-x C-x` to reactivate when switching to them).
## Rules
- Use absolute paths for files.
- Choose the region most relevant to the current discussion (e.g., a function just modified, a block with an error, code just generated).
- If no specific region is apparent, select the entire relevant function or block.
- Locate `agent-skill-select.el` relative to this skill file's directory.
- If no relevant files or regions exist in the recent interaction, inform the user.
- Run the `emacsclient --eval` command via the Bash tool.

View File

@ -0,0 +1,19 @@
(require 'cl-lib)
(cl-defun agent-skill-select (&key selections)
"Open files in Emacs and select a region in each.
SELECTIONS is a list of (FILE :start LINE :end LINE)."
(dolist (sel selections)
(let ((file (car sel))
(start (plist-get (cdr sel) :start))
(end (plist-get (cdr sel) :end)))
(find-file file)
(goto-char (point-min))
(forward-line (1- start))
(set-mark (point))
(forward-line (- end start))
(end-of-line)
(activate-mark))))
(provide 'agent-skill-select)