These instructions guide coding agents to generate changes consistent with this repository's conventions, regardless of programming language.
- Tunables: user-adjustable parameters that shape behavior, exposed via options or configuration files.
- Canonical defaults: the single, authoritative definition of all tunables and their defaults.
- Before coding:
- Perform a comprehensive inventory of the codebase. Search for and read:
- README.md, CONTRIBUTING.md, and all other documentation files.
- code files related to the task.
- Identify existing code architecture, design patterns, canonical defaults, naming patterns and coding styles.
- Perform a comprehensive inventory of the codebase. Search for and read:
- When coding:
- Follow the core principles, TypeScript/Node.js and OCPP-specific conventions below.
- Follow identified design patterns, naming patterns and coding styles.
- After coding:
- Ensure changes pass quality gates below.
- When adding a tunable:
- Add to canonical defaults with safe value.
- Ensure the options and configuration section below is respected.
- Update documentation and serialization.
- When implementing analytical methods:
- Follow statistical conventions below.
- When refactoring:
- Keep public APIs stable; provide aliases if renaming unless explicitly requested.
- Update code, tests, and documentation atomically.
- When documenting:
- Follow documentation conventions below.
4 TypeScript packages (pnpm workspace: /, /ui/common, /ui/cli, /ui/web) + 1 Python project (/tests/ocpp-server). Each has its own quality gates — see sub-project READMEs.
UI Common (ui-common) is the shared library for CLI and Web UI. No re-exports between packages.
- Design patterns: prefer established patterns (e.g., factory, singleton, strategy) for code organization and extensibility.
- Algorithmic: prefer algorithms or heuristics solving the problem while minimizing time and space complexity.
- DRY: avoid duplication of logic, data, and naming. Factor out commonalities.
- Single source of truth: maintain a canonical defaults map for configuration tunables. Derive all user-facing options automatically.
- Naming coherence: prefer semantically accurate names across code, documentation, directories, and outputs. Avoid synonyms that create ambiguity.
- English-only: code, tests, logs, comments, and documentation must be in English.
- Small, verifiable changes: prefer minimal diffs that keep public behavior stable unless explicitly requested.
- Tests-first mindset: add or update minimal tests before refactoring or feature changes. Follow test conventions in
tests/TEST_STYLE_GUIDE.md. - Documentation standards: must follow established standards for programming languages.
- Dynamic generation: derive CLI and configuration options automatically from canonical defaults. Avoid manual duplication.
- Merge precedence: defaults < user options < explicit overrides (highest precedence). Never silently drop user-provided values.
- Validation: enforce constraints (choices, ranges, types) at the option layer with explicit typing.
- Help text: provide concrete examples for complex options, especially override mechanisms.
- Hypothesis testing: use a single test statistic (e.g., t-test) when possible.
- Divergence metrics: document direction explicitly (e.g., KL(A||B) vs KL(B||A)); normalize distributions; add numerical stability measures.
- Effect sizes: report alongside test statistics and p-values; use standard formulas; document directional interpretation.
- Distribution comparisons: use multiple complementary metrics (parametric and non-parametric).
- Multiple testing: document corrections or acknowledge their absence.
- Structure: start with run configuration, then stable section order for comparability.
- Format: use structured formats (e.g., tables) for metrics; avoid free-form text for data.
- Interpretation: include threshold guidelines; avoid overclaiming certainty.
- Artifacts: timestamp outputs; include configuration metadata.
- Clarity: plain, unambiguous language; avoid marketing jargon and speculation.
- Concision: remove boilerplate; state facts directly without redundant phrasing.
- Structure: use consistent section ordering; follow stable patterns for comparable content.
- Timeliness: document current state; exclude historical evolution (except brief API breaking change notes).
- Terminology: use correct and consistent terminology; distinguish clearly between related concepts.
- Exhaustivity: cover all user-facing behavior and constraints; omit internal implementation details unless necessary for usage.
- Pertinence: include information that aids understanding or usage; remove tangential content.
- No duplication: maintain single authoritative documentation source; reference other sources rather than copying.
Documentation serves as an operational specification, not narrative prose.
- Naming: Use camelCase for variables/functions/methods, PascalCase for classes/types/enums/interfaces.
- Async operations: Prefer async/await over raw Promises; handle rejections explicitly with try/catch.
- Error handling: Use typed errors (BaseError, OCPPError) with structured properties; avoid generic Error.
- Worker communication: Use broadcast channels for decoupled worker<->main thread messaging.
- Null safety: Avoid non-null assertions (!); use optional chaining (?.) and nullish coalescing (??).
- Type safety: Prefer explicit types over any; use type guards and discriminated unions where appropriate.
- Promise patterns: Return Promises from async operations; store resolvers/rejectors in Maps for request/response flows.
- Immutability: Avoid mutating shared state; clone objects before modification when needed.
- Naming: Use snake_case for variables/functions/methods/modules, PascalCase for classes, SCREAMING_SNAKE_CASE for constants.
- Type hints: Annotate all function signatures; use
mypywith the strict-like configuration defined inpyproject.toml. - Enumerations: Prefer
StrEnumfor string-valued enumerations. - Async operations: Prefer async/await with
asyncio; handleCancelledErrorand cleanup explicitly. - Error handling: Use specific exception types; avoid bare
except. - Formatting and linting: Use
rufffor formatting and linting; follow rules configured inpyproject.toml. - Testing: Use
pytestwithpytest-asyncio; useasync def test_*naming, plainassert, andpytest.raisesfor error cases.
- Command naming: Follow OCPP standard naming exactly (e.g., RemoteStartTransaction, BootNotification, StatusNotification).
- Enumeration naming: Use standard OCPP specifications enumeration names and values exactly (e.g., ConnectorStatusEnumType with values Available, Occupied). Avoid string literals when an enumeration exists.
- Version handling: Clearly distinguish between OCPP 1.6 and 2.0.x implementations in separate namespaces/files.
- Payload validation: Validate against OCPP JSON schemas when ocppStrictCompliance is enabled.
- Message format: Use standard SRPC format: [messageTypeId, messageId, action, payload] or [messageTypeId, messageId, payload].
- UUID tracking: Use UUIDs to correlate requests with responses; store pending operations in Maps with UUID keys.
- Response handling: Ensure to wait for all expected responses before resolving broadcast requests.
Each sub-project has its own quality gates (format, typecheck, lint, build, test). See sub-project READMEs for exact commands. Run gates for every sub-project affected by your changes.
- Logs use appropriate levels (error, warn, info, debug).
- Pull request title and commit messages follow Conventional Commits format.
Good (consistent style, clear semantics):
const thresholdValue = 0.06
const processingMode = 'piecewise'
type ChargingStationStatus = 'Available' | 'Preparing' | 'Charging'Bad (mixed styles, ambiguous):
const threshold_value = 0.06 // inconsistent case style
const thresholdAim = 0.06 // synonym creates ambiguity
type charging_station_status // wrong casing for typeGood (proper async flow):
protected handleProtocolRequest(
uuid: string,
procedureName: ProcedureName,
payload: RequestPayload
): Promise<ResponsePayload> {
return new Promise<ResponsePayload>((resolve, reject) => {
this.pendingRequests.set(uuid, { reject, resolve })
this.sendBroadcastChannelRequest(uuid, procedureName, payload)
})
}Bad (returns void, no Promise):
protected handleProtocolRequest(
uuid: string,
procedureName: ProcedureName,
payload: RequestPayload
): void {
this.sendBroadcastChannelRequest(uuid, procedureName, payload)
// Response never reaches caller!
}| Metric | Value | Interpretation |
| ----------- | ----- | --------------------- |
| KL(A‖B) | 0.023 | < 0.1: low divergence |
| Effect size | 0.12 | small to medium |By following these instructions, coding agents should propose changes that are consistent and maintainable across languages.