AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Typescript Audit

skill-bensheridanedwards-architectplaybook-typescript-audit · by BenSheridanEdwards

Audit a TypeScript project's type discipline against an opinionated baseline spanning compiler configuration, type quality in source, type system usage, and type safety at IO boundaries. Static-first with optional --with-run enrichment from tsc --noEmit. Optionally generates an implementation plan for the gaps.

No reviews yet
0 installs
18 views
0.0% view→install

Install

$ agentstack add skill-bensheridanedwards-architectplaybook-typescript-audit

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-bensheridanedwards-architectplaybook-typescript-audit)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Typescript Audit? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

/typescript-audit

Audit a TypeScript project's type discipline against an opinionated baseline organised in four layers — compiler configuration, type quality in source, type system usage, type safety at boundaries — preceded by a diagnostic snapshot. Then offer to generate an implementation plan for the gaps.

The default mental model is TypeScript and React. Layers 1, 2, 3 apply to any TypeScript codebase; layer 4's IO-boundary checks lean toward frontends and full-stack applications, but most checks apply equally to backend TypeScript.

How this differs from neighbouring audits

| Concern | Owner | | --- | --- | | Whether tsc --noEmit runs at every lifecycle stage | /quality-gates-audit | | @typescript-eslint plugin coverage and rule selection | /linting-audit | | incremental and project references for build performance | /bundle-build-audit | | useUnknownInCatchVariables as it affects catch typing | /error-handling-audit | | Whether the compiler is configured strictly | /typescript-audit | | Quality of types written in source (any, assertions, @ts-ignore) | /typescript-audit | | Type system usage (discriminated unions, branded types, utility types) | /typescript-audit | | Type safety at IO boundaries (runtime validation of network/form/storage data) | /typescript-audit |

When a single fix passes multiple audits — for example, enabling useUnknownInCatchVariables satisfies both /error-handling-audit (which checks the resulting catch typing) and /typescript-audit (which checks the compiler flag) — every relevant audit surfaces the same gap so the user sees it once and resolves it once.

Static-first design with optional run enrichment

This skill is read-only and never modifies anything. Two modes:

  • Static (default). Read tsconfig.json (and any extends-chained configs), package.json, and source files. Pattern-detect type-quality signals across .ts and .tsx files.
  • Static plus opt-in --with-run. Invoke npx tsc --noEmit (no emit, no side effects) and parse the diagnostics. Provides a real error count and the actual locations of every type error, which sharpens layer 2 substantially.

tsc --noEmit is genuinely read-only — it does not write to dist/, .next/, or anywhere else. The skill never invokes the compiler with any other flag, never installs anything, and never edits configuration.

Usage

/typescript-audit                                 # default: concise Top 5 + full report saved + ask about plan
/typescript-audit --worktree                          # create an isolated Git worktree, then run the audit there
/typescript-audit --learn                         # mid-level engineer teaching mode (detailed explanations + file/line examples)
/typescript-audit --teach                         # alias for --learn
/typescript-audit --with-run                      # static plus enrichment from tsc --noEmit
/typescript-audit --threshold-any-per-file=5      # override default 3
/typescript-audit --threshold-as-per-file=10      # override default 5 (excluding `as const`)
/typescript-audit --threshold-non-null-assertion-per-file=5  # override default 3
/typescript-audit --threshold-conditional-type-depth=4       # override default 3

💡 Pro tip: Add --worktree to run this audit in an isolated Git worktree.

The skill never accepts --apply. The implementation plan is descriptive Markdown.

💡 Pro tip: Run /preflight --audit=typescript first to detect — and optionally install — the development dependency that makes --with-run useful (typescript, which provides tsc --noEmit). Skip if you already know the tooling is wired up.

The opinionated baseline

A check resolves to one of four statuses:

  • present — the invariant holds.
  • partial — most signals resolve, with a small number of exceptions, or the codebase shows mixed adherence to a soft check.
  • missing — a structural prerequisite is absent (no tsconfig.json, for example — the skill stops earlier in that case, but the status is reserved).
  • violation — the audit identified concrete configuration or source that breaks the invariant.

Layer 0 is informational only and has no status.

Layer 0 — Diagnostic snapshot (always written, no pass/fail)

  • TypeScript version (resolved from the lockfile).
  • tsconfig.json path(s); when extends is used, the resolved final configuration is recorded.
  • Detected runtime validation library: zod, valibot, arktype, io-ts, yup, joi, superstruct, runtypes — or none.
  • Strict-flag adoption: which of strict, noImplicitAny, strictNullChecks, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, noImplicitThis, alwaysStrict, useUnknownInCatchVariables, noUncheckedIndexedAccess, exactOptionalPropertyTypes, noImplicitReturns, noFallthroughCasesInSwitch, noImplicitOverride are enabled.
  • Type-quality counts across source: any annotations, unknown annotations, as assertions (excluding as const), as const assertions, non-null assertions (!), @ts-ignore, @ts-expect-error, @ts-nocheck.
  • Top 10 files by any count, top 10 by as count, top 10 by ! count.
  • Project references count (composite projects in monorepos).
  • tsc --noEmit total error count when --with-run.

Layer 1 — Compiler configuration

| Check | Expectation | Violation signal | | --- | --- | --- | | strict: true | The strict family is enabled wholesale via the strict flag. | strict: false, or strict absent and individual strict-family flags missing. | | noUncheckedIndexedAccess enabled | Distinguishes array[i]: T from array[i]: T \| undefined, catching a major source of runtime errors that the compiler otherwise ignores. | Flag missing or false. | | exactOptionalPropertyTypes enabled | Distinguishes prop?: T from prop: T \| undefined. Soft check — reported as partial because some codebases legitimately can't enable it without significant refactoring. | Flag missing or false. | | noImplicitReturns enabled | Catches functions that fall off the end without returning when their type says they should. | Flag missing or false. | | noFallthroughCasesInSwitch enabled | Catches missing break or return in switch cases. | Flag missing or false. | | useUnknownInCatchVariables enabled | Catch variables default to unknown, not any. (Overlap with /error-handling-audit; both surface so a single fix passes both.) | Flag missing or false. | | noImplicitOverride enabled | Class methods that override a parent must use the override keyword. Soft check — reported as partial for codebases with no classes. | Flag missing in a class-using codebase. | | isolatedModules enabled | Required by every modern bundler (Vite, esbuild, swc, Bun) for safe per-file transpilation. | Flag missing or false in a project using one of those bundlers. | | skipLibCheck is a deliberate choice | The flag is either explicitly true (with the awareness that third-party .d.ts files won't be type-checked) or explicitly false. The check verifies the choice was made; it doesn't pick a side. Soft check. | The flag is absent and the default behaviour applies (which differs across TypeScript versions). | | target and module appropriate | target matches the runtime (ES2022 or newer for modern Node and modern browsers). module is ESNext, NodeNext, or Preserve — not CommonJS for browser code. | target: 'ES5' or older in a project that ships modern environments only; or module mismatched against the resolution model. | | moduleResolution set explicitly | moduleResolution is Bundler (Vite, esbuild) or NodeNext (Node), set explicitly rather than defaulting. | Flag absent. | | Composite or project references for monorepos | Monorepos use TypeScript project references (composite projects) so type-checks scale across packages. Skipped silently outside monorepos. Soft check. | Multi-package project without project references. |

Layer 2 — Type quality in source

| Check | Expectation | Violation signal | | --- | --- | --- | | any usage is rare | The total any annotation count per file is at or below the threshold (default 3; tunable via --threshold-any-per-file). The audit counts both scalar any and any[]. | Files exceeding the per-file threshold. | | unknown preferred over any for opaque values | unknown appears in the codebase as the safe alternative to any when typing genuinely opaque shapes. Soft check — reported as partial when no unknown appears at all in a non-trivial codebase. | A codebase with substantial any usage and zero unknown. | | @ts-ignore replaced by @ts-expect-error with description | No @ts-ignore directives remain; all suppressions are @ts-expect-error with a free-text justification on the same or adjacent line. | Any @ts-ignore in source. | | No @ts-nocheck at file level | No file disables type checking entirely. | Any @ts-nocheck at the top of a source file. | | Type assertions (as) are rare | The total as assertion count per file is at or below the threshold (default 5; tunable via --threshold-as-per-file). The audit recognises that as const is not a type assertion in the dangerous sense and excludes it from the count. | Files exceeding the per-file threshold. | | Non-null assertions (!) are rare | The total non-null assertion count per file is at or below the threshold (default 3; tunable via --threshold-non-null-assertion-per-file). | Files exceeding the per-file threshold. | | No Function type | Use specific function signatures, not the unsafe Function type (which permits any callable). | Any Function annotation in source. | | No Object type | Use Record, a specific shape, or object (lowercase). | Any Object annotation in source. | | No primitive wrapper types | Use string, number, boolean — not String, Number, Boolean (the wrapper-object types). | Any wrapper-type annotation in source. | | No empty interfaces | Interfaces declare at least one member, or extend another type. An empty interface either does nothing or is a same-shape alias for what it extends. | interface Foo {} declarations. |

Layer 3 — Type system usage

| Check | Expectation | Violation signal | | --- | --- | --- | | Discriminated unions for state machines | Multi-stage state is modelled as a discriminated union ({ status: 'idle' } \| { status: 'loading' } \| { status: 'success'; data: T } \| { status: 'error'; error: E }), not as multiple booleans or wide objects with optional fields. (Overlap with /react-audit's "status enums over multiple booleans"; both surface.) Soft check — reported as partial. | Multi-state shapes hand-rolled with several optional fields and no discriminant. | | Branded or nominal types for IDs | Identifier types (UserId, OrderId, WorkspaceId) are branded so the compiler distinguishes UserId from OrderId even though both carry string at runtime. Soft check — reported as partial. | Identifier types declared as bare string aliases. | | as const for literal preservation | Configuration objects, route lists, and similar literal values use as const so the compiler infers the narrow literal type rather than widening to string or number. Soft check — reported as partial. | Patterns where as const would tighten inference and is missing. | | Utility types preferred over hand-rolled | Use Pick, Omit, Partial, Required, Readonly, Record, NonNullable, Awaited, ReturnType, Parameters rather than hand-rolling equivalents. | Hand-rolled mapped types that duplicate a built-in utility. | | Generic constraints used | Generic parameters that are operated on with .length, indexing, or property access have extends constraints, not bare T. | Bare T generics whose body operates on the parameter assuming a shape. | | Conditional types used judiciously | Conditional types in source are bounded — no nested-deeper-than-threshold conditional chains in application code. The threshold is tunable via --threshold-conditional-type-depth=N (default 3). The audit isn't strict about this; library code can warrant complexity. Soft check — reported as partial when the depth threshold is exceeded. | Nested conditional types deeper than the threshold. |

Layer 4 — Type safety at boundaries

| Check | Expectation | Violation signal | | --- | --- | --- | | Runtime validation library installed | One of zod, valibot, arktype, io-ts, yup, joi, superstruct, runtypes is in dependencies. Soft check — reported as partial when absent (a project may legitimately have no untyped IO boundaries beyond a fully-typed framework like tRPC end-to-end). | None present in a project that performs network requests, parses JSON, or reads form/URL/storage data. | | Network response data validated | Calls to fetch, axios, framework data primitives have their JSON parsed through a validator (zod schema, etc.) before being typed. The audit recognises framework-level type-safe layers (tRPC, GraphQL Code Generator outputs) as equivalent. | Network responses cast directly with as or implicitly typed without runtime validation. | | JSON.parse results validated | JSON.parse(...) outputs are validated, not typed by direct assertion. | JSON.parse(...) as MyType patterns. | | Form data validated | Forms validate input with the form library's schema integration (react-hook-form + resolver, formik + Yup, equivalent) or a standalone validator. (Overlap with /react-audit's form-library check; both surface.) | Form data passed straight to a typed handler with no validator. | | URL parameters validated | Router-extracted params (useSearchParams, useParams, router.query) are validated before being typed as anything stricter than string or string[]. | URL parameters cast to specific types or assumed narrower than their actual runtime type. | | localStorage/sessionStorage reads validated | Storage reads are parsed and validated before being typed. | JSON.parse(localStorage.getItem('key')!) patterns with no validator. | | Environment variables validated | Environment-variable access (process.env, import.meta.env) goes through a validated configuration module — not direct reads scattered across the codebase. Soft check — reported as partial. | Direct process.env.X reads in feature code rather than a validated config module. |

What this skill does

  1. Reads the knowledge graph when present. Soft dependency: when graphify-out/graph.json exists, the audit cross-references type-quality offenders (high-any, high-as, high-! files) against graph centrality and prioritises god nodes in the implementation plan. The audit still runs in full when the graph is absent.
  2. Confirms a TypeScript project. Detects package.json, tsconfig.json, and typescript in dependencies. If any are absent, the skill stops and tells the user it currently supports TypeScript projects only.
  3. Resolves the effective tsconfig.json by following any extends chain. Records the final resolved configuration in metadata.
  4. Detects the runtime validation library (zod, valibot, arktype, io-ts, yup, joi, superstruct, runtypes) for the diagnostic snapshot and for the layer 4 checks.
  5. When --with-run is set, invokes npx tsc --noEmit and parses the diagnostics. If tsc fails to start (not installed in the project), records the failure, prints to the chat and prepends to findings.md: "--with-run was requested but typescript is not installed. Run /preflight --audit=typescript --install to install it, then re-run this audit. The static analysis has been completed; only the run-dependent enrichment degraded to partial." Records recoveryHint: "/preflight --audit=typescript --install" on each run-dependent check that degraded in findings.json. Continues w

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.