Skip to content

Commit 79867c5

Browse files
feat(v1.10.0): "Name to fit in" naming convention (detect-and-conform) (#6)
Adds an explicit naming convention closing two recurring AI failure modes: - casing drift (model imposes its language-default snake_case/camelCase instead of detecting and conforming to the repo's actual style, per kind and per local module) - wrong granularity (names too vague like get() or too verbose/leaking like 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. Rationale in new ADR 0010. Touchpoints: - AGENTS.md "Write less, fit in" — tight "Name to fit in" bullet (kept under the 8 KiB lean budget per ADR 0009) - templates/AGENTS.md.example — same bullet, self-contained (shipped artifact) - docs/conventions.md — new "## Naming" section with detection mechanics + granularity guidance - docs/adr/0010-*.md + index entry - CHANGELOG [1.10.0]; version bump 1.9.0 -> 1.10.0 (plugin.json + marketplace.json). Context-map rebuilt. 132 tests pass.
1 parent 1f0ec4b commit 79867c5

9 files changed

Lines changed: 183 additions & 10 deletions

.claude-leverage-context-map.json

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,30 @@
33
"anchor_count": 34,
44
"builder_version": "1.8.0",
55
"file_count": 20,
6-
"generated_at": "2026-06-01T07:07:10+00:00",
6+
"generated_at": "2026-06-01T11:17:26+00:00",
77
"generator": "scripts/build-context-map.py",
88
"repo_root": ".",
99
"schema_version": 1
1010
},
1111
"files": {
1212
"docs/conventions.md": {
13-
"adrs": [],
13+
"adrs": [
14+
"docs/adr/0010-naming-detect-and-conform-over-house-style.md"
15+
],
1416
"agents_md": [
1517
"AGENTS.md"
1618
],
1719
"anchors_in_dir": [],
1820
"anchors_in_file": [
1921
{
2022
"deadline": "2026-08-01",
21-
"line": 47,
23+
"line": 86,
2224
"text": "replace the polling loop with webhooks",
2325
"type": "AIDEV-TODO"
2426
},
2527
{
2628
"deadline": "2026-07-15",
27-
"line": 48,
29+
"line": 87,
2830
"text": "is the encoding always UTF-8 here?",
2931
"type": "AIDEV-QUESTION"
3032
}
@@ -767,7 +769,8 @@
767769
},
768770
"templates/AGENTS.md.example": {
769771
"adrs": [
770-
"docs/adr/0009-agents-md-lean-budget-and-size-tiers.md"
772+
"docs/adr/0009-agents-md-lean-budget-and-size-tiers.md",
773+
"docs/adr/0010-naming-detect-and-conform-over-house-style.md"
771774
],
772775
"agents_md": [
773776
"AGENTS.md"
@@ -776,7 +779,7 @@
776779
"anchors_in_file": [
777780
{
778781
"deadline": "2026-08-01",
779-
"line": 193,
782+
"line": 200,
780783
"text": "replace the polling loop with webhooks # preferred",
781784
"type": "AIDEV-TODO"
782785
}

.claude-plugin/marketplace.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"url": "https://github.com/Filip-Podstavec/claude-leverage.git"
1313
},
1414
"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.",
15-
"version": "1.9.0",
15+
"version": "1.10.0",
1616
"category": "workflow",
1717
"keywords": [
1818
"ai-first",

.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "claude-leverage",
3-
"version": "1.9.0",
3+
"version": "1.10.0",
44
"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.",
55
"author": {
66
"name": "Filip Podstavec",

AGENTS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ smallest change that works.
7272
density, and idioms should look like the rest of the module — new code
7373
shouldn't be identifiable as "the AI-written part." Where existing code is
7474
inconsistent, follow this AGENTS.md and the cleanest nearby example.
75+
- **Name to fit in.** Detect the repo's casing/separator style (camelCase /
76+
snake_case / kebab-case; PascalCase for types) and follow it — don't impose
77+
your language default. Pitch granularity at the function's intent — neither
78+
`get()` nor `getting_data_from_mobile()`.
7579
- **Comments explain WHY, not WHAT.** The code already says what it does; a
7680
comment restating the line below it is noise that goes stale. Comment the
7781
non-obvious — the constraint, the gotcha, the reason for the unusual choice.

CHANGELOG.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,28 @@ All notable changes to `claude-leverage` are recorded here.
55
Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) +
66
[SemVer](https://semver.org/spec/v2.0.0.html).
77

8-
## [Unreleased]
8+
## [1.10.0] — 2026-06-01
9+
10+
### Added
11+
12+
- **`Name to fit in` naming convention** in both `templates/AGENTS.md.example`
13+
(the artifact installed into client repos) and the root `AGENTS.md`, with the
14+
mechanics in [`docs/conventions.md`](docs/conventions.md) ("Naming") and the
15+
rationale in [ADR 0010](docs/adr/0010-naming-detect-and-conform-over-house-style.md).
16+
Closes two recurring AI naming failure modes: casing
17+
drift (the model imposing its language default `snake_case`/`camelCase` instead
18+
of detecting and conforming to the repo's actual style, per kind and per local
19+
module) and wrong granularity (names that are too vague — `get()` — or too
20+
verbose/leaking — `getting_data_from_mobile()`). Deliberately
21+
detect-and-conform, **not** a prescribed house style — a house style would
22+
contradict the stack's "fit in" north star and be wrong in most client repos.
923

1024
### Changed
1125

1226
- **Slimmed the root `AGENTS.md` from ~19 KiB to ~7.7 KiB** — the focused
13-
follow-up the 1.9.0 lean-budget ADR ([0009]) deadlined as an `AIDEV-TODO`.
27+
follow-up the 1.9.0 lean-budget ADR
28+
([0009](docs/adr/0009-agents-md-lean-budget-and-size-tiers.md)) deadlined as an
29+
`AIDEV-TODO`.
1430
Always-on load-bearing rules stay inline (mission, reading order, `Write
1531
less, fit in`, AIDEV anchors, security guardrails, build/test, keep-lean
1632
rule); topic depth moved behind *when-to-read* links to two new docs:
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
---
2+
status: accepted
3+
date: 2026-06-01
4+
deciders: Filip Podstavec
5+
consulted: Claude Opus 4.8 (brainstorming session)
6+
informed: stack users
7+
---
8+
9+
# 0010. Naming convention: detect-and-conform, not a prescribed house style
10+
11+
## Context and Problem Statement
12+
13+
The stack documents how code should be *shaped* (`Write less, fit in`) but
14+
says almost nothing about how identifiers should be *named*, beyond a single
15+
clause — "Naming … should look like the rest of the module." Naming is one of
16+
the highest-signal factors in whether the *next* agent can safely modify a
17+
codebase, and AI agents have a specific, repeatable failure mode here:
18+
19+
1. **Casing drift.** A model carries a strong language-default prior
20+
(Python → `snake_case`, JS → `camelCase`). Dropped into a client repo that
21+
deviates from that default, it silently imposes its own style, so new code
22+
reads as "the AI-written part" and the repo's casing fragments.
23+
2. **Wrong granularity.** Generated names land at the wrong altitude — either
24+
too vague (`get()`, `data()`, `handle()`) or implementation-leaking and
25+
verbose (`getting_data_from_mobile()`). Both make the call site harder to
26+
read than a name pitched at the function's actual intent.
27+
28+
The open question is **what kind** of naming guidance the stack should carry:
29+
its own opinionated rules, or a discipline for conforming to whatever the
30+
target repo already does.
31+
32+
## Decision Drivers
33+
34+
- The stack's north star is **"fit in"** — new code should be
35+
indistinguishable from the surrounding module. A house style that overrides
36+
the repo's existing convention directly contradicts that.
37+
- Client repos are heterogeneous: the same agent works in `camelCase`,
38+
`snake_case`, and `kebab-case` repos in the same week. A single prescribed
39+
style would be wrong in most of them.
40+
- Even within one repo, casing legitimately differs **by kind** (types
41+
`PascalCase`, functions `camelCase`/`snake_case`, constants `UPPER_SNAKE`),
42+
so a flat global rule cannot be right.
43+
- Must stay lean per [ADR 0009](0009-agents-md-lean-budget-and-size-tiers.md):
44+
inline only the always-true principle; push depth to `docs/`.
45+
46+
## Considered Options
47+
48+
1. **Prescribed house style.** The stack ships a naming-rules table every repo
49+
must follow. Rejected: directly violates "fit in", and is wrong in any repo
50+
whose existing convention differs — which is most of them.
51+
2. **Stay implicit.** Rely on the existing "Naming should look like the rest of
52+
the module" clause. Rejected: it states the goal but not the *discipline*
53+
(detect first, don't impose your default) and ignores the granularity axis
54+
entirely, so both failure modes above survive.
55+
3. **Detect-and-conform discipline + a universal quality principle. Selected.**
56+
Casing/separator style is treated as repo-specific — the agent must *detect*
57+
the existing convention (per kind, per local module) and conform, never
58+
impose its language default. Granularity/clarity is treated as a universal
59+
principle — name to the function's intent, neither vague nor rambling.
60+
61+
## Decision Outcome
62+
63+
**Chosen: Option 3.** Two layers, with deliberately different epistemics:
64+
65+
- **Casing / separator → descriptive.** There is no stack-wide "correct"
66+
style; the correct style is whatever the surrounding code already uses. The
67+
agent detects it (scan sibling files / nearby identifiers; in a mixed repo,
68+
match the *local* module over the global majority) and conforms per kind.
69+
- **Granularity / clarity → universal.** Independent of the repo: a name states
70+
intent at the right altitude — neither `get()` nor
71+
`getting_data_from_mobile()`. This is the one prescriptive bit, and it is
72+
about *quality*, not *style*.
73+
74+
Anchored as a tight `Name to fit in` bullet inline in the `Write less, fit in`
75+
section of both the root `AGENTS.md` and the shipped
76+
`templates/AGENTS.md.example`, with the detection mechanics and worked examples
77+
in [`docs/conventions.md`](../conventions.md) per the ADR 0009 lean budget.
78+
79+
### Consequences
80+
81+
**Positive:**
82+
- Closes both AI naming failure modes (casing drift, wrong granularity) with a
83+
rule that reinforces "fit in" instead of fighting it.
84+
- Correct across heterogeneous client repos by construction — there is no
85+
global style to be wrong about.
86+
87+
**Negative / costs:**
88+
- "Detect the convention" is softer than a lookup table; in a genuinely
89+
inconsistent repo the agent must exercise judgment about which local example
90+
to follow. Accepted — that judgment is the point, and a wrong-but-uniform
91+
house style would be worse.
92+
- One more always-on bullet in `AGENTS.md` (~0.3 KiB), kept within the 8 KiB
93+
budget by housing the depth in `docs/conventions.md`.
94+
95+
## References
96+
97+
- [ADR 0009](0009-agents-md-lean-budget-and-size-tiers.md) — the lean budget
98+
that dictates inline-principle / docs-depth placement.
99+
- [ADR 0002](0002-agents-md-canonical-claude-md-import.md) — why AGENTS.md is
100+
the canonical surface the principle lands in.
101+
- `AGENTS.md` ("Write less, fit in") and `docs/conventions.md` ("Naming") — the
102+
convention as carried in this repo.
103+
- `templates/AGENTS.md.example` — the convention as shipped to client repos.

docs/adr/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ the original choice.
3434
- [0007 — Sync drift detection in `/repo-doctor` (Dimensions 16–20)](0007-sync-drift-detection-in-repo-doctor.md)
3535
- [0008 — Smart context surfacing via PreToolUse hook (cuts per-session token tax)](0008-smart-context-surfacing-via-pretooluse-hook.md)
3636
- [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)
37+
- [0010 — Naming: detect-and-conform over a prescribed house style](0010-naming-detect-and-conform-over-house-style.md)
3738

3839
(Keep this index in sync with the files in this directory; `/adr-new` will
3940
append to it automatically.)

docs/conventions.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,45 @@ These conventions apply to code you ship in this repo AND are what the stack
1010
documents for other repos via
1111
[`templates/AGENTS.md.example`](../templates/AGENTS.md.example).
1212

13+
## Naming
14+
15+
The inline rule is `Name to fit in` (`AGENTS.md` → "Write less, fit in"). The
16+
discipline behind it, and why it is detect-and-conform rather than a house style,
17+
is in [ADR 0010](adr/0010-naming-detect-and-conform-over-house-style.md). The
18+
mechanics:
19+
20+
**Casing / separator — detect, then conform.** There is no stack-wide "correct"
21+
style; the correct style is whatever the surrounding code already uses. A model's
22+
language default (Python → `snake_case`, JS → `camelCase`) is a *prior*, not a
23+
license to impose. Before naming anything new:
24+
25+
- **Scan first.** Look at sibling files and nearby identifiers of the *same kind*
26+
to read off the convention. `grep` a few existing definitions if unsure.
27+
- **Match per kind.** Casing legitimately differs by kind even within one repo —
28+
`PascalCase` types, `camelCase`/`snake_case` functions and locals,
29+
`UPPER_SNAKE` constants, `kebab-case` files/CLI flags. Conform each kind to its
30+
own neighbours, not to a single global rule.
31+
- **Local over global.** In a repo with inconsistent history, match the *local
32+
module* you're editing over the repo-wide majority — fitting the immediate
33+
context beats a "correct" name that clashes with everything around it.
34+
- **Idioms only if the repo uses them.** Predicate prefixes (`is_`/`has_`/
35+
`should_`), hungarian-ish suffixes, `_async` markers, etc. — adopt them only
36+
when the surrounding code already does. Don't import a convention the repo
37+
never chose.
38+
39+
**Granularity / clarity — universal.** Independent of the repo, a name states
40+
intent at the right altitude:
41+
42+
- **Too vague** (`get()`, `data()`, `handle()`, `process()`, `tmp`) forces the
43+
reader to open the body to learn what it does.
44+
- **Too verbose / leaking** (`getting_data_from_mobile()`,
45+
`user_list_array_final2`) bakes implementation detail or history into the name,
46+
so it reads as noise and goes stale when the internals change.
47+
- **Right** names the *what/why* at the call site's level of abstraction:
48+
`fetch_mobile_profile()`, `pending_invoices`, `is_expired`. If a good name is
49+
hard to find, the unit is often doing too much — that's a design signal, not a
50+
naming problem.
51+
1352
## Repo layout
1453

1554
```

templates/AGENTS.md.example

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,13 @@ Prefer the smallest change that works.
165165
shouldn't be identifiable as "the AI-written part." Where the existing code is
166166
inconsistent, follow this AGENTS.md and the cleanest nearby example rather than
167167
copying a one-off.
168+
- **Name to fit in.** Detect the convention this repo already uses and conform —
169+
don't impose your language default. Casing/separator style is per-repo *and*
170+
per-kind (e.g. `camelCase`/`snake_case`/`kebab-case` for names, `PascalCase`
171+
for types, `UPPER_SNAKE` for constants); match each kind to its neighbours, and
172+
in a mixed repo follow the local module over the global majority. Pitch
173+
granularity at the symbol's intent — descriptive without rambling, neither
174+
`get()` nor `getting_data_from_mobile()`.
168175
- **Comments explain WHY, not WHAT.** The code already says what it does; a
169176
comment that restates the line below it is noise that goes stale. Comment the
170177
non-obvious — the constraint, the gotcha, the reason for the unusual choice.

0 commit comments

Comments
 (0)