Skip to content
Agentmart
Submit a tool

naming-conventions

Names files, routes, exports, hooks, booleans, kinds, testIDs, message keys, app ids and env vars.

Skill by zakariaf

IndexedMIT★ 11
Write a review

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.

We use your email only for this newsletter. Privacy

About

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).

No 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 .` and

From zakariaf/ReactNative-Skills, MIT.

More from zakariaf/ReactNative-Skills

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
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from zakariaf

Cite this page

naming-conventions skill. Agent Mart. https://agentmart.dev/skills/zakariaf-naming-conventions (last updated 2026-10-24)