naming-conventions
Names files, routes, exports, hooks, booleans, kinds, testIDs, message keys, app ids and env vars.
Skill by zakariaf
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/zakariaf-naming-conventions
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md and code. Checked Oct 26, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
- Runs as
- Node.js package
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/naming-conventions
What's inside
- Skill name
naming-conventions- Description
- Names files, routes, exports, hooks, booleans, kinds, testIDs, message keys, app ids and env vars. Use when adding or renaming anything or on a naming lint error. Not for placement (architecture-and-boundaries).
- License
- MIT
- Instructions
- 236 lines in SKILL.md · view on GitHub
Before installing
- Ships executable scripts
Files (97)
- SKILL.md
- naming-contract.schema.json · assets/
- naming-rules.json · assets/
- shared.json · assets/
- template-placeholders.json · assets/
- 01-add-task.yaml · examples/
- lights-out-types.ts · examples/
- task-details-route.tsx · examples/
- task-row.tsx · examples/
- task-sync-types.ts · examples/
- tasks-reducer.test.ts · examples/
- tasks-reducer.ts · examples/
- code-identifiers.md · references/
- contract-and-checkers.md · references/
- files-and-folders.md · references/
- kinds-testids-and-keys.md · references/
- naming-rules.md · references/
- packages-scripts-env-and-tags.md · references/
- check-code-names.mjs · scripts/
- check-file-names.mjs · scripts/
- check-lib.mjs · scripts/
- app-config-ids.mjs · scripts/lib/
- names.mjs · scripts/lib/
- naming-scope.mjs · scripts/lib/
- source-scan.mjs · scripts/lib/
- workspaces.mjs · scripts/lib/
- selftest.mjs · scripts/
- naming.json · templates/contracts/
- string-union.test.ts · templates/
- string-union.ts · templates/
- SKILL.md · tests/bases/app/.agents/skills/decoy/
- utils.ts · tests/bases/app/.agents/skills/decoy/templates/src/features/Bad_Feature/
- english.json · tests/bases/app/.agents/skills/decoy/templates/src/i18n/catalogs/
- config.yaml · tests/bases/app/.maestro/
- 02-complete-task.yaml · tests/bases/app/.maestro/flows/journeys/
- 01-add-task.yaml · tests/bases/app/.maestro/flows/smoke/
- grant-notifications.yaml · tests/bases/app/.maestro/subflows/
- open-deep-link.yaml · tests/bases/app/.maestro/subflows/
- expo-iap.ts · tests/bases/app/__mocks__/
- app.config.ts · tests/bases/app/
- jest.setup.ts · tests/bases/app/
- package.json · tests/bases/app/
- with-android-queries.ts · tests/bases/app/plugins/
- check-env.ts · tests/bases/app/scripts/quality/
- BadHelpers.ts · tests/bases/app/scripts/vendor/naming-kit/
- SKILL.md · tests/bases/app/scripts/vendor/naming-kit/
- SKILL.md · tests/bases/app/skills/decoy/
- first.yaml · tests/bases/app/skills/decoy/tests/fixtures/bad/.maestro/flows/
- index.ts · tests/bases/app/skills/decoy/tests/fixtures/bad/src/ui/
- _layout.tsx · tests/bases/app/src/app/(tabs)/
- index.tsx · tests/bases/app/src/app/(tabs)/
- settings.tsx · tests/bases/app/src/app/(tabs)/
- +not-found.tsx · tests/bases/app/src/app/
- _layout.tsx · tests/bases/app/src/app/
- [taskId].tsx · tests/bases/app/src/app/tasks/
- app-variant.ts · tests/bases/app/src/config/
- add-days.ts · tests/bases/app/src/core/dates/
- date-key.ts · tests/bases/app/src/core/dates/
- expo-sqlite-sql-driver.ts · tests/bases/app/src/data/
- tasks-db-v1.full.json · tests/bases/app/src/data/fixtures/
- …and 37 more
SKILL.md (first lines)
# Naming conventions
One naming scheme for an Expo app, so every name is predictable from the thing it names and every
thing is findable from its name: agents and reviewers find code by `grep` and by path, and names are
the search index. This skill holds the rules, a repo-owned contract for the app's own naming facts,
and two zero-dependency checkers that prove the repo follows them.
## Rules that must hold
1. **Files and folders are kebab-case; route files follow the Expo Router grammar.** `task-row.tsx`,
`use-tasks-model.ts`, `task-details/`; middle extensions (`.test`, `.golden.test`, `.sim.test`,
`.perf.test`, `.d`, `.config`) and platform extensions (`.ios`, `.android`, `.web`) are fine. In
`src/app/`: kebab URL segments, `(group)` folders, `[camelCaseParam]`, `[...rest]`, `_layout`,
`index`, `+not-found`. Why: macOS (also EAS's iOS builders) ignores case, but Linux CI and EAS's
Android (Linux) workers do not, and a param name becomes the key of `useLocalSearchParams()`.
2. **The main export is named after its file.** `task-row.tsx` → `TaskRow`, `use-tasks-model.ts` →
`useTasksModel`, `tasks-screen.tsx` → `TasksScreen`, `system-clock-adapter.ts` →
`createSystemClockAdapter`, `fake-clock.ts` → `createFakeClock`, `clock-port.ts` → `ClockPort`,
`src/stores/tasks-store.ts` → `useTasksStore`, `tasks-reducer.ts` → `tasksReducer`,
`plugins/with-x.ts` → `withX`. A route file default-exports `<Name>Route` (`<Name>Layout` in
`_layout.tsx`), never anonymous and never `<Name>Screen`. Why: the file name alone tells what to
import, and the screen name stays unique.
3. **No grab-bag files or folders, no barrels.** No `utils.ts`, `helpers.ts`, `common.ts`, `shared.ts`,
`misc.ts`, `stuff.ts`, no `src/utils/`; the only `index` files are route files and files a tool
requires (declared in `contracts/naming.json`). Why: grab-bags grow without limit and barrels
create import cycles.
4. **Line 1 of every `.ts`/`.tsx`/`.js`/`.mjs`/`.cjs` file names its path.** `// src/ui/app-text.tsx`
(a note may follow after `: ` or a space; after a `#!` line, line 2; a directive comes after it).
Why: snippets, diffs and tool output always show where code lives. This skill owns the rule; other
skills cite it. On by default; `"pathHeader": false` in the contract turns it off.
5. **Case by kind.** Values and functions camelCase; components and types PascalCase; module-level
fixed data (a literal, a regex, an `as const` table) UPPER_CASE; objects built by a call stay
camelCase (`styles`, `queryClient`). Acronyms are words (`SqlDriver`, `isRtl`, `ApiClient`); no
leading or trailing underscores except unused parameters. Why: word boundaries and mutability stay
visible.
6. **Booleans read as questions.** Every boolean variable and parameter starts with `is`, `has`, `can`,
`should`, `did`, `will` or `was`; destructured booleans are renamed (`{ disabled: isDisabled }`).
Why: `if (isDone)` reads as a question at the call site.
7. **Types are `type`, never `interface` (outside `*.d.ts` merging), never `I`-prefixed, never
`enum`.** A closed set is an `as const` array plus a derived union. Suffixes say whose:
`<Component>Props`, `<Domain>State`, `<Domain>Action`, `<Operation>Error`, `<Function>Options`,
`<Concern>Port`; type parameters `T` or `TName`. Why: erasable syntax, exhaustive switches, and
names that say what they belong to.
8. **React names the React way.** Handlers inside a component are `handleX`, callback props `onX`,
hooks `useX` in `use-x.ts` (one per file; a second hook exported there is only a building block
`useX` calls, like `useFontScale` beside `useTextStyle`; a context's own hook stays beside its
private context in `<x>-context.tsx`, which exports `XProvider`), screens `<Name>Screen` in
`<name>-screen.tsx`, a feature's model hook `use-<feature>-model.ts`. Why: the React Compiler and
`react-hooks` rules rely on `use`; readers rely on the rest.
9. **`kind` and `type` values are kebab-case with a grammar.** Commands imperative
(`'complete-task'`), events past tense (`'task-completed'`), errors a noun phrase
(`'stale-revision'`), reducer actions imperative (`'set-filter'`). A stored value is a data format:
renaming it needs a migration. A value a format or library owns is not a kind: MIME types,
react-hook-form's `setError` types, an adapter's SDK options. Why: one grep finds every producer
and consumer.
10. **testIDs are `<screen>.<element>[.<key>]` and flows select only by id.** `tasks.add-button`,
`tasks.task-row.<task id>`; repeated items append a stable data key as its own segment, never a
list index; interactive elements end in their role (`-button`, `-row`, `-switch`, `-input`). OS-owned UI
without a testID is tapped only under a `# system-ui: <why>` comment. Why: Maestro's `id:` matches
`testID` on iOS and Android, so one flow runs in every locale on both platforms.
11. **Message keys are semantic literals with typed placeholders.** 2-5 dot-separated kebab segments
(`tasks.add-button.label`), the first a feature folder or a declared area (`common`, `errors`, ...),
written as a literal or picked from a typed table, never built; placeholders camelCase and typed
(`{count, number}`, `{taskCount, plural, ...}`, free text `{listName}`). Why: a wording change never
renames a key, and tools can check what they can see.
12. **Tests and flows are named after what they cover.** `<unit>.test.ts(x)` next to the unit
(`.golden.test.ts`, `.sim.test.ts`, `.android.test.tsx`, Node-API tests in root `test/`); `describe('<export>')` →
`describe('when ...')` → `it('<third-person verb> ...')`, `it` never `test`; flows
`.maestro/flows/<area>/<nn>-<name>.yaml`, sub-flows `.maestro/subflows/<name>.yaml`; a folder of
flows CI deliberately skips is declared in `contracts/naming.json` `extraE2eFolders`. Why: Jest
projects select by suffix and Maestro runs only the top level of the folder it is given.
13. **Ids outside the code have one shape.** The iOS bundle id and Android package are one lowercase
reverse-DNS id with no Java keyword segment (`com.acme.tasks`); product ids are
`<app id>.<product>` (`<last app-id segment>.<product>` only when that passes the limit), valid
on both stores, at most 40 characters; the slug is kebab-case; an id already live on a store or
EAS keeps its shape and is recorded in `contracts/naming.json` `published*`. Env vars are
UPPER_SNAKE_CASE; app code reads only `EXPO_PUBLIC_*` and Expo's own `EXPO_OS`, `EXPO_SERVER`,
`EXPO_BASE_URL`, `NODE_ENV`, by name with dot access (never destructured, copied, spread or
bracketed), while server code (`+api.ts`, `+middleware.ts`, `src/server/`) reads secrets under
plain names, never under an `EXPO_PUBLIC_` name; npm scripts `<verb>` or `<area>:<verb>`; one
package scope when multi-package. Why: both stores, both native projects and Expo's inlining
accept exactly these shapes (anything else read in app code is `undefined` in a release build),
and changing a live id ships a new app.
14. **Canonical names are declared and never renamed silently.** Port types, npm scripts and env vars
that other code, CI or docs depend on are listed in `contracts/naming.json` `canonical`; renaming
one is a stop-and-ask decision. Why: lint exemptions, fakes, CI jobs and EAS config match them by
name.
## Workflow
1. Name what you are about to create before writing it. Find the kind of name in the table below and
read that reference section; for anything new, start with
[references/naming-rules.md](references/naming-rules.md) (every rule with a good/bad table).
2. First time in a repo: copy [templates/contracts/naming.json](templates/contracts/naming.json) to
`contracts/naming.json` and fill the app's `locales`, `keyAreas` (drop template areas no key
uses), `canonical` names and `storeProductIds`. Product ids are permanent on both stores: stop and
ask the developer before writing a new one. In an app that is already published, ask which bundle
id, package, slug and products are live and record them in `publishedAppIds`, `publishedSlugs`,
`publishedProductIds` (each with its `why`) instead of "fixing" them.
3. For a closed set of values (filters, priorities, variants), copy
[templates/string-union.ts](templates/string-union.ts) and its test
[templates/string-union.test.ts](templates/string-union.test.ts) to
`src/features/<feature>/<name>.ts` and fill every `__PLACEHOLDER__`.
4. Imitate the examples: [examples/task-row.tsx](examples/task-row.tsx) (component, props, boolean
prop, handler, testID), [examples/task-details-route.tsx](examples/task-details-route.tsx) (route
file), [examples/tasks-reducer.ts](examples/tasks-reducer.ts) and its test (state, actions, test
titles), [examples/task-sync-types.ts](examples/task-sync-types.ts) (the kind grammar),
[examples/01-add-task.yaml](examples/01-add-task.yaml) (flow selectors), and for the games plugin
[examples/lights-out-types.ts](examples/lights-out-types.ts).
5. Renaming: change the file, its path header, its main export and every import in one commit. A
stored name (a `kind` value, an analytics event, a catalog key) also needs a migration or a catalog
update, and a `Gate-Change:` trailer when a golden or frozen fixture changes (git-commits-and-reporting
owns the trailer). A route file rename changes a URL: keep a redirect for deep links and app links.
A canonical name (rule 14): stop and ask the reviewer, then update the contract in the same commit.
Never rename a bundle id, package, slug or product id that is live: that ships a new app and breaks
updates, purchases and links; stop, ask the developer, and record it as published.
6. Check (validation loop): when `node_modules` exist, `npx eslint . --max-warnings 0` (the
naming-convention, check-file, testID and kind rules). Always:
`node ${CLAUDE_SKILL_DIR}/scripts/check-file-names.mjs .` andFrom zakariaf/ReactNative-Skills, MIT.
More from zakariaf/ReactNative-Skills
- 0.606score
debug-menu-and-test-hooks
zakariaf
Gates test-only code behind one literal TEST_ONLY switch: debug menu, debug link, simulated clock and offline.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
accessibility-as-code
zakariaf
Enforces a11y labels, 44pt targets, 200% text, VoiceOver, TalkBack.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
adaptive-layout
zakariaf
Lays screens out by window, not device: breakpoints, master-detail panes, readable widths, grids.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
admob-ads-and-consent
zakariaf
Builds AdMob ads behind a port - banners, interstitials, rewarded, UMP consent then ATT, pacing, ADS_MODE test IDs.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
analytics-and-consent
zakariaf
Gates analytics on opt-in consent: no SDK before a yes, typed events without personal data, ATT.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
android-release-play
zakariaf
Ships Android App Bundles to Google Play: upload key, Play App Signing, AAB gate, versionCode, tracks, rollout.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
architecture-and-boundaries
zakariaf
Places app code in the src/ layout and checks import boundaries: one-way zones, pure core, ports with fakes, one composition root.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
async-safety
zakariaf
Prevents silent async bugs: effect races, stale results, lost promises, leaked listeners and timers, AbortSignal gaps.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
audio-and-haptics-feedback
zakariaf
Builds SFX and haptics behind ports.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
auth-and-secure-storage
zakariaf
Builds sign-in - tokens in expo-secure-store, shared refresh, protected routes, OAuth PKCE, Apple sign-in.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
background-tasks
zakariaf
Builds expo-background-task jobs: idempotent, budgeted runs.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
canvas-gestures-and-hit-testing
zakariaf
Turns canvas taps, swipes, drags and aim into typed intents: one gesture module, hit-testing on the drawn layout.
SkillAFreshness: A★ 11Claude Code +9
Signals
- Stars
- 11
- Forks
- 2
- Open issues
- 0
- Last commit (this folder)
- Oct 17, 2026 (12 days ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- Repository
- github.com/zakariaf/ReactNative-Skills
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from zakariaf
- 0.606score
canvas-gestures-and-hit-testing
zakariaf
Turns canvas taps, swipes, drags and aim into typed intents: one gesture module, hit-testing on the drawn layout.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
debug-menu-and-test-hooks
zakariaf
Gates test-only code behind one literal TEST_ONLY switch: debug menu, debug link, simulated clock and offline.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
accessibility-as-code
zakariaf
Enforces a11y labels, 44pt targets, 200% text, VoiceOver, TalkBack.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
adaptive-layout
zakariaf
Lays screens out by window, not device: breakpoints, master-detail panes, readable widths, grids.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
admob-ads-and-consent
zakariaf
Builds AdMob ads behind a port - banners, interstitials, rewarded, UMP consent then ATT, pacing, ADS_MODE test IDs.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
analytics-and-consent
zakariaf
Gates analytics on opt-in consent: no SDK before a yes, typed events without personal data, ATT.
SkillAFreshness: A★ 11Claude Code +9
Cite this page
naming-conventions skill. Agent Mart. https://agentmart.dev/skills/zakariaf-naming-conventions (last updated 2026-10-24)