Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions .claude-leverage-context-map.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,30 @@
"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"
],
"anchors_in_dir": [],
"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"
}
Expand Down Expand Up @@ -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"
Expand All @@ -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"
}
Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
4 changes: 4 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
20 changes: 18 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
103 changes: 103 additions & 0 deletions docs/adr/0010-naming-detect-and-conform-over-house-style.md
Original file line number Diff line number Diff line change
@@ -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.
1 change: 1 addition & 0 deletions docs/adr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.)
39 changes: 39 additions & 0 deletions docs/conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

```
Expand Down
7 changes: 7 additions & 0 deletions templates/AGENTS.md.example
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading