Shared conventions for all AI coding tools (Claude Code, Opencode, Cursor, etc.).
Always use Bun — never Node.js, npm, pnpm, or Vite.
| Instead of | Use |
|---|---|
node <file> / ts-node <file> |
bun <file> |
npm install / yarn / pnpm install |
bun install |
npm run <script> |
bun run <script> |
npx <pkg> |
bunx <pkg> |
jest / vitest |
bun test |
webpack / esbuild |
bun build <file> |
dotenv |
(not needed — Bun loads .env automatically) |
Prefer Bun-native APIs over third-party equivalents:
Bun.serve()— HTTP server with WebSocket support. Don't useexpress.bun:sqlite— SQLite. Don't usebetter-sqlite3.Bun.redis— Redis. Don't useioredis.Bun.sql— Postgres. Don't usepgorpostgres.js.WebSocket— built-in. Don't usews.Bun.file()— file I/O. Don't usenode:fsreadFile/writeFile.Bun.$— shell commands. Don't useexeca.
apps/ # deployable applications (Next.js, Elysia, Cloudflare Workers, etc.)
libs/ # shared packages imported via @<project>/* path alias
scripts/ # one-off tooling scripts
- Path alias:
@<project>/*→/workspace/libs/*/src - Monorepo tasks (lint, typecheck, test, build) are defined in
.moon/tasks.ymland run viamoon
- Formatter/linter: Biome — run as
bunx biome check --write . - Commits: Conventional Commits enforced by commitlint (
feat,fix,refactor,chore,docs,test) - TypeScript: strict mode, extend from the appropriate base config in the repo root:
tsconfig.base.json— general usetsconfig.lib.base.json— shared librariestsconfig.next.base.json— Next.js appstsconfig.worker.base.json— Cloudflare Workers
ALWAYS commit and push after completing each significant change. Do NOT wait for the user to ask. Before committing, update /workspace/CHANGES.md with a dated entry (Goal + How to implement).
Secrets are host-mounted, not environment variables in the image:
- Common:
~/.config/devcontainer/secrets— shared across all projects - Per-project:
~/.config/devcontainer/secrets.d/<DEVCONTAINER_PROJECT>— overrides common
See .devcontainer/secrets.example for a list of expected keys.