Coding conventions for the hyperfrontend Nx monorepo. Use when refactoring, adding features, fixing bugs, or writing any new code across libs/, apps/, tools/, or plugins/.
Installation
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Coding conventions for the hyperfrontend Nx monorepo. Use when refactoring, adding features, fixing bugs, or writing any new code across libs/, apps/, tools/, or plugins/.
allowed-tools
["Read","Write","Edit","Grep","Glob","Terminal"]
Coding Skill
Know all enforced rules before generating code. Violations will be caught by lint; fix them preemptively.
Reference Locations
What
Where
Shared libs
libs/
Frontend apps
apps/frontend/
Backend apps
apps/backend/
Tooling
tools/, plugins/
ESLint rule docs
tools/eslint-rules/docs/
Base ESLint config
eslint.base.config.cjs
TS path aliases
tsconfig.base.json โ paths
Immutable-safe builtins
@hyperfrontend/immutable-api-utils
Validation Workflow
Run in order, targeting only affected projects:
nx test <project-name>
nx lint <project-name> --fix
nx run <project-name>:typecheck
nx format:write --projects=<project-name>
Module Boundary Tags
Tag
Can depend on
type:core
nothing
type:util
type:core, type:util
type:feature
type:core, type:util, type:feature
type:protocol
type:core, type:util, type:protocol
type:app
type:util
type:demo
nothing (npm packages only)
scope:standalone
nothing (npm packages only)
Import Rules
Order
importtype { Foo } from'./types'// 1. type importsimport { readFileSync } from'node:fs'// 2. node: builtinsimport express from'express'// 3. externalimport { bar } from'@hyperfrontend/utils/string'// 4. workspaceimport { helper } from'../../shared/helper'// 5. relative (deep first)import { local } from'./local'// 6. current dir
// โconst value = map.get(key)!
// โ โ type narrowingconst value = map.get(key)
if (value === undefined) thrownewError(`key not found: ${key}`)
// โ โ optional chainingconst name = user?.profile?.name
JSDoc
Required on all exported .ts members: functions, classes, methods, properties.
@param with description
@returns with description
No @deprecated โ use the issue tracker
No @todo
Member docs go above the member as JSDoc, never as trailing comments:
Every // comment must use a recognized prefix or be a tooling directive:
Prefix
why:
how:
context:
magic:
todo:
fixme:
note:
ref:
// โ// Initialize the counter// โ // why: Counter starts at 0 to match the API's 0-based indexing
No decorative header comments (banners, ASCII art)
No section dividers (==== blocks)
Never write // TODO / // to-do / /** @todo */ โ the lowercase todo: prefix is distinct and allowed
File Size
Only applies when a file has more than one function:
File type
Max lines
Implementation
400
Test (.spec.*)
700
When a file approaches the limit, split into discrete functions. Colocate internal helpers in the same folder as the module they support (e.g. a utils/ or shared/ subfolder beside the main file โ not <workspace-root>/libs).
Before extracting a helper as reusable, confirm it immediately deduplicates existing code. Check local utils/, shared/, and feature-adjacent folders first. Only promote to a shared location if other code can be deduplicated right now.
Testing
Names โ assertive, no "should"
// โit('should return the correct value', ...)
// โ it('returns the correct value', ...)
Assertions โ one per test, use Jest APIs, consolidate with asymmetric matchers
One assertion per test. Each it block should express a single observable fact. Multiple expect calls are only acceptable when asserting over a collection or validating tightly coupled state that cannot be expressed as a single matcher.
Use built-in Jest matchers (expect, toBe, toEqual, toThrow, toHaveBeenCalledWith, etc.). Do not introduce raw assertion libraries or custom matchers unless they already exist in the file.
Consolidate multiple property checks into a single toEqual with asymmetric matchers:
Do not add branches that cannot be reached, and avoid defensive branching that adds complexity without observable behaviour. Every new branch requires a corresponding unit test; if the test cannot be written, the branch should not exist.
New Library Checklist
project.json โ name starts with lib-, has description and tags