Introduction
Shapelint is a deterministic linter for the shape, naming, placement, imports, and design-system usage of your TypeScript files, the conventions that ESLint structurally cannot express. You declare each convention by writing the code you want to see, as a template. Any file that doesn't conform fails the check with a precise, prescriptive error.
Why Shapelint
AI coding agents don't reliably follow architectural guidance written in prose, for two reasons:
- Prose guidance is advisory. Rules in
CLAUDE.md/AGENTS.mdare suggestions a model may or may not follow, so one repo drifts into three different component styles. - Prose guidance is expensive. To be followed at all, the rules must sit in the context window every turn, and they grow until they crowd out the work.
Shapelint moves those conventions into a machine-checked gate. Non-conforming code fails, the agent gets an exact, prescriptive error and fixes it, and the rules no longer need to live in context.
Shapelint complements ESLint and
tsc; it does not replace them. ESLint governs code quality within a file. Shapelint governs code structure across the repo. It deliberately never re-reports anything ESLint or the TypeScript compiler already catches.
100% Framework Agnostic
Shapelint does not contain hardcoded assumptions about your application framework, backend runtime, or UI library. Because it operates directly on the TypeScript AST and pattern matching by example, the same engine enforces architecture across any paradigm:
- Frontend UI: React, Vue, Svelte, Angular, Solid, or Next.js (e.g. component props, hook order, JSX tag constraints).
- Backend Services & APIs: NestJS, Express, Fastify, Hono, or Koa (e.g. controller decorators, route contracts, constructor dependency injection).
- Domain & Layered Architecture: Clean Architecture, DDD, Hexagonal (e.g. repository contracts, data models, layer graphs, sibling isolation).
- Shared Libraries & Monorepos: Pure TypeScript modules, utility functions, enums, DTOs, and barrel files.
Rules, by example
// shapelint.config.ts
import { defineConfig } from 'shapelint';
export default defineConfig({
root: 'src',
rules: [
// Frontend: UI primitives must follow naming and export conventions
{
name: 'ui-component',
files: 'components/ui/**/*.tsx',
pattern: `
interface IProps {}
const $Name: React.FC<IProps> = () => {}
export default $Name
`,
filename: '$Name.tsx',
hint: 'Primitives are presentational, lift data access into a block.',
},
// Backend: Controllers must declare @Controller and match filename
{
name: 'controller',
files: 'controllers/**/*.controller.ts',
pattern: '@Controller($_) export class ${Name}Controller {}',
filename: '$name.controller.ts',
hint: 'Controllers must follow $name.controller.ts naming.',
},
],
});Every .tsx under components/ui/ must have a props interface named IProps, a component declared as React.FC<IProps> whose name matches the filename, and a default export. Similarly, every controller under controllers/ must be decorated with @Controller and named in correlation with its filename (users.controller.ts ⇒ UsersController). Bodies, extra private helpers, and interface/class members are not constrained (the template is a lower bound).
What Shapelint enforces
- Shape: a file's declaration surface, by example (pattern, one template or a list of acceptable shapes).
- Naming & placement: filename & folder conventions;
belongsHerecatches misplaced files. - Imports: layer boundaries (denyImports / allowImports).
- Usage: require the design-system component, ban raw elements/calls (usage rules).
- Completeness:
requiressiblings, closed export surface,unmatchedso every file is governed. - Semantics (opt-in): an AI
judgefor the few conventions that resist static encoding.
The workflow
check, fix, new, baseline, explain, init, output as human, agent, JSON, or GitHub annotations. An agent can scaffold a conforming file, get corrected mechanically or prescriptively, and a legacy repo can adopt gradually.
Next steps
- Getting started, install, write a config, run the check
- Generate a config with AI, let an agent write it for you
- Configuration reference, every rule and config option