From typescript
ALWAYS invoke this skill when writing or fixing implementation code for TypeScript.
How this skill is triggered — by the user, by Claude, or both
Slash command
/typescript:coding-typescriptThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Invoke the `typescript:standardizing-typescript` skill before proceeding. If that skill is unavailable, report the missing skill and continue with the closest available workflow.
Invoke the typescript:standardizing-typescript skill before proceeding. If that skill is unavailable, report the missing skill and continue with the closest available workflow.
Invoke the typescript:standardizing-typescript-tests skill before proceeding. If that skill is unavailable, report the missing skill and continue with the closest available workflow.
<accessing_skill_files> When this skill is invoked, Claude Code provides the base directory in the loading message:
Base directory for this skill: {skill_dir}
Use this path to access skill files:
{skill_dir}/references/{skill_dir}/workflows/IMPORTANT: Do NOT search the product directory for skill files. </accessing_skill_files>
<reference_loading>
Standards are pre-loaded above. Check for spx/local/typescript.md and spx/local/typescript-tests.md at the repository root and apply each file that exists as repo-local routing to the product's governing specs and decisions. A local overlay supplements skill behavior; it does not declare product truth.
</reference_loading>
<essential_principles> NO MOCKING. DEPENDENCY INJECTION. BEHAVIOR ONLY. TEST FIRST.
strict: true, no any without justification</essential_principles>
<mandatory_code_patterns> These patterns are enforced by the reviewer. Violations will be REJECTED.
All literal values (strings, numbers) must be module-level constants:
// ❌ REJECTED: Magic values inline
function validateScore(score: number): boolean {
return score >= 0 && score <= 100;
}
// ✅ REQUIRED: Named constants
const MIN_SCORE = 0;
const MAX_SCORE = 100;
function validateScore(score: number): boolean {
return score >= MIN_SCORE && score <= MAX_SCORE;
}
Share constants between code and tests — tests import from the module under test:
// src/scoring.ts
export const MIN_SCORE = 0;
export const MAX_SCORE = 100;
// spx/.../tests/scoring.mapping.l1.test.ts
import { MIN_SCORE, validateScore } from "@/scoring";
it("rejects below minimum", () => {
expect(validateScore(MIN_SCORE - 1)).toBe(false);
});
External dependencies must be injected, not imported directly:
// ❌ REJECTED: Direct import
import { execa } from "execa";
async function syncFiles(src: string, dest: string): Promise<boolean> {
const result = await execa("rsync", [src, dest]);
return result.exitCode === 0;
}
// ✅ REQUIRED: Dependency injection
interface SyncDeps {
execa: typeof execa;
}
async function syncFiles(
src: string,
dest: string,
deps: SyncDeps,
): Promise<boolean> {
const result = await deps.execa("rsync", [src, dest]);
return result.exitCode === 0;
}
</mandatory_code_patterns>
<hierarchy_of_authority> Where to look for guidance, in order of precedence:
| Priority | Source | What It Provides |
|---|---|---|
| 1 | docs/, README.md | Product architecture, design decisions, intended APIs |
| 2 | CLAUDE.md | Product-specific rules for Claude |
| 3 | ADRs/PDRs, specs | Documented decisions and requirements |
| 4 | This skill (SKILL.md) | Generic TypeScript best practices |
| 5 | Existing code (reference) | Evidence of implementation, NOT authority |
CRITICAL: Existing code is NOT authoritative.
Never copy patterns from existing code without verifying they match documented intent.
</hierarchy_of_authority>
<codebase_discovery> BEFORE writing any code, discover what already exists.
Run these searches before implementation:
# 1. Read product documentation
Read: README.md, docs/, CLAUDE.md, CONTRIBUTING.md
# 2. Load the authoritative methodology
Read: relevant skills and spec docs before inferring any convention
# 3. Check available dependencies (don't add what exists)
Read: package.json → dependencies, devDependencies
# 4. Locate concrete artifacts to reuse
Glob/Grep: actual modules, harnesses, fixtures, registries, and entrypoints
# 5. Confirm local file placement
Read: existing files in the same directory you'll write to
| Question | How to Answer It |
|---|---|
| What conventions govern this work? | Read the relevant skill, spec, ADR/PDR, CLAUDE.md, and product docs first |
| What libraries are available? | package.json → dependencies |
| What concrete modules already exist to reuse? | Glob/Grep for actual modules, registries, harnesses, fixtures, and helpers |
| What error classes already exist? | Locate existing error modules; do not infer policy from random call sites |
| What logging facility already exists? | Locate the logger module or logging package, then follow documented rules |
| How are configs structured? | Find config modules and config docs; do not infer config policy from ad hoc use |
| If this is a script, which arg parser is canonical? | Read package.json, docs, and existing checked-in scripts/ entrypoints |
// ❌ WRONG: Adding lodash when ramda is already used
import _ from "lodash"; // package.json has ramda, not lodash
// ❌ WRONG: Creating new logger when one exists
const logger = console; // Product has @lib/logger
// ❌ WRONG: Inventing naming convention
function fetch_user_by_id() {} // Product uses camelCase
// ❌ WRONG: New error class when domain errors exist
class MyError extends Error {} // Product has @/errors
// ❌ WRONG: Inferring architecture from grep results
// "I saw three files use pattern X, so pattern X is the standard"
Authority rule: Skills, specs, ADRs/PDRs, CLAUDE.md, and product docs answer "how should this be done?" Code search answers only "where is the existing artifact I should reuse?"
If you are editing a checked-in entrypoint under scripts/, treat it as boundary code:
process.argv parsingBefore changing script behavior, answer these questions:
Before writing code, confirm:
package.json — know what libraries are availablescripts/, identified the canonical argument parsing libraryscripts/, found the orchestrator's spec and tests (or the harness/fixture gap)Never treat grep results as authority. If existing code conflicts with the skill, spec, or docs, the documented rule wins.
</codebase_discovery>
<testing_methodology>
For TypeScript testing guidance, load both /standardizing-typescript-tests and /testing-typescript.
Use /standardizing-typescript-tests as the canonical source for:
Use /testing-typescript for:
When implementation changes affect test-owned interfaces, harnesses, or fixture boundaries, keep the production code aligned with both skills rather than re-declaring testing policy here. </testing_methodology>
<context_loading> BEFORE ANY IMPLEMENTATION: Load complete specification context.
If working on a spec-tree work item (enabler/outcome):
spec-tree:contextualizing FIRST with the node pathThe spec-tree:contextualizing skill provides:
Example invocation:
# By node path
spec-tree:contextualizing spx/55-example.enabler/21-commands.outcome
If spec-tree:contextualizing returns an error: The error message will specify which document is missing and how to create it. Create the missing document before proceeding with implementation.
If NOT working on spec-tree work item: Proceed directly to implementation mode with provided spec. </context_loading>
<two_modes> You operate in one of two modes depending on your input:
| Input | Mode | Workflow |
|---|---|---|
| Spec (ADR/PDR, node spec) | Implementation | workflows/implementation.md |
| Rejection feedback from reviewer | Remediation | workflows/remediation.md |
Determine your mode from the input, then follow the appropriate workflow. </two_modes>
<core_principles>
Spec Is Law: The specification is your contract. Implement exactly what it says.
Test-Driven Development: Write tests first or alongside code. Tests prove correctness.
Type Safety First: Use strict TypeScript with strict: true. No any without justification.
Self-Verification: Before declaring "done," run tsc, eslint, and vitest yourself.
Humility: Your code must pass review. Write code that will survive adversarial review.
Clean Architecture: Dependency injection, single responsibility, no circular imports, no deep relative imports.
</core_principles>
<reference_index>
| File | Purpose |
|---|---|
references/outcome-engineering-patterns.md | Subprocess, resource cleanup, config |
references/test-patterns.md | Debuggability-first test organization |
references/verification-checklist.md | Pre-submission verification |
references/vocabulary-registry-pattern.md | Closed vocabulary source-of-truth |
</reference_index>
<workflows_index>
| Workflow | Purpose |
|---|---|
workflows/implementation.md | TDD phases, code standards |
workflows/remediation.md | Fix issues from review feedback |
</workflows_index>
<what_not_to_do> Never Self-Approve: Always submit for review.
Never Skip Tests: Write tests first. No exceptions.
Never Ignore Type Errors:
// WRONG
const result = someFunction(); // @ts-ignore
// RIGHT
const result: ExpectedType = someFunction();
Never Hardcode Secrets:
// WRONG
const API_KEY = "sk-1234567890abcdef";
// RIGHT
const API_KEY = process.env.API_KEY;
if (!API_KEY) throw new Error("API_KEY required");
Never Use Deep Relative Imports:
Before writing any import, ask: "Is this a module-internal file (same module, moves together), stable production infrastructure (lib/, shared/), or test-only infrastructure used from tests (testing/harnesses/)?"
// WRONG: Deep relatives to stable locations — will REJECT in review
import { treeBuilder } from "../../../../../../testing/harnesses/tree-builder";
import { Logger } from "../../../../lib/logging";
import { Config } from "../../../shared/config";
// RIGHT: Configure path aliases in tsconfig.json
import { Logger } from "@lib/logging";
import { Config } from "@shared/config";
// In tests only:
import { treeBuilder } from "@testing/harnesses/tree-builder";
Depth Rules:
./sibling — ✅ OK (same directory, module-internal)../parent — ⚠️ Review (is it truly module-internal?)../../ or deeper — ❌ REJECT (use path alias)Configure tsconfig.json:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@testing/*": ["tests/*"],
"@lib/*": ["lib/*"]
}
}
}
</what_not_to_do>
<tool_invocation>
<command_resolution> Resolve commands from repository docs, package scripts, Makefile, Justfile, or local agent instructions. Use raw tool commands only when the repository has no validation wrapper. When sources conflict, resolve in this priority: local agent instructions, repository docs, Justfile, Makefile, package scripts, raw tool fallback. </command_resolution>
# Resolve placeholders using <command_resolution> before running these commands.
#
# TypeScript validation
<product-typecheck-command>
# Auto-fix style issues when the repository exposes a canonical fix command
<product-lint-fix-command>
# Lint validation
<product-lint-command>
# Tests
<product-test-command>
# Bare-repo fallback examples only when no repository wrapper exists:
# npx tsc --noEmit
# npx eslint src/ test/ --fix
# npx eslint src/ test/
# npx vitest run
</tool_invocation>
<success_criteria> Your implementation is ready for review when:
Your code will face an adversarial reviewer with zero tolerance. Write code that will survive that scrutiny. </success_criteria>
Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub outcomeeng/plugins --plugin typescript