Naming Conventions
SkillFiles & storageLets your agent turn Chinese descriptions into English PascalCase names for code elements.
Use Naming Conventions in Claude, ChatGPT or Ahel Desktop
Free. Sign in, add Naming Conventions and connect your AI. About a minute.
Also: Claude Code · Cursor · Codex
Then ask your AI: use the Naming Conventions skill
Details
Instructions available. Your AI can read the instructions. Execution depends on the setup they require.
Account requirements not reviewed. Check the skill instructions before use; Ahel provides instructions and does not run this skill.
No other account needed.
Add Ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
About this skill
Generates English identifiers (PascalCase) from Chinese descriptions. Use when the user mentions "命名", "起名", "叫啥", "取个名", "这个叫啥", "what should this module/component/class/file be called", or any scenario requiring English names for code elements, even if the user doesn't explicitly say "generate an
What this skill tells your AI
The instructions your AI receives, as published by bd-dxg/my-pi in skills/naming/SKILL.md and read by Ahel’s review.
Every rule here governs a name we author. A name a dependency reads or writes is its own — that boundary,
and the shapes it takes, is references/names-a-dependency-owns.md.
A sibling takes the identifier word, never the prose one — grep the concept's existing type, guard and constant and match them exactly (references/concept-words.md).
Settled — do not re-propose
- A lint rule for filename-is-the-export — a store file exports
use<Name>Storefor a<name>.tsand takes its parent's word where the leaf collides (battle/player.ts→useBattlePlayerStore), andindex.tsandconstants.tsare the two multi-export names, so the exceptions are a roster; it stays a reading rule. - A word list for abbreviations — only the short forms with no site left are denylisted (
references/abbreviations.md); a name still in use would buy disables instead of coverage. - A selector for a
<script setup>constant's casing — whether a top-level literal is fixed or captures a ref needs scope analysis no selector has. - A ban on a bare-identifier initialiser (
const a = b) — it is also how a mutable binding is snapshotted before it is cleared and how a return shorthand is earned; a trial selector reported dozens of such sites and no alias. _inid-denylist— xml2js spells an element's text as the_key, so parse-tmx and xml2js declare it by that name throughout, andno-underscore-danglerefuses a prefixed loop declarator; a loop binding nothing reads stays bare.- A generic value in a shared namespace (
host://,"SESSION_SECRET",%LOCALAPPDATA%\Host) — another program claims the same name, and the reader's own variable or handler is read or deleted as ours (references/shared-namespaces.md). - An enum member copying the outside casing (
eq,objectgroup) — one enum then reads in two casings and a member is indistinguishable from a value at the call site (references/enum-members.md).
| Read when | Page |
|---|---|
Two boolean spellings both look right — a predicate vs a flag, isPending vs isLoading | references/boolean-families.md |
| Two prefixes both look right — derivation vs fetch, setter vs push, on vs handle | references/verb-families.md |
Joining more than one id into one string — a key, a :key, a blob name | references/composite-keys.md |
| Writing a duration, a date, or a literal big enough to miscount | references/numbers-and-time.md |
| A module-scope binding could be SCREAMING_SNAKE_CASE or PascalCase, or need no name | references/constant-casing.md |
| A name could be shortened, or a compound holds a word the denylist cannot see | references/abbreviations.md |
| An enum member's value comes from outside — a wire string, a library's enum, a notation | references/enum-members.md |
| Naming something that mirrors a library — its option, key, method or wire value | references/names-a-dependency-owns.md |
| A concept has a prose word and an identifier word, and a sibling needs naming | references/concept-words.md |
| Naming a map, a record, or a function that looks one up | references/map-names.md |
| A call's result is about to be nested into the next call | references/named-intermediates.md |
| Naming the session user's id, or a read scoped to the caller | references/session-user.md |
| Naming a local editable copy of a prop or store field | references/edited-copies.md |
| A parameter or a loop binding nothing reads | references/unused-bindings.md |
| Naming a file, or renaming its export | references/file-names.md |
| Setting a boolean environment variable the repo owns | references/env-values.md |
| Choosing a scheme, env var, registry key, app-data folder or title other programs share | references/shared-namespaces.md |
| Naming a panel's subsections, or a list whose labels are also its ids | references/section-enums.md |
Booleans
is*prefix for boolean variables and properties only:isMuted,isRoomOwner. Never for callable functionscheck*prefix for all boolean-returning functions (top-level, exported, or callback param):checkIsManageable,checkIsStale. Makes callability unambiguous —checkIsManageable(...)is always a call,isManageableis always a stored value. Anis*/has*declarator holding a function with a: booleanor type-predicate return is ano-restricted-syntaxerrorhas*only whenis*reads unnaturally — possession/membership checks:hasMore,hasThumbnail. Nevercan*orshould*— enforced byno-restricted-syntaxon the declarator name, which leaves a dependency's own key alone (LiveKit'scanPublishgrant,URL.canParse). A permission ishasManageRoles, a capabilityisScreenShareSupportedshow*is banned on a value — rename tois*Visible:showFoo→isFooVisible(no-restricted-syntax, for a declarator and abooleaninterface member)isPendingfor a request in flight,isLoadingfor a wait that is not one requestisDirtyfor tracking unsaved state — never achangedspellinginitial*for the last-saved snapshot used in dirty comparisons:initialDataSource- Boolean-valued
LocalStorageKeyregistry entries follow the sameis*rule — thefile-organizationskill (references/local-storage-keys.md) owns that registry
Functions
get*for derivation/display functions:getFooTooltip,getFooTitleread*for async data-fetching functions — neverfetch*(fetchis reserved for the Web API):readFooscompute*for a value an algorithm produces from a collection or a dataset- CRUD prefixes (
create*,update*,delete*) for data/store operations set*for a function that writes stored state, named after the field it writesto*for a pure conversion handing the subject back in another representation:toTitleCase,toColumnKeystore*prefix for subscription-driven state-update counterparts of async user actions:deleteFoo(user action) +storeDeleteFoo(subscription update). Never on unpaired methodson*for a function something else calls with an event or an input it did not initiate; direct actions use the action name (submit,save,delete)- No cardinality suffixes — upgrading single-item → batch pluralises the noun and adds nothing (
readFoo→readFoos)
Variables
- No abbreviations —
directMessageFoonotdmFoo,existingDirectMessagenotexisting(bareexistingis inid-denylist). Exception:Mssuffix for time values:slowmodeMs,durationMs. Where the rule stops — the short forms lint actually bans, the compound spellings it cannot see, and the exported, component and file names that spell the word out —references/abbreviations.md - A name carries its type, never a bare generic like
parsed(id-denylist) —parsedDate,parsedResult - A map or record is
<key><value>Map, never<value>By<key>or<key>To<value>; a function keeps itsBy<Selector>(references/map-names.md) - Name variables after their full domain type, dropping only the schema
InMessagesuffix — a value typed asBan(tablebansInMessage) isconst ban, neverconst bannedUsernorconst banInMessage. Where the suffix is kept it is the table's own name and never pluralised —InMessagesis ano-restricted-syntaxerror - A call's result gets a name rather than being nested into the next call, named after the function with
get/readdropped (references/named-intermediates.md) - No
current*prefix for reactive refs/computeds — they are always the current value. Exception: global store identifiers distinguishing the active item from a collection:currentRoomId userIdfor the session user's ID — neverme,myIdorself;my*on a read scopes it to the caller (references/session-user.md)- A comparator's pair is named for what it compares —
(firstRoom, secondRoom), never(a, b)(no-restricted-syntaxon asort/toSortedcallback) new{PropName}foronUpdate:*handler parameters:(newItemsPerPage) =>,(newModelValue) =>edited{PropName}for a local editable copy of a prop or store field — never{prop}Value(references/edited-copies.md)- Unused params keep the
_prefix and a readable name —_event, never bare_, except a loop binding (references/unused-bindings.md) display*for presentation-layer computed that sorts/filters raw store data:displayFoos. Neversorted*orfiltered*- A composite key is joined with
ID_SEPARATOR, never a hand-written delimiter —references/composite-keys.md
Environment Variables
- A value in a namespace the machine shares carries the product's prefix; the identifier holding it never does —
HOST_SCHEME = "esposter-host",SESSION_SECRET_ENVIRONMENT_VARIABLE = "ESPOSTER_SESSION_SECRET", never"host"or"SESSION_SECRET", and our own text drops the name.naming/no-site-name-literalreports a string spelling it out (references/shared-namespaces.md) - Our own env var values are always the strings
"true"/"false"— never"0"/"1"(references/env-values.md)
Import Aliases
- No
_prefix for import aliases (no-restricted-syntax) — usebase*prefix when renaming an import to avoid a name clash:import { getMentions as baseMentions }. Neverimport { getMentions as _getMentions }
TypeScript & Interfaces
- No
Withprefix on mixin interfaces — name after the capability:SourceColumnId, neverWith-prefixed. Schemas and their factories follow:sourceColumnIdSchema/create<Capability>Schema, nevercreateWith<Capability>Schema Aprefix for abstract classes only —AColumn(abstract class) ✓,SlashCommand(interface) ✓. Lint refuses it on an interface, so the question is what to call one instead: an interface holding the shape its implementors share takesBase*, matching thebase*Schemait is usually declared beside (BaseColumnForm,BaseExecuteAdminActionInput); anything else is named after what it holds- Interface fields use full type name —
aggregationType: AggregationTransformationTypenottransform,mode, ortype. Never abbreviate enum field names - A wrong name is corrected in place, never aliased — no re-export shim, no version suffix, no comment explaining the history, and neither "it is deployed" nor "it is published" is an exemption (
apps/web/content/docs/architecture/no-compatibility-debt.md; the mechanics of the rename are thefile-organizationskill'sreferences/renames.md). A name that is still accurate is left alone: correctness is the criterion, not symmetry with its neighbours. - A file's name is its single export's name, and renaming the export renames the file in the same change (
references/file-names.md) - An enum member is PascalCase; its value keeps the outside spelling —
Dark = "dark",Eq = "eq"; lint refuses any other member casing. Where an outside spelling seems to belong on the member, and the two that keep it behind a disable —references/enum-members.md - A panel's subsections, or any list whose labels are also its ids, are one enum per group —
references/section-enums.md
Constants
- A module-scope constant holding a fixed scalar is SCREAMING_SNAKE_CASE —
MAX_INVITE_ID_RETRIES,SEARCH_SIMILARITY_THRESHOLD. Where PascalCase competes with it — a lookup table, a fixed list that is not one,apps/infra's one-per-file rule — and where the literal should carry no name at all:references/constant-casing.md - Named regex constants use
_REGEXsuffix —FOO_REGEX. Never_RE,_PATTERN, or any other suffix (no-restricted-syntax, for a module-scope regex ornew RegExp)
Framework-Specific Naming
Framework naming lives with its framework: Vue (props interface, modelValue, template refs, prop shorthand) is the vue skill's; store variables the pinia skill's; procedures, subscriptions and DB result variables the trpc skill's.
Signals
- GitHub stars
- 88
- Forks
- 13
- Last commit
- Oct 2026
Advanced
- Item type
- skill
- Key
naming- Source
- github.com/bd-dxg/my-pi