@coryrylan/tools
Shared ESLint, Prettier, Stylelint, Vale, Vite, and Vitest configs, custom lint rules, and pi coding-agent extensions - for keeping codebases maintainable when coding agents are the primary contributors.
Package details
Install @coryrylan/tools from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@coryrylan/tools- Package
@coryrylan/tools- Version
1.1.0- Published
- Jul 22, 2026
- Downloads
- 151/mo · 151/wk
- Author
- coryrylan
- License
- MIT
- Types
- extension
- Size
- 158.5 KB
- Dependencies
- 0 dependencies · 19 peers
Pi manifest JSON
{
"extensions": [
"./dist/pi/greeting/index.js",
"./dist/pi/audio-summary/index.js",
"./dist/pi/hooks/index.js"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@coryrylan/tools
Shared tooling configs - ESLint, Prettier, Stylelint, Vale, Vite, and Vitest - plus custom ESLint rules for keeping codebases maintainable when coding agents are the primary contributors.
Philosophy
When an agent is the one writing most of a diff, prose instructions living in
an AGENTS.md file are advisory at best. They have to be loaded into
context, correctly interpreted, and remembered turns later, and none of that
is guaranteed on any given run. Prose decays: it drifts out of context, gets
skimmed instead of read, or is outweighed by whatever the agent is focused on
in the moment. A lint rule has none of these failure modes: it runs on every
diff, every time, and fails the build instead of hoping to be noticed. Every
rule and every shared config in this package exists to replace a paragraph an
agent would otherwise have to read (and might ignore, forget, or misapply)
with a deterministic check or preset that gates the diff instead.
Surfaces
| Entry | What it ships |
|---|---|
@coryrylan/tools/eslint |
Flat configs plus the custom tools/* rule plugin. |
@coryrylan/tools/prettier |
The shared Prettier config. |
@coryrylan/tools/stylelint |
Shared Stylelint config (standard + logical properties + design-token checks). |
@coryrylan/tools/vite |
createNodeLibraryBuildConfig / createBrowserLibraryBuildConfig factories. |
@coryrylan/tools/vite/plugins/write-if-changed |
Vite plugin that skips writing chunks whose content didn't change. |
@coryrylan/tools/vite/plugins/dts |
Vite plugin that runs the consumer's TypeScript compiler for declaration output. |
@coryrylan/tools/vitest |
nodeTestConfig preset for node-environment unit tests. |
@coryrylan/tools/vitest/browser |
browserTestConfig preset for browser-mode (Playwright Chromium) tests. |
dist/vale/ |
Vale starter kit: ini template plus shared accept/reject vocabulary. |
@coryrylan/tools/pi/greeting |
Pi extension - speaks a greeting via macOS say on session start. |
@coryrylan/tools/pi/audio-summary |
Pi extension - speaks a short summary of each agent turn. |
@coryrylan/tools/pi/hooks |
Pi extension - Claude-Code-style lifecycle hooks from .agents/hooks.json. |
ESLint
pnpm add -D eslint @coryrylan/tools typescript typescript-eslint
The remaining peers (@eslint/js, @eslint/json, eslint-plugin-jsdoc)
install automatically as regular peer dependencies under pnpm 10 or npm.
Yarn users should add them to devDependencies explicitly.
// eslint.config.js
import { typescriptConfig, jsonConfig } from '@coryrylan/tools/eslint';
export default [...typescriptConfig, ...jsonConfig];
A default export is also available if you'd rather reach into the plugin and
config map directly: import agentLintRules from '@coryrylan/tools/eslint'
exposes { plugin, configs }, where configs is keyed by typescript, tests, browser, html, and json.
Configs
| Config | What it enables | Requirements |
|---|---|---|
typescriptConfig |
On all JS/TS files: size/complexity budgets (complexity 8, max-depth 3, max-params 3, max-lines 500, max-statements 15, max-lines-per-function 50, max-nested-callbacks 3) plus eqeqeq, prefer-const, no-shadow, no-warning-comments, no-param-reassign, and friends, and 5 syntax-only tools/* rules. On TS files: type-aware strictTypeChecked, plus @typescript-eslint/no-floating-promises, only-throw-error, consistent-type-imports, switch-exhaustiveness-check, explicit-member-accessibility (no-public), a #private-over-private selector, no-explicit-any, no-unnecessary-boolean-literal-compare, jsdoc checks (informative-docs, no-types, valid-types, check-tag-names), and the type-aware tools/no-deep-class-inheritance rule. The default starting point for a new agent-maintained project - relax specific rules per-project rather than swapping this config out. |
typescript-eslint, eslint-plugin-jsdoc, typescript >=5.5.0 <6.1.0, parserOptions.projectService |
testsConfig |
Relaxes size/complexity budgets (max-lines, max-lines-per-function, max-statements, max-nested-callbacks, unused-expression checks) for *.test.* / *.spec.* files. |
combine with another config |
browserConfig |
globalThis-over-window/document/location restrictions, plus 3 cleanup rules (require-listener-cleanup, require-observer-cleanup, require-timer-cleanup). |
none extra |
htmlConfig |
@html-eslint recommended structural rules for *.html files (duplicate ids/attrs, obsolete tags, lang/alt requirements, baseline feature checks), with pure-formatting rules off in favor of Prettier and frontmatter-aware parsing for static-site templates. |
@html-eslint/eslint-plugin, @html-eslint/parser |
jsonConfig |
@eslint/json structural rules for *.json (JSONC variant for tsconfig*.json), plus no-unpinned-dependency-ranges scoped to package.json. |
@eslint/json |
Rules
| Rule | What it catches | Enabled by |
|---|---|---|
tools/no-dead-code |
Disallow commented-out source code left behind in comments. | typescript |
tools/no-deep-class-inheritance |
Disallow class inheritance chains deeper than a configured maximum. | typescript |
tools/no-single-consumer-abstraction |
Disallow exported abstractions (base classes) with fewer than two implementation consumers. | typescript |
tools/no-unjustified-disable |
Require every eslint-disable* directive to carry a reason (and, by default, an explicit rule list). |
typescript |
tools/no-reexport-barrels |
Flag files that re-export from more than a configured number of modules. | typescript |
tools/consistent-error-messages |
Require thrown/constructed Errors to carry a non-empty, informative message. |
typescript |
tools/require-listener-cleanup |
Require a matching removeEventListener for every addEventListener added in a setup lifecycle method; forbid addEventListener in the constructor. |
browser |
tools/require-observer-cleanup |
Flag ResizeObserver/MutationObserver/IntersectionObserver/PerformanceObserver instances created without storing a reference. |
browser |
tools/require-timer-cleanup |
Flag setInterval handles that are never stored or never cleared. |
browser |
tools/no-unpinned-dependency-ranges |
Require package.json dependency version specifiers appropriate to the package's publish status and dependency kind. |
json |
Prettier
pnpm add -D @coryrylan/tools prettier
Reference the config straight from package.json:
{ "prettier": "@coryrylan/tools/prettier" }
Or import and spread it in a prettier.config.js to override options.
Embedded template literals stay hand-formatted
(embeddedLanguageFormatting: 'off'). See
src/prettier/docs.
Stylelint
pnpm add -D @coryrylan/tools stylelint stylelint-config-standard
// stylelint.config.js
export { default } from '@coryrylan/tools/stylelint';
Layers stylelint-config-standard with logical-property enforcement (no
physical margin-*/padding-*) and design-token checks (no hardcoded pixel
values in spacing properties). See
src/stylelint/docs.
Vale
Install the Vale binary (mise use vale, or brew), then point a .vale.ini
at the styles this package ships:
StylesPath = node_modules/@coryrylan/tools/dist/vale/styles
Vocab = Tools
Packages = Google, write-good
Run vale sync once to download the style packages. The full template with
per-filetype sections lives at src/vale/vale.ini. See
src/vale/docs.
Vite
pnpm add -D @coryrylan/tools vite
// vite.config.ts
import { defineConfig, mergeConfig } from 'vite';
import { createNodeLibraryBuildConfig } from '@coryrylan/tools/vite';
export default defineConfig(mergeConfig(createNodeLibraryBuildConfig({ entry: { index: 'src/index.ts' } }), {}));
ESM-only, every bare specifier externalized, preserveModules for deep
imports, no minification. The write-if-changed and dts plugins ship as
deep imports under @coryrylan/tools/vite/plugins/. See
src/vite/docs.
Vitest
pnpm add -D @coryrylan/tools vitest
// vitest.config.ts
import { defineConfig } from 'vitest/config';
import { nodeTestConfig } from '@coryrylan/tools/vitest';
export default defineConfig(nodeTestConfig);
@coryrylan/tools/vitest/browser exports browserTestConfig for real-Chromium
browser-mode tests (requires the optional @vitest/browser-playwright,
@vitest/coverage-istanbul, and playwright peers) with istanbul coverage
gated at 90% across lines, branches, functions, and statements. See
src/vitest/docs.
Pi extensions
pi install npm:@coryrylan/tools
Three pi coding-agent extensions, shipped as a pi package
(pi manifest key in package.json, pi-package keyword): greeting,
audio-summary, and hooks. Pi provides
@earendil-works/pi-ai/@earendil-works/pi-coding-agent/typebox at
runtime, so there is nothing extra to install. See
src/pi/docs.
Peer dependencies
Every peer beyond eslint is scoped to the surface that needs it; the
non-ESLint peers are marked optional, so install them with the surface you
use.
typescriptmust satisfy>=5.5.0 <6.1.0for type-aware linting (typescriptConfig) - this is the rangetypescript-eslintsupports; newertypescriptmajors are not yet compatible with type-aware rules here. Note that a barepnpm add -D typescriptresolves to 7.x (the native compiler, which no longer ships the JS compiler APItypescript-eslintneeds), so install an explicittypescript@6untiltypescript-eslintsupports 7.typescript-eslint >=8.40.0andeslint-plugin-jsdoc >=60.0.0are only needed if you usetypescriptConfig.@eslint/json >=0.13.0is only needed if you usejsonConfig.@html-eslint/eslint-plugin >=0.61.0and@html-eslint/parser >=0.61.0are only needed if you usehtmlConfig.prettier >=3for the Prettier config;stylelint >=17andstylelint-config-standard >=40for the Stylelint config.vite >=8for the Vite factories and plugins;vitest >=4for the test presets, plus@vitest/browser-playwright >=4,@vitest/coverage-istanbul >=4, andplaywright >=1.50forbrowserTestConfig.@earendil-works/pi-ai,@earendil-works/pi-coding-agent, andtypeboxfor the pi extensions - thepiCLI provides all three at runtime, so they're optional peers with no version floor.
License
MIT - see LICENSE. Copyright (c) 2026 Cory Rylan.