| name | stacks-lint |
| description | Use when linting or formatting code in a Stacks project. CRITICAL - always use pickier, NEVER eslint directly. Run 'bunx --bun pickier .' to lint, 'bunx --bun pickier . --fix' to auto-fix. For unused variables, prefer eslint-disable-next-line comments over underscore prefix. Covers @stacksjs/lint and config/code-style.ts. |
| license | MIT |
| compatibility | Bun >= 1.3.0, TypeScript |
| allowed-tools | Read Edit Write Bash Grep Glob |
Stacks Linting
CRITICAL RULES
- ALWAYS use
bunx --bun pickier . to lint -- NEVER use eslint directly
- Auto-fix:
bunx --bun pickier . --fix
- For unused variable warnings: prefer
// eslint-disable-next-line comments over prefixing with _
Key Paths
- Lint package:
storage/framework/core/lint/ (package: @stacksjs/lint)
- Configuration:
config/code-style.ts (auto-loaded via pickier's bunfig alias code-style; pickier handles both linting and formatting)
- Lint command source:
storage/framework/core/buddy/src/commands/lint.ts
Package Details
- Package name:
@stacksjs/lint
- Version: tracks framework version (currently 0.70.23)
- The lint package is a thin wrapper -- the actual linting is done by pickier
storage/framework/core/lint/build.ts is a no-op (nothing to build)
- Dev dependencies:
better-dx, @stacksjs/gitlint, bun-git-hooks
Commands
Via buddy CLI
The buddy lint command internally runs pickier with the project's pickier config:
buddy lint
buddy lint --fix
buddy lint:fix
buddy format
buddy format --write
buddy format --check
buddy format:check
Direct pickier usage
bunx --bun pickier .
bunx --bun pickier . --fix
bun run lint
bun run lint:fix
bun run format
bun run format:check
config/code-style.ts (PickierOptions)
The actual configuration used by the project. This is the source of truth for all lint settings:
import type { PickierOptions } from 'pickier'
const config: PickierOptions = {
format: {
extensions: ['ts', 'js', 'stx', 'json', 'yaml', 'md'],
indent: 2,
quotes: 'single',
semi: false,
},
rules: {
noDebugger: 'off',
noConsole: 'off',
},
pluginRules: {
'regexp/no-unused-capturing-group': 'off',
'regexp/no-super-linear-backtracking': 'off',
'regexp/optimal-quantifier-concatenation': 'off',
'style/brace-style': 'off',
'style/max-statements-per-line': 'off',
'style/quotes': 'off',
'indent': 'off',
'quotes': 'off',
'ts/no-top-level-await': 'off',
'no-console': 'off',
'markdown/heading-increment': 'off',
'markdown/no-empty-links': 'off',
},
ignores: [
'**/fixtures/**',
'**/coverage/**',
'**/temp/**',
],
}
export default config
Format Settings (enforced)
- Indent: 2 spaces
- Quotes: single quotes
- Semicolons: none (no semicolons)
- Extensions: ts, js, stx, json, yaml, md
Handling Unused Variables
When pickier/eslint reports unused variables, use eslint-disable comments -- do NOT prefix with underscore:
const unusedVar = someFunction()
function handler(req, res, next) {
res.send('ok')
}
const _unusedVar = someFunction()
Internal Implementation
The buddy lint command (in storage/framework/core/buddy/src/commands/lint.ts) delegates entirely to pickier:
buddy
.command('lint', 'Automagically lints your project codebase')
.option('-f, --fix', 'Automagically fixes all lint errors', { default: false })
.action(async (options: LintOptions) => {
if (options.fix)
await runCommand('bunx --bun pickier run --mode lint --config ./pickier.config.ts --fix', { cwd: path.projectPath() })
else
await runCommand('bunx --bun pickier run --mode lint --config ./pickier.config.ts', { cwd: path.projectPath() })
})
The format command uses pickier in format mode:
buddy
.command('format', 'Format your project codebase')
.option('-w, --write', 'Write changes to files', { default: false })
.option('-c, --check', 'Check formatting without making changes', { default: false })
.action(async (options) => {
if (options.check)
await runCommand('bunx --bun pickier run --mode format --config ./pickier.config.ts --check', { cwd: path.projectPath() })
else
await runCommand('bunx --bun pickier run --mode format --config ./pickier.config.ts --write', { cwd: path.projectPath() })
})
Gotchas
- Pickier is the Stacks linting tool -- it wraps eslint with Stacks-specific config
- NEVER run
eslint directly -- always go through bunx --bun pickier or buddy lint
- The
config/code-style.ts file exports a PickierOptions object -- not an eslint config (auto-discovered by pickier via bunfig alias code-style)
- The project intentionally allows
console.* calls (noConsole: 'off', 'no-console': 'off')
- The project intentionally allows
debugger statements (noDebugger: 'off')
- Top-level await is allowed (
'ts/no-top-level-await': 'off')
- Brace style and max-statements-per-line rules are disabled to avoid conflicts with generated code
- Run
bunx --bun pickier . --fix after code generation to clean up
buddy lint exits through the lint:* wildcard handler if an invalid sub-command is used
buddy format defaults to --write mode (writes changes) unless --check is specified
- The lint package (
@stacksjs/lint) itself has no source files to build -- it is a configuration-only package