# AGENTS.md This file provides guidelines for AI agents operating in this repository. ## Project Overview This is a bilingual personal portfolio site built with **Astro 5**, **React 19**, and **Tailwind CSS 4**. Current project capabilities from codebase: - EN/ZH localized site with Astro i18n routing (`en` default, `zh` under `/zh`) - Portfolio pages: home, projects, services, now, hire, about - Blog system with posts, tag pages, and category pages in both locales - React interactive islands for header/theme switch, typewriter effect, back-to-top, comments, and animations - Waline comment integration (`@waline/client`) and Umami analytics script in production - SEO/sitemap integration via `@astrojs/sitemap` ## Package Manager Rule (Mandatory) Use **pnpm only** for dependency and script commands. - Always use `pnpm` commands in documentation, scripts, and instructions - Do not use `npm`, `yarn`, or `bun` commands in this repo - If existing text shows `npm run ...`, replace with `pnpm ...` Examples: ```bash pnpm install pnpm dev pnpm build pnpm preview ``` ## Build Commands ```bash # Install dependencies pnpm install # Development server pnpm dev # Build for production pnpm build # Preview production build locally pnpm preview ``` No lint or test commands are configured. Run `pnpm build` to verify changes. ## Code Style Guidelines ### General Principles - Write concise, self-documenting code - Avoid unnecessary comments (only explain complex logic) - Follow existing patterns in the codebase - Prioritize readability over cleverness ### Imports - Use `@/` alias for src imports (configured in `tsconfig.json`) - Order imports: React → libraries → components → utilities - Use named exports for components and utilities ```typescript // Good import * as React from "react"; import { Slot } from "@radix-ui/react-slot"; import { cva, type VariantProps } from "class-variance-authority"; import { cn } from "@/lib/utils"; // Avoid import utils from '@/lib/utils'; import { useState, useEffect } from 'react'; ``` ### TypeScript - Use TypeScript for all new files (`.ts`, `.tsx`) - Extend Astro strict TypeScript config - Use explicit types for component props - Avoid `any`, use `unknown` or specific types ```typescript // Good interface ButtonProps extends React.ButtonHTMLAttributes, VariantProps { asChild?: boolean; } // Avoid const handleClick = (e: any) => { ... } ``` ### Components **Astro Components (`.astro`)**: - Use frontmatter fence `---` at top - Separate imports, props, and logic - Use `client:only="react"` for React components needing browser APIs - Use `client:load` for interactive components that should hydrate on load - Static content should not have client directives **React Components (`.tsx`)**: - Use `React.forwardRef` for components that need refs - Use class-variance-authority (CVA) for component variants where applicable - Use Radix UI primitives when available - Prefer named exports (unless file already follows a default-export pattern) ### Styling (Tailwind CSS) - Use Tailwind utility classes as the primary styling approach - Use `cn()` utility to merge classes with conditional logic - Avoid inline style objects unless strictly necessary - Dark mode styles should use `dark:` variants and existing tokens ### i18n (Internationalization) - All UI text must be in `src/i18n/translations.ts` (and related i18n helpers) - Use translation helpers (`useTranslations(lang)`) - Avoid hardcoded strings in `.astro` and `.tsx` when user-facing text is localized - Keep EN/ZH content parity for shared pages/components ### Naming Conventions - **Components**: PascalCase (e.g., `GlassHeader`) - **Files**: kebab-case for Astro routes, PascalCase for React components - **Variables/functions**: camelCase - **Constants**: SCREAMING_SNAKE_CASE - **Types/Interfaces**: PascalCase, with `Props` suffix for component props ### Error Handling - Use TypeScript types to prevent runtime errors - Handle null/undefined explicitly - Prefer optional chaining (`?.`) and nullish coalescing (`??`) - Avoid broad `try/catch` unless handling known async boundaries ## Astro-Specific Conventions - Pages use file-based routing under `src/pages/` - English routes are root-level; Chinese routes are under `src/pages/zh/` - Blog content uses markdown posts in: - `src/pages/blog/posts/` - `src/pages/zh/blog/posts/` - Layouts are in `src/layouts/` - Reusable UI/components are in `src/components/` - Data source modules are in `src/lib/data/` ## Project Structure ```text src/ ├── components/ # UI components (React & Astro) │ ├── blog/ # Blog-specific components (meta, lists, comments) │ ├── layout/ # Layout helper components (TOC, blog nav) │ ├── markdown/ # Markdown rendering components │ └── ui/ # Reusable UI primitives ├── layouts/ # Shared page layouts ├── pages/ # Routes (including blog and locale routes) │ ├── blog/ │ └── zh/ ├── lib/ │ ├── data/ # Personal info, projects, services │ └── utils.ts ├── i18n/ # Locale constants, translation maps, helpers ├── styles/ # Global and integration styles ├── types/ # Type definitions └── utils/ # Utility functions for blog and helpers ``` ## Important Notes - This is a bilingual site (EN/ZH); maintain both locales - Default language is English (`defaultLang = 'en'`) - Use `Astro.currentLocale` to detect language context - Keep `services` semantics as capabilities/skill offerings - Components depending on `window`, `document`, or `localStorage` must use proper client directives - Preserve existing integrations: MDX, sitemap i18n, Waline comments, and analytics behavior