plugins/dev/skills/validate-type-safety/SKILL.md
Run the full 5-step TypeScript validation gate: type check, reward hacking scan, test inclusion, tests, and lint. This skill provides a structured multi-step pipeline that you cannot replicate on your own — it detects the project's package manager and linter automatically, checks tsconfig strictness, and invokes /scan-reward-hacking internally. **ALWAYS consult this skill when** the user mentions 'validate types', 'check type safety', 'type validation', 'type safety gate', wants to verify TypeScript changes before a PR, after completing a plan phase, or says anything about running type checks + tests + lint together. Even if you think you can run tsc yourself, use this skill — it catches issues you'd miss (tsconfig strictness, test exclusions, reward hacking patterns).
npx skillsauth add coalesce-labs/catalyst validate-type-safetyInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Final verification gate before marking any TypeScript work complete. Combines type checking with reward hacking detection, test verification, and linting. ALL 5 steps must pass.
Before running any commands, detect the project's package manager and linting tool. Do NOT
hardcode bun, npm, or trunk — detect from what's available.
Check for lockfiles in the project root:
| Lockfile | Package Manager | Run Command |
|----------|----------------|-------------|
| bun.lockb or bun.lock | bun | bun run |
| pnpm-lock.yaml | pnpm | pnpm run |
| yarn.lock | yarn | yarn run |
| package-lock.json | npm | npm run |
If multiple exist, prefer in the order listed above. Store as $PM_RUN (e.g., bun run).
Check for linting tools in this order:
| Check | Linter | Command |
|-------|--------|---------|
| .trunk/ directory exists | Trunk | trunk check --ci --upstream origin/main |
| biome.json or biome.jsonc exists | Biome | ${PM_RUN} biome check . |
| eslint.config.* or .eslintrc.* exists | ESLint | ${PM_RUN} eslint . |
If none found, skip Step 5 and note it in the output.
Look for a type-check or typecheck script in package.json:
${PM_RUN} type-check (or typecheck)npx tsc --noEmit (fallback)For monorepos, check if the root package.json has a workspace-level type-check script first.
Read the project's tsconfig.json (or the tsconfig covering changed files in a monorepo). Verify:
"strict": true is set — WARN if missing"noUncheckedIndexedAccess": true — INFO if missing (recommended)"noImplicitReturns": true — INFO if missing (recommended)"exactOptionalPropertyTypes": true — INFO if missing (recommended)For monorepos: use the Glob tool to find tsconfig.json files, then identify which one covers the
changed files (check include/exclude paths and references).
This step is informational only — it does not cause a FAIL verdict, but findings are reported.
${PM_RUN} type-check # or detected equivalent
Expected: Zero errors, exit code 0.
If errors exist, they MUST be fixed. Do not proceed to Step 2 until type-check passes.
Execute the /scan-reward-hacking skill on the changed files.
Expected: PASS verdict with no unfixed CRITICAL or HIGH severity patterns.
Check that test files are NOT excluded from type checking. Use Grep to search tsconfig files (in changed packages for monorepos):
\.test\.ts or \.spec\.ts in exclude arrays of tsconfig filesexclude arraysExpected: No tsconfig files exclude test files from type checking.
${PM_RUN} test
For monorepos with many packages, if the project has a --filter or --scope option, run tests
only for affected packages when possible.
Expected: All tests pass. Type fixes should not break functionality.
# Use detected linter command from Tooling Detection
trunk check --ci --upstream origin/main # or biome/eslint equivalent
Expected: Zero lint errors.
If no linter was detected, skip this step and note it in the output.
If type-coverage is available (check with which type-coverage or npx type-coverage --help),
report the numeric coverage score:
npx type-coverage --at-least 0
This is informational only — does not affect the verdict.
Present results in this format:
## Type Safety Validation Results
### Tooling Detected
- Package manager: {bun|pnpm|yarn|npm}
- Linter: {trunk|biome|eslint|none}
- Type check command: {detected command}
### Step 0: tsconfig Strictness (Informational)
- strict: true — {YES / MISSING}
- noUncheckedIndexedAccess — {YES / missing (recommended)}
- noImplicitReturns — {YES / missing (recommended)}
- exactOptionalPropertyTypes — {YES / missing (recommended)}
### Step 1: TypeScript Type Check
- Status: PASS / FAIL
- Errors: {count} (list if any)
### Step 2: Reward Hacking Scan
- Status: PASS / FAIL
- Critical: {count}
- High: {count}
- (Details if any issues found)
### Step 3: Test File Inclusion
- Status: PASS / FAIL
- tsconfig files excluding tests: {count} (list if any)
### Step 4: Tests
- Status: PASS / FAIL
- Failed tests: {count} (list if any)
### Step 5: Lint Check
- Status: PASS / FAIL / SKIPPED (no linter detected)
- Errors: {count} (list if any)
### Type Coverage (if available)
- Coverage: {X}% ({Y}/{Z} types)
---
## Overall Verdict: PASS / FAIL
{If FAIL, list all items that must be fixed}
PASS requires ALL of the following:
FAIL if ANY check fails.
Do NOT mark the work as complete. Instead:
For efficiency, stop on the first failing step. Report which step failed and what needs fixing. Re-run the full validation after fixes are applied.
/implement-plan as part of quality gates/oneshot Phase 4 (Validate + Quality Gates)/scan-reward-hacking internally for Step 2testing
Phase-agent that fixes a failing verify verdict so the pipeline self-heals instead of stalling to needs-human (CTL-653). Reads `${ORCH_DIR}/workers/<ticket>/verify.json`, fixes the `findings[]` (every severity:"high" plus the regression_risk drivers) directly via Edit/Write, commits the remediation, and emits `phase.remediate.complete.<ticket>`. The scheduler's router then re-dispatches `verify` to re-check (the verify⇄remediate cycle, cap 3). Dispatched as a `claude --bg` job by `phase-agent-dispatch`, which invokes it via slash command — hence `user-invocable: true`.
tools
--- name: phase-triage description: Phase agent that triages a Linear ticket — expands acronyms, classifies (feature/bug/docs/refactor/chore), identifies genuine blockers (a semantic second-pass over the backlog — NOT a prose scrape; CTL-838), estimates scope, writes triage.json, and posts a triage analysis comment to Linear. Triage completion is signaled by that comment plus the local triage.json — there is no `triaged` label. Emits phase.triage.complete.<TICKET> on success and phase.triage.fai
tools
Phase agent for the research step of the 9-phase orchestrator pipeline (CTL-450). Wraps /catalyst-dev:research-codebase and produces thoughts/shared/research/<date>-<ticket>.md, then emits phase.research.complete.<ticket>. Reads triage.json from the worker dir as its prior-phase artifact. Spawned via plugins/dev/scripts/phase-agent-dispatch, which invokes it via slash command — hence `user-invocable: true`.
development
Phase-agent wrapper that opens the pull request after implementation completes (CTL-449 Initiative 1 Phase 3). Delegates to `/catalyst-dev:create-pr` (which already auto-runs `describe-pr` and transitions Linear to `inReview`), then writes the PR number + URL into the phase signal file so the downstream `phase-monitor-merge` agent can read it without re-querying GitHub. Dispatched as a `claude --bg` job by `phase-agent-dispatch`, which invokes it via slash command — hence `user-invocable: true`.