Coding rules
11 rule sets with 39 groups. A project switches a set on in docs/project/coding_rules.md; group IDs CR-<set>-<name> are stable.
Coding rules — Bash
Source: .act/coding/bash.md
Summary: strict mode, quoting, exit codes, error messages, shellcheck, pitfalls
Rules for Bash scripts. Group IDs (CR-bash-<name>) are stable and never reassigned; a group
whose purpose no longer holds gets a new ID and is listed as retired: in this header.
CR-bash-basics
Section titled “CR-bash-basics”Strict mode, quoting, error handling, shellcheck
Summary: set -euo pipefail, quoting, deliberate exit codes, errors on stderr, shellcheck, pitfalls
- Start every script with
set -euo pipefailas the first executable line. - Quote variables consistently (
"$var"), especially paths that may contain spaces. - Set exit codes deliberately (
exit 0/exit 1/specific codes) instead of letting the last command’s status pass through implicitly. - Check arguments and inputs before use (count, whether a path exists); report failures on stderr, and name what failed and with what — not a bare “error”.
- Run
shellcheckas the stack’s standard linter before every commit; do not suppress its warnings wholesale. - Pitfalls:
- Never parse the output of
lsin a loop — use globbing orfind ... -print0withread -d ''. - Check the result of
cd(cd dir || exit 1); otherwise following commands run in the wrong directory.
- Never parse the output of
CR-bash-script-shape
Section titled “CR-bash-script-shape”One script, one purpose
Summary: header comment, functions over duplication, single-purpose scripts
- Start with a header comment stating purpose, an example call, and the expected output/exit behavior.
- Use functions for reusable sections instead of copying the same command sequence.
- One script, one clearly named purpose — no multi-purpose script with mode flags for unrelated tasks.
csharp
Section titled “csharp”Coding rules — C#
Source: .act/coding/csharp.md
Summary: nullable context, async conventions, error handling, analyzers, DI, library code
Rules for C# projects. Group IDs (CR-csharp-<name>) are stable and never reassigned; a group
whose purpose no longer holds gets a new ID and is listed as retired: in this header.
CR-csharp-basics
Section titled “CR-csharp-basics”Nullable context, async, error handling, analyzers
Summary: nullable enabled, async suffix, no async void, no blocking on tasks, using, exceptions
- Keep the nullable context (
<Nullable>enable</Nullable>) on project-wide; do not suppress the warnings it produces. - Name asynchronous methods with the
Asyncsuffix and returnTask/Task<T>. - Never use
async voidoutside event handlers — useasync Task, otherwise exceptions are swallowed. - Avoid
.Result/.Wait()on tasks; blocking on a task this way risks a deadlock in synchronous contexts. - Manage every
IDisposableresource exclusively throughusing/await using. - Use exceptions for exceptional cases, not for regular control flow — consider a return type
(
Result<T>/bool) for expected failure cases; wherever an exception is thrown, its message names what failed and with what. - Run
dotnet formatand the analyzer rules (.editorconfigsectiondotnet_diagnostic) as the stack’s standard linting/static analysis; set them up in every project, run what is installed.
CR-csharp-conventions
Section titled “CR-csharp-conventions”var, records, one type per file
Summary: var only for an obvious type, records for value objects, one public type per file
- Use
varonly when the type is obvious from the right-hand side, an explicit type otherwise. - Use records for immutable value objects/DTOs, classes for objects with identity and behavior.
- One public type per file, with the file name matching the type name.
CR-csharp-dependency-injection
Section titled “CR-csharp-dependency-injection”Constructor injection
Summary: constructor injection, no service locator
- Inject dependencies through the constructor; no hidden service-locator access.
CR-csharp-library-code
Section titled “CR-csharp-library-code”ConfigureAwait in library code
Summary: ConfigureAwait(false) in code without a UI context
- Use
ConfigureAwait(false)in library code that has no dependency on a UI context.
Coding rules — Go
Source: .act/coding/go.md
Summary: strict error checking, static analysis tooling, package design
Rules for Go projects. Group IDs (CR-go-<name>) are stable and never reassigned; a group
whose purpose no longer holds gets a new ID and is listed as retired: in this header.
CR-go-basics
Section titled “CR-go-basics”Error handling, formatting, static analysis
Summary: check and wrap errors, format with gofmt, run vet/staticcheck, avoid panics and leaks
- Format every file with
gofmt/goimportsbefore committing; no hand-tuned deviation from either. - Check an error immediately after the call that returned it (
if err != nil) instead of collecting errors for later, and never discard a return value with_when it comes with an unchecked error. - Wrap errors with
%w(fmt.Errorf("...: %w", err)) soerrors.Is/errors.Askeep working further up the call chain; never lose or flatten the underlying error. - Run
go vetandstaticcheckin CI as the stack’s standard static analysis — set them up, but run only what is installed; if a tool is missing, say so once and install nothing unasked. - No panics in library code for expected failure cases; panic only for genuine programming errors.
context.Contextis the first parameter of any function that must propagate cancellation, a deadline, or request-scoped values.- Every goroutine has a visible lifecycle end (
WaitGroupor context cancellation) — a goroutine with no way to stop is a leak. - Synchronize state shared between goroutines through channels or explicit locks, never silently.
CR-go-package-design
Section titled “CR-go-package-design”Small interfaces, no grab-bag packages
Summary: interfaces defined by the consumer, packages named and cut by domain
- Define interfaces on the consumer side (small, often one or two methods), not upfront by the provider that implements them.
- Give packages short, meaningful names cut by domain; no
util/commongrab-bag package without a real subject of its own.
Coding rules — Java
Source: .act/coding/java.md
Summary: nullability, error handling, structure, toolchain, tests
Rules for Java projects. Group IDs (CR-java-<name>) are stable and never reassigned; a group
whose purpose no longer holds gets a new ID and is listed as retired: in this header.
CR-java-basics
Section titled “CR-java-basics”Nullability, error handling, established pitfalls
Summary: explicit nullability, no raw types, correct exception handling, logging and SQL safety
- Make nullability explicit on fields, parameters and return types (JSpecify
@Nullable/@NonNullor the alternative the project has fixed on) instead of leaving it implicit. - No raw
Object, no raw types on generics. - No empty
catchblocks and nocatch (Exception e)without a concrete reason; use unchecked exceptions for programming errors and checked exceptions for expected, recoverable failures — the message must name what failed and with what. - Manage resources exclusively through try-with-resources.
- Use
java.util.concurrent(executors,CompletableFuture, concurrent collections) instead of manualsynchronized/wait/notify. - Log through SLF4J, parametrized (
log.info("user {} failed", id), never string concatenation) — seeR-safe-no-secret-logfor what never goes into a log line at all. - Use
varonly where the type is obvious from the right-hand side, otherwise spell out the type. - Return
Optional<T>only as a method’s return type for “possibly no result” — never as a field, a parameter, or inside a collection. - Pitfalls: override
equals/hashCodeonly together; usejava.time, neverDate/Calendar; useBigDecimalfor money, neverfloat/double; stateUTF_8explicitly, never rely on the platform default; use only parametrized SQL, never string-concatenated queries; a plain loop may read better than forcing a Stream. - Static analysis is the stack’s standard — set it up, but run only what is installed; if a tool is missing, say so once and install nothing unasked.
CR-java-modern-idioms
Section titled “CR-java-modern-idioms”Records, sealed types, text blocks, virtual threads
Summary: modern language features, requires Java 17 for most, Java 21 for virtual threads
- Use records for immutable data carriers (DTOs, value objects) instead of a manual class with
getters,
equals,hashCodeand a constructor — requires Java 17 (records) or 16 (preview). - Use sealed interfaces/classes with pattern matching (
switchon type) instead ofinstanceofchains — requires Java 17. - Use text blocks for multi-line strings (SQL, JSON templates) instead of concatenation — requires Java 17.
- Use virtual threads only where the runtime and every library on the path support them — requires Java 21.
CR-java-structure
Section titled “CR-java-structure”Package cut, immutability, constructor injection
Summary: packages by domain, immutability as the default, constructor injection
- Cut packages by business domain, not by technical layer.
- Keep visibility as narrow as possible, fields
final, no setter without a reason — immutability is the default and the best guard against concurrency bugs. - Use constructor injection instead of field injection, even outside a DI container.
CR-java-toolchain
Section titled “CR-java-toolchain”Build and static analysis tools
Summary: Maven or Gradle by default; static analysis whichever the project has set up
- Build with Maven or Gradle — the project decides which.
- Enforce formatting and static analysis in CI: Spotless or google-java-format for formatting, plus
Checkstyle, SpotBugs, Error Prone or PMD — the template’s usual choice; run whatever the project
actually has set up (see
R-code-tools).
CR-java-tests
Section titled “CR-java-tests”JUnit 5 with AssertJ by default
Summary: JUnit 5/AssertJ by default, behavior-describing names, no unseeded randomness, no Thread.sleep
- Write tests with JUnit 5 and AssertJ — the template’s usual choice; use the test framework the
project actually has set up instead (see
R-code-tools). - Name tests after the expected behavior, not after the method under test.
- Never use randomness without a fixed seed.
- Never wait with
Thread.sleep; wait on the actual condition instead.
Coding rules — Nuxt
Source: .act/coding/nuxt.md
Summary: directory conventions, data fetching, runtime config, SSR mode, tooling
requires: vue, typescript
Rules for Nuxt projects. Group IDs (CR-nuxt-<name>) are stable and never reassigned; a group
whose purpose no longer holds gets a new ID and is listed as retired: in this header.
CR-nuxt-basics
Section titled “CR-nuxt-basics”Established Nuxt defaults
Summary: directory layout, data fetching, typed handlers, runtime config, pitfalls
-
Follow the directory convention (
pages/,components/,composables/,server/) instead of inventing a structure; use auto-imports, no manual re-exports for files in those directories. -
Read data with
useFetch/useAsyncDatawhile rendering, use$fetchfor one-off writes and actions. -
Never copy the return value of
useFetch/useAsyncDatainto your ownref— pass the returned object through andawaitit wheredata/status/errorreach the template. Copying loses awaitability: the call resolves later, the server renders without data, the client fills it in, and the result is a hydration mismatch.```ts// Wrong — awaitability is lostfunction useThing() {const result = ref()useFetch('/api/thing').then(r => (result.value = r.data.value))return result}// Right — pass the returned object through unchangedasync function useThing() {return await useFetch('/api/thing')}``` -
Declare path aliases in
tsconfig.jsonandnuxt.config.ts. Since Nuxt 4,~points atapp/, so without its own entry~/typesresolves somewhere other than~types. -
Use
runtimeConfigfor configuration values instead of readingprocess.envin components; secrets live in the private part ofruntimeConfig, never underpublic. -
Write out types for props, emits, store actions, composables and
defineEventHandler, including return types. -
Name server routes under
server/api/with a verb suffix (login.post.ts,users.get.ts) and return failures withcreateErrorand a matching HTTP status — never swallow an error or answer 200. -
Lint and typecheck are the stack’s standard and belong in the project;
nuxt typecheckneedsvue-tscas a dependency, without it there is no typecheck. Run what is installed, install nothing unasked. -
Keep the npm scripts named the same everywhere:
lint(eslint .),typecheck(nuxt typecheck), plustest(vitest run) andtest:e2e(playwright test) where tests exist. -
Pitfalls:
- SSR code must not touch browser globals (
window,document) without a guard. - Use
<ClientOnly>only where a component genuinely cannot render on the server, not as a default fix. - Security: never keep per-request state in a module-level
ref/reactive. On the server such a value outlives the request and is shared between users — the next request sees the previous one’s data. UseuseStatefor state that must survive the request. - Forms with
@submit.preventalso needmethod="post"(seeCR-vue-basics). - Windows: an aborted dev server can keep its port bound; the next start moves to the next free
port and HMR/WebSocket errors follow. Kill the running process (
netstat -ano | findstr :3000,taskkill /PID <pid> /F;lsof -i :3000,kill <pid>) instead of configuring a custom HMR port.
- SSR code must not touch browser globals (
CR-nuxt-root-folders
Section titled “CR-nuxt-root-folders”Fixed root folders with their own aliases
Summary: /types, /constants and /server at the repo root, each the only place of its kind
- Keep three folders at the repository root, each with its own alias and each the only place of its kind:
/types(~types, shared types and interfaces),/constants(~constants, constants, enumerations, fixed keys),/server(~server, the Nitro backend). - Import types and constants from there instead of duplicating them in components. A second type folder
under
app/types/is a mistake, not an addition.
CR-nuxt-ssr
Section titled “CR-nuxt-ssr”Choose the SSR mode on purpose
Summary: ask before assuming SSR, know the hydration cost, check for mismatches after SSR work
ssr: falseor a plain SPA is often the simpler choice for a purely local UI with no SEO or first-paint requirement (e.g. an admin tool). Ask the user once, when scaffolding or restructuring the app, instead of defaulting to SSR without asking.- Know what SSR costs: every page render runs twice, once on the server and once on the client.
Anything that only exists in the browser or differs between the two runs — timestamps, random
values,
window,localStorage, locale or timezone detection — produces a hydration mismatch. - After working on a component that renders server-side, check for hydration errors on purpose: load the page in the browser and read the console warning “Hydration … mismatch” — it names the component and the node. Treat that warning as a finding, not a footnote.
- Known causes and their fix, in short: gate browser-only values behind
onMounted/import.meta.client; share request-scoped state throughuseState, never a module-levelref; fix invalid HTML nesting (e.g. a block element inside a<p>); reach for<ClientOnly>only as the last resort. - Copying a
useFetch/useAsyncDataresult into your ownrefis a common hydration-mismatch cause too — seeCR-nuxt-basicsfor why and the fix, not repeated here.
CR-nuxt-toolchain
Section titled “CR-nuxt-toolchain”Lint and format tooling
Summary: ESLint with @nuxt/eslint plus Prettier, whichever the project has set up
- ESLint with
@nuxt/eslint, configured ineslint.config.mjs, and Prettier for formatting are the template’s usual choice; what the project actually has installed and configured governs (seeR-code-tools).
CR-nuxt-tests
Section titled “CR-nuxt-tests”Unit and end-to-end tests
Summary: vitest/Playwright by default, but whichever suite the project runs must pass
vitest(vitest.config.ts) for unit and component tests,@playwright/test(playwright.config.ts) for end-to-end tests — the template’s usual choice; if the project has a different test runner installed and configured (e.g. Selenium, Nightwatch, Cypress), use that one instead (seeR-code-tools).- Whichever test suites the project actually has exist and run; a change that breaks them is not done.
Coding rules — PHP
Source: .act/coding/php.md
Summary: strict types, PSR-12/PSR-4, exceptions, prepared statements, toolchain
Rules for PHP projects (8.x and later). Group IDs (CR-php-<name>) are stable and never reassigned; a
group whose purpose no longer holds gets a new ID and is listed as retired: in this header.
CR-php-basics
Section titled “CR-php-basics”Strict types, safe errors, safe queries
Summary: strict_types, PSR-12/PSR-4, typed methods, exceptions, PDO, production errors, static analysis
- Put
declare(strict_types=1);as the first statement in every PHP file. - Follow PSR-12 for formatting (4-space indentation) and PSR-4 for namespaces, one namespace per Composer autoload root.
- Keep one class per file, with the filename matching the class name.
- Manage dependencies through Composer only; never include a library by hand.
- Declare parameter and return types on every public method. Use
mixedonly with a comment justifying it, and mark nullable types (?Type) explicitly instead of falling back to an implicitnull. - Throw exceptions instead of returning
falseor an error code. Define one exception class per error domain rather than throwing a blanket\Exception, and let the message name what failed and with what — a database exception names the query or table, a validation exception names the field and the value it rejected. - Keep business logic out of templates (Blade, Twig, plain PHP templates); templates render, they don’t decide.
- Access the database only through PDO with prepared statements; never build SQL by concatenating values into the query string.
- Use
===/!==wherever type equality is meant, not the loose operators. - Turn
display_errorsoff in production; errors go to the log, not into the response. - Static analysis is the stack’s standard and belongs in the project. Run what is installed, install nothing unasked.
CR-php-conventions
Section titled “CR-php-conventions”Closures over global callbacks
Summary: arrow functions and closures instead of global callback functions
- Use arrow functions/closures instead of global callback functions.
CR-php-toolchain
Section titled “CR-php-toolchain”Formatter and static analysis tooling
Summary: PHP-CS-Fixer/PHP_CodeSniffer plus PHPStan/Psalm by default, or what the project has set up
- PHP-CS-Fixer or PHP_CodeSniffer, configured for PSR-12, and PHPStan or Psalm for static analysis —
the template’s usual choice; run whatever the project actually has set up (see
R-code-tools).
python
Section titled “python”Coding rules — Python
Source: .act/coding/python.md
Summary: strict annotations, stdlib-first, data models, module layout, toolchain, tests
Rules for Python 3 with type annotations, a stdlib-first preference and automated linting. Group IDs
(CR-python-<name>) are stable and never reassigned; a group whose purpose no longer holds gets a new ID
and is listed as retired: in this header.
CR-python-basics
Section titled “CR-python-basics”Established Python defaults
Summary: annotations, f-strings, context managers, exception handling, venv, lint
- Annotate every function signature (parameters and return value), including internal/private functions.
- Use f-strings, not
%formatting or.format(). - Use
withfor anything that must be opened and closed (files, locks, connections). - Never use a mutable default argument (
def f(x: list = [])) — default toNoneand initialize inside the function body. - Catch specific exception types; never a bare
except Exceptionwithout re-raising or logging it. Every raised or logged error states what failed and with what value — a caller or log reader must find the cause without opening the source. - Use
is/is notonly for identity comparisons (None, singletons), never for values. - One virtual environment (
venv) per project, dependencies pinned in a lockfile (requirements.txt,poetry.lock); never a global install of project dependencies. - Lint is the stack’s standard and belongs in the project; run what is installed, install nothing unasked.
CR-python-stdlib-first
Section titled “CR-python-stdlib-first”Standard library before a new dependency
Summary: reach for the stdlib before adding a package
- Prefer the standard library over adding an external dependency; add one only where the stdlib genuinely falls short.
CR-python-data-models
Section titled “CR-python-data-models”Typed data instead of loose dicts
Summary: dataclasses, TypedDict or pydantic for structured data
- Model structured data with
dataclasses,TypedDictorpydantic, not a loosedict.
CR-python-module-structure
Section titled “CR-python-module-structure”One module per responsibility
Summary: module boundaries, no circular imports
- One module per functional responsibility, no catch-all module without a clear boundary.
- Resolve circular imports by fixing the module boundaries, not by working around them with deferred or local imports.
CR-python-toolchain
Section titled “CR-python-toolchain”Lint and format tooling
Summary: ruff by default for lint and formatting, or what the project has set up
rufffor both linting and formatting is the template’s usual choice;blackremains a common alternative for formatting in existing projects — either way, run what the project actually has configured (seeR-code-tools).
CR-python-tests
Section titled “CR-python-tests”Unit tests
Summary: pytest by default, or the test runner the project has set up
pytestis the template’s usual choice, with fixtures instead of repeating setup code in every test module; use the test runner the project actually has configured (seeR-code-tools).
Coding rules — SQL
Source: .act/coding/sql.md
Summary: query safety, transactions, indexing, naming, migrations
Rules for schema changes and database access from application code. Group IDs (CR-sql-<name>) are
stable and never reassigned; a group whose purpose no longer holds gets a new ID and is listed as
retired: in this header.
CR-sql-basics
Section titled “CR-sql-basics”Query safety and schema discipline
Summary: parametrized queries, transactions, UTC, indexing, no hidden logic, locking
- Use parametrized queries only — never build a query by concatenating values into the SQL string, in any language or driver.
- Never
SELECT *in application code; name columns explicitly, so a schema change breaks visibly instead of silently changing what a query returns. - Bundle multi-step writes into one transaction; don’t reconcile partial failures by hand afterward.
- Store timestamps in UTC; convert to a time zone only in the presentation layer.
- Add an index to every foreign-key column — without one, joins and cascading deletes degrade as the table grows.
- Keep application logic out of stored procedures and triggers; logic that isn’t visible in the application code isn’t reviewable.
- Check a column type change on a large table for lock behavior and expected runtime before running it live.
CR-sql-naming
Section titled “CR-sql-naming”Identifier naming
Summary: snake_case, plural tables, singular columns
- Name tables and columns in
snake_case. - Use the plural for table names, the singular for column names.
CR-sql-migrations
Section titled “CR-sql-migrations”Migration discipline
Summary: versioned naming, idempotent, reversible, one tool
- Name migrations with a version (sequence number or timestamp) plus a description; one file per change.
- Write migrations idempotently (
IF NOT EXISTSor an existence check) — running an already-migrated state again must not fail. - Ship a down-migration with every migration where the migration tool supports it.
- Use one migration tool consistently (e.g. Flyway, Prisma Migrate, Alembic); don’t mix.
tailwind
Section titled “tailwind”Coding rules — Tailwind
Source: .act/coding/tailwind.md
Summary: utility-first styling, design tokens, dark mode, class sorting
Rules for Tailwind CSS, usually applied inside a frontend framework. Group IDs (CR-tailwind-<name>) are
stable and never reassigned; a group whose purpose no longer holds gets a new ID and is listed as retired:
in this header.
CR-tailwind-basics
Section titled “CR-tailwind-basics”Established Tailwind defaults
Summary: utilities in markup, tokens, theme, dark mode, extraction, tooling, pitfalls
- Write utility classes directly in markup; no separate CSS files without a concrete reason.
- Use design tokens (the spacing, color and radius scale from the config) instead of arbitrary values —
p-[13px]only as a documented exception. - Keep theme changes (colors, fonts, breakpoints) centralized in the Tailwind config, not scattered across files.
- Map dark mode through the configured tokens/variants, never parallel hardcoded color values.
- Extract a repeated class combination into a component/partial; never copy it around as a text snippet.
- Lint/format tooling is the stack’s standard and belongs in the project:
prettier-plugin-tailwindcssfor automatic class sorting (layout, box model, typography, color, state), enforced by the formatter instead of sorted by hand. Run what is installed, install nothing unasked. - Pitfalls:
- Use
@applyonly in exceptions (e.g. base styles of a third-party component), never as the default way to style. - Keep
contentpaths in the config correct — a wrong or missing path either drops classes that are actually used or leaves unused utility classes in the build.
- Use
typescript
Section titled “typescript”Coding rules — TypeScript
Source: .act/coding/typescript.md
Summary: strict mode, no any, typed errors, module structure, tooling
Rules for TypeScript projects in strict mode. Group IDs (CR-typescript-<name>) are stable and never
reassigned; a group whose purpose no longer holds gets a new ID and is listed as retired: in this
header.
CR-typescript-basics
Section titled “CR-typescript-basics”Strict mode, narrowing, typed errors
Summary: strict, no any, return types, as/!, error handling, lint
- Enable
strict: trueintsconfig.json; loosen it only with a comment explaining why. - Never use
any— type unknown values asunknownand narrow them before use. - Draw the line where strictness stops helping: a type nested deeper than the code it describes
(heavily nested generics, chained conditional types, stretched mapped types) is worse than a
simpler one. Fall back to
unknownwith a check at the boundary, or a narrowinterfacefor just the fields used, with a comment saying why — the exception serves readability, not convenience, andanystays excluded even here. - Give exported functions an explicit return type instead of relying on inference.
- Use
as Typeonly when narrowing cannot do the job, and say why in a comment. - Never use the non-null assertion (
!) — it suppresses a real nullability check. - Raise errors as typed Error objects, never
throwan arbitrary value; whatever is thrown, logged or rethrown, its message names what failed and with what — a caller must find the cause without opening the source. - Lint and typecheck (
tsc --noEmit) are the stack’s standard and belong in the project; run what is installed, install nothing unasked.
CR-typescript-conventions
Section titled “CR-typescript-conventions”interface, type, generics
Summary: interface for shapes, type for unions, no enums, generics from second use
- Use
interfacefor object shapes/contracts,typefor unions, intersections and derived types. - Avoid enums — use
as constobjects or union literal types instead. - Introduce a generic only once a second concrete use exists; a concrete type is fine for the first.
CR-typescript-module-structure
Section titled “CR-typescript-module-structure”Central types, explicit exports
Summary: shared types in one place, public exports through an index
- Define shared types/schemas in one central place and import them, instead of redeclaring them per module.
- Expose a module’s public API through an explicit index, not deep import paths into another module.
CR-typescript-toolchain
Section titled “CR-typescript-toolchain”Lint and format tooling
Summary: ESLint with @typescript-eslint plus Prettier by default, or what the project has set up
- ESLint with
@typescript-eslintand Prettier for formatting are the template’s usual choice; what the project actually has installed and configured governs (seeR-code-tools).
Coding rules — Vue
Source: .act/coding/vue.md
Summary: composition API, typed props, SFC order, shared state, tooling
requires: typescript
Rules for Vue 3 components using the Composition API. Group IDs (CR-vue-<name>) are stable and
never reassigned; a group whose purpose no longer holds gets a new ID and is listed as retired: in
this header.
CR-vue-basics
Section titled “CR-vue-basics”Composition API, typed props, safe forms
Summary: script setup, typed props/emits, conventions, error handling, pitfalls
- Use
<script setup lang="ts">in every component; no Options API in new code. - Type
defineProps<...>()anddefineEmits<...>()— no loose object props. - Keep no business logic in the
<template>— move computations intocomputedor a method. - Choose
reffor primitive/atomic values,reactiveonly for one connected object state. - Give composables a
useXname and an explicit return type when it is not trivially inferred. - Clean up a watcher/effect that binds a resource (timer, listener) once it is no longer needed.
- Catch errors around calls in components and composables on purpose: surface them where the
template can show them, or rethrow — never swallow one silently; the message names what failed
and with what. Use
onErrorCapturedto handle a child component’s error deliberately, not as a global catch-all. - Lint is the stack’s standard and belongs in the project; run what is installed, install nothing unasked.
- Pitfalls:
- Never combine
v-ifandv-foron the same element. - Never mutate a prop directly — report a change to the parent through an event.
- Security: a form using
@submit.preventalso needsmethod="post"on the<form>element. The handler only exists once hydration finishes; a submit before that point (a password manager pressing enter, a slow connection, a blocked JS bundle) triggers the browser’s native submit. Withoutmethodthat is a GET to the current URL — a form carrying credentials puts the values in the address bar, browser history and server log. Applies to every server-rendered app, not only auth forms (see GHSA-gj2h-2fpw-fhv9, the same bug in@nuxt/uibefore 4.8.1).
- Never combine
CR-vue-sfc-order
Section titled “CR-vue-sfc-order”Fixed SFC block order
Summary: template, script setup, style
- Order SFC blocks as
<template>,<script setup>,<style>.
CR-vue-state-store
Section titled “CR-vue-state-store”Store module for shared state
Summary: Pinia store instead of provide/inject
- Keep state shared across the app in a dedicated store module (Pinia), not in
provide/inject.
CR-vue-toolchain
Section titled “CR-vue-toolchain”Lint and format tooling
Summary: ESLint with eslint-plugin-vue plus Prettier by default, or what the project has set up
- ESLint with
eslint-plugin-vueand Prettier for formatting are the template’s usual choice; what the project actually has installed and configured governs (seeR-code-tools).