| name | ts-rig |
| description | Applies a rigorous JavaScript and TypeScript development workflow focused on clean project structure, strict single responsibility, DRY design, TDD and ATDD, dependency injection, strict typing, readable error handling, and lint or static-analysis discipline. Use when implementing or repairing JS/TS business logic, tightening tests around behavior changes, removing weak types such as any, replacing hidden dependencies, cleaning up hardcoded values, or enforcing stronger code quality guardrails. |
| metadata | {"slash-command":"enabled"} |
TS Rig
Use this skill after CLAUDE.md and .claude/rules/ts-patterns.md have been loaded. Treat those as baseline project policy. Use this skill to add stricter guardrails when a JS/TS change is easy to get wrong, hard to test, or likely to spread weak patterns.
When to Use
Use this skill when:
- implementing a new feature or business logic change
- removing
any types or tightening weak types in touched code
- replacing hidden infrastructure dependencies with explicit injection
- tightening tests around behavior changes or acceptance criteria
- cleaning up hardcoded secrets, ports, or environment-specific values
- enforcing stricter code quality in a PR or code review
Operating Rules
- Inspect the nearest
package.json, lockfile, tsconfig*.json, and lint or test config before editing.
- Reuse the repo's existing scripts, frameworks, module style, and test patterns.
- Keep the diff narrow and reviewable. Avoid opportunistic refactors.
- Prefer concrete, verifiable behavior over clean-code slogans.
- Keep project structure clean, predictable, and separated by responsibility.
- Avoid adding new layers, interfaces, or helpers unless they improve correctness, testability, or reuse in the touched area.
Workflow
- Read the target files and the nearest config before deciding on structure.
- Identify the exact behavior or contract that is changing.
- For user-visible changes, write the acceptance-level test first (ATDD). For internal logic, write the smallest failing unit test first (TDD).
- Implement the smallest fix or feature that satisfies the behavior.
- Tighten types, dependency boundaries, and error handling while the code is open.
- Run the narrowest relevant verification commands and expand only if needed.
If the repo has no test framework, no manifest, or no runnable scripts, do not invent them unless the user asked for that setup. State the limitation clearly and keep the change scoped.
Testing
- ATDD first for user-visible changes:
- Express the boundary behavior (Given/When/Then or equivalent scenario)
- Add or update the acceptance-level test
- Write the next smallest failing unit test
- Implement the minimum change that makes it pass
- Refactor while green
- Repeat for the next behavior increment
- TDD is the default workflow for internal behavior changes: red, green, refactor.
- Test everything you write that changes behavior, fixes a bug, or establishes a reusable contract.
- Prefer unit tests for pure logic, integration tests for adapters and boundaries, and end-to-end tests only for user-visible flows.
- Follow the repo's existing test style for naming, fixtures, and assertions.
- Add or update tests when behavior changes. Do not add broad new test infrastructure for a small local fix.
- Use ATDD extensively for user-facing flows and acceptance criteria. Prefer Given/When/Then style scenarios when the repo already supports them.
- Do not fix unrelated failing tests unless they block the requested change.
TypeScript and JavaScript
- Prefer TypeScript for new shared logic unless the surrounding code is intentionally plain JavaScript.
- Remove
any from touched code when practical. Prefer unknown, unions, generics, or narrower interfaces.
- Narrow untrusted input at system boundaries instead of pushing loose types inward.
- Add explicit types to exported functions, public APIs, and non-obvious return values when inference is weak.
- Preserve the repo's runtime and module style. Do not mix ESM and CommonJS without a clear reason.
- Add JSDoc in
.js files only when it materially improves a public or non-obvious API.
- Keep formatting, indentation, and whitespace consistent with the repo formatter and linter.
- Prefer readable names, short functions, and obvious control flow over cleverness.
- Apply SRP strictly to functions, modules, and classes.
- Apply DRY to duplicated business rules, config, and transformations.
Dependency Boundaries
- Follow the Open/Closed Principle: prefer extension through composition, interfaces, and configuration over repeated edits to stable logic.
- Inject infrastructure dependencies when business logic would otherwise instantiate databases, HTTP clients, filesystem access, time, randomness, or external services directly.
- Pass dependencies as arguments or constructor parameters to manage code relationships cleanly.
- Keep domain logic independent from framework and I/O details where practical.
- Reuse existing abstractions before introducing a new interface or wrapper.
- Do not force constructor injection for trivial local helpers that are not real dependencies.
- Do not hardcode dependencies inside business logic.
Use this testability check:
- If the code is hard to test without network, disk, time, or process coupling, move that dependency to the boundary.
- If the code is already simple and local, do not abstract it further just to satisfy a pattern.
class OrderService {
constructor(
private readonly store: OrderStore,
private readonly clock: Clock,
) {}
async create(input: CreateOrderInput): Promise<Order> {
const now = this.clock.now();
return this.store.save({ ...input, createdAt: now });
}
}
Error Handling
- Keep error handling clear, concise, readable, and explicit.
- Fail with context at boundaries. Do not swallow errors silently.
- Preserve the original cause when wrapping errors:
new Error('context message', { cause: originalErr }).
- Return
null, undefined, or fallback values only when the contract explicitly allows it.
- Keep error messages actionable and specific enough to debug.
- Never log secrets, tokens, credentials, or sensitive payloads.
Configuration and Constants
- Move secrets, tokens, URLs, ports, and environment-specific values into the repo's existing config pattern.
- Do not hardcode values that represent business rules, environment settings, or shared behavior.
- Extract a constant when a value is reused, domain-significant, or non-obvious.
- Leave obvious single-use literals inline when extracting them would make the code harder to read.
- Reuse existing config helpers instead of creating parallel configuration paths.
Comments
- Write comments thoughtfully and only when they improve understanding.
- Prefer comments that explain why, constraints, invariants, edge cases, or tradeoffs.
- Do not write comments that merely restate the code.
- Keep public API documentation concise and accurate.
Lint and Static Analysis
- Run linting, typechecking, and any configured static-analysis tools for the touched area.
- Treat lint and static-analysis findings as required feedback to resolve or explicitly justify.
- Prefer repo scripts over handcrafted commands when both exist.
Reject These Patterns
any added or left in touched code without explicit justification
- infrastructure (HTTP clients, DB, filesystem, time, randomness) instantiated inside domain or business logic
- hardcoded secrets, tokens, ports, or environment-specific values in source files
- errors caught and swallowed silently without re-throw or structured logging
var used when const or let would be correct
- deeply nested callbacks or promise chains when
async/await would be clearer
- functions mixing multiple unrelated responsibilities
- new abstractions (interfaces, wrappers, helpers) added without an existing consumer
- snapshots or generated files updated without inspecting the semantic diff
- type assertions (
as, non-null !) used to silence type errors instead of fixing the type
- production design distorted to satisfy a test double or mock framework
Review Checklist
Success Criteria
This skill is being followed correctly when:
- behavior changes are covered by tests before the implementation ships
- types in touched code are more precise after the change, not less
- infrastructure dependencies moved to the boundary, not deeper into domain logic
- the diff is narrow, reviewable, and free of opportunistic refactors
- verification commands ran and passed for the affected scope
- hardcoded values and weak types are gone from touched code