From harness-claude
Critiques identifier names (variables, functions, types, files) for clarity, concreteness, and weight. Uses a rubric catalog from Martin/Beck/Karlton for PR review and refactoring.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:naming-craftThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> LLM-judgment skill that critiques identifier names — variables, functions, types, and files — for clarity, concreteness, weight, and predictive power. First member of the craft-pipeline initiative (sub-project #1 of 10). Uses a curated rubric catalog seeded from Martin / Beck / Karlton. Emits 3-axis findings (tier × impact × confidence per ADR 0019).
LLM-judgment skill that critiques identifier names — variables, functions, types, and files — for clarity, concreteness, weight, and predictive power. First member of the craft-pipeline initiative (sub-project #1 of 10). Uses a curated rubric catalog seeded from Martin / Beck / Karlton. Emits 3-axis findings (tier × impact × confidence per ADR 0019).
align-naming ships the fix path)Read project configuration. Check harness.config.json for:
craft.naming.enabled — gate (default true)craft.naming.maxFiles — file count cap (default 100)craft.naming.maxIdentifiersPerFile — per-file sampling cap (default 15)Walk project files (.ts / .tsx / .js / .jsx). Skip node_modules, dist, build, coverage, dotdirs.
Extract identifiers per file via TS Compiler API:
const x =, let x =, destructuring bindersfunction x(), const x = () =>, class methods, arrow functions assigned to a nametype X, interface X, class Xshort = body ≤10 lines; long = otherwise), and ±2 context lines for LLM prompt construction.For each identifier kind, sample up to N=500 identifiers across the project and infer the dominant convention via majority-rule:
>50% majority threshold per kind. Below threshold → null (no dominant convention) and the convention-conformance rubric silently skips.
For each file:
Sample identifiers weighted by importance:
maxIdentifiersPerFile per file (default 15).For each (identifier, rubric) in the cross-product:
null (rubric doesn't apply / name is fine) or { tier, impact, confidence, message }.NamingFinding with cite.rubricId populated for ADR 0020 traceability.v1 rubric catalog (6 seed rubrics):
NAME-R001 predictive power (Martin) — does the name predict the contract?NAME-R002 concreteness (Martin / Beck) — concrete > vagueNAME-R003 verb/noun honesty (Beck) — verb for functions; noun for types; questions for booleansNAME-R004 convention conformance (Karlton) — matches project conventionNAME-R005 scope match (Beck) — length proportional to scopeNAME-R006 encoded measure (Pragmatic Programmer) — silent units cause real bugsEmit NamingCraftOutput:
{
findings: NamingFinding[];
summary: {
phaseRun: ['critique'];
durationMs: number;
llmCalls: { provider, model, count, costUsd };
catalog: { rubricsApplied: string[] };
convention: { variables, functions, types, files };
runId: string;
}
}
harness naming-craft — CLI entry. --files <glob> / --kinds <variable|function|type|file> / --max-files <n> / --max-identifiers-per-file <n> / --json / --verbose.mcp__harness__naming_craft — MCP tool. Two modes (see "In-session flow" below).mcp__harness__naming_craft_finalize — MCP tool that completes the in-session flow.critiqueNamesInFile(file, opts) exported from packages/cli/src/naming-craft/index.ts. Future craft skills (docs-craft, test-craft, code-craft) import and invoke this when they want naming critique on a file they're already processing — no project re-walk needed.harness.config.json. The shared selector in packages/cli/src/shared/craft/llm/provider.ts reads two blocks:
agent.backends — named backend definitions, shared with the orchestrator. Supported types: claude, anthropic, openai, local, pi, mock. (local and pi are OpenAI-compatible — point them at Ollama / LM Studio / vLLM / LiteLLM / any compliant server.)craft.llm — either { "backend": "<name>" } to route through one of the entries above, or { "mode": "in-session" | "mock" } for the non-backend modes. Default when nothing is set: in-session (host chat answers prompts via the two-step MCP flow).HARNESS_CRAFT_LLM env var overrides the file. Accepts in-session, mock, or the name of any entry in agent.backends.harness.orchestrator.mdIf you already declared agent.backends in harness.orchestrator.md, the craft selector reads from it as a fallback and emits a one-time warning on first run. Run harness migrate backends (preview with --dry-run) to copy the entries into harness.config.json so both files share a single source of truth.
Example config snippet for routing craft skills to a local Ollama:
{
"agent": {
"backends": {
"ollama": {
"type": "local",
"endpoint": "http://localhost:11434/v1",
"model": ["deepseek-coder-v2", "qwen3:8b"],
},
},
},
"craft": { "llm": { "backend": "ollama" } },
}
When HARNESS_CRAFT_LLM is unset (or set to in-session), the MCP tool does not call any LLM. Instead it returns a list of prompts for the calling agent to answer with its own model. This is a two-step protocol:
Step 1 — mcp__harness__naming_craft({ path, ... }) returns:
{
"status": "collected",
"runId": "<uuid>",
"pendingPrompts": [
{ "promptId": "p1", "systemPrompt": "...", "userPrompt": "..." },
...
],
"projection": { "promptCount": N, "budget": 100 }
}
If projection.promptCount > budget, status is "budget-exceeded" and pendingPrompts is empty — re-invoke with smaller maxFiles / maxIdentifiersPerFile, or pass promptBudget to raise the ceiling.
Step 2 — for each pending prompt, generate the fenced-JSON response as if you were a senior engineer applying the rubric to the identifier. The required response shape (per prompt) is:
```json
null
```
if the rubric does not apply or the name is fine, OR:
```json
{
"tier": "foundational|polish|aspirational",
"impact": "small|medium|large",
"confidence": "high|medium|low",
"message": "<critique with suggested rename when possible>"
}
```
Step 3 — mcp__harness__naming_craft_finalize({ path, runId, responses: [{ promptId, raw }, ...] }) parses the responses, applies the same validation the inline path uses, and returns the standard NamingCraftOutput.
If you want the inline behavior (skill calls an LLM directly), pass mode: 'inline' to step 1 and set HARNESS_CRAFT_LLM to a non-in-session provider.
See docs/changes/craft-pipeline/naming-craft/proposal.md for the full 34 success criteria. Highlights:
catalog/rubrics/<id>.ts (file-per-rubric matches design-craft pattern)cite.rubricId populated on every finding per ADR 0020null when no dominant convention (>50% threshold)critiqueNamesInFile API exported for future craft skillsInput: src/orders/processor.ts:
export function processData(orders: Order[]) { ... }
Output (mock LLM):
NAME-R002 [polish/medium/low] function processData:14
"processData" is a vague verb-pair where the operation and subject
are both unstated. Consider `applyDiscountsToOrders` or
`convertOrdersToInvoices` depending on the actual transform.
NAME-R001 [polish/medium/medium] function processData:14
The name predicts neither the input shape (orders) nor the operation.
(Real LLM responses vary; mock provider returns deterministic low-confidence findings for test determinism.)
Input:
const timeout = 5000;
Output:
NAME-R006 [foundational/medium/high] variable timeout:1
"timeout" implies a time measure but the unit is silent. Use
`timeoutMs` so the call site can't be misread as seconds.
Input: A project with 60% camelCase, 30% snake_case, 10% PascalCase variables. No >50% camelCase majority (60% IS >50%, so convention=camelCase). But with 45/40/15 split: no convention.
Output: convention-conformance rubric (NAME-R004) silently skips for the variables kind. Other rubrics still run.
align-naming may add safe-rename codemods.maxIdentifiersPerFile to 10 or maxFiles to 50. Cost = files × identifiers × rubrics × per-call cost.craft.naming.disabledRubrics: ['NAME-R005']. Until then: filter findings by cite.rubricId in your consumer.--files <glob> or call critiqueNamesInFile() via the cross-cutting API.v1 — in implementation. See:
docs/changes/craft-pipeline/naming-craft/proposal.mdcraft-pipeline sub-project #1 (the first member)harness-design-craft (design-pipeline #6 — the LLM-judgment template this follows)critiqueNamesInFile() for their domain-specific naming critique.npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeEnforces precise naming for variables, functions, classes, files, and identifiers. Bans vague names like data/temp/result/info/handle/manager; promotes semantic accuracy and domain-specific terms via specificity ladder.
Suggests improved names for variables, functions, classes, files, DB tables, and API endpoints using language-specific conventions like camelCase or snake_case.
Choosing meaningful, pronounceable names that reveal intent for functions, variables, classes, and modules.