Skip to content

alexgorbatchev/typescript-ai-policy

Repository files navigation

@alexgorbatchev/typescript-ai-policy

Shared Oxfmt and Oxlint config for teams that want AI-assisted TypeScript to stay strict, predictable, and reviewable.

This package is opinionated on purpose. It does not try to be a flexible style preset. It encodes repository contracts as lint rules so generated and modified code lands in a shape you can actually trust.

Who this is for

Use this package if you want to:

  • enforce stricter structure on AI-generated or AI-modified TypeScript
  • replace hand-wavy coding guidance with machine-checkable rules
  • keep React, tests, fixtures, and type boundaries deterministic
  • ship one shared policy pack across repositories

If you want a loose collection of optional style rules, this package is the wrong tool.

What you get

  • shared Oxfmt config
  • shared Oxlint config
  • custom @alexgorbatchev/* rules aimed at common LLM failure modes
  • diagnostics written as direct repair instructions
  • the typescript-ai-policy CLI with fix-semantic and guidance commands

Upstream Oxlint, TypeScript, and Jest rules stay enabled as baseline correctness guardrails.

Install

bun add -d @alexgorbatchev/typescript-ai-policy oxfmt oxlint

If you want to use the typescript-ai-policy fix-semantic command, install its optional peer dependencies too:

bun add -d typescript @typescript/native-preview

The published package ships compiled .js runtime files plus .d.ts declarations. The installed typescript-ai-policy CLI runs through Bun, so Bun is required to execute the package-installed bin. The fix-semantic command still expects its optional peer dependencies to be installed in the consuming project, while guidance only reads the published policy metadata.

Quick start

oxfmt.config.ts

import createOxfmtConfig from "@alexgorbatchev/typescript-ai-policy/oxfmt-config";

export default createOxfmtConfig(() => ({
  ignorePatterns: ["vendor/**"],
}));

oxlint.config.ts

import createOxlintConfig from "@alexgorbatchev/typescript-ai-policy/oxlint-config";

export default createOxlintConfig(() => ({
  ignorePatterns: ["coverage"],
  rules: {
    "no-var": "error",
  },
}));

Both config entrypoints export factory functions. The callback is optional and is deep-merged before the shared defaults, so the shared policy still wins on conflicting keys.

For Oxlint specifically, consumer configs are extension-only. If the callback tries to redefine a shared rule, the factory throws instead of letting repositories silently weaken the policy downstream.

When you run Oxlint manually, use Bun to launch the CLI:

bun --bun oxlint .

Treat bun --bun oxlint ... as the canonical invocation form for this package and for consumer repositories using these TypeScript config entrypoints.

What it enforces

At a glance, the shared policy enforces:

  • baseline guardrails such as strict equality and no any
  • component ownership files that export exactly one main component or one multipart component family, plus type-only secondary API, and live under canonical components/, templates/, or layouts/ directories
  • hook ownership files that export exactly one main use* hook, plus type-only secondary API, and live as direct-child hooks/use*.ts[x] files
  • JSX-only React component code instead of React.createElement(...)
  • matching Storybook files for component ownership files under sibling stories/ directories, with story support files limited to helpers.ts[x], fixtures.ts[x], or fixtures/
  • matching test files for hook ownership files under sibling __tests__/ directories, with test support files limited to helpers.ts[x], fixtures.ts[x], or fixtures/
  • typed Storybook meta with package-relative titles, typed story exports, and required play functions
  • deterministic component test ids such as ComponentName and ComponentName--child, plus required root test ids for exported ownership components
  • canonical component ownership directories (components/, templates/, layouts/) as the only .tsx surface allowed to render raw intrinsic JSX or pass direct className / style props
  • strict boundaries between runtime code, test code, story code, and fixture code, including no imports from __tests__/ into runtime code and no type imports from constants.ts
  • test-file discipline: no skipped or focused tests, no conditional logic, no throw, no module mocking, no test-file exports, and no inline fixture bindings
  • fixture discipline: canonical location, single entrypoint, constrained export naming and export types, no local type declarations, and canonical fixture import paths
  • explicit type/value ownership rules for files such as index.ts, constants.ts, and types.ts
  • strict type and function-contract rules: I* interfaces only, no I* type aliases, no direct interface-to-type passthrough aliases, no trivial property-selector forwarding wrappers whose names merely restate the selected property, no inline type imports or inline structural type expressions, and indented multiline template literals
  • a policy stance that inline lint-disable comments are not an acceptable escape hatch for fixing violations

Lint-disable comments are not a valid repair strategy

Agents and developers are expected to satisfy the shared policy directly, not suppress it locally with comments such as // oxlint-disable-next-line or /* oxlint-disable */.

This package explicitly bans inline lint-disable comments for both ESLint and Oxlint. Treat this as a hard policy signal, not as an obstacle to bypass. The enforcement strategy assumes you will fix the underlying contract violation rather than suppressing the warning.

The important contract is simple:

  • do not use inline lint-disable comments to get around the shared policy
  • fix the code so it satisfies the rule set instead
  • if the policy itself is wrong, change the shared package deliberately rather than bypassing it locally

Storybook is the React component contract

For React components, this policy is intentionally story-first.

Every component ownership file must have a matching Storybook file, every story meta must be typed and use a package-relative title, and every exported story must be typed and include a play function. In practice, that makes Storybook the canonical artifact for component behavior:

  • the same story layer can back CI interaction coverage
  • the same stories also act as the human visual reference for the component
  • component structure and component verification stay in one place instead of drifting across separate ad-hoc test files

This package does not wire your CI for you, but it does enforce the repository shape required for Storybook-driven component verification.

Expected layout shape

The policy enforces canonical role directories inside your feature tree.

That means repositories can choose their feature boundaries, but component, story, hook, and test files still have fixed ownership locations:

  • component ownership .tsx files live under components/, templates/, or layouts/
  • nested subdirectories inside those component ownership areas are allowed but not required
  • non-story, non-test .tsx files must not render raw intrinsic JSX such as <div>, <span>, or <p> unless the file lives inside one of those canonical component ownership areas
  • direct className and style props are only allowed in files inside those canonical component ownership areas
  • story files live under sibling stories/ directories, and that area is reserved for *.stories.tsx, helpers.ts[x], fixtures.ts[x], and fixtures/
  • exported runtime hooks whose names start with use live under direct-child hooks/ ownership files
  • test files live under sibling __tests__/ directories, and that area is reserved for *.test.ts[x], helpers.ts[x], fixtures.ts[x], and fixtures/
  • fixture entrypoints and fixture directories live under stories/ or __tests__/
  • component filenames match the exported PascalCase component name in PascalCase or kebab-case form
  • hook filenames match the exported use* hook name in camelCase or kebab-case form
  • index.ts is reserved for pure barrel re-exports only
  • constants.ts is for runtime values only
  • types.ts is for type-only exports only

Example:

feature/
├── components/
│   ├── AccountPanel.tsx
│   └── stories/
│       └── AccountPanel.stories.tsx
└── hooks/
    ├── useAccount.ts
    └── __tests__/
        └── useAccount.test.ts

Minimal config:

import createOxlintConfig from "@alexgorbatchev/typescript-ai-policy/oxlint-config";

export default createOxlintConfig();

With that config in place, routes, pages, feature views, and other non-story, non-test .tsx files must render imported components instead of raw DOM tags, and they must not pass direct className or style props. Raw intrinsic JSX and direct styling props stay inside canonical component ownership areas.

In a consuming repository, use typescript-ai-policy check through your package manager's local binary runner to execute the shared formatter and linter checks against that repo.

When a consuming harness supports environment injection, configure that harness to run shell commands with AGENT=1 so typescript-ai-policy check emits agent-formatted oxlint output automatically for agent workflows and more token-efficient lint output.

CLI tooling

The package includes the typescript-ai-policy CLI. Its fix-semantic command is backed by tsgo --lsp --stdio, and its guidance command prints authoritative repair guidance for the local @alexgorbatchev/* rules as a wrapped Markdown bullet list with bold rule names or as JSON.

Package-installed usage:

  • bun run typescript-ai-policy -- check — run the package formatter and linter checks in the consuming repository. When the consuming harness is configured to inject AGENT=1, the oxlint step uses agent formatting automatically for agent workflows and more token-efficient output.
  • bun run typescript-ai-policy -- guidance — print the published rule guidance that the package exposes for AI agents as a wrapped Markdown bullet list with bold rule names.
  • bun run typescript-ai-policy -- guidance --json — print the same published rule guidance as JSON objects with ruleName and resolved guidance fields.
  • bun run typescript-ai-policy -- fix-semantic <target-directory> — run Oxlint with this package's policy config, collect supported diagnostics, and apply semantic fixes to the target directory.
  • bun run typescript-ai-policy -- fix-semantic <target-directory> --dry-run — print the planned semantic-fix scope without mutating files.

The published guidance output is package-level repair guidance, not a repository-specific config dump. Agents should still inspect the consuming repository's actual oxlint.config.ts before applying file-specific guidance in another codebase.

Repository-local development usage:

  • bun run cli -- guidance — run the repository-local CLI entrypoint directly from TypeScript source.
  • bun run cli -- guidance --json — print the same repository-local guidance output as JSON.
  • bun run cli -- fix-semantic <target-directory> — run the repository-local CLI entrypoint for semantic fixes.
  • bun run fix:semantic -- <target-directory> — run the same fix-semantic command from this repository checkout while developing the package itself.

The repository-local development command uses Bun to execute the TypeScript source directly. The published npm package also uses a compiled Bun-targeted bin.

Today the framework applies three conservative semantic fixes:

  • @alexgorbatchev/interface-naming-convention — rename repository-owned interfaces to their required I* form when the existing name can be normalized safely.
  • @alexgorbatchev/no-i-prefixed-type-aliases — rename repository-owned type aliases to drop the interface-style I* prefix when the diagnostic resolves to a concrete type alias name safely.
  • @alexgorbatchev/test-file-location-convention — move misplaced .test.ts / .test.tsx files into a sibling __tests__/ directory as __tests__/basename.test.ts[x] and rewrite the moved file's relative imports.

The command and backend shape remain intentionally generic so more rule-backed semantic operations can be added later.

Learn more

  • src/oxlint/README.md — full rule catalog, rationale, and examples
  • AGENTS.md — repository guidance for coding agents working on this package

Local package setup

This repository also consumes its own shared configs at the root:

  • oxfmt.config.ts
  • oxlint.config.ts

About

AI first lint and format rules for TypeScript and React code bases.

Topics

Resources

Stars

Watchers

Forks

Contributors