Scripts Skill
This skill documents the conventions and expectations for repository scripts. Follow these rules when adding or changing scripts so they remain discoverable, testable, and consistent with the project's lint/type conventions.
Naming & Location ✅
- •File name pattern: kebab-case.bun.ts (example:
generate-schemas.bun.ts) 💡- •This convention makes it immediately obvious the file is a Bun-executable script.
- •Directory: Place scripts under
scripts/in a descriptive sub-path when helpful:- •
scripts/build/generate-effect-schemas/generate-effect-schemas.bun.ts
- •
- •Special rule: The repository also follows the general import/export file naming rules:
- •Files that have a single exported symbol: PascalCase (e.g.,
MyService.ts) — use this for normal modules. - •Files that export multiple symbols: kebab-case (e.g.,
helpers-io.ts). - •Exception: scripts themselves must use
kebab-case.bun.tsregardless of exported symbols.
- •Files that have a single exported symbol: PascalCase (e.g.,
File format & runtime 🔧
- •Add a shebang at the top so scripts can be run directly:
ts
#!/usr/bin/env bun
- •Use ESM imports (this project uses ESM everywhere):
ts
import { readFileSync } from "node:fs"; - •Prefer running scripts via
npx bunso CI environments that don't have bun globally still work:- •Run directly:
npx bun ./scripts/my-script.bun.ts - •Or:
bun run ./scripts/my-script.bun.tswhen bun is available
- •Run directly:
- •When appropriate, add an entry in
package.jsonscript to simplify execution (optional):json"scripts": { "generate:schemas": "bun run ./scripts/build/generate-effect-schemas/generate-effect-schemas.bun.ts" }
TypeScript, typing & linting rules (strict) ⚠️
- •Strict types:
tsconfigis strict. Avoidany. Useunknownand explicit narrowing where needed. - •No null literals: Prefer
undefinedand type guards. - •No
continuestatements are preferred in loops; prefer structured control flow. - •JSDoc rules: Add JSDoc for exported functions and modules with concise descriptions (no type annotations in JSDoc). Use
@returnswhere applicable and be explicit about side-effects. - •Export policy: Avoid barrel files. Export directly from source files.
Lint & Format ✅
- •Format with:
npx oxfmt .(ornpm run format) - •Lint with:
npx oxlint --config .oxlintrc.json --type-aware .(ornpm run lint) - •Fixable lint issues should be auto-fixed where possible; otherwise discuss with reviewers before suppressing rules.
Tests & Placement 🧪
- •Put tests next to the script under the same directory.
- •Naming: test files should be named exactly after the file they test, with the
.test.tssuffix. Example:- •Script:
scripts/find-missing-jsdoc/find-missing-jsdoc.bun.ts - •Test:
scripts/find-missing-jsdoc/find-missing-jsdoc.bun.test.ts
- •Script:
- •Use Vitest for unit/integration tests and follow the repo's test conventions (colocated tests, descriptive test names, no magic numbers, etc.).
- •When adding an integration-style script test that executes
npx bun, make tests tolerant to environments that do not havebunavailable (use conditional describe/test skip logic or allow environment-specific outcomes to be accepted by assertions).
Examples ✍️
- •Create a Bun script:
- •
scripts/debug-analyze.bun.tswith a shebang and ESM imports - •Execute:
npx bun ./scripts/debug-analyze.bun.tsornpm run debug:analyze(if added topackage.json)
- •
- •Add a test:
scripts/debug-analyze.bun.test.tsthat runs the script (or the internal API) and asserts behavior.
Validation & CI checks 🔁
- •Before submitting a PR run:
- •
npx oxfmt --check .ornpm run format:check - •
npx oxlint --config .oxlintrc.json --type-aware .ornpm run lint - •
npx tsc -b .(typecheck) - •
npm run test:unit -- <path-to-test>(run tests related to your changes)
- •
Rationale / Best Practices 💡
- •Using
kebab-case.bun.tsmakes scripts discoverable and indicates runtime (Bun) at a glance. - •Running via
npx bunensures CI portability without requiring global Bun installs. - •Strict typing and lint rules maintain long-term maintainability and prevent runtime surprises.
Follow these conventions when adding or updating scripts; they keep the repo consistent and make automation predictable for contributors and CI.