diff options
Diffstat (limited to 'claude-rules')
| -rw-r--r-- | claude-rules/commits.md | 31 | ||||
| -rw-r--r-- | claude-rules/desktop-capture.md | 57 | ||||
| -rw-r--r-- | claude-rules/emacs.md | 18 | ||||
| -rw-r--r-- | claude-rules/interaction.md | 11 | ||||
| -rw-r--r-- | claude-rules/knowledge-base.md | 2 | ||||
| -rw-r--r-- | claude-rules/todo-format.md | 23 | ||||
| -rw-r--r-- | claude-rules/ui-prototyping.md | 93 | ||||
| -rw-r--r-- | claude-rules/verification.md | 2 |
8 files changed, 235 insertions, 2 deletions
diff --git a/claude-rules/commits.md b/claude-rules/commits.md index 4509cee..c4eb2cd 100644 --- a/claude-rules/commits.md +++ b/claude-rules/commits.md @@ -19,6 +19,7 @@ Absolutely no AI/LLM/Claude/Anthropic attribution in: - Code comments - Commit trailers - Release notes, changelogs, and any public-facing artifact +- Document author metadata — an org `#+AUTHOR:` line, YAML frontmatter `author:`, a docx or PDF author property, a byline This means: @@ -32,6 +33,34 @@ If a tool, template, or default config inserts attribution, remove it. If settings.json needs it, set `attribution.commit: ""` and `attribution.pr: ""` to suppress the defaults. +### Generated documents carry the human author only + +Every document an agent writes or updates — a daily prep, a session log, a +spec, an explainer, a meeting summary — names the human as its sole author. +`#+AUTHOR: Craig Jennings`, never `Craig Jennings & Claude`, and never an +agent's name standing alone. + +The failure mode is imitation, not intent. No template stamps this line; +agents copy the author header from whatever sits nearby — yesterday's prep, +the workflow file they're reading, the doc next to the one they're writing. +So a single stray `& Claude` propagates through everything generated +afterward, and no amount of fixing individual files stops it. Fix the files +an agent reads, and state the rule here. + +The stakes are highest where the rule is least visible. A private notes repo +tolerates a co-author line; many employers do not, and their policy is that +work product carries employee names alone. An `#+AUTHOR:` line survives +conversion into docx, a published wiki page, or a PDF handed to a customer, +so a header written in a scratch document three months ago can surface inside +a deliverable. Write the header correctly at creation. + +Two things this rule does not ask for. Don't rewrite historical records — +archived session logs and past dated documents stay as they are, because +they're a record of what happened rather than a live artifact. And don't +relabel a document another agent genuinely authored: if Codex wrote it, the +byline stays Codex. The rule removes false co-authorship, not true +authorship. + ## Commit Message Format Commit messages follow the [Conventional Commits](https://www.conventionalcommits.org/) spec. @@ -357,7 +386,7 @@ Pick the shape first. Most reviews are Shape 1. 3. Run `/voice personal` on the file once. The skill walks its full pattern list across every block at the same time. The separators stay intact because they aren't prose. -4. Print the final draft inline in the terminal. Every block, exactly as it'll be posted, with its separator header. State that the skill ran (e.g. "/voice personal — full pattern walk across summary + 3 inline"). Surface any pattern #39 warnings. +4. Print the final draft inline in the terminal. Every block — the summary body AND the full prose of every inline comment — exactly as it'll be posted, with its separator header. Print the inline in full; never describe it in place of printing it ("I'd pair it with one inline on…"). Craig approves the exact words that post under his name, so the exact words must be on screen. State that the skill ran (e.g. "/voice personal — full pattern walk across summary + 3 inline"). Surface any pattern #39 warnings. 5. Ask: approve, request changes, or open in editor. Wait for an explicit answer. Do not open the file in `emacsclient` (or any editor) by default. - **Approve** → continue to step 6. diff --git a/claude-rules/desktop-capture.md b/claude-rules/desktop-capture.md new file mode 100644 index 0000000..0051c4d --- /dev/null +++ b/claude-rules/desktop-capture.md @@ -0,0 +1,57 @@ +# Off-Workspace Windows and Captures + +Applies to: `**/*` (any task that opens a window or takes a screenshot on the user's live desktop) + +Never open a window or take a screenshot on the user's active workspace. When +visual verification needs a real window on the user's live desktop, keep it off +the workspace they're working in. An agent doing its own visual verification +shouldn't hijack the desktop the user is actively using. + +The principle is environment-general: don't commandeer the user's active +workspace for agent-side visual work. The recipe below is the Hyprland/Wayland +implementation; other environments implement the same principle with their own +off-screen mechanism. + +## Captures for your own verification + +Render and grab the window off the user's physical screen, then tear it down. On +Hyprland this is a virtual headless output, verified non-disruptive on ratio +2026-07-06 — the physical monitor stayed on its workspace, focused, throughout: + +```sh +hyprctl output create headless # virtual output on its own workspace +setsid <app> >/tmp/x.log 2>&1 </dev/null & +addr=$(hyprctl -j clients | python3 -c 'import json,sys; print(next((c["address"] for c in json.load(sys.stdin) if c.get("class")=="<CLASS>"), ""))') +hyprctl dispatch movetoworkspacesilent "<ws-on-headless>,address:$addr" # silent = keeps the user's focus +grim -o HEADLESS-<n> /tmp/shot.png # capture the virtual output only +pkill -f '<app>$'; hyprctl output remove HEADLESS-<n> # tear down, restore the display +``` + +Key constraint: `grim` captures a *visible output*, so a window merely parked on +another Hyprland workspace can't be screenshotted — it must render on the +headless (or another real) output. That's why a headless output, not just +"another workspace," is the tool for self-captures. A nested compositor +(weston/cage/sway) is the alternative on non-Hyprland Wayland or when a headless +output isn't available; it needs the compositor installed. + +## Showing the user something + +Open it on a *separate* real workspace and tell them which one, so it never +grabs their active workspace. They switch when ready. Craig's viewer preference +is `imv`; launch it through the compositor (`hyprctl dispatch exec "imv +<files>"`) so it survives the agent's shell rather than a bare `&` job that gets +reaped. + +## Always clean up + +Close the window and remove any headless output afterward. Verify the user's +display is restored: physical monitor back to its workspace, no orphan +processes. + +## Related + +- `verification.md` — this is part of how visual verification is done without + disrupting the user. +- `interaction.md` — the broader "don't disrupt the user's active work" concern. +- `emacs.md` — the screenshot note for Emacs changes uses the same off-screen + capture approach. diff --git a/claude-rules/emacs.md b/claude-rules/emacs.md index ae4f7cb..2c3b729 100644 --- a/claude-rules/emacs.md +++ b/claude-rules/emacs.md @@ -33,3 +33,21 @@ This replaces the quit → relaunch → re-find-and-load-files cycle for most ed The reload caveats above are about pushing changes *into* the daemon. The inverse hazard: a tool that edits a file *on disk* while the daemon has an indirect buffer cloned from it. org-capture works through such a buffer, and a disk write (a hand edit, a `git pull` that fast-forwards the file, a `sed`/Write) reverts the base buffer underneath the capture. The capture is left on stale state, can no longer finalize with `C-c C-c`, and a freshly-typed item can be lost or written back against post-edit content. Orphaned `CAPTURE-*` buffers piling up as Craig retries is the visible symptom. The roam inbox (`~/org/roam/inbox.org`) is the live case — Craig captures into it constantly, and the inbox workflow's roam mode (Phase D) edits it. Before a disk write to a file the daemon may be capturing into, check first: `.ai/scripts/capture-guard <file>` exits non-zero (and names the buffer) when a live capture is cloned from `<file>`, and exits 0 — safe — when there's no capture or no reachable Emacs. Same principle as the reload rule, one layer out: leave the daemon's live buffers authoritative rather than yanking the file from under them. + +## SVG Rendering for Emacs App UIs + +Consider SVG rendering (`svg.el`) as the default for any Emacs app UI with real visual structure — boards, meters, gauges, status panels (Craig's directive, 2026-07-11). Verified on Emacs 30.2 pgtk via jotto's librsvg spike: `svg.el` cleanly renders rounded rects, linear gradients, fill-opacity, bold/italic/letter-spaced text, stroked shapes, and theme-derived colors. + +The payoff is the prototyping pipeline: design the UI as an HTML prototype first (per `ui-prototyping.md` — browser iteration), then port near-1:1 to `svg.el`, since browser SVG and librsvg share primitives. + +Constraints to design around: + +- **GUI-only.** No tty rendering — ship a second text renderer or accept GUI-only. +- **The SVG region is an image, not text.** Input stays minibuffer/keymaps; no point-and-click into the drawing. +- **Theme colors are pulled by hand.** Read them from faces at render time (`face-attribute`); the image inherits nothing. +- **Whole-image regeneration per state change.** Design the render as a pure state → SVG function so regeneration is cheap to reason about. +- **Stick to a librsvg-safe subset.** No SMIL, no JS-in-SVG, conservative CSS and filters. `feDropShadow` renders without error but is visually unverified — don't lean on it. + +Recommended shape: hybrid layouts — SVG for boards, meters, and visual state; text buffers for prose and transcripts. + +Prior art: archsetup's instrument-console widget gallery (`docs/prototypes/2026-07-03-panel-widget-gallery-prototype.html` in archsetup); jotto's spec records the full pipeline and constraint sheet. diff --git a/claude-rules/interaction.md b/claude-rules/interaction.md index 9148b4f..8d65799 100644 --- a/claude-rules/interaction.md +++ b/claude-rules/interaction.md @@ -57,3 +57,14 @@ In conversational output to the user, do not use Markdown bold (`**...**`) or in - 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. + +## Showing Craig Visuals + +Craig runs Claude Code inside Emacs EAT (through tmux). EAT renders SendUserFile and inline terminal images as an `[image] path.png` text line — the visual itself never appears. In one session ~20 renders went out that way and Craig approved UI he had never seen (takuzu, 2026-07-11). Never rely on SendUserFile or inline image display to show a visual. SendUserFile stays fine for *delivering* a file; it just doesn't display one. + +Two display lanes, by what the visual is for: + +- **Durable or interactive visuals** — HTML prototypes, full renders, anything Craig will study or click: open in the browser (`google-chrome-stable "file://<abs-path>" &>/dev/null &`) or imv, on a separate workspace per `desktop-capture.md`. +- **Quick inline glances** — a chart, a did-it-render check: sixel in the terminal. Encode with ImageMagick (`magick <img> sixel:<out>`; img2sixel silently emits zero bytes on some builds) and display in a separate tmux window (`tmux new-window -d -n <name>`, then `tmux send-keys -t <name> "clear; cat <out>" Enter`, tell Craig the window name) rather than the Claude Code pane, whose TUI repaints over anything drawn into it. With native tmux sixel active, the image lives in tmux's grid and survives window switches, scrolling, and resizing. + +**Capability gate.** Native sixel needs two config pieces: EAT answering the XTWINOPS cell-size query (patched eat.el, owned by .emacs.d) and `terminal-features 'xterm*:sixel'` in tmux.conf (owned by dotfiles). Check before relying on it: `tmux display -p '#{client_cell_width}'` — nonzero means go; 0 means the chain is missing a piece, so fall back to the browser lane. (Diagnosed 2026-07-13: tmux won't transmit sixel until it knows the client's cell pixel size, and stock EAT 0.9.4 silently ignores the CSI 14 t query tmux uses to ask.) diff --git a/claude-rules/knowledge-base.md b/claude-rules/knowledge-base.md index 5658498..d8aa6a6 100644 --- a/claude-rules/knowledge-base.md +++ b/claude-rules/knowledge-base.md @@ -53,7 +53,7 @@ Pull before writing, commit and push after (`git -C ~/org/roam add -A && git com ## Capture, then promote -Harness memory (`~/.claude/projects/<enc>/memory/`) remains the per-project capture layer: fast, automatic, allowed to be at-risk. At wrap-up (or a task audit, or an explicit prompt), promote facts that meet the inclusion bar into the KB as nodes. The wrap-up workflow asks; answer it honestly — promotion discipline is what keeps the capture layer from silting up. +Harness memory (`~/.claude/projects/<enc>/memory/`) remains the per-project capture layer: fast, automatic, allowed to be at-risk. An agent running without harness memory (a non-Claude runtime) captures into its session log instead and promotes from there — the promotion discipline is the same. At wrap-up (or a task audit, or an explicit prompt), promote facts that meet the inclusion bar into the KB as nodes. The wrap-up workflow asks; answer it honestly — promotion discipline is what keeps the capture layer from silting up. ## Inventory diff --git a/claude-rules/todo-format.md b/claude-rules/todo-format.md index 5e9ca32..2cdc76c 100644 --- a/claude-rules/todo-format.md +++ b/claude-rules/todo-format.md @@ -110,6 +110,29 @@ the letter mapping are fixed. and safety issues are graded on severity alone — one occurrence with the right consequences is a showstopper no matter how rarely it would be hit. +**Don't double-count rarity.** Grade severity by the rate of harm once the +failure state is entered, not by how rare it is to enter. Frequency already +carries the rarity; letting it discount severity too grades the same fact twice, +and that buries exactly the bugs that compound — the ones where a rare trigger +produces unbounded harm. A leak that repeats every timeout period until the +process restarts is Major even when reaching that state is a rare edge case +("accumulates slowly" describes a bounded trickle, not a fixed-rate leak with no +workaround). Grade the *being-in-it*, and let the frequency row carry the +*getting-into-it*. + +**Record the grading in the task body.** State the severity band, the frequency +row, and the arithmetic (e.g. "Major severity × rare edge case = P3 = [#C]"). A +bare priority cookie can't be argued with; a stated read can be re-checked +against the source and corrected. This is what lets a misgrade move — a chime +watchdog bug went [#D] → [#C] an hour after grading precisely because the read +was written down and re-checked. + +**Disagreeing with a grade means fixing an input.** If a letter looks wrong, +don't override the letter — re-read the severity band and the frequency row +against the source and correct whichever input is wrong. Overriding the cookie +directly turns the matrix into a formality and puts you back to grading by +instinct, which is the thing it exists to replace. + ## The Rule A todo entry has two parts: diff --git a/claude-rules/ui-prototyping.md b/claude-rules/ui-prototyping.md new file mode 100644 index 0000000..c453258 --- /dev/null +++ b/claude-rules/ui-prototyping.md @@ -0,0 +1,93 @@ +# UI Prototyping for Specs + +Applies to: `**/*` (any spec whose deliverable has a non-trivial UI) + +How to settle a UI design before committing implementation code: research the +category, brainstorm the UX in the spec, build a handful of full working +prototypes, then iterate one to a final. The prototype is the evidence a design +decision is recorded against. Discovered building archsetup's timer-panel spec, +promoted here so any UI-bearing spec follows the same shape. + +## When this applies — non-trivial UI only + +The process fires when a spec's deliverable is a real UI: a panel, a +multi-control surface, a visual layout with interacting parts. Not a single +dialog, a CLI flag, or a one-off prompt. The test: if "which of these layouts +is right?" can't be answered from a sentence, it qualifies. + +A spec with no UI, or a trivial one, skips this rule entirely. + +## The process + +### 1. Research first — during brainstorming, before any prototype + +Before building anything, survey how existing and best-in-class tools solve the +same UX: the category's well-regarded apps, prior art, the conventions users +already expect. Feed the findings into the spec's Goals and Design so the UX is +understood before a single prototype exists. Prototyping blind wastes iterations +re-deriving what a 20-minute survey would have told you. Cite the sources in the +spec. + +### 2. Brainstorm the UX in the spec + +Informed by the research, write the goals, the interactions, and the functional +surface into the spec. This is the "what and why" the prototypes make real. + +### 3. Prototype — ~5 distinct directions, then iterate one to final + +Build about five genuinely different directions — distinct layouts and +interaction models, not variations of one — as full working prototypes over one +shared engine, in the project's design language. Pick a direction, then iterate +that one across numbered passes to the final. Save each meaningful pass as its +own numbered prototype so the design history is walkable. + +For an Emacs app UI, the production port target is `svg.el` — browser SVG and +librsvg share primitives, so the winning prototype ports near-1:1. Keep every +prototype within the librsvg-safe constraint sheet in `emacs.md` (SVG Rendering +section) so the port stays mechanical. + +### 4. Full working prototypes, not mockups + +The prototypes must be functional: real state, real controls, real behavior, so +decisions are made against how it feels to use rather than against a picture. A +static mockup hides the interaction problems that only surface when you drive it. + +### 5. Naming and location + +`docs/prototypes/<spec-name>-prototype-<N>.html`, where `<spec-name>` is the +spec's dated slug with the `-spec` suffix dropped, and `N` is the iteration +number. For `docs/specs/2026-07-02-timer-panel-spec.org`, the prototypes are +`docs/prototypes/2026-07-02-timer-panel-prototype-1.html`, `-2.html`, `-3.html`. + +### 6. Link from the spec; keep every iteration in history + +The spec links the final prototype in its design section, and keeps links to +every prior iteration in a "Prototype iterations" subsection under the status +heading — newest last — so the design's evolution is walkable from the spec. + +### 7. Decisions get recorded once seen working + +A design decision moves into the spec's Decisions only after it has been seen +working in a prototype. "Resolved live through the prototype iteration" — the +prototype is the evidence, not an argument on the page. + +## How the spec workflows hook in + +- **spec-create**: for a non-trivial-UI spec, add the "research → brainstorm → + prototype (5 directions → iterate)" step before the design is treated as + settled, and require the "Prototype iterations" subsection under the status + heading. +- **spec-review**: for a non-trivial-UI spec, verify the process ran — research + cited, final prototype linked, iterations present in history, and each UI + design decision backed by a prototype rather than asserted. + +Both workflows point here rather than restating the process, so the rule stays +the single source of truth. + +## Why + +A UI design argued on paper is a guess. Five working directions surface the +interaction problems a mockup hides, and iterating one of them to a final makes +the tradeoffs concrete before any production code is written. Recording each +decision only once it's been seen working keeps the spec honest: the Decisions +section documents what the prototype proved, not what the author hoped. diff --git a/claude-rules/verification.md b/claude-rules/verification.md index 26d05b5..2c2088e 100644 --- a/claude-rules/verification.md +++ b/claude-rules/verification.md @@ -68,6 +68,8 @@ Do not let an unverifiable check vanish into a confident summary. State it plain Some checks can only be run by the user: interactive UI a script can't drive, a live external service, visual rendering (colors, layout, faces), a real device, or anything where the verification *is* a human looking at the result. When the gap needs the user's hands or eyes — not just a command they could paste — don't bury the steps in prose. Write them as a structured, runnable checklist in the project's task file. +When *you* need a window on the user's live desktop to verify something visually — render a panel, grab a screenshot — keep it off the workspace they're actively using. Capture on an off-screen output and tear it down; when showing the user something, open it on a separate workspace and name it. See `desktop-capture.md` for the rule and the Hyprland recipe. + Create (or append to) a single parent task named **"Manual testing and validation"** in the project's todo file (`todo.org`, or the project's equivalent). Under it, write **one org sub-header per test**: - **Title** — descriptive, naming the behavior under test (not "test 1"). |
