From ea5d0076e0d56dfe34aeb9885c5963cafe6302ef Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:53:48 -0400 Subject: [PATCH 1/6] feat(naming): add name-it-better plugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New single-skill plugin. /naming:name-it-better generates fresh name candidates by fanning out ~3 blind, fresh-context generators from distinct lenses (responsibility-literal, moment-of-use, domain-lore), scores a collision-checked shortlist against the consuming org's naming criteria, and recommends — the human always picks, never an auto-locked name. Optional tournament action adds elimination rounds with independent judges for high-stakes, hard-to-refactor names, framed honestly as an adaptation rather than a documented technique. Repo-agnostic: scores against the consuming project's declared naming conventions when present, degrading to the general criteria grounded in the skill's context/sources.md when none is declared. Ships warranted evals and the method-grounding sources file. Co-authored-by: Claude Fable 5 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- .claude-plugin/marketplace.json | 6 + README.md | 1 + plugins/naming/.claude-plugin/plugin.json | 12 ++ plugins/naming/CHANGELOG.md | 18 +++ plugins/naming/README.md | 60 ++++++++++ plugins/naming/skills/name-it-better/SKILL.md | 111 ++++++++++++++++++ .../skills/name-it-better/context/sources.md | 94 +++++++++++++++ .../skills/name-it-better/evals/evals.json | 54 +++++++++ 8 files changed, 356 insertions(+) create mode 100644 plugins/naming/.claude-plugin/plugin.json create mode 100644 plugins/naming/CHANGELOG.md create mode 100644 plugins/naming/README.md create mode 100644 plugins/naming/skills/name-it-better/SKILL.md create mode 100644 plugins/naming/skills/name-it-better/context/sources.md create mode 100644 plugins/naming/skills/name-it-better/evals/evals.json diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 55e8c0f220..727eeea59a 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -193,6 +193,12 @@ "category": "design", "tags": ["planning", "wayfind", "decision-map", "brainstorm", "prd", "interview", "domain-modeling", "ubiquitous-language", "glossary", "design", "design-handoff", "devils-advocate", "architect", "stress-test", "skill"] }, + { + "name": "naming", + "source": "./plugins/naming", + "category": "design", + "tags": ["naming", "name", "rename", "identifier", "candidates", "anti-anchoring", "skill"] + }, { "name": "review", "source": "./plugins/review", diff --git a/README.md b/README.md index c6ddb68347..6fd57bc214 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ Browse and manage with `/plugin`. To refresh after updates: `/plugin marketplace - [`architecture`](plugins/architecture) — Scans an existing codebase for module-level architecture friction — shallow modules, seam leaks, and locality gaps — using Ousterhout's deep-module lens, presents candidates as a self-contained HTML report, and runs an interview loop on the selected candidate before handing off for planning. - [`prototype`](plugins/prototype) — Builds throwaway code to answer a design question before committing to architecture — a logic facet (an interactive terminal app over a portable state model) and a UI facet (radically different visual variants on one route). - [`planning`](plugins/planning) — Pre-implementation planning pipeline: chart a too-big, foggy effort as a decision map, diverge on candidate approaches, lock product intent and the engineering contract, actively maintain resolved domain language, explore the design space, stress-test adversarially, and produce a structured implementation plan with an approval gate. +- [`naming`](plugins/naming) — Generates and evaluates fresh name candidates for anything — an identifier, file, module, skill, repo, or domain term — by fanning out blind, fresh-context generators from distinct lenses (responsibility-literal, moment-of-use, domain-lore), then scoring a shortlist against the consuming org's naming criteria. The human always picks; it never auto-locks a name. An optional tournament mode adds elimination rounds with independent judges for high-stakes, hard-to-refactor names. - [`event-storming`](plugins/event-storming) — EventStorming for domain discovery — a methodology skill (Big Picture / Process Modeling / Design-Level facilitation reference, notation, patterns) and a simulation skill (agentic multi-persona workshops that produce a structured-markdown model by default; a live Miro-board rendering path is available when the first-party miro plugin is enabled). - [`miro`](plugins/miro) — Miro board management over the Model Context Protocol: create and manage boards, sticky notes, shapes, frames, connectors, and tags for EventStorming, brainstorming, and diagramming. Bundles a local stdio MCP server (single self-contained Node artifact); installs disabled — opt in and supply a Miro API token. diff --git a/plugins/naming/.claude-plugin/plugin.json b/plugins/naming/.claude-plugin/plugin.json new file mode 100644 index 0000000000..a2c2b28ae4 --- /dev/null +++ b/plugins/naming/.claude-plugin/plugin.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", + "name": "naming", + "version": "0.1.0", + "description": "Generates and evaluates fresh name candidates for anything — an identifier, file, module, skill, repo, or domain term — by fanning out blind, fresh-context generators from distinct lenses (responsibility-literal, moment-of-use, domain-lore), then scoring a shortlist against the consuming org's naming criteria. The human always picks; it never auto-locks a name. An optional tournament mode adds elimination rounds with independent judges for high-stakes, hard-to-refactor names.", + "author": { + "name": "Melodic Software", + "email": "info@melodicsoftware.com" + }, + "license": "MIT", + "keywords": ["naming", "name", "rename", "identifier", "candidates", "anti-anchoring", "skill"] +} diff --git a/plugins/naming/CHANGELOG.md b/plugins/naming/CHANGELOG.md new file mode 100644 index 0000000000..51c4dc4710 --- /dev/null +++ b/plugins/naming/CHANGELOG.md @@ -0,0 +1,18 @@ +# Changelog + +All notable changes to the `naming` plugin are documented here. Format follows +[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. + +## [0.1.0] + +### Added + +- **Initial release.** `/naming:name-it-better` — generate fresh name + candidates by fanning out blind, fresh-context generators from distinct lenses + (responsibility-literal, moment-of-use, domain-lore), score a shortlist against + the consuming org's naming criteria, and recommend — the human always picks, + never an auto-locked name. Optional `tournament` action adds elimination rounds + with independent judges for high-stakes, hard-to-refactor names. +- Repo-agnostic: scores against the consuming project's declared naming + conventions when present, degrading to the general criteria grounded in the + skill's `context/sources.md` when none is declared. diff --git a/plugins/naming/README.md b/plugins/naming/README.md new file mode 100644 index 0000000000..8460d8f542 --- /dev/null +++ b/plugins/naming/README.md @@ -0,0 +1,60 @@ +# naming + +A Claude Code plugin for generating and evaluating name candidates. One +skill, one job: when a name was just rejected — or none exists yet — break +the anchor by fanning out blind, fresh-context generators from distinct +lenses, then hand the human a scored shortlist to choose from. + +| Skill | What it does | +|---|---| +| `/naming:name-it-better` | Generate fresh name candidates from blind lenses, score them, recommend a shortlist — the human picks | + +## Why blind generators + +The dominant trigger is a reactive retry: a name was suggested and +rejected, and the same context that produced it will only produce more of +the same. So the generators run BLIND to the conversation, seeded only with +a distilled context brief, each working a distinct lens +(responsibility-literal, moment-of-use, domain-lore). Diverge widely from +independent perspectives, then converge once — and keep the first-seen +suggestion from anchoring the choice. The method grounding is in the +skill's `context/sources.md`. + +**The human always picks.** The skill narrows and recommends; it never +auto-locks a name. + +```shell +/naming:name-it-better # blind lenses → scored shortlist → human picks +/naming:name-it-better tournament # ~5 generators + elimination rounds for high-stakes names +``` + +`tournament` is an honest adaptation of elimination brackets plus pairwise +social-choice scoring — not a documented naming technique; the skill +presents it as such. + +## Consumer conventions + +- **Criteria source of truth.** The skill scores against the consuming + organization's naming and domain-language conventions when the project + declares them (its `CLAUDE.md` / `.claude/rules/` or a standards source + it points to). When none is declared, it falls back to the general + naming criteria grounded in the skill's `context/sources.md`. A criterion + the user wants that is missing from their conventions flows UP into those + conventions, not into the skill. +- **Adjacent capabilities.** Resolving what a domain concept IS routes to a + domain-modelling capability; propagating a chosen name across call sites + routes to a rename-references capability — each invoked through its slash + command when present, degrading to prose guidance when absent. + +## Install + +```shell +/plugin marketplace add melodic-software/claude-code-plugins +/plugin install naming@melodic-software +``` + +## Configuration + +No `userConfig`. No persistent state. Network: the generators are +subagents; `context/sources.md` carries external reference links for the +method, not fetched at runtime. diff --git a/plugins/naming/skills/name-it-better/SKILL.md b/plugins/naming/skills/name-it-better/SKILL.md new file mode 100644 index 0000000000..7ce36a3b04 --- /dev/null +++ b/plugins/naming/skills/name-it-better/SKILL.md @@ -0,0 +1,111 @@ +--- +name: name-it-better +description: "Generate and evaluate fresh name candidates for anything — a variable, function, file, module, skill, repo, or domain term — then let the human pick. Use when: 'name it better', 'better name', 'rename this', 'that name is wrong', 'suggest names', 'what should I call this', 'need a name for', 'come up with a name'. Spawns blind fresh-context generators from distinct lenses; never auto-locks a name. Optional 'tournament' arg for high-stakes, hard-to-refactor names." +argument-hint: "[tournament]" +user-invocable: true +disable-model-invocation: true +--- + +# Name it better + +## Purpose + +Produce better name candidates for anything that needs one — an +identifier, file, module, skill, repo, or domain term — and hand the +human a scored shortlist to choose from. The dominant trigger is a +reactive retry: a name was just suggested and rejected, and the same +context that produced it will only produce more of the same. So the +generators run BLIND to the conversation, from distinct lenses, to break +the anchor. A blank-slate naming request is the same machinery without a +rejected incumbent. + +**The human always picks.** This skill narrows and recommends; it never +auto-locks a name. + +## Criteria — cite the source of truth, do not copy it + +Score against the consuming organization's naming criteria, resolved from +its own context, never from a baked-in path: + +1. **Declared conventions win.** When the consuming project names where its + naming and domain-language conventions live — its `CLAUDE.md`, + `.claude/rules/`, a shared standards source it points to — score against + THAT. Read the criteria there; do not restate them here. A criterion the + user wants that is missing from those conventions flows UP into them + (their standards change), not hardcoded into this skill. +2. **None declared → the general criteria** grounded in + [`context/sources.md`](context/sources.md): intention-revealing and + semantically accurate to the responsibility, evolution-safe (the name + sets scope and bounds), context-sensitive, free of overloaded or + disinformative terms, and drawn from the domain's ubiquitous language. + +## Default pass + +1. **Distill a context brief.** Capture, in a few lines: the + responsibility of the thing, its scope and lifetime, hard constraints + (language casing rules, length, collisions to avoid), the existing + surrounding vocabulary, and a blocklist of overloaded terms to avoid. + This brief — NOT the conversation — is all the generators receive. +2. **Fan out blind generators.** Spawn ~3 fresh-context subagents, each + seeded ONLY with the brief (blind to this conversation and to each + other), each working a distinct lens: + - **responsibility-literal** — name exactly what it does; + - **moment-of-use** — name for how it reads at the call site; + - **domain-lore** — name from the domain's ubiquitous language. + + Running them blind and independent is deliberate anti-anchoring; the + method grounding is in [`context/sources.md`](context/sources.md). +3. **Merge and score.** Pool the candidates, dedupe, check each for + collisions against the existing vocabulary, and score every survivor + against the criteria resolved above. +4. **Shortlist + recommend.** Present a short ranked list with a + one-line rationale per candidate and a single RECOMMENDED pick, marked + and listed first. +5. **Human picks.** Stop and let the user choose. Do not apply the name. + +## `tournament` action + +When `$ARGUMENTS` contains `tournament`, run this in place of the default +pass. + +`/naming:name-it-better tournament` — for a high-stakes name that will be +hard to refactor later. Widen to ~5 generators (optionally different +models), then run elimination rounds with independent scoring judges until +one candidate remains, and present it plus the runners-up for the human +choice. + +HONEST FRAMING: a "naming tournament / bracket" is NOT a documented +software-naming technique. This mode ADAPTS elimination brackets plus +pairwise social-choice scoring as a convergence mechanism — see +[`context/sources.md`](context/sources.md). Present it as such, not as an +established standard. + +## Adjacent skills — hand off, do not overlap + +- Resolving what a domain concept IS (not just its label) → a + domain-modelling capability. Hand a settled domain term there. +- Sweeping references after a rename is decided → a rename-references + capability. This skill picks the name; that one propagates it. + +Invoke an adjacent capability through its slash command when present; +degrade to prose guidance when it is absent. + +## What this skill does NOT do + +- **Never auto-locks a name.** It always ends at a human choice. +- **Does not apply the rename.** Propagating a chosen name across call + sites is a rename-references capability's job. +- **Does not copy or invent criteria.** It scores against the resolved + source of truth; missing criteria route upstream, not into the skill. +- **Does not claim tournament mode is a documented technique** — it is an + adaptation, flagged as one. + +## Gotchas + +- If the generators are fed the conversation instead of just the brief, + the anti-anchoring purpose is defeated — they will re-derive the + rejected name. Seed them with the brief ONLY. +- A candidate that scores well but collides with existing vocabulary is + disqualified, not shortlisted — collision-check before scoring. +- `tournament` costs several generators plus judges; reserve it for names + that are genuinely expensive to change, not routine locals. diff --git a/plugins/naming/skills/name-it-better/context/sources.md b/plugins/naming/skills/name-it-better/context/sources.md new file mode 100644 index 0000000000..9fcc6e7e21 --- /dev/null +++ b/plugins/naming/skills/name-it-better/context/sources.md @@ -0,0 +1,94 @@ +# Method sources — name-it-better + +The naming CRITERIA are owned elsewhere (the consuming org's conventions — +see the skill body). This file grounds the skill's METHOD: how candidates +are generated, why generators run blind, and what the `tournament` mode is +actually adapted from. Read it only when judging a method question or +extending the skill. Tiers: PRIMARY = author's own words / official +spec; AUTHORITATIVE = faithful canonical write-up by the originators or +their collaborators; SECONDARY = derivative. + +## Naming as a process (staged refinement) + +The backbone of the default pass's distinct lenses. A name is refined +through stages rather than guessed in one shot: from missing/misleading, +to obvious-nonsense, to honest, to completely-honest, to +does-the-right-thing, to intent-revealing, to domain-abstraction. The +"responsibility-literal → moment-of-use → domain-lore" lenses map onto +the honest → intent → domain-abstraction progression. + +- Origin, Arlo Belshee ("Read by Refactoring"): [belshee-origin] — PRIMARY. + Flag: this host was DNS-unreachable during research, so Belshee's exact + per-stage prose is corroborated by the Deep Roots rewrite below rather + than quoted from the origin. +- Canonical rewrite, Tim Ottinger + Llewellyn Falco: [deeproots-series] + and [deeproots-path] — AUTHORITATIVE. Confirm the ordered stages and the + three-phase structure. + +## Naming criteria lineage (Ottinger / Clean Code) + +Backs the scoring rubric's shape (the authoritative criteria source of +truth is the consuming org's conventions). + +- Ottinger's Rules: [ottinger-rules] — AUTHORITATIVE. Intention-revealing, + avoid disinformation, pronounceable, no encodings, one word per concept, + meaningful in context. +- Clean Code, ch. 2 "Meaningful Names" (Martin, with Ottinger): + [clean-code-ch2] — PRIMARY. + +## Domain language + +Backs the domain-lore lens and the "name from the shared domain +vocabulary" criterion. + +- DDD Reference (Eric Evans): [ddd-reference] — PRIMARY. +- Ubiquitous Language (Fowler): [fowler-ubiquitous] — AUTHORITATIVE. + +## Blind generation → human convergence (anti-anchoring) + +Why generators run BLIND to the conversation and the human always makes +the final pick: diverge widely from independent perspectives, then +converge once — and keep the first-seen suggestion from anchoring the +choice. + +- Double Diamond (diverge/converge), UK Design Council: [double-diamond] + — AUTHORITATIVE. +- Anchoring bias, Tversky & Kahneman (1974), "Judgment under Uncertainty": + [tk-1974] (open PDF: [tk-1974-pdf]) — PRIMARY. First value seen biases + the final judgment; independent-before-shared review reduces it. + +## `tournament` mode — adapted, NOT a documented naming technique + +HONEST FLAG: there is no primary source describing a "naming tournament" +or "naming bracket" method for choosing identifiers. The mode is an +ADAPTATION, presented as a local convergence mechanism, not an +established naming standard. It borrows two documented, unrelated things: + +- Elimination brackets (single/double elimination): [elim-bracket] — + SECONDARY (generic, not naming). +- Pairwise social-choice aggregation (Condorcet / Copeland / Minimax) for + turning head-to-head judgements into a ranking: [condorcet] — the + rigorous basis if judges score candidates pairwise. + +## Framework / style-guide naming (supporting) + +- .NET naming guidelines (Microsoft): [dotnet-naming] — PRIMARY. +- Kevlin Henney, "Seven Ineffective Coding Habits" (naming): [henney] — + PRIMARY. Meaning over word-count; "adding words is not adding meaning". +- Google style guides (per-language naming): [google-style] — PRIMARY. + +[belshee-origin]: https://arlobelshee.com/good-naming-is-a-process-not-a-single-step/ +[deeproots-series]: https://www.digdeeproots.com/articles/naming-process/naming-as-a-process/ +[deeproots-path]: https://www.digdeeproots.com/articles/naming-process/naming-as-a-process-learning-path/ +[ottinger-rules]: https://exelearning.org/wiki/OttingersNaming/ +[clean-code-ch2]: https://www.oreilly.com/library/view/clean-code-a/9780136083238/chapter02.xhtml +[ddd-reference]: https://www.domainlanguage.com/wp-content/uploads/2016/05/DDD_Reference_2015-03.pdf +[fowler-ubiquitous]: https://martinfowler.com/bliki/UbiquitousLanguage.html +[double-diamond]: https://en.wikipedia.org/wiki/Double_Diamond_(design_process_model) +[tk-1974]: https://www.science.org/doi/10.1126/science.185.4157.1124 +[tk-1974-pdf]: https://www.cs.tufts.edu/comp/150AIH/pdf/TverskyKa74.pdf +[elim-bracket]: https://en.wikipedia.org/wiki/Double-elimination_tournament +[condorcet]: https://en.wikipedia.org/wiki/Condorcet_method +[dotnet-naming]: https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/naming-guidelines +[henney]: https://www.infoq.com/presentations/7-ineffective-coding-habits/ +[google-style]: https://google.github.io/styleguide/ diff --git a/plugins/naming/skills/name-it-better/evals/evals.json b/plugins/naming/skills/name-it-better/evals/evals.json new file mode 100644 index 0000000000..6a141fbd5e --- /dev/null +++ b/plugins/naming/skills/name-it-better/evals/evals.json @@ -0,0 +1,54 @@ +{ + "skill_name": "name-it-better", + "evals": [ + { + "id": 1, + "name": "rejected-name-blind-retry-to-human-pick", + "prompt": "name it better — you suggested `DataManager` for the class that validates and persists orders and I don't like it.", + "expected_output": "The skill distills a context brief (responsibility, scope, constraints, surrounding vocabulary, overloaded-term blocklist), fans out ~3 fresh-context generators seeded ONLY with the brief (blind to this conversation) across the three lenses, merges and collision-checks, scores against the resolved criteria, and presents a ranked shortlist with a single marked RECOMMENDED pick — then stops for the human to choose.", + "files": [], + "expectations": [ + "Distills a context brief and seeds the generators with the brief ONLY (blind to the conversation), not the rejected name", + "Fans out ~3 fresh-context generators across distinct lenses (responsibility-literal, moment-of-use, domain-lore)", + "Presents a ranked shortlist with one marked RECOMMENDED pick listed first", + "STOPS for the human to choose — does not auto-lock or apply a name" + ] + }, + { + "id": 2, + "name": "collision-check-disqualifies", + "prompt": "name it better for a new module — the surrounding codebase already has a `Session` type and a `Context` type, don't collide with those.", + "expected_output": "Candidates are collision-checked against the existing vocabulary BEFORE scoring; a candidate that collides with `Session` or `Context` is disqualified rather than shortlisted, even if it would otherwise score well.", + "files": [], + "expectations": [ + "Collision-checks candidates against the existing vocabulary before scoring", + "Disqualifies a colliding candidate rather than ranking it", + "Still ends at a human choice over the surviving shortlist" + ] + }, + { + "id": 3, + "name": "tournament-honest-framing", + "prompt": "/naming:name-it-better tournament — this is the public package name, very hard to change later.", + "expected_output": "The tournament action widens to ~5 generators and runs elimination rounds with independent scoring judges, presenting the finalist plus runners-up for the human choice. It frames the tournament HONESTLY as an adaptation of elimination brackets plus pairwise scoring, not as a documented naming technique.", + "files": [], + "expectations": [ + "Widens to ~5 generators and runs elimination rounds with independent judges", + "Explicitly frames tournament mode as an adaptation, not an established naming standard", + "Presents the finalist plus runners-up for the human to pick" + ] + }, + { + "id": 4, + "name": "missing-criterion-routes-upstream", + "prompt": "name it better, and also our team wants a new naming rule that every repository name must start with the product code — bake that into how you score.", + "expected_output": "The skill scores against the resolved criteria source of truth and does NOT hardcode the new rule into itself: it routes the missing criterion UP into the consuming org's conventions (a standards change) rather than embedding it in the skill, then proceeds with the naming pass.", + "files": [], + "expectations": [ + "Does not bake the new criterion into the skill itself", + "Routes the missing criterion up into the consuming org's naming conventions (a standards change)", + "Proceeds with generation and scoring against the resolved source of truth, ending at a human pick" + ] + } + ] +} From 5790430b42b77f8af8458e27dacbb552ab02d2b2 Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Fri, 17 Jul 2026 10:12:53 -0400 Subject: [PATCH 2/6] build(naming): exclude bot-blocked method-source URLs from lychee MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sources.md cites three authoritative naming references whose hosts refuse automated link-checking — arlobelshee.com (DNS-unreachable, flagged in the file and corroborated via digdeeproots) and science.org / oreilly.com (403 to non-browser clients). Add them to the online-lane exclude list, matching the existing bot-blocked-URL entries; the Tversky-Kahneman open-PDF mirror stays checked. Verified with lychee: 12 OK, 0 errors, 3 excluded. Co-authored-by: Claude Fable 5 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- lychee.toml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lychee.toml b/lychee.toml index b2f59c38e2..5e9fa2591b 100644 --- a/lychee.toml +++ b/lychee.toml @@ -25,6 +25,14 @@ exclude = [ '^https?://bsky\.app/', '^https?://(www\.)?medium\.com/@ziobrando/the-rise-and-fall-of-the-dungeon-master-c2d511eed12f/?([?#].*)?$', '^https?://help\.miro\.com/hc/en-us/articles/31624028247058/?([?#].*)?$', + # naming plugin method sources — authoritative citations whose hosts block + # or refuse automated checks: arlobelshee.com is DNS-unreachable (the source + # file itself flags this and corroborates via digdeeproots), and science.org + # and oreilly.com return 403 to non-browser clients. The Tversky-Kahneman + # paper also has an open-PDF mirror (cs.tufts.edu) that stays checked. + '^https?://(www\.)?arlobelshee\.com/good-naming-is-a-process-not-a-single-step/?([?#].*)?$', + '^https?://(www\.)?science\.org/doi/10\.1126/science\.185\.4157\.1124/?([?#].*)?$', + '^https?://(www\.)?oreilly\.com/library/view/clean-code-a/9780136083238/chapter02\.xhtml/?([?#].*)?$', '^https?://isdown\.app/status/anthropic/?([?#].*)?$', '^https?://(www\.)?npmjs\.com/package/(firecrawl-cli|@mirohq/miro-api)/?([?#].*)?$', '^https?://localhost', From 9c4eb2b099b797255921ff0a27bda7363c92ef6b Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Fri, 17 Jul 2026 11:21:51 -0400 Subject: [PATCH 3/6] fix(naming): restore model invocation, disqualify rejected incumbent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two Codex review findings on the reactive-retry naming workflow: - SKILL.md advertised natural-language trigger phrases ('name it better', 'better name', ...) in "Use when:" form while disable-model-invocation: true kept its description out of context, so those phrases could never load the skill. Per the Skills docs (https://code.claude.com/docs/en/skills#control-who-invokes-a-skill), that flag hides the description entirely rather than merely requiring a slash command. Remove it so the advertised triggers work, matching other action skills in this repo (debugging/diagnose, discovery/explore). - The merge step deduped and collision-checked against existing vocabulary but never excluded the rejected incumbent itself, so a blind generator that independently re-derived a common name (e.g. DataManager, Manager, Context) could still land in the shortlist and defeat the anti-anchoring purpose. Carry the rejected name as an explicit main-thread reject list — never shared with the blind generators — and disqualify it at merge time. Extend eval case 1 to assert the rejected incumbent cannot reappear in the shortlist. Co-authored-by: Claude Sonnet 5 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- plugins/naming/skills/name-it-better/SKILL.md | 13 +++++++++---- .../naming/skills/name-it-better/evals/evals.json | 2 ++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/plugins/naming/skills/name-it-better/SKILL.md b/plugins/naming/skills/name-it-better/SKILL.md index 7ce36a3b04..9522c33257 100644 --- a/plugins/naming/skills/name-it-better/SKILL.md +++ b/plugins/naming/skills/name-it-better/SKILL.md @@ -3,7 +3,6 @@ name: name-it-better description: "Generate and evaluate fresh name candidates for anything — a variable, function, file, module, skill, repo, or domain term — then let the human pick. Use when: 'name it better', 'better name', 'rename this', 'that name is wrong', 'suggest names', 'what should I call this', 'need a name for', 'come up with a name'. Spawns blind fresh-context generators from distinct lenses; never auto-locks a name. Optional 'tournament' arg for high-stakes, hard-to-refactor names." argument-hint: "[tournament]" user-invocable: true -disable-model-invocation: true --- # Name it better @@ -55,9 +54,11 @@ its own context, never from a baked-in path: Running them blind and independent is deliberate anti-anchoring; the method grounding is in [`context/sources.md`](context/sources.md). -3. **Merge and score.** Pool the candidates, dedupe, check each for - collisions against the existing vocabulary, and score every survivor - against the criteria resolved above. +3. **Merge and score.** Pool the candidates, dedupe, and disqualify any + candidate that matches the rejected incumbent (if any) — carried by the + main thread as an explicit reject list, never shared with the + generators — or that collides with the existing vocabulary. Score every + surviving candidate against the criteria resolved above. 4. **Shortlist + recommend.** Present a short ranked list with a one-line rationale per candidate and a single RECOMMENDED pick, marked and listed first. @@ -105,6 +106,10 @@ degrade to prose guidance when it is absent. - If the generators are fed the conversation instead of just the brief, the anti-anchoring purpose is defeated — they will re-derive the rejected name. Seed them with the brief ONLY. +- A blind generator can still independently re-derive the rejected + incumbent (common for generic labels like `Manager` or `Context`). That + is not a blinding failure — the main thread's reject list disqualifies + it at merge time regardless of how a candidate was produced. - A candidate that scores well but collides with existing vocabulary is disqualified, not shortlisted — collision-check before scoring. - `tournament` costs several generators plus judges; reserve it for names diff --git a/plugins/naming/skills/name-it-better/evals/evals.json b/plugins/naming/skills/name-it-better/evals/evals.json index 6a141fbd5e..1316bf80af 100644 --- a/plugins/naming/skills/name-it-better/evals/evals.json +++ b/plugins/naming/skills/name-it-better/evals/evals.json @@ -10,6 +10,8 @@ "expectations": [ "Distills a context brief and seeds the generators with the brief ONLY (blind to the conversation), not the rejected name", "Fans out ~3 fresh-context generators across distinct lenses (responsibility-literal, moment-of-use, domain-lore)", + "Carries `DataManager` as a main-thread reject list and disqualifies it at merge time, even if a generator independently re-derives it", + "The rejected incumbent (`DataManager`) does not appear in the final shortlist", "Presents a ranked shortlist with one marked RECOMMENDED pick listed first", "STOPS for the human to choose — does not auto-lock or apply a name" ] From b2bd63c04013c66bd191a3db6944eac0fc46e088 Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Fri, 17 Jul 2026 11:37:43 -0400 Subject: [PATCH 4/6] fix(naming): preserve reject and collision filters in tournament mode The tournament action runs in place of the default pass but never carried over the default pass's reject-list and collision disqualification. A tournament triggered after a rejection (or with a collision constraint) could present an already-rejected or colliding name as the winner. Gate bracket entry on the same disqualification: pool the widened candidates and drop reject-list/collision matches before the elimination rounds begin, so a rejected or colliding name can never reach the finalist. Add an eval locking this behavior. --- plugins/naming/skills/name-it-better/SKILL.md | 6 ++++++ .../naming/skills/name-it-better/evals/evals.json | 13 +++++++++++++ 2 files changed, 19 insertions(+) diff --git a/plugins/naming/skills/name-it-better/SKILL.md b/plugins/naming/skills/name-it-better/SKILL.md index 9522c33257..c1d48e7610 100644 --- a/plugins/naming/skills/name-it-better/SKILL.md +++ b/plugins/naming/skills/name-it-better/SKILL.md @@ -75,6 +75,12 @@ models), then run elimination rounds with independent scoring judges until one candidate remains, and present it plus the runners-up for the human choice. +The reject-list and collision disqualification from the default pass's +merge step still apply: pool the widened candidates and disqualify any that +match the rejected incumbent or collide with the existing vocabulary BEFORE +the elimination rounds begin — a rejected or colliding name must never enter +the bracket, let alone reach the finalist. + HONEST FRAMING: a "naming tournament / bracket" is NOT a documented software-naming technique. This mode ADAPTS elimination brackets plus pairwise social-choice scoring as a convergence mechanism — see diff --git a/plugins/naming/skills/name-it-better/evals/evals.json b/plugins/naming/skills/name-it-better/evals/evals.json index 1316bf80af..2a57821848 100644 --- a/plugins/naming/skills/name-it-better/evals/evals.json +++ b/plugins/naming/skills/name-it-better/evals/evals.json @@ -51,6 +51,19 @@ "Routes the missing criterion up into the consuming org's naming conventions (a standards change)", "Proceeds with generation and scoring against the resolved source of truth, ending at a human pick" ] + }, + { + "id": 5, + "name": "tournament-preserves-reject-and-collision-filters", + "prompt": "/naming:name-it-better tournament — you already suggested `OrderManager` for this and I rejected it, and it must not collide with the existing `OrderService` type. This is the public API name, very hard to change later.", + "expected_output": "The tournament action widens to ~5 generators and runs elimination rounds, but first carries `OrderManager` as a main-thread reject list and treats `OrderService` as an existing-vocabulary collision. Both the rejected incumbent and the colliding candidate are disqualified before the elimination rounds begin, so neither can enter the bracket or reach the finalist. It presents a finalist plus runners-up for the human to pick.", + "files": [], + "expectations": [ + "Carries `OrderManager` as a main-thread reject list even in tournament mode", + "Disqualifies the rejected incumbent and any candidate colliding with `OrderService` BEFORE the elimination rounds begin, not just at the finalist", + "Neither the rejected incumbent nor a colliding candidate appears as the finalist or among the runners-up", + "Still widens to ~5 generators, runs elimination rounds with independent judges, and ends at a human pick" + ] } ] } From 6c6f2bb1560f552e113914b7e82c95ebe8e81626 Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Fri, 17 Jul 2026 11:57:18 -0400 Subject: [PATCH 5/6] fix(naming): route already-decided renames away from name generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name-it-better description advertised a bare 'rename this' trigger. Because Claude uses the description to auto-load skills, a prompt like "rename Foo to Bar" — where the target name is already chosen — could load this name generator, which then stops to ask for candidate selection instead of applying/sweeping the decided rename. That prompt belongs to docs-hygiene:rename-references, whose description explicitly handles 'rename X to Y'. Narrow the trigger to the undecided-name case: drop bare 'rename this', scope the phrase list to "name is still UNDECIDED", and add an explicit skip clause routing already-decided renames ('rename X to Y', 'I renamed X') to the rename-references sweep. Preserve the help-me-pick affordance with 'help me rename this to something better'. --- plugins/naming/skills/name-it-better/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/naming/skills/name-it-better/SKILL.md b/plugins/naming/skills/name-it-better/SKILL.md index c1d48e7610..731e61d79a 100644 --- a/plugins/naming/skills/name-it-better/SKILL.md +++ b/plugins/naming/skills/name-it-better/SKILL.md @@ -1,6 +1,6 @@ --- name: name-it-better -description: "Generate and evaluate fresh name candidates for anything — a variable, function, file, module, skill, repo, or domain term — then let the human pick. Use when: 'name it better', 'better name', 'rename this', 'that name is wrong', 'suggest names', 'what should I call this', 'need a name for', 'come up with a name'. Spawns blind fresh-context generators from distinct lenses; never auto-locks a name. Optional 'tournament' arg for high-stakes, hard-to-refactor names." +description: "Generate and evaluate fresh name candidates for anything — a variable, function, file, module, skill, repo, or domain term — then let the human pick. Use when the target name is still UNDECIDED: 'name it better', 'better name', 'that name is wrong', 'suggest names', 'what should I call this', 'need a name for', 'come up with a name', 'help me rename this to something better'. Not for an already-decided rename ('rename X to Y', 'I renamed X') — that routes to the rename-references sweep. Spawns blind fresh-context generators from distinct lenses; never auto-locks a name. Optional 'tournament' arg for high-stakes, hard-to-refactor names." argument-hint: "[tournament]" user-invocable: true --- From 1162aac7e698a3d719137e813f804debf1d2e4e5 Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Fri, 17 Jul 2026 12:18:47 -0400 Subject: [PATCH 6/6] build(naming): cite bot-blocked sources as code spans, not lychee excludes The prior commit added three exclude patterns (arlobelshee.com, science.org, oreilly.com) to root lychee.toml so the online link-check would skip method-source URLs whose hosts are DNS-dead or 403 non-browser clients. But lychee.toml is a standards-synced, upstream-managed config (see AGENTS.md and standards/distribution/sync-manifest.yml): a local edit is silently overwritten on the next sync, dropping the excludes and re-breaking the check. The fix belongs in the branch-owned source file. Revert lychee.toml to be byte-identical to main, and reformat the three blocked citations in the naming plugin's sources.md from markdown reference links to inline code-span URLs. lychee skips verbatim/code segments by default (include_verbatim is unset; the link-check lane passes only --config lychee.toml, no --include-verbatim), so a code-span URL is not extracted for checking while remaining a readable, useful citation. Verified with lychee 0.24.2 --dump against sources.md: the three blocked URLs no longer appear in extraction, and the reachable cs.tufts open-PDF mirror (tk-1974-pdf, still a reference link) does. Remove the three now-orphaned reference definitions; no dangling labels remain. --- lychee.toml | 8 -------- .../skills/name-it-better/context/sources.md | 14 +++++++------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/lychee.toml b/lychee.toml index 5e9fa2591b..b2f59c38e2 100644 --- a/lychee.toml +++ b/lychee.toml @@ -25,14 +25,6 @@ exclude = [ '^https?://bsky\.app/', '^https?://(www\.)?medium\.com/@ziobrando/the-rise-and-fall-of-the-dungeon-master-c2d511eed12f/?([?#].*)?$', '^https?://help\.miro\.com/hc/en-us/articles/31624028247058/?([?#].*)?$', - # naming plugin method sources — authoritative citations whose hosts block - # or refuse automated checks: arlobelshee.com is DNS-unreachable (the source - # file itself flags this and corroborates via digdeeproots), and science.org - # and oreilly.com return 403 to non-browser clients. The Tversky-Kahneman - # paper also has an open-PDF mirror (cs.tufts.edu) that stays checked. - '^https?://(www\.)?arlobelshee\.com/good-naming-is-a-process-not-a-single-step/?([?#].*)?$', - '^https?://(www\.)?science\.org/doi/10\.1126/science\.185\.4157\.1124/?([?#].*)?$', - '^https?://(www\.)?oreilly\.com/library/view/clean-code-a/9780136083238/chapter02\.xhtml/?([?#].*)?$', '^https?://isdown\.app/status/anthropic/?([?#].*)?$', '^https?://(www\.)?npmjs\.com/package/(firecrawl-cli|@mirohq/miro-api)/?([?#].*)?$', '^https?://localhost', diff --git a/plugins/naming/skills/name-it-better/context/sources.md b/plugins/naming/skills/name-it-better/context/sources.md index 9fcc6e7e21..55874738af 100644 --- a/plugins/naming/skills/name-it-better/context/sources.md +++ b/plugins/naming/skills/name-it-better/context/sources.md @@ -17,8 +17,9 @@ does-the-right-thing, to intent-revealing, to domain-abstraction. The "responsibility-literal → moment-of-use → domain-lore" lenses map onto the honest → intent → domain-abstraction progression. -- Origin, Arlo Belshee ("Read by Refactoring"): [belshee-origin] — PRIMARY. - Flag: this host was DNS-unreachable during research, so Belshee's exact +- Origin, Arlo Belshee ("Read by Refactoring"): + `https://arlobelshee.com/good-naming-is-a-process-not-a-single-step/` — + PRIMARY. Flag: this host was DNS-unreachable during research, so Belshee's exact per-stage prose is corroborated by the Deep Roots rewrite below rather than quoted from the origin. - Canonical rewrite, Tim Ottinger + Llewellyn Falco: [deeproots-series] @@ -34,7 +35,8 @@ truth is the consuming org's conventions). avoid disinformation, pronounceable, no encodings, one word per concept, meaningful in context. - Clean Code, ch. 2 "Meaningful Names" (Martin, with Ottinger): - [clean-code-ch2] — PRIMARY. + `https://www.oreilly.com/library/view/clean-code-a/9780136083238/chapter02.xhtml` + — PRIMARY. ## Domain language @@ -54,7 +56,8 @@ choice. - Double Diamond (diverge/converge), UK Design Council: [double-diamond] — AUTHORITATIVE. - Anchoring bias, Tversky & Kahneman (1974), "Judgment under Uncertainty": - [tk-1974] (open PDF: [tk-1974-pdf]) — PRIMARY. First value seen biases + `https://www.science.org/doi/10.1126/science.185.4157.1124` + (open PDF: [tk-1974-pdf]) — PRIMARY. First value seen biases the final judgment; independent-before-shared review reduces it. ## `tournament` mode — adapted, NOT a documented naming technique @@ -77,15 +80,12 @@ established naming standard. It borrows two documented, unrelated things: PRIMARY. Meaning over word-count; "adding words is not adding meaning". - Google style guides (per-language naming): [google-style] — PRIMARY. -[belshee-origin]: https://arlobelshee.com/good-naming-is-a-process-not-a-single-step/ [deeproots-series]: https://www.digdeeproots.com/articles/naming-process/naming-as-a-process/ [deeproots-path]: https://www.digdeeproots.com/articles/naming-process/naming-as-a-process-learning-path/ [ottinger-rules]: https://exelearning.org/wiki/OttingersNaming/ -[clean-code-ch2]: https://www.oreilly.com/library/view/clean-code-a/9780136083238/chapter02.xhtml [ddd-reference]: https://www.domainlanguage.com/wp-content/uploads/2016/05/DDD_Reference_2015-03.pdf [fowler-ubiquitous]: https://martinfowler.com/bliki/UbiquitousLanguage.html [double-diamond]: https://en.wikipedia.org/wiki/Double_Diamond_(design_process_model) -[tk-1974]: https://www.science.org/doi/10.1126/science.185.4157.1124 [tk-1974-pdf]: https://www.cs.tufts.edu/comp/150AIH/pdf/TverskyKa74.pdf [elim-bracket]: https://en.wikipedia.org/wiki/Double-elimination_tournament [condorcet]: https://en.wikipedia.org/wiki/Condorcet_method