Install Anti-Slop Oxlint Rules
dmmulroy/anti-slop
Installs, updates or migrates the vendored anti-slop Oxlint plugin in a repository, keeping local rule changes and the plugin's license and provenance files.
Correct-by-construction TypeScript standards. An agent skill from dmmulroy/skills.
$ npx skills add dmmulroy/skills --skill coding-standards -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install dmmulroy/skills coding-standards --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/dmmulroy/skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/coding-standards .claude/skills/coding-standards && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "coding-standards" agent skill from https://github.com/dmmulroy/skills/tree/main/coding-standards into .claude/skills/coding-standards/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "coding-standards", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/dmmulroy/skills/tree/main/coding-standardsType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add dmmulroy/skills --skill coding-standards -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install dmmulroy/skills coding-standards --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/dmmulroy/skills.git skills-src && mkdir -p .agents/skills && cp -r skills-src/coding-standards .agents/skills/coding-standards && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "coding-standards" agent skill from https://github.com/dmmulroy/skills/tree/main/coding-standards into .agents/skills/coding-standards/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "coding-standards", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add dmmulroy/skills --skill coding-standards -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install dmmulroy/skills coding-standards --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/dmmulroy/skills.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/coding-standards .cursor/skills/coding-standards && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "coding-standards" agent skill from https://github.com/dmmulroy/skills/tree/main/coding-standards into .cursor/skills/coding-standards/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "coding-standards", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/dmmulroy/skills.git --path coding-standards--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add dmmulroy/skills --skill coding-standards -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install dmmulroy/skills coding-standards --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/dmmulroy/skills.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/coding-standards .gemini/skills/coding-standards && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "coding-standards" agent skill from https://github.com/dmmulroy/skills/tree/main/coding-standards into .gemini/skills/coding-standards/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "coding-standards", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install dmmulroy/skills coding-standardsInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add dmmulroy/skills --skill coding-standards -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/dmmulroy/skills.git skills-src && mkdir -p .github/skills && cp -r skills-src/coding-standards .github/skills/coding-standards && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "coding-standards" agent skill from https://github.com/dmmulroy/skills/tree/main/coding-standards into .github/skills/coding-standards/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "coding-standards", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add dmmulroy/skills --skill coding-standards -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install dmmulroy/skills coding-standards --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/dmmulroy/skills.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/coding-standards .opencode/skills/coding-standards && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "coding-standards" agent skill from https://github.com/dmmulroy/skills/tree/main/coding-standards into .opencode/skills/coding-standards/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "coding-standards", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
coding-standardsCorrect-by-construction TypeScript standards. An agent skill from dmmulroy/skills.
Coding Standards is an agent skill from dmmulroy/skills. Correct-by-construction TypeScript standards. Use for TypeScript engineering or when another skill needs the user's coding standards.
Its SKILL.md is about 8.3k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Development, covering Code quality. It works with TypeScript. The licence is MIT.
6 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit 8603380. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
No scripts in the folder and no shell commands in SKILL.md (its code samples are typescript).
From the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Coding Standards loads about 8.3k tokens when it runs. Until then it costs about 38 tokens; SKILL.md has 3,778 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from dmmulroy/skills at commit 8603380, republished under its MIT licence (© dmmulroy). 3,778 words, ~8,318 tokens.
.claude/skills/coding-standards/SKILL.md (or your agent's skills folder).These standards describe how to design and write TypeScript code in this codebase. They are especially intended for agents: inspect existing code before adding patterns, libraries, Adapters, or abstractions, but apply these standards to all new and refactored behavior. Follow existing conventions only when they are compatible with these standards.
When rules pull in different directions, use this order:
throw / rejected promises for expected failures.Before adding a new pattern or library, inspect the repo for existing choices around:
Apply these standards to all new code and to the full behavior being refactored. Do not preserve weaker patterns merely for consistency. Keep unrelated old code unchanged and translate incompatible patterns at the nearest boundary.
For example, if existing code uses exception-style errors, do not rewrite the whole system for an unrelated change. Represent known failures as typed values in new or refactored code, then translate them at the boundary into the outcome required by the existing framework. Preserve existing logging, tracing, metrics, and error-reporting hooks.
Every known failure mode should appear in the return type as a custom tagged error, even when the immediate caller cannot recover. A caller must handle the error or return it upward. At the outermost boundary, translate it into a valid outcome such as an HTTP response, CLI exit code, retry decision, dead letter, or startup error message.
Known failures include domain, parsing, authorization, integration, I/O, persistence, configuration, and workflow failures.
Preferred order:
better-result, when available and appropriate.type Result<T, E extends Error> =
| { readonly _tag: "ok"; readonly value: T }
| { readonly _tag: "err"; readonly error: E };Prefer:
Promise<Result<User, UserLookupError>>not:
Promise<User> // rejects for ordinary lookup/storage failuresPromise rejection is equivalent to throwing. Catch unclassified third-party rejection inside the owning Adapter and translate it into a known tagged error before it crosses the Adapter boundary. Rejection may escape application code only for a defect.
Throw or panic only when a defect makes correct execution impossible, not merely because the current caller has no recovery strategy. Defects include:
notYetImplemented pathsKnown configuration failures are values; the composition root reports them safely and terminates startup.
Use established shared defect helpers where available, or the panic helper from the project's result library:
export function casesHandled(unexpectedCase: never): never;
export function shouldNeverHappen(msg?: string): never;
export function notYetImplemented(msg?: string): never;Use casesHandled for exhaustive union handling. Avoid names like absurd or one-off assertNever helpers when the project already has these helpers.
Expected failures should use custom tagged errors, generally extending:
ErrorTaggedError from better-resultSchema.TaggedErrorClass in Effect codebasesCustom errors should include:
cause: unknownExample:
export class UserStoreUnavailable extends Error {
readonly _tag = "UserStoreUnavailable" as const;
constructor(
readonly operation: "findActiveByEmail",
readonly provider: "postgres",
readonly cause: unknown,
) {
super(`User store unavailable during ${operation}`);
}
}Keep error unions precise at module boundaries:
Result<User, UserNotFound | UserStoreUnavailable>Avoid broad AppError-style types except near entrypoints, orchestration, logging, and rendering layers.
Prefer end-to-end structured tracing across requests, jobs, workflows, application modules, adapters, and external calls.
Tracing/logging should make failures diagnosable with safe fields:
Do not put secrets in errors, traces, logs, or snapshots.
Use a Redacted<T> wrapper for sensitive values such as tokens, API keys, passwords, raw credentials, and secrets. Prefer Effect's Redacted.Redacted in Effect codebases or a local shared Redacted<T> wrapper.
Wrap sensitive values at the boundary and unwrap only where the raw value is needed, usually inside an adapter making an external call.
Boundary code should turn unknown or less-structured input into application or domain types before it enters inner code.
Use a separate protocol projection only when its shape or meaning differs enough to be useful. DTO describes a boundary role in prose; never use DTO or Dto in a symbol name. Name the symbol after its actual protocol or persistence meaning, such as CreateUserRequest, StripeCustomerResponse, or UserRecord:
unknown -> CreateUserRequest -> CreateUserInput -> EmailAddress/UserId/etc.Otherwise, parse directly into the application input:
unknown -> CreateUserInputDo not pass a schema-inferred transport shape throughout the application:
unknown -> z.infer<typeof CreateUserSchema>Use names that preserve meaning:
parseX(input): Result<X, ParseXError> for untrusted or less-structured inputmakeX(...) / createX(...) for smart constructors from already-typed piecesisX(value): value is X for true predicatesassertX(...) rarely, mostly at tests/framework boundariesAvoid validateX when the function returns a refined value. It parsed something.
Use schema libraries as boundary parsers, not as ad-hoc validators sprinkled through core logic.
Preference:
Schema parsing should produce refined/domain types and typed custom errors where practical.
Use branded/refined types when they prevent realistic misuse or invalid construction, especially for:
UserId, OrgId, WorkflowIdEmailAddress, NonEmptyString, UrlPositiveInt, Cents, PercentageMilliseconds, Bytes, UsdCentsConstruct branded values through parsers or smart constructors. Avoid passing raw strings/numbers where a domain type exists.
Avoid optional/null/undefined values in functions that require a value. Push optionality outward. Branch or parse before calling.
Avoid Partial<T> as an application/domain input unless partiality is the real domain concept. Prefer explicit input types for each operation.
When an entity has meaningful lifecycle states, model them with tagged unions or equivalent value classes.
Prefer:
type Invoice =
| { readonly _tag: "Draft"; readonly id: InvoiceId; readonly lines: NonEmptyArray<LineItem> }
| { readonly _tag: "Sent"; readonly id: InvoiceId; readonly sentAt: Instant }
| { readonly _tag: "Paid"; readonly id: InvoiceId; readonly paidAt: Instant };Avoid:
type Invoice = {
readonly isSent: boolean;
readonly isPaid: boolean;
readonly sentAt?: Date;
readonly paidAt?: Date;
};Avoid boolean parameters that control behavior:
createUser(input, true);Prefer named options or domain types:
createUser(input, { emailVerification: "skip" });Booleans are fine as clear predicate return values:
isExpired(token): boolean;
hasPermission(user, permission): boolean;Domain Module, Application Service Module, and Adapter Module name responsibilities, not required folders, suffixes, or TypeScript constructs. A module may be a function, object, class, file, or package with a cohesive public interface. Use the roles at any scale; do not create three layers when the behavior does not need them.
The normal dependency and call flow for an operation with application policy or effects is:
external input -> inbound Adapter -> Application Service -> Domain Module
|
+-> application-owned port
-> outbound Adapter -> external systemAn inbound Adapter may call a Domain Module directly only for a pure operation with no authorization, application policy, persistence, external calls, or effect sequencing:
external input -> inbound Adapter -> Domain ModuleThe composition root constructs concrete Adapters and supplies them to Application Services. Dependencies point inward: Domain Modules know neither services nor Adapters; Application Services know application-owned port contracts, not concrete technologies; Adapters depend on those contracts and translate at the edge.
Classify code by the responsibility that would make it change:
Split an abstraction when it owns more than one of these reasons to change. Do not split code merely to satisfy the taxonomy: a pure operation may need only a Domain Module, while a simple boundary may call an Application Service with no new domain type.
For a new feature or a local refactor:
Apply these responsibilities inside the project's existing layout and framework vocabulary. Migrate mixed code only across the feature's required semantic surface; otherwise contain the old convention at an Adapter seam rather than forcing a broad rewrite.
For example, in password reset: EmailAddress and ResetToken are Domain Modules; PasswordReset is the Application Service; an HTTP route is an inbound Adapter; Postgres and email-provider implementations are outbound Adapters; bootstrap performs the wiring.
A deep module hides substantial behavior, invariants, policy, sequencing, or translation behind a cohesive, low-burden interface. Low-burden does not necessarily mean few functions.
Avoid shallow abstractions that merely forward calls, mirror tables, rename another API, or expose implementation steps.
Use the deletion test:
A Domain Module is a pure, type-centric abstract data type in the OCaml tradition. It centers one primary domain type or tightly related type family and owns what values mean and which operations are legal.
Use one when the code has a meaningful domain distinction, invariant, calculation, decision, or lifecycle. Keep a primitive or local pure function when introducing a domain abstraction would prevent no realistic misuse and centralize no meaningful rule.
A Domain Module should:
It may define pure permission decisions over parsed domain values. It should not authenticate callers, gather authorization context, enforce permissions while carrying out an application operation, choose effect order, query storage, call a network, or expose transport/persistence DTOs. Callers use its operations instead of recreating its checks or branding values with casts.
Example:
// email-address.ts
/** A parsed, normalized email address. */
export type EmailAddress = Brand<string, "EmailAddress">;
/** Parse an email address from untrusted input. */
export function parse(input: string): Result<EmailAddress, InvalidEmailAddress>;
/** Render an email address as a string. */
export function toString(email: EmailAddress): string;
/** Compare two email addresses for equality. */
export function equals(left: EmailAddress, right: EmailAddress): boolean;Domain Modules may use plain functions, immutable value classes, or static-style classes when cohesive. If using classes:
parse / make / smart constructorsAn Application Service Module owns one cohesive application operation or capability, such as PasswordReset, Invitations, or SubscriptionLifecycle. It applies application policy and sequences effects through narrow, application-owned ports while delegating intrinsic business rules to Domain Modules.
Use one when an operation must coordinate authorization, domain decisions, persistence, external calls, transactions, messages, time, IDs, or telemetry—or when the same operation must be callable from multiple entrypoints. A direct Domain Module call is enough when no application policy or effect orchestration exists.
An Application Service should:
It should not parse protocol envelopes, render responses, execute SQL, translate vendor DTOs, or duplicate Domain Module invariants. Prefer constructor injection for dependency-bearing classes; in Effect codebases, use services/tags/layers. Avoid dependency bags passed into every call.
There is no arbitrary method limit. Split methods that represent unrelated capabilities, change for different reasons, or require unrelated dependencies. Avoid vague names such as Manager, Processor, Helper, or generic UserService unless established by the project.
An Adapter Module owns one boundary's translation and technology mechanics. Use one whenever application code crosses a framework, protocol, serialization, process, persistence, runtime, or third-party boundary.
There are two directions:
An Adapter should own schema/DTO translation, framework lifecycle, external error classification, and safe diagnostics for its boundary. It may retry a short-lived technical failure only when the operation is safely repeatable and the retry does not change the port's meaning. It should not decide business eligibility, authorization policy, legal state transitions, or application-operation ordering. Keep raw external types inside the Adapter or composition root.
A port is not an Adapter. A port is the application-owned contract that states what an operation needs; an outbound Adapter is one replaceable implementation. Do not add an Adapter that only forwards the same shape to another internal module without hiding real translation or mechanics.
The composition root parses environment and configuration, acquires resources, constructs concrete Adapters, and injects them into Application Services. Keep framework bindings and concrete wiring here; do not turn the composition root into a place for domain rules, application policy, or reusable boundary translation.
Define ports beside the Application Service that needs them and in the application's language, not the provider's language. Depend on the smallest meaningful capability the operation uses; let a cohesive concrete Adapter be wider. Port inputs, outputs, and errors must be application/domain types rather than raw rows, SDK objects, or framework values.
Because TypeScript is structurally typed, this works well:
type UsersForPasswordReset = {
findActiveByEmail(email: EmailAddress): Promise<Result<ActiveUser, UserLookupError>>;
};
export class PasswordReset {
constructor(private readonly users: UsersForPasswordReset) {}
}A wider adapter can satisfy it:
export class PostgresUsers {
findActiveByEmail(...) { ... }
findById(...) { ... }
updateProfile(...) { ... }
}This avoids both mega-repositories and one-method adapter sprawl.
Before creating a new adapter or service, agents must audit existing adapters/services.
Prefer, in order:
Do not require an ADR for a routine feature-level Adapter or Application Service. Create an ADR when the new module introduces a lasting architectural boundary, shared pattern, provider strategy, or deliberate exception to these standards. The ADR should explain:
Avoid repository-per-table by default.
Repository-like adapters are acceptable when they represent a cohesive domain persistence capability. They should expose meaningful domain operations and return parsed domain types / typed errors, not raw rows and ORM errors.
Treat raw database rows and ORM models as infrastructure DTOs. Parse them before application/core logic. Keep SQL/ORM details inside infrastructure adapters or persistence modules.
Domain Modules form the functional core. Application Service Modules and Adapter Modules form the imperative shell, but only Adapters contain technology-specific concerns. This keeps the same application operation reusable across REST, CLI, GraphQL, workers, and other entrypoints.
The functional core contains domain parsers, invariants, state transitions, calculations, combinators, and decision functions. It avoids I/O, hidden dependencies, ambient time/randomness, thrown expected failures, and framework-specific concerns.
The imperative shell has two distinct responsibilities:
Entrypoint Adapters should be thin protocol translation layers. They parse protocol-specific input, call Domain Module parsers to obtain refined values, invoke an Application Service when application policy or effects are involved, and render protocol-specific output. A pure operation may call a Domain Module directly as described above. Do not duplicate business rules in controllers, resolvers, commands, or handlers.
Within authentication and authorization, inbound Adapters verify boundary credentials and produce a parsed identity such as Principal, Session, or CommandActor. Domain Modules may define pure permission decisions over parsed domain values. Application Services gather the required context and enforce those decisions while carrying out an application operation. Adapters project missing or invalid credentials and denied operations into protocol-specific outcomes; they do not define permission policy.
Use ordinary function calls or database transactions for simple single-boundary operations.
Use a saga or durable workflow when progress must survive process loss or redelivery, or when the operation requires long delays, compensation, resumability, timers, human approval, cross-service coordination, or multiple transaction boundaries. A short-lived retry by itself does not require durable workflow machinery.
Adapters own safe, short-lived technical retries. Application Services decide whether an application operation should be attempted again. Durable workflows own retries that must survive crashes, delays, or redelivery.
Do not hold database transactions open across network calls or long-running operations.
Any externally observable mutation or state transition that may be retried needs an explicit idempotency strategy:
Retrying should not rely on “probably safe” side effects.
Add an end-to-end test whenever the behavior can be exercised through its real public entrypoint in the normal test environment without unreliable third parties or unreasonable setup, runtime, or cost. Add lower-level tests when they provide extra coverage for important cases.
Prefer confidence-oriented tests:
Never use vi.mock or jest.mock for module mocking. Use real seams:
Prefer tests that assert observable input/output behavior:
Avoid spy-driven tests like expect(sendEmail).toHaveBeenCalledWith(...) unless the interaction itself is the only observable behavior.
For persistence behavior, prefer SQLite/local DB-backed tests over hand-rolled in-memory fakes when SQL/schema/transaction behavior matters.
Use fast-check where properties are clearer than examples, especially for:
Use arbitraries for mock/test data generation. Prefer exporting arbitraries near the domain module they support:
src/billing/
invoice-number.ts
invoice-number.test.ts
invoice-number.arbitrary.tsTests should not bypass parsers, smart constructors, or invariants.
Use strict TypeScript settings where practical:
strict: truenoUncheckedIndexedAccess: trueexactOptionalPropertyTypes: truenoImplicitOverride: truenoFallthroughCasesInSwitch: truePrefer immutable values:
type CreateUserInput = {
readonly email: EmailAddress;
readonly roles: ReadonlyArray<Role>;
};Mutation is acceptable inside localized imperative shell code, performance-sensitive internals, builders, or adapters when hidden behind a precise interface.
any, and non-null assertionsAvoid:
any!)as Typeas const is fine.
Rare exceptions are allowed for highly generic helpers, branding internals, interop boundaries, or combinators where TypeScript cannot express the invariant.
Any non-as const cast requires a Rust-like safety comment:
// SAFETY: TypeScript cannot express the brand. parseEmailAddress checked the normalized string before branding. Callers cannot construct EmailAddress except through this parser.
return normalized as EmailAddress;Rare any also requires a targeted oxlint ignore and justification:
// oxlint-disable-next-line no-explicit-any -- SAFETY: This helper preserves arbitrary function parameters; TypeScript cannot express this variadic constraint without any.
type Fn = (...args: any[]) => unknown;Do not use !. Branch, parse, or refine instead.
Prefer direct imports from the file that owns the abstraction. Avoid barrel files / index.ts re-export layers by default.
For domain modules, namespace imports often preserve the module shape:
import * as EmailAddress from "./email-address";
EmailAddress.parse(input);Use named imports for classes and focused shared helpers:
import { PasswordReset } from "./password-reset";Use import type / export type for type-only imports and exports.
Export only what callers should use. Keep internal helpers unexported unless intentionally shared. Do not export internals just for tests.
Avoid TypeScript namespace unless there is a compelling interop reason.
Avoid vague files:
utils.ts
helpers.ts
common.ts
misc.tsUse precise names:
email-address.ts
billing-period.ts
string-case.ts
array.tsTiny ubiquitous generic helpers/types may share one explicit module when no more precise owner exists. Appropriate contents include:
casesHandledshouldNeverHappennotYetImplementedRedactedTags, ExtractTag, and ExcludeTagResult helpers when the project uses neither Effect nor better-resultKeep only helpers justified by the target project. Keep domain and application policy with their owning modules.
No arbitrary file-size limits. Prefer cohesion and discoverability over small files for their own sake. Split when a file has multiple unrelated reasons to change or callers must understand unrelated concepts.
Comments should explain invariants, trade-offs, non-obvious domain rules, and safety justifications. Avoid comments that narrate obvious code.
Every exported symbol from a JavaScript or TypeScript module requires JSDoc. Public methods and properties of an exported class also require JSDoc. Private and otherwise internal code requires documentation only when its complexity warrants it. Put documentation on the original declaration; re-exports do not need duplicate documentation.
Do not use @inheritDoc, @inherit, or similar inheritance tags. Write the required documentation explicitly on each symbol or member.
Use standard JSDoc syntax:
/**
* Parse an email address from untrusted input.
*
* @param input - The untrusted string to parse.
* @returns A parsed email address, or `InvalidEmailAddress` when the input is invalid.
*/
export function parse(input: string): Result<EmailAddress, InvalidEmailAddress>;For generics:
/**
* Map the success value of a result.
*
* @template T - The original success type.
* @template U - The mapped success type.
* @template E - The error type.
* @param result - The result to map.
* @param fn - The function applied to the success value.
* @returns A result with the mapped success value, or the original error.
*/
export function map<T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E>;Use @throws only for unrecoverable defects, framework-required behavior, or temporary notYetImplemented paths. Do not document expected typed errors as throws.
For complex exported object types, document fields when helpful:
/** Input required to create a user. */
export type CreateUserInput = {
/** The actor creating the user. */
readonly actor: AdminUser;
/** The parsed email address for the new user. */
readonly email: EmailAddress;
};Parse environment/config at startup or the earliest boundary into typed config with branded/redacted values where appropriate. Return known configuration failures as tagged error values. The composition root should report a safe startup message and terminate rather than treating invalid configuration as an internal defect.
Do not read process.env throughout the app. Missing or invalid config is a startup failure with useful, safe context.
Avoid top-level side effects except in true entrypoint/bootstrap files. Modules should not start servers, open connections, read env, register handlers, or perform I/O at import time.
Resource creation and cleanup should be explicit and owned by bootstrap/imperative shell code or Effect layers when using Effect.
Avoid mutable singletons/global state. Constants and pure lookup tables are fine. If a singleton is required by a framework/runtime, isolate it at the boundary.
Inject Clock / Random services into dependency-bearing modules. Pure domain functions may accept explicit now / random values.
Before coding:
Partial<T> in core/application logic.fast-check arbitraries for generated test data when practical.© dmmulroy, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in coding-standards of dmmulroy/skills.
Open the folder on GitHubat commit 8603380
Coding Standards next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Coding Standards this skilldmmulroy/skills | 429 | — | ~8.3k | Automated safety check: Pass | MIT | |
| Install Anti-Slop Oxlint Rulesdmmulroy/anti-slop | 5.2k | — | ~2.2k | Automated safety check: Pass | MIT | |
| Code Reviewerjewbetcha/opentrace | 116 | 2 repos | ~1.1k | Automated safety check: Notes | MIT | |
| Coding Standardskurealnum/dotfiles | 290 | 17 repos | ~2.9k | Automated safety check: Pass | None | |
| Code Qualityredis/RedisInsight | 8.9k | — | ~1.2k | Automated safety check: Pass | Custom licence | |
| Cross-Language Coding Standardszereight/gitlab-mcp | 2k | 1 repos | ~1.4k | Automated safety check: Pass | MIT |
dmmulroy/anti-slop
Installs, updates or migrates the vendored anti-slop Oxlint plugin in a repository, keeping local rule changes and the plugin's license and provenance files.
jewbetcha/opentrace
Comprehensive code review skill for TypeScript, JavaScript, Python, Swift, Kotlin, Go.
kurealnum/dotfiles
Universal coding standards, best practices, and patterns for TypeScript, JavaScript, React, and Node.js development.
redis/RedisInsight
Code-quality standards for RedisInsight: TypeScript strictness, naming conventions (camelCase, PascalCase, UPPERSNAKECASE), linting rules, no any without reason, no !important in styles, and…
zereight/gitlab-mcp
Shared reference for naming, function size, complexity and error handling rules that reviewer agents apply across TypeScript, Python, Go, Rust, Java, C# and Swift.
kucherenko/jscpd
Removes copy-paste duplication found by jscpd, starting with exact clones and hotspots, then renamed and near-miss copies, using proven refactoring strategies.
dmmulroy/skills
Design Effect services. An agent skill from dmmulroy/skills.
dmmulroy/skills
Composition roots for Hono and Cloudflare. An agent skill from dmmulroy/skills.
dmmulroy/skills
Control Herdr, a terminl multiplexer for coding agents. An agent skill from dmmulroy/skills.
dmmulroy/skills
Prelude bootstrapping for TypeScript. An agent skill from dmmulroy/skills.
dmmulroy/skills
Write a typed call-stack architecture handoff. An agent skill from dmmulroy/skills.
Works with
Categories
Correct-by-construction TypeScript standards. An agent skill from dmmulroy/skills. Coding Standards is an agent skill from dmmulroy/skills. Correct-by-construction TypeScript standards.
Coding Standards fits situations like: typeScript engineering; another skill needs the users coding standards.
Run `npx skills add dmmulroy/skills --skill coding-standards -a claude-code`. Or copy the skill folder (coding-standards in dmmulroy/skills) into .claude/skills/coding-standards in your project. Claude Code loads it when a task matches its description.
Run `npx skills add dmmulroy/skills --skill coding-standards -a codex`. Or copy the skill folder (coding-standards in dmmulroy/skills) into .agents/skills/coding-standards in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add dmmulroy/skills --skill coding-standards -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/coding-standards, .gemini/skills/coding-standards, .github/skills/coding-standards and .opencode/skills/coding-standards in your project.
SKILL.md names no scripts, command-line tools or credentials: Coding Standards is instructions for the agent only.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Coding Standards is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 8.3k tokens (SKILL.md is roughly 33k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Coding Standards: Install Anti-Slop Oxlint Rules (dmmulroy/anti-slop, 5.2k stars), Code Reviewer (jewbetcha/opentrace, 116 stars), Coding Standards (kurealnum/dotfiles, 290 stars) and Code Quality (redis/RedisInsight, 8.9k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
dmmulroy (a GitHub user) maintains it in dmmulroy/skills, which has 429 GitHub stars. The repository holds 6 skills in this directory. The repository was last updated on July 23, 2026.
Source: dmmulroy/skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.