This file provides guidance to coding agents when working with code in this repository.
This project uses bun as the package manager. The repository enforces this via a preinstall script, so do not use npm, yarn, or pnpm.
make devorbun run dev- Start the Next.js development servermake buildorbun run build- Build the production applicationbun run postbuild- Generate sitemap (runs automatically after build)
make lintorbun run lint- Run ESLintmake formatorbun run format- Format code with Prettier
make installormake iorbun install- Install dependencies
make startorbun run start- Start the production servermake export- Export static site
This is a Next.js 16 application using the App Router (not Pages Router). The main application code lives in the app/ directory.
app/- Next.js app router pages and componentsapp/(writing)/- Route group for blog content (doesn't affect URL structure)app/(writing)/content/- MDX blog post filesapp/(writing)/[slug]/page.tsx- Dynamic route for individual blog postsapp/(writing)/posts.json- Post metadata (id, title, date) for static generation
app/components/- Shared components (Navbar, Footer, ThemeSwitch, etc.)app/hooks/- Custom React hooks (useTheme,useLockBodyScroll)app/store/- Redux Toolkit store, reducers, and selectorsapp/writing/page.tsx- Blog listing pageapp/bookmarks/page.tsx- Bookmarks page
mdx-components.ts- MDX component mappings for blog posts
Redux Toolkit is used for global state management with two slices:
- theme: Manages dark/light theme state
- writing: Manages image overlay functionality for blog posts
The Redux store is provided to the app via app/components/Providers.tsx which wraps the application in app/layout.tsx.
The theme uses a hybrid approach:
- An inline script in
app/layout.tsxruns before React hydration to prevent flash of incorrect theme - The script reads from localStorage and sets the initial theme class on the
<html>element - React components (ThemeSwitch) sync with this via the Redux store
- This avoids server/client mismatch while maintaining fast theme initialization
Blog posts are MDX files stored in app/(writing)/content/. Each post:
- Exports a
metadataobject containing title, description, and openGraph data - Is dynamically imported in
app/(writing)/[slug]/page.tsxbased on the slug - Uses custom MDX components (h1, h2, p, code, image, etc.) defined in
mdx-components.ts - Must be registered in
app/(writing)/posts.jsonto appear in the blog listing and enable static generation
To add a new blog post:
- Create a new
.mdxfile inapp/(writing)/content/with a URL-friendly filename (e.g.,my-post-title.mdx) - Add metadata export at the top of the file
- Add the post to
posts.jsonwith matching id (filename without .mdx), title, and date
The project uses @/* path aliases (configured in tsconfig.json) that resolve to the root directory. Use these for imports: @/app/components/Navbar instead of relative paths.
Create a .env file based on .env.example. Sentry variables are optional - the site functions without them.
- TailwindCSS 4.x is used for styling
- Uses Geist and Geist Mono fonts from
next/font/google - Dark mode is implemented via the
darkclass on the<html>element
This project uses the experimental React Compiler (reactCompiler: true in next.config.js) for automatic memoization.
MDX is configured in next.config.js with:
@next/mdxpluginmdxRs: truefor the faster Rust-based MDX compiler- Custom component provider pointing to
mdx-components.ts
Sentry is integrated for error tracking via @sentry/nextjs with configuration in:
sentry.client.config.tssentry.edge.config.tssentry.server.config.ts