aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-07 09:32:39 -0500
committerCraig Jennings <c@cjennings.net>2026-05-07 09:32:39 -0500
commit5bee32b3e11dfc8fa3eefa589a8fc18932abaa79 (patch)
tree2829a7ad66b2c30ed38014b03de2117eb7bc8137
parentfd3eda377aee1e797fa4bcf975d656ec25d66bd0 (diff)
downloadrulesets-5bee32b3e11dfc8fa3eefa589a8fc18932abaa79.tar.gz
rulesets-5bee32b3e11dfc8fa3eefa589a8fc18932abaa79.zip
chore: migrate humanizer callers to /voice personal
I switched the three publish subflows in commits.md (commit messages, PR descriptions, PR review comments) from "run humanizer; apply five personal-style passes in order" to a single "run /voice personal" invocation. The new skill walks 39 patterns in one editorial review and absorbs the five passes wholesale, plus four more personal-style additions (felt-experience cut, fragment-in-prose rewrite, terse cut, public-artifact scope flag) and six universal good-writing patterns. The numbered steps in each subflow collapse from 5 to 4 (commits) and 9 to 8 (PRs) since the dedicated personal-style step folds into the voice invocation. The Multi-pass gate paragraph becomes a Single-skill gate. The mid-flow "all the passes" prompt now means re-run the full 39-pattern walk in personal mode rather than reapplying six discrete steps. I also updated respond-to-cj-comments.md to invoke /voice personal for public writing and /voice general for the lighter pass on internal notes when wanted, and updated start-work.md's Phase 7 summary to match. The humanizer skill itself stays in place for now. The next commit removes it.
-rw-r--r--.claude/commands/respond-to-cj-comments.md30
-rw-r--r--.claude/commands/start-work.md4
-rw-r--r--claude-rules/commits.md47
3 files changed, 30 insertions, 51 deletions
diff --git a/.claude/commands/respond-to-cj-comments.md b/.claude/commands/respond-to-cj-comments.md
index 35977d1..ba36f6c 100644
--- a/.claude/commands/respond-to-cj-comments.md
+++ b/.claude/commands/respond-to-cj-comments.md
@@ -1,5 +1,5 @@
---
-description: Scan a target file for inline `cj:` annotations (Craig's in-line questions and instructions; multi-line continuations recognized across most comment markers) and process each via subagent-delegated accuracy. Each item is classified instruction / question / both, then dispatched to an instruction subagent (proposes a file:line patch) or a question subagent (researches with explicit scope, reports answer + evidence + confidence). Main thread reviews proposals before editing — subagents don't write to the source file. Org-mode TODO parents flip to DOING; new content lands under timestamped subheadings one level deeper. Public-facing writing (commits, PRs, Slack, email, public docs) gets a humanizer pass plus `commits.md` voice rules; private writing skips humanizer. Summary lists handled instructions, answered questions with evidence + confidence, follow-ups, unresolved items, and an explicit clean / N-remain verdict. Long summaries (>6-8 items or >500 words) write to `/tmp/` and open in `emacsclient -n`. File paths render as clickable absolute org-mode links. Use when a file accumulates inline `cj:` comments. Do NOT use for general code review (`/review-code`), new work without inline comments, or trivial items.
+description: Scan a target file for inline `cj:` annotations (Craig's in-line questions and instructions; multi-line continuations recognized across most comment markers) and process each via subagent-delegated accuracy. Each item is classified instruction / question / both, then dispatched to an instruction subagent (proposes a file:line patch) or a question subagent (researches with explicit scope, reports answer + evidence + confidence). Main thread reviews proposals before editing — subagents don't write to the source file. Org-mode TODO parents flip to DOING; new content lands under timestamped subheadings one level deeper. Public-facing writing (commits, PRs, Slack, email, public docs) gets `/voice personal`; private writing skips the voice pass. Summary lists handled instructions, answered questions with evidence + confidence, follow-ups, unresolved items, and an explicit clean / N-remain verdict. Long summaries (>6-8 items or >500 words) write to `/tmp/` and open in `emacsclient -n`. File paths render as clickable absolute org-mode links. Use when a file accumulates inline `cj:` comments. Do NOT use for general code review (`/review-code`), new work without inline comments, or trivial items.
disable-model-invocation: true
---
@@ -112,27 +112,9 @@ For **questions**:
For **writing destined for public channels** (commit messages, PR descriptions, PR comments, Slack or email messages, public docs):
-1. Invoke `/humanizer` on the draft.
-2. Apply these voice and attribution rules to the writing you produced (adapted from `/home/cjennings/code/rulesets/claude-rules/commits.md`):
+1. Invoke `/voice personal` on the draft. The skill walks 39 patterns covering humanizer's signs of AI writing, universal good-writing rules (Strunk & White, Orwell, Plain English, Garner), and personal voice patterns (first-person rewrite, semicolons → periods/commas, contractions, sentence-split, felt-experience cut, sentence-fragment rewrite, terse cut, public-artifact scope flag).
- **No AI attribution, anywhere.** Never include AI, LLM, Claude, or Anthropic attribution in any public-facing text. That means:
- - No `Co-Authored-By: Claude` (or Claude Code, or any AI) trailers
- - No "Generated with Claude Code" footers or equivalents
- - No emojis implying AI authorship
- - No references to Claude, Anthropic, LLM, or "AI tool" as a credited contributor
- - Strip any attribution a tool or template inserts by default
-
- **First person where it fits.** When the subject is Craig or a decision he made, use "I". When the subject is a team decision or shared rationale, "we" fits. Name other authors when crediting their work ("Kostya's PR #116 did X"). Avoid third-person press-release voice ("This PR introduces X", "This change restores Y") unless the code or system is the actor.
-
- **Brief. Terse is fine.** A one-sentence body beats a paragraph saying the same thing. If the subject line covers it, skip the body entirely. Cut every clause that restates what the diff, the card, or the surrounding context already shows. Length isn't a proxy for care. Rhetorical padding ("worth noting", "it's important to understand") always comes out.
-
- **Kind.** Text directed at a specific person: acknowledge them when it fits, without pouring it on. Frame disagreement as your read ("I think...", "my read was...", "did you mean X?"). Leave room for the other person to have seen something you didn't. A polite question beats a defensive explanation.
-
- **Plain English.** Complete sentences a low- or mid-level engineer who isn't a native speaker can read without stumbling. Replace semicolons with periods or commas. Prefer contractions ("it's", "that's", "don't", "we're"). Split long sentences on conjunctions ("so", "and", "but") when meaning survives the split. No em-dashes, use regular dashes instead. Em-dashes break in GitHub, Linear, and Slack.
-
- **Don't stack jargon.** A sentence that chains three or more type signatures, API names, or compiler concepts reads as a wall. Break it into shorter sentences. Keep the terms a reader will grep for, drop the ones that name compiler internals.
-
-3. Scan the output for AI-attribution tells. If you catch yourself having written any of these, stop, delete, and rewrite:
+2. Scan the output for AI-attribution tells. If you catch yourself having written any of these, stop, delete, and rewrite:
- `Co-Authored-By: Claude`
- `Generated with Claude Code` (with or without the robot emoji)
- "Created with Claude Code"
@@ -142,7 +124,7 @@ For **writing destined for public channels** (commit messages, PR descriptions,
If the writing will be *posted* (not just saved as a draft), follow the Review and Publish flow in `commits.md` — draft to `/tmp/`, open in `emacsclient -n`, wait for Craig's explicit approval before posting.
-**Private writing** (todo.org entries, session-context.org, scratch notes, internal rulesets) skips the humanizer pass. Voice rules still apply where relevant, but the overhead of a draft-and-approve cycle is not warranted.
+**Private writing** (todo.org entries, session-context.org, scratch notes, internal rulesets) skips `/voice personal`. Use `/voice general` for the AI-detection + universal-good-writing passes when relevant, but the overhead of a draft-and-approve cycle is not warranted for internal notes.
### 5. Report
@@ -201,14 +183,14 @@ Confirm the cleanup by re-scanning the file after removals. If any `cj:` line su
- **Don't guess.** If a question needs verification and verification isn't possible, say so. Surface unknowns rather than fabricate.
- **Preserve the file.** Don't reformat surrounding lines. Don't reorder tasks. Touch only what the comment asks for, plus the comment's own removal.
- **The user reads the summary, not the process log.** Write summaries that are directly useful.
-- **Public writing gets humanizer + commits.md. Private writing doesn't.** Don't over-process internal notes.
+- **Public writing gets `/voice personal`. Private writing doesn't.** Don't over-process internal notes.
## Anti-patterns
- Handling complex `cj:` items inline in the main thread instead of subagenting.
- Batching unrelated `cj:` comments into one giant subagent prompt.
- Removing a `cj:` comment before the user has seen the answer in the summary.
-- Skipping the humanizer + commits.md pass on public-facing writing because it "looked fine already."
+- Skipping the `/voice personal` pass on public-facing writing because it "looked fine already."
- Guessing on a question instead of spawning a research subagent.
- Letting a subagent edit the source file directly — review surface loss.
diff --git a/.claude/commands/start-work.md b/.claude/commands/start-work.md
index bf32801..2224490 100644
--- a/.claude/commands/start-work.md
+++ b/.claude/commands/start-work.md
@@ -236,9 +236,9 @@ If deviations are significant, the user may want to loop back and revise the app
Follow `commits.md` exactly. Summary of the flow:
1. Run `/review-code --staged` before each commit, or `/review-code` on the whole branch before the PR. Block on Critical or Important findings.
-2. Draft the commit message to `/tmp/commit-<slug>.md`. Run `humanizer`. Apply the plain-English pass. Replace semicolons. Stop for approval.
+2. Draft the commit message to `/tmp/commit-<slug>.md`. Run `/voice personal`. Stop for approval.
3. After approval, commit.
-4. Draft the PR body to `/tmp/pr-<ticket-or-slug>.md`. Body must include a `Linear:` or equivalent cross-link line. Run `humanizer`. Apply the plain-English pass. Replace semicolons. Stop for approval.
+4. Draft the PR body to `/tmp/pr-<ticket-or-slug>.md`. Body must include a `Linear:` or equivalent cross-link line. Run `/voice personal`. Stop for approval.
5. After approval, push and run `gh pr create`.
6. Post the PR URL back to the Linear ticket, GitHub issue, or todo.org entry.
7. Move the Linear or GitHub status to **Dev Review**. Todo.org has no equivalent. Leave the todo.org entry as `DOING` until the PR merges.
diff --git a/claude-rules/commits.md b/claude-rules/commits.md
index d059b9c..b485506 100644
--- a/claude-rules/commits.md
+++ b/claude-rules/commits.md
@@ -249,45 +249,42 @@ enough to skip review" exemption on top of it.
**For commit messages:**
1. Write the proposed message to `/tmp/commit-<short-slug>.md`.
-2. Run the `humanizer` skill on the file. Always — commit messages get the same prose-review treatment as PR descriptions.
-3. Apply the personal-style passes in order on the humanized output: (a) rewrite the body in first person as if it's coming from me — "I added a test for...", "I missed the X branch", "I kept Y because..." — instead of impersonal third-person ("Add...", "The change adds...", "This PR introduces..."). The subject line stays imperative per Conventional Commits. Skip the first-person rewrite only when the body is purely mechanical (a chore bump, a typo fix) and the subject alone carries the message; (b) rewrite dev-jargon fragments ("Empty X throws", "Hard throw not a clamp", "all green") as plain, brief, complete sentences a low- or mid-level engineer who is not a native English speaker can read without stumbling; (c) replace semicolons with either a period or a comma; (d) prefer contractions ("it's", "that's", "don't", "we're") over their expanded forms; (e) break up long sentences. Few engineers use semicolons in prose — they make the writing feel unnecessarily literary. Uncontracted English reads stiff in a short prose body unless a negation or emphasis needs the weight. A sentence that stacks three or four clauses with commas and conjunctions reads easier as two or three shorter ones. If you can split it on a conjunction ("so", "and", "but") without losing meaning, split it. Also re-check the colleague-tone framing in *Voice and Focus* — the message should read like one engineer talking to another.
-4. Print the final draft inline in the terminal. Every line, exactly as it'll be committed. No truncation, no summary. Name the passes that ran (e.g. "humanizer + first-person + jargon + semicolons + contractions + sentence-split — all applied").
-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 — print first, edit only if asked.
+2. Run `/voice personal` on the file. Always. The skill walks 39 patterns covering humanizer's signs of AI writing, universal good-writing rules (Strunk & White, Orwell, Plain English, Garner), and the personal voice patterns (first-person rewrite, semicolons → periods/commas, contractions, sentence-split on conjunctions, felt-experience cut, sentence-fragment rewrite, terse cut for rhetorical padding, public-artifact scope flag). The commit subject line stays imperative per Conventional Commits — `/voice personal` rewrites the body, not the subject. Skip the pass for purely mechanical commits (a chore version bump, a typo fix) where the subject alone carries the message.
+3. Print the final draft inline in the terminal. Every line, exactly as it'll be committed. No truncation, no summary. State that the skill ran (e.g. "/voice personal — 39 patterns walked"). If pattern #39 (public-artifact scope) flagged anything, surface those warnings; the user resolves them manually.
+4. 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 — print first, edit only if asked.
- **Approve** → commit with `git commit -F /tmp/commit-<short-slug>.md`.
- - **Request changes** → make them, re-run `humanizer`, re-apply the personal-style passes, re-print inline, ask again.
+ - **Request changes** → make them, re-run `/voice personal`, re-print inline, ask again.
- **Open in editor** → only if the user asks. `emacsclient -n /tmp/commit-<short-slug>.md`. After the editor closes, re-read the file, re-print the contents inline, and ask again.
**For PR descriptions:**
1. Write the title as line 1 and the body below it to `/tmp/pr-<ticket-or-slug>.md`. **Title format:** `<conventional-commit subject> (<TICKET-ID>)` — the ticket ID goes at the end in parentheses (e.g. `refactor: remove dead if-count-is-not-None check in admin (SE-289)`). If there is no ticket, omit the parenthetical. The body must also include a `Linear: [<TICKET-ID>](<linear-url>)` line so Linear's GitHub integration auto-cross-links the PR to the ticket. If there is no ticket, state that explicitly ("Linear: n/a") so reviewers know it was considered.
-2. Run the `humanizer` skill on the file.
-3. Apply the personal-style passes in order on the humanized output: (a) rewrite the body in first person as if it's coming from me — "I added X", "I missed Y", "I kept Z because..." — instead of impersonal third-person ("Add...", "The change adds...", "This PR introduces..."). The PR title stays imperative per Conventional Commits. Skip the first-person rewrite only when the body is purely mechanical and the title alone carries the message; (b) rewrite dev-jargon fragments as plain, brief, complete sentences a low- or mid-level engineer who is not a native English speaker can read without stumbling; (c) replace semicolons with periods or commas — few engineers use semicolons in prose, they make the writing feel unnecessarily literary; (d) prefer contractions ("it's", "that's", "don't", "we're") over their expanded forms — uncontracted English reads stiff in a short prose body; (e) break up long sentences. A sentence that stacks three or four clauses with commas and conjunctions reads easier as two or three shorter ones. If you can split it on a conjunction ("so", "and", "but") without losing meaning, split it. Also re-check the colleague-tone framing in *Voice and Focus*.
-4. Print the final draft inline in the terminal. Title on line 1, blank line, then body — exactly as it'll be posted. Name the passes that ran.
-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.
- - **Request changes** → make them, re-run `humanizer`, re-apply the personal-style passes, re-print inline, ask again.
+2. Run `/voice personal` on the file. The PR title stays imperative per Conventional Commits — `/voice personal` rewrites the body, not the title.
+3. Print the final draft inline in the terminal. Title on line 1, blank line, then body — exactly as it'll be posted. State that the skill ran. Surface any pattern #39 (public-artifact scope) warnings.
+4. 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 5.
+ - **Request changes** → make them, re-run `/voice personal`, re-print inline, ask again.
- **Open in editor** → only if the user asks. `emacsclient -n /tmp/pr-<ticket-or-slug>.md`. After the editor closes, re-read the file, re-print inline, ask again.
-6. Split the file on the first blank line and pass the title and body to `gh pr create --title "..." --body "$(tail -n +3 <file>)"` (or a heredoc) so formatting is preserved. Add `--reviewer <user[,user...]>` in the same call when you already know who should review.
-7. Request reviewers on the new PR if you didn't pass `--reviewer` at create time. Use `gh pr edit <N> --add-reviewer <user>`. If the repo has a `CODEOWNERS` file, GitHub auto-suggests based on touched paths. Still issue the explicit request so the reviewer gets notified. Pick reviewers per the team's convention for the area touched (often documented in the per-repo `CLAUDE.md`). For follow-up PRs, consider tagging the parent PR's author if their context would help. PRs without a human reviewer request stall — "checks passed" is not a substitute for review.
-8. After `gh pr create` returns a URL, post a comment on the linked Linear ticket with the PR URL (use the Linear MCP `save_comment` tool, or open the ticket manually if MCP is unavailable). This closes the ticket→PR direction of the cross-link.
-9. Move the Linear ticket to the "Dev Review" status (use `save_issue` with the Dev Review state ID, or the Linear UI). The ticket should not remain "In Progress" once a PR is open against it.
+5. Split the file on the first blank line and pass the title and body to `gh pr create --title "..." --body "$(tail -n +3 <file>)"` (or a heredoc) so formatting is preserved. Add `--reviewer <user[,user...]>` in the same call when you already know who should review.
+6. Request reviewers on the new PR if you didn't pass `--reviewer` at create time. Use `gh pr edit <N> --add-reviewer <user>`. If the repo has a `CODEOWNERS` file, GitHub auto-suggests based on touched paths. Still issue the explicit request so the reviewer gets notified. Pick reviewers per the team's convention for the area touched (often documented in the per-repo `CLAUDE.md`). For follow-up PRs, consider tagging the parent PR's author if their context would help. PRs without a human reviewer request stall — "checks passed" is not a substitute for review.
+7. After `gh pr create` returns a URL, post a comment on the linked Linear ticket with the PR URL (use the Linear MCP `save_comment` tool, or open the ticket manually if MCP is unavailable). This closes the ticket→PR direction of the cross-link.
+8. Move the Linear ticket to the "Dev Review" status (use `save_issue` with the Dev Review state ID, or the Linear UI). The ticket should not remain "In Progress" once a PR is open against it.
**For PR review comments and replies (review verdicts, threaded discussion, follow-up notes on someone else's PR or your own):**
1. Write the proposed comment to `/tmp/pr-<N>-comment.md` (or `/tmp/pr-<ticket>-comment.md` if the ticket ID is clearer).
-2. Run the `humanizer` skill on the file. Always.
-3. Apply the personal-style passes in order on the humanized output: (a) rewrite in first person as if it's coming from me — "I think...", "I tried X but...", "I'd rather..." — instead of impersonal third-person ("The change does...", "It seems..."). Comments are directed at a specific person, the voice should be mine, not a generated narrator's; (b) rewrite dev-jargon fragments as plain, brief, complete sentences a low- or mid-level engineer who is not a native English speaker can read without stumbling; (c) replace semicolons with periods or commas; (d) prefer contractions ("it's", "that's", "don't", "we're") over their expanded forms; (e) break up long sentences on conjunctions ("so", "and", "but"). The *Voice and Focus* rules — especially the colleague-tone framing — matter the most here. The comment is directed at a specific person who will reply, and the thread is public.
-4. Print the final draft inline in the terminal. Name the passes that ran.
-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.
- - **Request changes** → make them, re-run `humanizer`, re-apply the personal-style passes, re-print inline, ask again.
+2. Run `/voice personal` on the file. Always. The *Voice and Focus* rules — especially the colleague-tone framing — matter the most here. The comment is directed at a specific person who will reply, and the thread is public.
+3. Print the final draft inline in the terminal. State that the skill ran. Surface any pattern #39 warnings.
+4. 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 5.
+ - **Request changes** → make them, re-run `/voice personal`, re-print inline, ask again.
- **Open in editor** → only if the user asks. `emacsclient -n /tmp/pr-<N>-comment.md`. After the editor closes, re-read the file, re-print inline, ask again.
-6. Post with the `gh` command that matches the comment type:
+5. Post with the `gh` command that matches the comment type:
- Review-shaped comment (the reviewer's overall verdict on the PR): `gh pr review <N> --comment --body-file /tmp/pr-<N>-comment.md` (use `--approve` or `--request-changes` in place of `--comment` when formally approving or blocking).
- Issue-thread comment (general PR discussion, not a formal review): `gh pr comment <N> --body-file /tmp/pr-<N>-comment.md`.
- Inline code comment pinned to a specific line/hunk: no direct `gh` flag — use `gh api /repos/<owner>/<repo>/pulls/<N>/comments -F body=@/tmp/pr-<N>-comment.md -F commit_id=... -F path=... -F line=...`.
-7. Verify the comment landed. `gh api /repos/<owner>/<repo>/pulls/<N>/reviews` for review-shaped comments, `gh api /repos/<owner>/<repo>/issues/<N>/comments` for issue-thread comments.
-8. **Notify the PR author on Slack** (review-shaped comments only — `--approve` or `--request-changes`). After the review posts, send a one-line Slack message to channel `C0AM2MWHCJU` via the `slack-deepsat` MCP. No humanizer or personal-style passes — the message is short and templated. Two cases:
+6. Verify the comment landed. `gh api /repos/<owner>/<repo>/pulls/<N>/reviews` for review-shaped comments, `gh api /repos/<owner>/<repo>/issues/<N>/comments` for issue-thread comments.
+7. **Notify the PR author on Slack** (review-shaped comments only — `--approve` or `--request-changes`). After the review posts, send a one-line Slack message to channel `C0AM2MWHCJU` via the `slack-deepsat` MCP. No `/voice personal` pass — the message is short and templated. Two cases:
- Approved: `<@author-slack-id> Approved PR #N.\n<pr-url>`
- Changes requested: `<@author-slack-id> Changes Requested PR #N\n<pr-url>`
Replace `#N` with the PR number and `<pr-url>` with the GHE URL of the PR. Always lead with an `<@author-slack-id>` mention so the engineer who owns the merge decision gets pinged — the message is useless without it. Resolve the Slack user ID via the slack-deepsat `users_search` tool using the PR author's name or email. The URL goes on its own line, immediately after the message. If the MCP doesn't have a post-message tool registered (for example, in a project where the Slack MCP is read-only), surface that to the user and skip the post — don't fall back to a different channel or asking the user to paste it.
@@ -301,7 +298,7 @@ conversation (e.g. "commit this as `chore: bump version`", "reply just
`/review-code` in Step 1 still runs when it applies; Phase 0 of that skill
handles trivial diffs, and acknowledgment-only replies don't need it at all.
-**Multi-pass gate.** Each of the three subflows above runs `humanizer` and five personal-style passes (first-person voice, jargon rewrite, semicolon swap, contractions, sentence split) before printing the draft. All six are mandatory — the printed draft must have been through every one. When the user asks mid-flow for "both passes" or "all the passes" or just "the humanizer step" on an in-progress draft, that means re-run *every* pass — not just the first or a representative subset. Always name the passes that ran when announcing the printed draft (e.g. "humanizer + first-person + jargon + semicolons + contractions + sentence-split — all applied"). Skipping a pass without flagging it is a defect.
+**Single-skill gate.** Each of the three subflows above runs `/voice personal` before printing the draft. The skill walks 39 patterns in one editorial review — humanizer's 25 signs of AI writing plus 6 universal good-writing patterns plus 8 personal-only patterns. Running it is mandatory; the printed draft must have been through it. When the user asks mid-flow for "the voice pass" on an in-progress draft, that means re-run the full 39-pattern walk in personal mode — not a subset. Always state that the skill ran when announcing the printed draft (e.g. "/voice personal — 39 patterns walked"). Skipping the pass without flagging it is a defect.
### Hook-level authorization