aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-26 07:47:03 -0500
committerCraig Jennings <c@cjennings.net>2026-05-26 07:47:03 -0500
commit85fa5f6b3d52c0c18043144653aaafeeb4dcf4a3 (patch)
treea6a2a54effe0811c4a11b4c66b165858d93558bf
parent35b5739e791965c837c2e715076b52d3fee9e156 (diff)
downloaddotemacs-85fa5f6b3d52c0c18043144653aaafeeb4dcf4a3.tar.gz
dotemacs-85fa5f6b3d52c0c18043144653aaafeeb4dcf4a3.zip
chore(claude): sync rules and hooks with the rulesets bundle
Bring .claude/hooks/validate-el.sh and .claude/rules/interaction.md back in line with the shared bundle, and add the new keybinding-display.md rule.
-rwxr-xr-x.claude/hooks/validate-el.sh2
-rw-r--r--.claude/rules/interaction.md16
-rw-r--r--.claude/rules/keybinding-display.md42
3 files changed, 60 insertions, 0 deletions
diff --git a/.claude/hooks/validate-el.sh b/.claude/hooks/validate-el.sh
index 803badf8..782f04ca 100755
--- a/.claude/hooks/validate-el.sh
+++ b/.claude/hooks/validate-el.sh
@@ -51,6 +51,7 @@ case "$f" in
-L "$PROJECT_ROOT" \
-L "$PROJECT_ROOT/modules" \
-L "$PROJECT_ROOT/tests" \
+ -L "$PROJECT_ROOT/themes" \
--eval '(package-initialize)' \
"$f" \
--eval '(check-parens)' \
@@ -92,6 +93,7 @@ if [ "$count" -ge 1 ] && [ "$count" -le "$MAX_AUTO_TEST_FILES" ]; then
-L "$PROJECT_ROOT" \
-L "$PROJECT_ROOT/modules" \
-L "$PROJECT_ROOT/tests" \
+ -L "$PROJECT_ROOT/themes" \
--eval '(package-initialize)' \
-l ert "${load_args[@]}" \
--eval "(ert-run-tests-batch-and-exit '(not (tag :slow)))" 2>&1)"; then
diff --git a/.claude/rules/interaction.md b/.claude/rules/interaction.md
index 4d9279ba..83afc45a 100644
--- a/.claude/rules/interaction.md
+++ b/.claude/rules/interaction.md
@@ -29,3 +29,19 @@ For multi-select decisions, say so explicitly: "Pick any combination — reply w
Reserve `AskUserQuestion` only when the user explicitly asks for the popup form ("use the popup for this one") or for genuinely free-form input where numbered options don't fit.
This rule applies to all three approval gates in the `commits.md` publish flow (commit message, PR description, PR review reply): print the draft inline, then offer numbered approve / changes / edit options inline. Do not switch to the popup form for the gate even though the prior protocol referenced it.
+
+**Enforcement:** a global `PreToolUse` hook (matcher `AskUserQuestion`) in `~/.claude/settings.json` hard-denies the popup and returns this rule as the reason — the prose alone proved too easy to forget. Because the deny is unconditional, the "use the popup for this one" exception above can't be honored in-turn; to get the popup, disable the hook via `/hooks` (or edit settings) first.
+
+## No Reverse-Video Highlighting in Chat Output
+
+In conversational output to the user, do not use Markdown bold (`**...**`) or inline-code spans (backtick `` `...` ``). The user's terminal renders both as reverse video, which is hard to read on the display.
+
+**Why:** The styling that looks like emphasis in most renderers comes through as inverted foreground/background here. Plain prose, plain identifiers, and plain key chords read cleanly; the "highlight" actively hurts legibility.
+
+**How to apply:**
+
+- Write command names, file paths, key chords, and code identifiers as plain text — `pearl-save-issue` becomes pearl-save-issue, `C-; L s s` becomes C-; L s s.
+- Use structure that doesn't invert colors: headers, numbered lists, dashes, parentheses, and double quotes for labels are all fine.
+- Fenced code blocks (triple backtick) are acceptable when the user explicitly wants a block to copy — they don't invert the way inline spans do. Default to plain text otherwise.
+
+This governs **chat output**, not the Markdown source of rule files, specs, or docs the user reads in an editor — those keep normal Markdown formatting. The constraint is the terminal rendering of the live conversation.
diff --git a/.claude/rules/keybinding-display.md b/.claude/rules/keybinding-display.md
new file mode 100644
index 00000000..ad45720f
--- /dev/null
+++ b/.claude/rules/keybinding-display.md
@@ -0,0 +1,42 @@
+# Keybinding Display Format
+
+Applies to: `**/*`
+
+How to present a keymap's bindings when the user asks to see them — "show the keybindings", "list the bindings", "what's bound under X", or any request to display a prefix keymap and its structure.
+
+## The Format
+
+A bulleted list grouped by **category**, where each category is one level of the keymap's prefix tree.
+
+- **One header per category.** Format: `<Package> <Category> — <full prefix>:`. The package name is the keymap's owner (e.g. `Pearl`); the category is the human name for that sub-map (`Save`, `Edit`, `Add`, `Delete`); the full prefix is the complete chord that lands on that sub-map.
+- **The top level is always the `General` category.** Its prefix is the base prefix itself. General lists the terminal commands bound directly off the base prefix **and** the sub-prefix keys that lead into the other categories — so the reader sees every door off the top level in one place.
+- **Each bullet is three fields:** `<full keybinding> — <command> — "<which-key label>"`.
+ - *Full keybinding* — the complete chord, base prefix included (`C-; L s s`), not just the leaf key. The reader should be able to type it verbatim.
+ - *Command* — the bound command symbol. For a sub-prefix entry in the General category, mark it as a prefix rather than a command (e.g. *(Save prefix)*).
+ - *Which-key label* — the short string that shows in the which-key popup, in quotes (`"save ticket"`). For a sub-prefix, use the which-key prefix label (`"+save"`).
+- **General comes first**, then one section per sub-category in a sensible order.
+
+## Plain text in chat
+
+Render this in chat as plain text — no Markdown bold and no inline-code spans. Headers, dashes, parentheses, and double-quoted labels carry the structure without them. See the "No Reverse-Video Highlighting in Chat Output" rule in [`interaction.md`](interaction.md): bold and backtick spans invert to reverse video on the user's terminal. The example below is shown the way it should appear in chat.
+
+## Example
+
+For an imaginary command set Pearl on base prefix C-; L:
+
+Pearl General — C-; L:
+- C-; L s — (save prefix) — "+save"
+- C-; L e — (edit prefix) — "+edit"
+- C-; L m — pearl-menu — "menu"
+
+Pearl Save — C-; L s:
+- C-; L s s — pearl-save-issue — "save ticket"
+- C-; L s a — pearl-save-all — "save all"
+
+Pearl Edit — C-; L e:
+- C-; L e p — pearl-set-priority — "priority"
+- C-; L e s — pearl-set-state — "state"
+
+## Why
+
+The header carries the full prefix so the category's depth is unambiguous — the reader knows exactly how many keys deep each section sits. Listing the sub-prefixes inside General makes the top level a complete map of where every door leads, rather than scattering that across the sections. The three-field bullet ties the chord a user types to the command it runs and the label they'll actually see in which-key, so the written view matches the on-screen view.