ubiquitous-language
Skill169 starsChanged 56 days agoMITView on GitHub
Maintain a project thesaurus (domain glossary) following DDD ubiquitous language principles. Use PROACTIVELY when naming anything: variables, functions, classes, modules, database fields, API endpoints, events, files, or directories. Also use when the user asks to "create thesaurus", "update glossary", "add term", "rename to match domain", "check naming consistency", "what should I call this", "domain language", "ubiquitous language", or "naming conventions". Ensures all names in the codebase are consistent, descriptive, and aligned with the shared domain vocabulary. Also mines git history to resolve naming ambiguities — when a name was born, which name replaced which, which spelling is dying. Not for general code style or linting — only for domain term consistency.
63 other projects use a version of this.
Adopted by
Most recently taken up by
- aegntic/compound-engineeringtheir own version, first seen Nov 8, 2026
- chrislacey89/skillstheir own version, first seen Nov 4, 2026
- Boom-Vitt/skills-thaitheir own version, first seen Nov 1, 2026
- kishan-ict/skillstheir own version, first seen Nov 1, 2026
- Future-CX/AI-Architecture-Toolkittheir own version, first seen Nov 1, 2026
- hmjBill/skillstheir own version, first seen Oct 29, 2026
Used with
Projects with it also use request-refactor-plan, edit-article and 10 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
simo97Skillrequest-refactor-plan
Use this skill when user wants to create a refactor plan.
Also in 40 projects that use this
simo97Skilledit-article
The user will invoke this skill to help them edit an article.
Also in 34 projects that use this
AnasX7Skillscaffold-exercises
Create exercise directory structures with sections, problems, solutions, and explainers that pass linting. Use when user wants to scaffold exercises, create exercise stubs, or set up a new course section.
Also in 29 projects that use this
HK-hubSkillprd-to-plan
Turn a PRD into a multi-phase implementation plan using tracer-bullet vertical slices, saved as a local Markdown file in ./plans/. Use when user wants to break down a PRD, create an implementation plan, plan phases from a PRD, or mentions "tracer bullets".
Also in 9 projects that use this
boyingliu01Skillbatch-grill-me
A relentless interview that asks every frontier question at once, round by round. Thin alias of `grilling` (#540) — upstream mattpocock/skills absorbed this protocol into grilling; XP-Gate keeps this name as the sprint-flow Phase 2 entry point so orchestration docs stay stable.
Also in 5 projects that use this
AnasX7Skillsetup-pre-commit
Set up Husky pre-commit hooks with lint-staged (Prettier), type checking, and tests in the current repo. Use when user wants to add pre-commit hooks, set up Husky, configure lint-staged, or add commit-time formatting/typechecking/testing.
Also in 37 projects that use this
- +4 more from simo97
Other versions63 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 63
- karlomikus/bar-assistant★ 1.1ksame name
- amazingloft999-droid/mattpocock-skills★ 422same name
- InditexTech/weavejs★ 266same name
- loulanyue/skills★ 231same name
- ayoubben18/ab-method★ 192same name
- aurorasoft2/Matt_Pocock_Skills★ 133same name
- VisualxIntelligence/mattpocok-skills★ 55same name
- jan-bogaerts/md2★ 42same name
- metrogg/AgentHub★ 19same name
- jscraik/Agent-Skills★ 9same name
53 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository23 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- agentic-readinessSkill
- bug-fix-protocolSkill
- clipboardSkill
- code-that-fits-in-your-headSkill
- fetch-url-as-markdownSkill
- fpf-problem-solvingSkill
- hooks-managementSkill
- installing-cli-toolsSkill
- investigating-repository-historySkill
- maintaining-macos-healthSkill
- maintaining-windows-healthSkill
- mcp-managementSkill
- plan-modeSkill
- plugins-managementSkill
- prompt-engineeringSkill
- refactoring-csharpSkill
- repo-activity-summarySkill
- semantic-scholar-deepSkill
- settings-managementSkill
- skills-managementSkill
- windows-qa-engineerSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
27 rules. 0 are common, 17 are distinctive, and 10 are very specific to this project.
0
Common
Most of the 59 edited versions we read keep these.
17
Distinctive
This author's own choices. Worth a look.
10
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 56
The codebase is primary evidence, not automatic authority: Use code to discover which terms are currently in circulation.
- Distinctive: line 62
If code contradicts the approved thesaurus — the thesaurus wins for new code
- Very specific: line 63
If the user says "fix legacy naming" — the user's directive overrides the codebase.
- Distinctive: line 72
If the user specified a path — use it
- Very specific: line 73
If THESAURUS.md already exists somewhere in the repo — use that location
- Very specific: line 105
Only the format is versioned in the file.
- Distinctive: line 127
Registry invariant: every name known to the project appears in exactly one registry line — an Index line (as Term, Identifier, or avoid), a …
- Very specific: line 185
One line per concept: All names for that concept live on that line — this is what makes reverse lookup (rg Purchase → "use Order") a single …
- Distinctive: line 228
Non-English domains: If the business domain operates in a non-English language, the
- Very specific: line 239
Check rg -n '^thesaurus-format:' — no key or 1.x means the old layout: the protocol below still works by plain text search, but offer …
- Distinctive: line 241
Read the Index: if it has ≤ ~60 lines — it is the entire vocabulary at one line per concept, cheaper than any search.
- Very specific: line 272
Check the bounded context: if Index lines carry ctx: — the same word may be canonical in one context and banned in another.
- Very specific: line 275
ALWAYS: run this before naming: classes, interfaces, types, enums, aggregates, entities, value objects, functions, methods, commands, …
- Distinctive: line 293
Only after all four fail, mint a new term:
- Distinctive: line 299
Then: use the term in code
- Distinctive: line 303
When existing code uses a term that contradicts the thesaurus:
- Very specific: line 310
When a name lands in ## Unresolved — two spellings for one concept, one spelling for two concepts, no obvious winner — the current tree …
- Distinctive: line 325
If the user accepts, read references/git-history-mining.md and follow it.
- Distinctive: line 363
Use the business domain term.
- Distinctive: line 435
Queries (read-only): Start with Get, Is, Has, Can, or a domain verb.
- Distinctive: line 484
Keep the domain noun clean and let framework coupling live in inheritance, annotations, or metadata — not in the class name.
- Distinctive: line 515
When different artifacts use different terms for the same concept across the knowledge chain, information is lost at each translation:
- Very specific: line 546
Use the EXACT Identifier — don't abbreviate (ord), don't expand (orderObject), don't synonym (purchase)
- Distinctive: line 554
When changing terms, use the least strong relation that tells the truth (from FPF F.13):
- Very specific: line 569
Alias parsimony: keep at most 1 legacy alias per term — the one readers will most likely encounter in old code.
- Distinctive: line 589
If the concept is new — did I add the Index line and the entry before using it?
- Distinctive: line 591
If any answer raises a concern — stop and fix before proceeding.
“Common” is measured: kept by at least 6 in 10 of the 59 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Ubiquitous Language: Project Thesaurus Manager
You enforce naming consistency across the codebase by maintaining a living thesaurus of domain terms and consulting it every time something needs a name.
Four modes:
- Naming consultation (frequent) — everything in this file
- Thesaurus generation (rare) — read references/generating-thesaurus.md
- Naming audit (periodic) — read references/naming-audit.md
- History mining (optional) — read references/git-history-mining.md
when
## Unresolveditems need evidence: which name came first, which replaced which, which is dying. Offered after generation, or on demand against an existing thesaurus.
Foundations
This skill combines two bodies of knowledge:
- Domain-Driven Design (DDD) by Eric Evans — ubiquitous language, bounded contexts, aggregate naming
- First Principles Framework (FPF) — a transdisciplinary "operating system for thought" that provides formal tools for semantic precision: bounded contexts as declared semantic frames, polysemy unpacking, lexical firewalls, cross-context bridges with loss notes, term continuity relations, and anti-explosion naming control. References like "FPF F.5" or "FPF A.1.1" point to specific sections of the FPF specification.
Core Principle
"A project should use a single, shared vocabulary. Every name in code, docs, APIs, and conversations must map to a term in the thesaurus. If a concept isn't in the thesaurus — add it before naming anything."
— Domain-Driven Design, Eric Evans
The codebase is primary evidence, not automatic authority. Use code to discover which terms are currently in circulation. Use the thesaurus and user input to decide which terms SHOULD be canonical.
- For what exists today — derive from code (classes, DB schemas, API routes, events)
- For what should become the standard — ask the user/domain expert
- If code contradicts the approved thesaurus — the thesaurus wins for new code
- If the user says "fix legacy naming" — the user's directive overrides the codebase;
map existing code names to
## Legacylines and use the user's terms as canonical
Tacit knowledge: For areas not yet implemented, the most important domain knowledge exists only in experts' heads, not in any artifact.
Thesaurus File
Locating the thesaurus:
- If the user specified a path — use it
- If
THESAURUS.mdalready exists somewhere in the repo — use that location - Default:
docs/THESAURUS.md
Single source of truth for domain vocabulary.
Versioning
The thesaurus declares its format version and the skill that maintains it in YAML frontmatter — machine-readable, outside the body, still one grep away:
---
thesaurus-format: "2.0"
skill: ubiquitous-language
---
# Project ThesaurusQuote the version — unquoted 2.10 is the YAML float 2.1.
rg -n '^thesaurus-format:' THESAURUS.md→ the version in one hit. No key = 1.0 (the pre-index prose layout shipped before skill 2.0) — unless the file already has- **Term** `Id` kind:Index lines: that is an unstamped 2.0 file from plugin 9.2.0; just add the stamp.- Format major = skill major (
metadata.versionin this file's frontmatter). Skill minor/patch releases never change the format. - Read any format ≤ your own; write only the current one. A major gap means migration first (see generating-thesaurus.md); a minor gap means new optional tokens — older readers keep working, you may add the tokens as you touch lines.
- A thesaurus with a format newer than yours: read it, don't rewrite it — tell the user to update the skill.
- Only the format is versioned in the file. The skill's own version is not recorded there —
it would go stale on every edit and
git logalready answers "who wrote this".skill:is a pointer, so an agent without the skill knows what to install.
| Format | Layout | Skill |
| 1.0 | ### Term entries with Synonyms to AVOID; ## Legacy Terms entries; ## Forbidden Lexicon table | ≤ 1.x (plugin ≤ 9.1.1) |
| 2.0 | grep-first: ## Index lines with kind:/ctx:/avoid:, use: Forbidden lines, → Legacy lines, SKOS bridges | 2.x |
Layout: grep-first
The file is designed so that one rg/grep for any name answers "what do I do with
this name?" without reading the surrounding text. Five sections, fixed order:
| Section | Shape | One line answers |
## Index | one line per concept | "Is there a term for this? Which name is canonical? What is banned?" |
## Terms | ### Term entries | "What exactly does it mean / not mean / relate to?" |
## Forbidden | one line per word | "Is this word banned from domain names?" |
## Legacy | one line per old name | "This old name is in the code — what replaced it?" |
## Unresolved | ### Term — problem entries | "Is this name an open question?" |
Registry invariant: every name known to the project appears in exactly one
registry line — an Index line (as Term, Identifier, or avoid), a Forbidden line, a Legacy
line, or an Unresolved header. Each kind of registry line has its own shape, so the
shape of the hit tells you its status and the line itself tells you the canonical
name. No -B/-A context needed.
Registry lines are bullet lines with labelled tokens, not Markdown tables: tables
need | (an alternation in rg), match by column position, and get re-padded by
formatters. Tokens (kind:, ctx:, avoid:, use:, in:, →) are position-free,
formatter-proof, and need no escaping.
# Project Thesaurus
## Index
- **Order** `Order` kind:aggregate avoid: `Purchase`, `Transaction`, `Buy`
- **Order Line Item** `OrderLineItem` kind:entity avoid: `LineItem`, `OrderItem`, `Item`
- **Order Placed** `OrderPlaced` kind:event avoid: `OrderCreated`, `NewOrder`
## Terms
### Order
- **Definition**: A customer's confirmed request to buy one or more products at agreed prices.
- **NOT**: A payment (that's `Payment`), a shipment, or a draft cart (that's `Cart`).
- **Related**: Order Line Item, Order Placed, Cart
## Forbidden
- `Manager` use: `OrderFulfillment` — hides responsibility; name the activity
## Legacy
- `UserManager` → `Customer` + `CustomerRegistration` in: `src/legacy/` — split in v3
## Unresolved
### Account — one word, two concepts (billing vs auth)
- **Found in**: `billing/Account.ts` (balance), `auth/Account.ts` (login)
- **Question**: Two bounded contexts, or one of them a naming mistake?
- **Impact**: 18 files
- **Options**: `BillingAccount` + `UserAccount`; or contexts Billing / IdentityIndex line
- **<Term>** `<Identifier>` kind:<kind> [ctx:<Context>] [avoid: `<name>`, `<name>`]| Field | Content | Rules |
| Term | Human name, as domain experts say it, in **bold** | May be multi-word or non-English. Also the ### header text of the entry |
| Identifier | PascalCase code form, in backticks | The thing you grep in code. All other casings derive from it mechanically (see Casing) |
| kind: | One of aggregate entity value event command query service role process state policy concept | Picks the naming rule below. concept when nothing fits |
| ctx: | Bounded context name | Only present once contexts are confirmed (see generating-thesaurus.md); the header then becomes ### Term (Context) |
| avoid: | Banned synonyms and abbreviations, each in backticks, comma-separated | Last on the line because it is the only variable-length field. Omit when empty |
- One line per concept. All names for that concept live on that line — this is what
makes reverse lookup (
rg Purchase→ "useOrder") a single hit. - Backticks around every identifier-like name.
rg '`Order`'is an exact match;rg Orderwould also hitOrderLineItemandReorder.rg -F '**Order**'is the exact Term. - Sorted alphabetically by Term. Entries under
## Termsfollow the same order. - avoid lists live only here. Entries do not repeat them — one place, no drift.
Forbidden and Legacy lines
- `<Word>` use: `<Identifier>`[, `<Identifier>`] — <why>
- `<OldName>` → `<Identifier>`[ + `<Identifier>`] in: <files/modules> — <note>
- `<OldName>` → — (see `<X>`, `<Y>`) in: <files> — retireduse: always points at an Index Identifier. → is the legacy marker: A + B means the
old name was split; → — means retired with no single successor.
Entry
### [Term]
- **Definition**: What this concept means in the business domain — one sentence
- **NOT**: What this term does NOT mean; name the neighbouring term it is confused with
- **Related**: Other Index Terms this connects to, written exactly as in the Term fieldOptional lines when they carry real information: **Broader**, **Narrower**,
**Part of**, **Has parts**, **Example**. Write them on one side only — rg gives
the inverse for free, mirrored copies only drift. Minimal viable entry is one line:
- **Definition**: … — the Index line already holds the rest.
Anchor grammar (so lookups are one regex): the header is exactly ### <Term> or
### <Term> (<Context>) — nothing else. Tags, status, and context prefixes belong in
the Index line, not in the header. Find an entry with rg -n '^### Order( \(|$)' —
\b alone is not enough, it would also match ### Order Line Item.
The thesaurus captures concepts, not behavior. It's strong at nouns (entity names, roles, process names) but won't replace behavioral specs for business rules. Don't try to turn the thesaurus into a specification — keep entries short. If a concept has a critical invariant, note it briefly in the definition, not as a separate section.
Non-English domains: If the business domain operates in a non-English language, the
Term uses the original language — the thesaurus should reflect how domain experts
actually speak. The Identifier carries the code form:
- **Счёт-фактура** `Invoice` kind:entity. This is exactly why both fields exist.
Lookup Protocol
Look up before inventing. This is the single most important step. Most naming tasks don't need a new term — the right name is already there.
- Locate the thesaurus (see above). If absent, tell the user and offer generation.
Check
rg -n '^thesaurus-format:'— no key or1.xmeans the old layout: the protocol below still works by plain text search, but offer migration once, up front. - Read the Index if it has ≤ ~60 lines — it is the entire vocabulary at one line per concept, cheaper than any search. For larger files, search instead.
Search every candidate name you are considering, plus whatever the surrounding code already calls the thing. Use
rg(the Grep tool) orgrep -E— same patterns:rg -n -i 'invoice' docs/THESAURUS.md # any role, any section rg -n '`OrderLineItem`' docs/THESAURUS.md # exact identifier as seen in code rg -n -F '**Order**' docs/THESAURUS.md # exact Term (not "Order Line Item") rg -n 'avoid:.*`Purchase`' docs/THESAURUS.md # is this word a banned synonym? rg -n 'kind:event' docs/THESAURUS.md # all terms of one kind rg -n 'ctx:Billing' docs/THESAURUS.md # everything one context owns rg -n '`Basket` →' docs/THESAURUS.md # legacy name and its replacement rg -n -A4 '^### Invoice( \(|$)' docs/THESAURUS.md # the entry itselfThe only trap:
*and|are regex metacharacters — use-Ffor**Term**, and never search for table pipes (there are none).Act on the shape of the line you hit:
Hit line looks like Meaning Do - **X** `X` kind:…— your word is the Term or IdentifierConcept exists Use the Identifier exactly. Stop - **X** … avoid: … `your word`You were about to use a banned synonym Use that line's Identifier instead - `word` use: …Word is banned from domain names Pick the Identifier after use:- `word` → …Old name still in code Use the replacement after →for new code; don't spread the legacy name### word — …under## UnresolvedOpen naming question Don't decide silently — surface it, ask the user, or offer history mining (see below) ###header / entry text onlyRelated concept Read the entry; it may inform composition No hit New concept Go to "If the concept is new" - Check the bounded context if Index lines carry
ctx:— the same word may be canonical in one context and banned in another.
ALWAYS run this before naming: classes, interfaces, types, enums, aggregates, entities, value objects, functions, methods, commands, queries, domain events, variables, constants, fields, parameters, DB tables/columns/collections, API endpoints and response fields, files, directories, modules, packages, feature flags, config keys, environment variables, and commit messages or PR titles that reference domain concepts.
If the Concept Is New
Before minting a new term, try four levers (from FPF F.14 "Name less, express more"):
- Reuse — does an existing term already cover this? Maybe the concept is a variant, not a new thing
- Compose — can you combine existing terms?
OrderLineItemreusesOrder+LineItem - Qualify — is this the same concept in a different state/window? Don't create
NightOperator— useOperatorwith a time qualifier - Ask — if still unclear: "I need to name [concept]. The thesaurus doesn't have a term for this. What does the domain call it?"
If the user doesn't have an answer either — that's a white spot, not a dead end.
Building a ubiquitous language is co-creation, not extraction. Add it to
## Unresolvedwith a[WHITE-SPOT]tag in the header. Don't force a name for an undefined concept.
Only after all four fail, mint a new term:
- Name what the invariants make true (FPF F.5) — don't name aspirationally. If the code doesn't enforce "Premium", don't call it
PremiumCustomer - Use minimal generality — choose the narrowest name whose rules you actually enforce. Don't upgrade
TasktoActivityto sound universal - Keep it to 1-3 words — no rhetorical adjectives ("robust", "optimal", "advanced")
- Add it to the thesaurus: an Index line (Term, Identifier,
kind:,avoid:— omitavoid:when empty) and a### Termentry with at least a Definition. Keep both sorted - Then use the term in code
If You Find an Inconsistency
When existing code uses a term that contradicts the thesaurus:
- Flag it: "Found
fetchPurchases()but the Index line saysOrder, withPurchaseunderavoid:" - Suggest a rename if scope is small
- For large-scale renames, note as tech debt and ask user how to proceed
If the Ambiguity Won't Resolve Itself
When a name lands in ## Unresolved — two spellings for one concept, one spelling for two
concepts, no obvious winner — the current tree can't settle it, but the repository's history
often can: which identifier was born first, which commit removed one while adding the other,
which one is dying.
Offer it, don't run it silently. Whenever you present ## Unresolved items — after
generation, after an audit, or when a naming question hits one — offer once:
"I can mine the git history for these — when each name was born, which replaced which, which is growing vs dying. Temporary index outside the repo, deleted afterwards. Want me to try that before you answer them by hand?"
Skip the offer if there is no .git, history is shorter than ~50 commits or squashed from
an import, or the items are [WHITE-SPOT] tags (an unnamed concept leaves no trace).
If the user accepts, read references/git-history-mining.md and follow it. The short version:
S=<skill-dir>/scripts/git_term_index.py
python3 $S build --repo-dir . --content # throwaway SQLite index in $TMPDIR, never in the repo
python3 $S query Account Customer # birth, dormancy, trajectory, renames, messages
python3 $S pair User Customer # competing names: birth order + swap commits
python3 $S contexts Account # where the name lives — the polysemy check
python3 $S search 'rename account' # BM25 search over commit messages
python3 $S clean # delete the index when doneThe index covers the whole diff history, so "born" means born. Use --pathspec src/
on large repos — it cuts build time and sharpens the signal at once.
pair ends in a labelled verdict — RENAME (strong / probable / possible), DRIFT,
NOT A RENAME, COEXISTENCE — with the direction inferred from evidence, not argument
order. Report the label as given; do not upgrade it. "RENAME — strong" means commits
exchange the names and a subject announces it; everything weaker needs git show first.
For polysemy (one word, two meanings, two modules) use the path split: pair prints
files: A in N, B in M, both in K, and contexts <name> gives the directory breakdown for a
single word. both in 0 — no file ever contained both — is real evidence for two bounded
contexts; shared files mean synonym drift, which history cannot settle. Only claim a path
split when the tool printed one. File-only renames (the file moved, the identifier did not)
appear in query's file-renames section, not in pair — run both.
History is evidence, not authority. It ranks candidates and cites commits; the user
decides. Report proposals in one batch with confidence levels, apply only what is approved,
and record the commit behind each applied decision (— renamed in a41f2c9 on the Legacy
line, or a - **History**: line on the entry).
Naming Rules by DDD Construct
The Index Kind column selects the rule.
Aggregates & Aggregate Roots (aggregate)
Use the business domain term. Singular. No technical suffixes.
GOOD: Order, Invoice, UserAccount, ShoppingCart
BAD: OrderAggregate, OrderRoot, OrderAggregateImpl, OrderEntityEntities (entity)
Singular noun from the domain. Something with identity.
GOOD: OrderLineItem, PaymentTransaction, Customer
BAD: OrderLineItemEntity, OrderLineItemImpl, OrderLineItemObjValue Objects (value)
Singular noun describing an immutable concept. Describes what it is, not what it does.
GOOD: Money, Email, PhoneNumber, Address, DateRange
BAD: MoneyValue, EmailValidator, PriceInfo, AmountDataDomain Events (event)
Past tense verb + noun. Something that happened.
GOOD: OrderPlaced, PaymentCaptured, InvoiceSent, InventoryReserved
BAD: OrderEvent, OnOrderPlaced, CreateOrder (that's a command)Commands (command)
Imperative verb + noun. An action requested.
GOOD: CreateOrder, CancelInvoice, ProcessRefund, ReserveInventory
BAD: OrderCreated (that's an event), NewOrder, OrderCommandQueries (query)
Question or retrieval. Verb + object or descriptive name.
GOOD: GetOrderById, FindInvoicesByCustomer, ListPendingOrders
BAD: RetrieveOrderData, OrderQuery, GetterForOrderDomain Services (service)
Named after business activities the domain expert recognizes.
GOOD: InvoiceCalculator, OrderFulfillment, NotificationSender
BAD: OrderManager, GenericService, HelperServiceRepositories
Repository suffix is acceptable — it's an infrastructure pattern. Repositories are not thesaurus terms; they take the name of the aggregate they store.
GOOD: OrderRepository, InvoiceRepository, CustomerRepository
BAD: OrderStorage, OrderPersistence, OrderFinder, OrderDaoMethods on Aggregates
Commands (change state): Imperative verb, no "Get" prefix.
GOOD: order.Cancel(), order.AddLineItem(product, quantity), order.Recalculate()
BAD: order.CancelOrderMethod(), order.GetCancelled(), order.DoCancelOrder()Queries (read-only): Start with Get, Is, Has, Can, or a domain verb.
GOOD: order.GetTotal(), order.IsExpired(), order.CanBeShipped()
BAD: order.FetchInfo(), order.CheckData()Naming Anti-Patterns to Detect and Flag
Lexical Firewall: the ## Forbidden section
The domain layer must be protected from transient jargon, vague terms, and
implementation details. The thesaurus's ## Forbidden section lists words that MUST NOT
appear in domain names and must always be replaced with a specific domain term.
Weasel Words (never use in domain layer)
| Weasel Word | Problem | Fix |
Info | Meaningless suffix | Remove it: UserInfo -> User |
Data | Says nothing about the concept | Use domain term: OrderData -> Order |
Manager | Vague, hides responsibility | Split by actual responsibility |
Handler | Generic, unclear intent | Name after what it handles |
Service | Overused catch-all | Use specific domain activity name |
Base | Technical distraction | Remove, use composition |
Item | Too generic | Use domain term: Item -> OrderLineItem, Product |
Util / Helper | Indicates bad design | Move logic to domain objects |
Object / Obj | Never appropriate | Remove suffix |
Record / Model | Database concept leaking into domain | Use domain term |
Config / Settings | Generic container hiding a concept | Config -> LoanProduct, Settings -> NotificationPreferences |
Technical Jargon in Domain Layer
Domain code must be free of implementation details:
BAD: MongoOrder, SqlUserRepository, HttpOrderService, OrderDto, OrderEntity
GOOD: Order, OrderRepository (interface), PaymentGateway, Order (just Order)Technical prefixes/suffixes belong ONLY in the infrastructure layer, and even there the domain role should lead:
INFRASTRUCTURE LAYER (OK): MongoOrderRepository, RedisSessionCache, HttpPaymentClient
DOMAIN LAYER (NEVER): MongoOrder, RedisSession, HttpPayment
NAME THE ROLE, NOT THE TECH: SessionStore not RedisCache, EventPublisher not KafkaProducerFramework caveat: In frameworks that intentionally blend domain and persistence (Active Record pattern, ORM-centric frameworks), the model IS the domain entity. Keep the domain noun clean and let framework coupling live in inheritance, annotations, or metadata — not in the class name. Flag technical jargon only when it becomes part of the business-facing name or leaks outside its boundary.
Synonym Drift
Same concept called different things in different parts of code:
PROBLEM: "Customer" in auth, "User" in API, "Account" in billing — all mean the same thing
FIX: Pick ONE canonical term per bounded context. Put the others in that line's `avoid:` list.Abbreviation Boundary
Ban abbreviations in durable, domain-bearing names: types, exported functions, modules, API fields, DB columns, events, config keys.
Allow conventional short-lived local identifiers when meaning is obvious in scope:
i, j, ctx, req, res, err, tx, db, e for events.
Allow industry-standard acronyms when they are the dominant term: SKU, VAT,
URL, ID, OAuth. Do NOT force unnatural expansions if experts use the acronym.
PROBLEM: usr, user, account, acct — competing abbreviations for the same durable concept
FIX: Pick ONE canonical form for domain-bearing names. Short-lived locals are exempt.Translation Chain ("Telephone Game")
When different artifacts use different terms for the same concept across the knowledge chain, information is lost at each translation:
SMELL: Domain expert says "Campaign" → PM writes "Promotion" in spec →
Dev codes `marketing_push` → QA tests "advertising effort"
FIX: Same term everywhere: expert, PM, dev, QA all say and write "Campaign"This is worse than synonym drift because each translation also loses nuance and business rules. How to detect: compare terms in requirements/specs/tickets against code names. If they don't match, the ubiquitous language has a translation gap — adopt the domain expert's term everywhere.
Casing Conventions
The Index Identifier is PascalCase. Every other form is derived from it mechanically
using the project's conventions — never re-worded:
| Context | Convention | Example (Identifier: OrderLineItem) |
| Class/Type | PascalCase | OrderLineItem |
| Function/Method | Project convention | addOrderLineItem / add_order_line_item |
| Variable | Project convention | orderLineItem / order_line_item |
| Constant | UPPER_SNAKE | MAX_ORDER_LINE_ITEMS |
| Database table | Project convention | order_line_items |
| API endpoint | kebab-case or convention | /orders/{id}/line-items |
| Event/Message | PascalCase with past-tense verb | OrderLineItemAdded |
| File/Directory | Project convention | order_line_item.py, OrderLineItem.cs |
Key rules:
- Use the EXACT Identifier — don't abbreviate (
ord), don't expand (orderObject), don't synonym (purchase) - Compound names combine Identifiers:
OrderLineItem, notPurchaseLineItem - Technical suffixes for infrastructure roles are fine:
OrderRepository,OrderDTO(in infra layer only) - Multi-word Identifiers keep all words in every casing:
ProcessingStage→processing_stage, neverproc_stage - Variables and parameters use full descriptive names:
totalAmountnotamt,customerEmailnotcEmail
Updating the Thesaurus
When changing terms, use the least strong relation that tells the truth (from FPF F.13):
| Operation | When | Effect on thesaurus |
| Add | New concept | Index line + entry. Minimum: Identifier, kind:, Definition |
| Rename | Wording improved, sense unchanged | Change Term/Identifier in the Index line and header; old Identifier → ## Legacy line `Old` → `New`; grep codebase, suggest renames |
| Split | One term covered two senses | Old line removed; two new lines + entries; old Identifier → ## Legacy line `Old` → `A` + `B`; disambiguation in each NOT |
| Merge | Two terms are really one sense | Keep one line; the other Identifier moves into its avoid: list; entries merged |
| Retire | Term was misleading, no single successor | ## Legacy line `Old` → — (see `X`, `Y`) |
| Deprecate | Concept being phased out | ## Legacy line with → replacement and in: locations |
Key test: Can you point to the same concept before and after the change?
- Yes, same concept, better wording → Rename (keep as legacy alias for reading old code)
- No, the concept actually changed → Split or Merge (not a rename)
Alias parsimony: keep at most 1 legacy alias per term — the one readers will most
likely encounter in old code. Registry invariant still holds after every edit: a name
is under avoid: or in Legacy, never both.
Old layout? No thesaurus-format frontmatter key (or 1.x) means the pre-index prose layout —
see "Migrating an Existing Thesaurus" in
references/generating-thesaurus.md.
Quick Checklist Before Naming Anything
- Did I grep the thesaurus for this name and its synonyms? Where did the hit land?
- Would a domain expert recognize this name?
- Does it contain a weasel word (Manager, Service, Handler, Info, Data, Item, Base, Util)?
- Is it too generic (could mean multiple things in different contexts)?
- Does it reveal infrastructure details (Mongo, Sql, Http, Dto, Entity, Model)?
- Is it consistent with other uses of this term across the codebase?
- Am I using the EXACT Identifier from the Index, or a synonym from its
avoid:list? - Am I in the right bounded context for this term?
- Does the name match its Kind — past tense for
event, imperative forcommand? - Can I explain what this name represents in one sentence using domain language?
- If the concept is new — did I add the Index line and the entry before using it?
If any answer raises a concern — stop and fix before proceeding.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

