Skip to content

Latest commit

 

History

History
199 lines (148 loc) · 6.19 KB

File metadata and controls

199 lines (148 loc) · 6.19 KB

AGENTS.md

Purpose

Guide for coding agents working in this repo. Use repo commands, follow existing patterns, and keep edits focused. Prefer nearby conventions over new abstractions.

Stack Snapshot

  • React Router (framework mode), React 18, TypeScript, Vite
  • Package manager: pnpm (pnpm-lock.yaml)
  • Runtime: Node >=24 (Volta pins Node 24.13.1)
  • Styling: Tailwind + custom CSS
  • Content: MDX in content/
  • Data/cache: Redis + @epic-web/cachified
  • Integrations: Inngest, Algolia, Sentry, Fly.io

Important Paths

  • App: app/
  • Routes: app/routes/
  • Utilities: app/utils/
  • Inngest: app/inngest/
  • Content: content/blog, content/til, content/pages
  • Server entry: index.mjs, server/index.mjs, server/dev-server.mjs
  • Config: tsconfig.json, eslint.config.mjs, prettier.config.js

Setup

  • Install deps: pnpm install
  • Pull env (optional): npx dotenv-vault pull
  • Start Redis: docker-compose up -d
  • Optional Inngest server: npx inngest-cli@latest dev
  • Start app: pnpm dev (usually http://localhost:8080)

Build/Lint/Typecheck/Test

Core commands

  • Clean: pnpm clean
  • Dev: pnpm dev
  • Build: pnpm build
  • Start prod: pnpm start
  • Lint: pnpm lint
  • Typecheck: pnpm typecheck
  • Format: pnpm format
  • Extra checks: pnpm knip

Test status

  • Runner: Vitest (vitest.config.ts)
  • Full suite: pnpm test (vitest run)
  • Current coverage is a small smoke suite in tests/smoke/*.test.ts

Running a single test

  • File: pnpm test:single tests/smoke/health-route.test.ts
  • Test name: pnpm test:single tests/smoke/env.server.test.ts -t "fallback"

Targeted command pattern

  • Lint one file: pnpm lint -- app/routes/_index.tsx
  • Typecheck is project-wide (tsc -b .), so use pnpm typecheck

Pre-commit and CI

  • Pre-commit hook (.husky/pre-commit) runs npx lint-staged
  • lint-staged runs clean, test, lint, typecheck, and prettier
  • CI deploy workflow runs lint + typecheck + test before deploy

Code Style Guidelines

Formatting and linting

  • Prettier is source of truth (prettier.config.js)
  • ESLint config is eslint.config.mjs
  • Prettier/ESLint both extend @epic-web/config/*
  • Prefer fixing warnings instead of disabling rules
  • Existing style: single quotes, trailing commas, minimal semicolons

Imports

  • Order: Node built-ins -> third-party -> ~/... -> relative
  • Prefer type imports for type-only symbols
  • Use ~/ alias for cross-app imports (~/* -> app/*)
  • Use relative imports for same-folder files

TypeScript and validation

  • strict: true is enabled; keep code strongly typed
  • Avoid any; use unknown and narrow
  • Use Zod for runtime validation of untrusted input
  • Infer schema types with z.infer<typeof schema>
  • In routes, prefer useLoaderData<typeof loader>()
  • Use LoaderFunctionArgs / ActionFunctionArgs from react-router

Naming conventions

  • Files/folders: kebab-case
  • Components and types: PascalCase
  • Variables/functions: camelCase
  • Booleans should read as predicates (isOpen, hasX, showX)
  • Server-only modules use .server.ts
  • Client-only modules use .client.tsx when applicable

Route/data patterns

  • Common route exports: loader, action, meta, shouldRevalidate, default
  • Use data(...), redirect(...), and thrown Response
  • Use invariantResponse for required params/data checks
  • Keep explicit status codes for expected failures

Error handling

  • Validate params, form data, JSON body, and env early
  • Log useful context in catch blocks
  • Rethrow when callers should fail
  • Return fallbacks only when intentionally graceful

Environment variables

  • Env schema is in app/utils/env.server.ts
  • Add new env vars there before use
  • Expose only safe values via getEnv()
  • Never leak secrets to window.ENV

Caching and async work

  • Follow Redis key patterns (gql:*, home:*)
  • Reuse existing cachified patterns in app/utils/*
  • For bulk refreshes, use bounded concurrency (p-queue)
  • Be careful changing cache key shapes

UI and MDX

  • Tailwind is the default styling approach
  • Use twMerge / twJoin for conditional classes
  • Reuse shared UI primitives before adding new ones
  • MDX compile path: app/utils/mdx.server.ts
  • MDX cache/list path: app/utils/mdx-utils.server.ts

Cursor/Copilot Rules

  • Checked .cursor/rules/, .cursorrules, .github/copilot-instructions.md
  • No Cursor or Copilot instruction files were found

Agent Working Agreement

  • Make minimal, targeted changes
  • Avoid bundling broad refactors with feature/fix work
  • Keep server/client boundaries intact (.server must not leak client-side)
  • After non-trivial edits, run pnpm lint and pnpm typecheck
  • If you add tests, add full-suite + single-test commands and update this file

Design Context

Users

  • Primary: Other software developers reading technical content
  • Context: Reading on desktop or mobile, often during work breaks or personal learning time
  • Job to be done: Find useful technical content quickly, browse TILs, stay updated on posts

Brand Personality

  • Playful developer - voice that feels like a real person, not a content machine
  • Confident monospace choice signals technical identity without apology
  • Humor and personality (Giphy errors, random quotes, easter eggs) is intentional, not accidental

Aesthetic Direction

  • Monospace-only typography: CommitMono as the single font family - bold choice that works
  • Pink accent: hsl(322, 83%, 57%) is the only color beyond neutrals - commit to it
  • Dark + light modes: Both supported, no "default" - user preference wins
  • Anti-patterns to avoid:
    • No gradient text
    • No glassmorphism
    • No hero metric layouts
    • No generic shadows or glowing effects
    • No centered-container everything

Design Principles

  1. Personality first - If a choice makes the site feel more like a real person, do it
  2. Technical identity - The monospace font IS the brand; lean into it, don't soften it
  3. Pink is enough - One accent color is stronger than five; resist adding more
  4. Avoid the template - If it's a pattern you'd see on 100 AI-generated sites, reject it
  5. Motion with purpose - Every animation should feel intentional, not decorative