diff --git a/.claude-leverage-context-map.json b/.claude-leverage-context-map.json index 3abcbd4..a145c72 100644 --- a/.claude-leverage-context-map.json +++ b/.claude-leverage-context-map.json @@ -3,14 +3,16 @@ "anchor_count": 34, "builder_version": "1.8.0", "file_count": 20, - "generated_at": "2026-06-01T07:07:10+00:00", + "generated_at": "2026-06-01T11:17:26+00:00", "generator": "scripts/build-context-map.py", "repo_root": ".", "schema_version": 1 }, "files": { "docs/conventions.md": { - "adrs": [], + "adrs": [ + "docs/adr/0010-naming-detect-and-conform-over-house-style.md" + ], "agents_md": [ "AGENTS.md" ], @@ -18,13 +20,13 @@ "anchors_in_file": [ { "deadline": "2026-08-01", - "line": 47, + "line": 86, "text": "replace the polling loop with webhooks", "type": "AIDEV-TODO" }, { "deadline": "2026-07-15", - "line": 48, + "line": 87, "text": "is the encoding always UTF-8 here?", "type": "AIDEV-QUESTION" } @@ -767,7 +769,8 @@ }, "templates/AGENTS.md.example": { "adrs": [ - "docs/adr/0009-agents-md-lean-budget-and-size-tiers.md" + "docs/adr/0009-agents-md-lean-budget-and-size-tiers.md", + "docs/adr/0010-naming-detect-and-conform-over-house-style.md" ], "agents_md": [ "AGENTS.md" @@ -776,7 +779,7 @@ "anchors_in_file": [ { "deadline": "2026-08-01", - "line": 193, + "line": 200, "text": "replace the polling loop with webhooks # preferred", "type": "AIDEV-TODO" } diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index ca43066..5e1fbf6 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -12,7 +12,7 @@ "url": "https://github.com/Filip-Podstavec/claude-leverage.git" }, "description": "Personal Claude Code + Codex dev stack: security hooks, AI-first code conventions, 14 on-demand skills (incl. /repo-doctor — AI-readiness audit with code↔docs drift detection — and /refresh-context-map for the v1.8.0 smart-context-surfacing hook), ADR + session-log conventions, portable statusline. Complements other skills-based plugins, not a replacement.", - "version": "1.9.0", + "version": "1.10.0", "category": "workflow", "keywords": [ "ai-first", diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 90a5f09..6d43d21 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "claude-leverage", - "version": "1.9.0", + "version": "1.10.0", "description": "Personal Claude Code + Codex dev stack: security hooks, AI-first code conventions, /security-review, /repo-map, /stack-check, portable statusline. Designed to complement other skills-based plugins, not replace them.", "author": { "name": "Filip Podstavec", diff --git a/AGENTS.md b/AGENTS.md index 6afecf8..78eb413 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -72,6 +72,10 @@ smallest change that works. density, and idioms should look like the rest of the module — new code shouldn't be identifiable as "the AI-written part." Where existing code is inconsistent, follow this AGENTS.md and the cleanest nearby example. +- **Name to fit in.** Detect the repo's casing/separator style (camelCase / + snake_case / kebab-case; PascalCase for types) and follow it — don't impose + your language default. Pitch granularity at the function's intent — neither + `get()` nor `getting_data_from_mobile()`. - **Comments explain WHY, not WHAT.** The code already says what it does; a comment restating the line below it is noise that goes stale. Comment the non-obvious — the constraint, the gotcha, the reason for the unusual choice. diff --git a/CHANGELOG.md b/CHANGELOG.md index d1aac0c..63d90f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,28 @@ All notable changes to `claude-leverage` are recorded here. Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) + [SemVer](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [1.10.0] — 2026-06-01 + +### Added + +- **`Name to fit in` naming convention** in both `templates/AGENTS.md.example` + (the artifact installed into client repos) and the root `AGENTS.md`, with the + mechanics in [`docs/conventions.md`](docs/conventions.md) ("Naming") and the + rationale in [ADR 0010](docs/adr/0010-naming-detect-and-conform-over-house-style.md). + Closes two recurring AI naming failure modes: casing + drift (the model imposing its language default `snake_case`/`camelCase` instead + of detecting and conforming to the repo's actual style, per kind and per local + module) and wrong granularity (names that are too vague — `get()` — or too + verbose/leaking — `getting_data_from_mobile()`). Deliberately + detect-and-conform, **not** a prescribed house style — a house style would + contradict the stack's "fit in" north star and be wrong in most client repos. ### Changed - **Slimmed the root `AGENTS.md` from ~19 KiB to ~7.7 KiB** — the focused - follow-up the 1.9.0 lean-budget ADR ([0009]) deadlined as an `AIDEV-TODO`. + follow-up the 1.9.0 lean-budget ADR + ([0009](docs/adr/0009-agents-md-lean-budget-and-size-tiers.md)) deadlined as an + `AIDEV-TODO`. Always-on load-bearing rules stay inline (mission, reading order, `Write less, fit in`, AIDEV anchors, security guardrails, build/test, keep-lean rule); topic depth moved behind *when-to-read* links to two new docs: diff --git a/docs/adr/0010-naming-detect-and-conform-over-house-style.md b/docs/adr/0010-naming-detect-and-conform-over-house-style.md new file mode 100644 index 0000000..1618bd6 --- /dev/null +++ b/docs/adr/0010-naming-detect-and-conform-over-house-style.md @@ -0,0 +1,103 @@ +--- +status: accepted +date: 2026-06-01 +deciders: Filip Podstavec +consulted: Claude Opus 4.8 (brainstorming session) +informed: stack users +--- + +# 0010. Naming convention: detect-and-conform, not a prescribed house style + +## Context and Problem Statement + +The stack documents how code should be *shaped* (`Write less, fit in`) but +says almost nothing about how identifiers should be *named*, beyond a single +clause — "Naming … should look like the rest of the module." Naming is one of +the highest-signal factors in whether the *next* agent can safely modify a +codebase, and AI agents have a specific, repeatable failure mode here: + +1. **Casing drift.** A model carries a strong language-default prior + (Python → `snake_case`, JS → `camelCase`). Dropped into a client repo that + deviates from that default, it silently imposes its own style, so new code + reads as "the AI-written part" and the repo's casing fragments. +2. **Wrong granularity.** Generated names land at the wrong altitude — either + too vague (`get()`, `data()`, `handle()`) or implementation-leaking and + verbose (`getting_data_from_mobile()`). Both make the call site harder to + read than a name pitched at the function's actual intent. + +The open question is **what kind** of naming guidance the stack should carry: +its own opinionated rules, or a discipline for conforming to whatever the +target repo already does. + +## Decision Drivers + +- The stack's north star is **"fit in"** — new code should be + indistinguishable from the surrounding module. A house style that overrides + the repo's existing convention directly contradicts that. +- Client repos are heterogeneous: the same agent works in `camelCase`, + `snake_case`, and `kebab-case` repos in the same week. A single prescribed + style would be wrong in most of them. +- Even within one repo, casing legitimately differs **by kind** (types + `PascalCase`, functions `camelCase`/`snake_case`, constants `UPPER_SNAKE`), + so a flat global rule cannot be right. +- Must stay lean per [ADR 0009](0009-agents-md-lean-budget-and-size-tiers.md): + inline only the always-true principle; push depth to `docs/`. + +## Considered Options + +1. **Prescribed house style.** The stack ships a naming-rules table every repo + must follow. Rejected: directly violates "fit in", and is wrong in any repo + whose existing convention differs — which is most of them. +2. **Stay implicit.** Rely on the existing "Naming should look like the rest of + the module" clause. Rejected: it states the goal but not the *discipline* + (detect first, don't impose your default) and ignores the granularity axis + entirely, so both failure modes above survive. +3. **Detect-and-conform discipline + a universal quality principle. Selected.** + Casing/separator style is treated as repo-specific — the agent must *detect* + the existing convention (per kind, per local module) and conform, never + impose its language default. Granularity/clarity is treated as a universal + principle — name to the function's intent, neither vague nor rambling. + +## Decision Outcome + +**Chosen: Option 3.** Two layers, with deliberately different epistemics: + +- **Casing / separator → descriptive.** There is no stack-wide "correct" + style; the correct style is whatever the surrounding code already uses. The + agent detects it (scan sibling files / nearby identifiers; in a mixed repo, + match the *local* module over the global majority) and conforms per kind. +- **Granularity / clarity → universal.** Independent of the repo: a name states + intent at the right altitude — neither `get()` nor + `getting_data_from_mobile()`. This is the one prescriptive bit, and it is + about *quality*, not *style*. + +Anchored as a tight `Name to fit in` bullet inline in the `Write less, fit in` +section of both the root `AGENTS.md` and the shipped +`templates/AGENTS.md.example`, with the detection mechanics and worked examples +in [`docs/conventions.md`](../conventions.md) per the ADR 0009 lean budget. + +### Consequences + +**Positive:** +- Closes both AI naming failure modes (casing drift, wrong granularity) with a + rule that reinforces "fit in" instead of fighting it. +- Correct across heterogeneous client repos by construction — there is no + global style to be wrong about. + +**Negative / costs:** +- "Detect the convention" is softer than a lookup table; in a genuinely + inconsistent repo the agent must exercise judgment about which local example + to follow. Accepted — that judgment is the point, and a wrong-but-uniform + house style would be worse. +- One more always-on bullet in `AGENTS.md` (~0.3 KiB), kept within the 8 KiB + budget by housing the depth in `docs/conventions.md`. + +## References + +- [ADR 0009](0009-agents-md-lean-budget-and-size-tiers.md) — the lean budget + that dictates inline-principle / docs-depth placement. +- [ADR 0002](0002-agents-md-canonical-claude-md-import.md) — why AGENTS.md is + the canonical surface the principle lands in. +- `AGENTS.md` ("Write less, fit in") and `docs/conventions.md` ("Naming") — the + convention as carried in this repo. +- `templates/AGENTS.md.example` — the convention as shipped to client repos. diff --git a/docs/adr/README.md b/docs/adr/README.md index dd9ebdc..1a5019d 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -34,6 +34,7 @@ the original choice. - [0007 — Sync drift detection in `/repo-doctor` (Dimensions 16–20)](0007-sync-drift-detection-in-repo-doctor.md) - [0008 — Smart context surfacing via PreToolUse hook (cuts per-session token tax)](0008-smart-context-surfacing-via-pretooluse-hook.md) - [0009 — AGENTS.md lean budget (8 KiB target / 32 KiB hard cap) and stack-check vs repo-doctor severity split](0009-agents-md-lean-budget-and-size-tiers.md) +- [0010 — Naming: detect-and-conform over a prescribed house style](0010-naming-detect-and-conform-over-house-style.md) (Keep this index in sync with the files in this directory; `/adr-new` will append to it automatically.) diff --git a/docs/conventions.md b/docs/conventions.md index 0523f1f..e081d6c 100644 --- a/docs/conventions.md +++ b/docs/conventions.md @@ -10,6 +10,45 @@ These conventions apply to code you ship in this repo AND are what the stack documents for other repos via [`templates/AGENTS.md.example`](../templates/AGENTS.md.example). +## Naming + +The inline rule is `Name to fit in` (`AGENTS.md` → "Write less, fit in"). The +discipline behind it, and why it is detect-and-conform rather than a house style, +is in [ADR 0010](adr/0010-naming-detect-and-conform-over-house-style.md). The +mechanics: + +**Casing / separator — detect, then conform.** There is no stack-wide "correct" +style; the correct style is whatever the surrounding code already uses. A model's +language default (Python → `snake_case`, JS → `camelCase`) is a *prior*, not a +license to impose. Before naming anything new: + +- **Scan first.** Look at sibling files and nearby identifiers of the *same kind* + to read off the convention. `grep` a few existing definitions if unsure. +- **Match per kind.** Casing legitimately differs by kind even within one repo — + `PascalCase` types, `camelCase`/`snake_case` functions and locals, + `UPPER_SNAKE` constants, `kebab-case` files/CLI flags. Conform each kind to its + own neighbours, not to a single global rule. +- **Local over global.** In a repo with inconsistent history, match the *local + module* you're editing over the repo-wide majority — fitting the immediate + context beats a "correct" name that clashes with everything around it. +- **Idioms only if the repo uses them.** Predicate prefixes (`is_`/`has_`/ + `should_`), hungarian-ish suffixes, `_async` markers, etc. — adopt them only + when the surrounding code already does. Don't import a convention the repo + never chose. + +**Granularity / clarity — universal.** Independent of the repo, a name states +intent at the right altitude: + +- **Too vague** (`get()`, `data()`, `handle()`, `process()`, `tmp`) forces the + reader to open the body to learn what it does. +- **Too verbose / leaking** (`getting_data_from_mobile()`, + `user_list_array_final2`) bakes implementation detail or history into the name, + so it reads as noise and goes stale when the internals change. +- **Right** names the *what/why* at the call site's level of abstraction: + `fetch_mobile_profile()`, `pending_invoices`, `is_expired`. If a good name is + hard to find, the unit is often doing too much — that's a design signal, not a + naming problem. + ## Repo layout ``` diff --git a/templates/AGENTS.md.example b/templates/AGENTS.md.example index 996b592..3c7cf47 100644 --- a/templates/AGENTS.md.example +++ b/templates/AGENTS.md.example @@ -165,6 +165,13 @@ Prefer the smallest change that works. shouldn't be identifiable as "the AI-written part." Where the existing code is inconsistent, follow this AGENTS.md and the cleanest nearby example rather than copying a one-off. +- **Name to fit in.** Detect the convention this repo already uses and conform — + don't impose your language default. Casing/separator style is per-repo *and* + per-kind (e.g. `camelCase`/`snake_case`/`kebab-case` for names, `PascalCase` + for types, `UPPER_SNAKE` for constants); match each kind to its neighbours, and + in a mixed repo follow the local module over the global majority. Pitch + granularity at the symbol's intent — descriptive without rambling, neither + `get()` nor `getting_data_from_mobile()`. - **Comments explain WHY, not WHAT.** The code already says what it does; a comment that restates the line below it is noise that goes stale. Comment the non-obvious — the constraint, the gotcha, the reason for the unusual choice.