Roadmap
This tracks the full backlog, grouped by theme and ordered by how directly each item serves the core goal: force AI-generated code to conform to your conventions. Shipped items move out of here into the reference pages.
Shipped
- Pattern matching: declare a file's shape by example (
pattern), one template or a list of acceptable shapes. filename: filename conventions + placeholder binding.sameType: fold equal type spellings (React.FC≡FC).denyImports/allowImports: import path boundaries.unmatched: every source file must be governed (escape-hatch closer).severity,ignore,sourceFiles.- Usage rules:
disallowElements,disallowCalls,within,except(ban raw<input>/fetch; require the design-system component). belongsHere: inverse check: a file that looks governed must live in the governed folder.- Closed export surface:
allowExtraExports; flag stray exports. requires: mandatory sibling files.- Suppressions:
// shapelint-disable-next-line <rule> -- reason. - Output formats:
human,agent,json,github. - CLI:
check,fix,new,explain,init. shapelint fix: mechanical autofix: rename symbol; change export form + rewrite importers; rename a file to a filename convention; move a misplaced (belongsHere) file into its governed folder, all with move-aware verify-and- rollback, dry-run by default, refuses a dirty tree without--force.shapelint new <rule> <Name>: scaffold a conforming file from a rule's pattern.requirescompanions:{stem}token requires a per-file companion (e.g.Button.tsx→Button.stories.tsx,orders.module.ts→orders.service.ts).--cache: content-hash cache for the pure per-file checks; invalidated by content or config change.shapelint baseline: grandfather existing violations for incremental adoption.- Semantic (AI) tier: provider-agnostic
judge, opt-in viacheck --semantic, non-blocking by default, content-hash cached. - Naming: repo-wide config
naming(files + folders) plus per-rulefilename/foldername, with rule-over-config precedence.
Near-term (not yet built)
| Feature | What it adds |
|---|---|
shapelint fix, alias-aware moves | Rewrite @/… path-alias importers on move (today the verify step refuses a move that would break one). |
shapelint fix, stub generation | Generate requires companions / barrel index.ts stubs. |
| Worker-thread pool | Parallelize cold runs on very large repos (the --cache already covers warm runs). |
Rule-expressiveness long tail (build on demand)
exact: ['members' | 'topLevel'] (closed-world negation) · maxLines · forbid (anti-pattern templates) · importedBy (inverse dependency) · resolveTypes (type-checker-backed comparison, opt-in and slow) · custom(ctx) predicate escape hatch.
Design principles (not future work)
- Deterministic core. The default
checkis fully static, reproducible, fast, free, safe to block a build. The semantic tier is strictly opt-in (--semantic), non-blocking by default, and cached, so it advises without compromising the gate. - Complements ESLint /
tsc, never re-reporting what they already catch.
Later (a separate product surface)
initfull-repo inference (v2): walk the whole repo, group files by directory, detect the dominant declaration/export shape in each, and generate a config whose rules already match the code. Todayinitonly writes a starter config with an example rule; this would make it genuinely infer one.- Agent-loop integration: a general adapter (Claude Code hooks, Cursor, Windsurf) so the gate is unavoidable in-session, not only at CI.
- MCP server: let an agent query a rule's shape before writing a file.
- Digest generator: emit a compact
AGENTS.mdblock from the config, so prose and enforcement can't drift.
Preset rule libraries & scoped packages
Today every project authors its own rules from scratch. The next distribution step is a library of predefined, battle-tested rule sets for common stacks, so a project can adopt sensible conventions with one line instead of hand-writing them:
- Framework/runtime presets: ready-made rules for React, Node, Next.js, NestJS, etc. (component-file shape, hook naming, no data fetching in UI primitives, service/controller layering, import boundaries…).
- Composable: a config
extendsone or more presets and overrides or disables individual rules, the same way ESLint shareable configs work.
This is delivered as a flagship-plus-scoped split on npm, the unscoped shapelint engine stays dependency-free, and presets ship under the @shapelint/* scope, opt-in:
| Package | Contents |
|---|---|
shapelint | The engine, defineConfig, the checkers, the CLI. No opinions. |
@shapelint/react | Preset rule set for React codebases. |
@shapelint/node | Preset rule set for Node services. |
@shapelint/… | Further stack presets (Next.js, NestJS, …) added on demand. |
// shapelint.config.ts (illustrative)
import { defineConfig } from 'shapelint';
import react from '@shapelint/react';
export default defineConfig({
root: 'src',
extends: [react.recommended],
rules: [
/* project-specific overrides */
],
});The shapelint package stays the engine and CLI; presets publish under the @shapelint/* scope and layer on top, so existing configs keep working.