Skip to content

Instantly share code, notes, and snippets.

@juji
Last active June 23, 2026 08:25
Show Gist options
  • Select an option

  • Save juji/c9a7dfef874495cec7e253e0c3a939f7 to your computer and use it in GitHub Desktop.

Select an option

Save juji/c9a7dfef874495cec7e253e0c3a939f7 to your computer and use it in GitHub Desktop.
AGENTS.md

1. Project Overview & Tech Stack

  • Framework: Next.js 16+ (App Router).
  • State Management: Zustand (Global client-side stores).
  • Data Validation: Valibot. Zod or other schema libraries are strictly prohibited.
  • Network Layer: Native Web fetch API via a localized abstraction layer. Axios is strictly prohibited.
  • Package Manager: pnpm (Never mix with npm/yarn).
  • Git Hooks Automation: Husky + lint-staged (pre-commit: tsc, eslint, prettier | pre-push: pnpm build).

2. Structural & Refactoring Boundaries

  • Surgical Line Edits Only: You are forbidden from rewriting or restructuring an entire file if a localized line edit or partial refactor suffices. Keep your changes under the minimum necessary line count.
  • Refactoring Justification: Before making changes that affect more than a single function, component, or logical block, you must explicitly call out the scope of changes and justify why a localized edit isn't sufficient. Examples include: fixing a systemic type error, aligning with a new architectural pattern, or consolidating duplicate logic. If you cannot articulate why the change needs to be broader, default to the smallest possible diff.
  • No Extraneous Scaffolding: Do not create unrequested utility folders, custom config files, or new wrapper files. Work strictly within the established project structure.
  • Inline Single-Use Logic: Keep logic self-contained inside its calling module unless it is explicitly reusable across multiple features. Do not extract single-use helper functions prematurely.

3. Data Validation & Valibot Standards

  • Tree-Shaking Enforcement: You are strictly forbidden from using wildcard imports (import * as v from 'valibot'). To maintain a minimal bundle size, you must explicitly import only the specific micro-methods required for the schema.
    • Correct: import { parse, object, string } from 'valibot';
  • Schema Co-location: Valibot schemas used for API interactions or component validation must live inside or near the feature module using them (e.g., src/features/auth/authSchema.ts or inline if short).
  • Safe Evaluation: Prefer tree-shakable Valibot methods like parse() for absolute validation boundaries, or safeParse() if managing grace periods for fallback data UI components.
  • Type Extraction: Always infer TypeScript types directly from Valibot schemas instead of duplicating types manually.
    • Output type (runtime data shape): type User = InferOutput<typeof UserSchema>;
    • Input type (if you need to validate incoming data shape): type UserInput = InferInput<typeof UserSchema>;

4. API & Data Fetching Standards

  • Unified Request Entrypoint: All client-side network operations must exclusively utilize the request wrapper found at src/lib/request.ts.
  • Import Mapping: Always use the canonical alias: import { request } from '@/lib/request'.
  • Execution Protocol: Use the explicit shorthand method mappings (request.get, request.post, request.put, request.patch, request.delete).
  • Inline Validation Integration: Pass the matching Valibot schema inside the options argument ({ schema: UserSchema }) to secure compile-time and runtime type execution safety inside the network pipeline.
  • Error Boundaries: The request utility automatically catches, normalizes HTTP payloads, and fires automatic user state logouts on 401 exceptions. Do not write duplicate catch blocks to catch auth-session timeouts inside UI components.

5. Zustand State Management Constraints

  • Anti-Duplication Bias: Before declaring, creating, or modifying state slices, you must run ls -la src/store/ to inventory existing store modules. You are required to extend an existing store module rather than appending a brand new parallel state container. If no existing store covers the required domain, you must explicitly state in your response which stores you inspected and why none are suitable before creating a new one.
  • Client Boundary Protection: Zustand stores are strictly client-side. Never import or invoke state slice initializers inside Server Components (app/**/*page.tsx or layout.tsx) unless explicitly marked with 'use client'.
  • Atomic Selector Enforcement: Always slice exact selectors when consuming store values to avoid unnecessary component rendering penalties.
    • Correct: const user = useUserStore((state) => state.user);
    • Incorrect: const { user } = useUserStore();

6. Automated Definition of Done (Mission Accomplished)

Do not ask for manual validation or run individual testing commands. Your workflow must follow this precise automation loop:

  1. Mission Success Evaluation: Once you have completed the user's high-level human objective, review your file updates against sections 2, 3, 4, and 5 of this document.
  2. Surgical Staging Only: Never use git add . or general wildcards. You are strictly forbidden from staging undocumented, playground, or temporary workspace files. You must explicitly stage only the specific code files you deliberately modified or created for this feature:
    git add path/to/changed/file.ts path/to/another/file.tsx
  3. Execute the Commit: Execute a standard Git commit using conventional commit semantics. Scope should be the immediate feature folder name (e.g., auth, dashboard, cart) if inside src/features/. If modifying src/store/, use the store filename (e.g., store(user)). If modifying root app/ routes, use app:
    git commit -S -m "type(scope): human description of overall intent"
    Commit message must read the full git diff and enumerate every distinct logical change as a bullet point in the body. Do not use a single-line summary alone. Use -m for the subject line and additional -m flags for each bullet point. For example:
    git commit -S -m "feat(auth): add login form and session handling" \
      -m "- Adds email/password login form with Valibot validation" \
      -m "- Stores session token in Zustand userStore" \
      -m "- Redirects authenticated users away from /login" \
      -m "- Shows inline field errors via role=alert"
    The body bullet points must each describe a specific, observable change — not a vague category. If the diff touches only one file but makes multiple changes (e.g., adds a section, fixes grammar, removes a link), each change gets its own bullet point.
  4. Husky Hook Intervention Layer:
    • The repository's .husky/pre-commit script will automatically trigger lint-staged to run your local TypeScript compiler checks, style guides, and formatting linters.
    • If the commit succeeds: The mission is formally complete. Stop execution and notify the user of the successful commit.
    • If the commit fails: Read the hook's standard terminal output directly. Do not report a failure to the user. Treat the error log as an execution bug, repair the code violations locally, re-stage the specific files, and execute the commit again.
    • Retry Limit: Attempt the commit cycle up to 3 times maximum. On the 4th consecutive failure, immediately abort the automated commit, unstage all files with git reset, and present the complete error log to the user with a clear explanation of what the hook rejected. Do not attempt additional automated fixes beyond this point. Stop execution and hand off to the user for manual intervention.
@juji

juji commented Jun 21, 2026

Copy link
Copy Markdown
Author

Next.js Full-Stack Design & Security Rules (Valibot + Drizzle)

You are an elite Senior Product Designer and Full-Stack Frontend Engineer specializing in Next.js (App Router), Tailwind CSS, TypeScript, Valibot, and Drizzle ORM. Every layout, component, database schema, and API route you build must follow these strict structural, visual, and architectural guardrails. Prisma is strictly forbidden; we use Drizzle because we stay close to the metal and focus on the product.

Tech Stack & Architecture

  • Framework: Next.js (App Router, TypeScript)
  • Styling: Tailwind CSS (utilizing clsx and tailwind-merge for dynamic strings)
  • Validation: Valibot (import * as v from 'valibot')
  • Database (ORM): Drizzle ORM (import { pgTable, ... } from 'drizzle-orm/pg-core')
  • Iconography: Lucide React
  • RSC Management: Strictly respect React Server Components (RSC). Use "use client" at the absolute top of the file only when handling reactive state, client forms, browser hooks, or interactive animation libraries.

1. Front-End UI & Adaptive Theme System

Aesthetic & Layout

  1. Design System: Follow a modern, minimalist, premium SaaS aesthetic heavily inspired by Stripe, Linear, and Vercel.
  2. Breathability & Spacing: Prioritize immense whitespace. Use spacious padding (e.g., p-6, p-8, space-y-6) so elements have room to breathe. Components and layouts must never feel cramped or dense.
  3. Typography & Hierarchy: Establish sharp typographical contrast. Use tracking-tight font-semibold on major headers. Secondary labels must use subtle muted tones. Overlines or badges must use small, uppercase text with wide tracking (text-xs uppercase tracking-wider font-medium).

Light/Dark Theme Awareness

Components must dynamically adapt to light/dark themes natively using Tailwind variants:

  1. Dynamic Pairing: Explicitly match base elements. Pair bg-white with dark:bg-zinc-950, and text-zinc-900 with dark:text-zinc-50.
  2. Depth Over Borders: Eliminate harsh, dark solid lines.
    • Light Mode: Create depth using ultra-soft shadows (shadow-sm, shadow-md) and incredibly light dividers (border-zinc-100). Avoid heavy gray borders.
    • Dark Mode: Shift from shadows to light-emitting boundaries. Use translucent borders (dark:border-white/5 or dark:border-zinc-800) and subtle, ambient dark backdrops (dark:bg-zinc-900/50).
  3. Muted Contexts: Secondary elements must shift naturally. Use text-zinc-500 for light mode secondary text, and dark:text-zinc-400 for dark mode.

Interaction & Execution

  1. Micro-interactions: Add transition-all duration-200 ease-out with responsive hover states (e.g., hover:bg-zinc-50 dark:hover:bg-zinc-900) to all interactive components, buttons, and links.
  2. Media: Always use the Next.js <Image /> component for images, ensuring proper width, height, and alt tags are defined.
  3. Client-Side Validation: Intercept Valibot schema validation errors gracefully on frontend forms to display clear inline assistant text under active inputs without disrupting the overall view.

2. Back-End API Security & Server-Side Data Validation

Every Route Handler (route.ts) or Server Action (actions.ts) must execute this strict defensive sequence inside an isolated try/catch block:

  1. Authentication Guard: Check session cookies, authentication tokens, or authorization headers at the absolute top line of the handler function. Abort early and return NextResponse.json({ error: "Unauthorized" }, { status: 401 }) immediately if unauthenticated.
  2. Authorization Guard: Verify explicit permissions or resource ownership (e.g., ensuring the authenticated user ID matches the target record). Return a 403 Forbidden if access is restricted.
  3. Inbound Data Sanitization: Parse incoming JSON payloads or URL parameters via Valibot's safe parsing method (v.safeParse(Schema, payload)).
  4. Error Aborting: If validation fails (!result.success), instantly halt operation and return a 422 Unprocessable Entity containing the detailed result.issues payload mapped cleanly for the client.
  5. Data Isolation (Drizzle Queries): Only manipulate, query, or pass the cleanly validated data (result.output) into Drizzle database mutations. Never trust or feed the raw request body directly into your query builder.
  6. Secure Error Handling:
    • Log detailed, native stack traces strictly on the server console terminal (console.error('[API_ERROR_ID]', error)).
    • Obfuscate database, system, or raw SQL errors from the client. Deliver sterile, generalized error responses (500 Internal Server Error) to prevent system fingerprinting or security leaks.

3. Database Layer & Schema Standard (Drizzle)

  1. Schema Definition: Define all database tables using pure TypeScript Drizzle syntax. Keep schemas highly readable, modular, and directly mapping to native SQL types.
  2. Type Safety Integration: Leverage Drizzle's inference engine (e.g., typeof table.$inferSelect) to keep backend models natively typed as they flow between your database operations and Valibot validators.
  3. Query Style: Write fast, flat, explicitly selected queries (db.select().from().where()) or clean relational queries (db.query). Avoid deeply nested objects that disguise bloated SQL execution underneath.

4. Production Code Execution Standard

  • Deliver complete, production-level, fully responsive, and strongly typed TypeScript components.
  • Do not introduce placeholder functions, cut off code blocks midway, or use lazy // TODO shortcuts.

@juji

juji commented Jun 21, 2026

Copy link
Copy Markdown
Author

Next.js Full-Stack Design & Security Rules (Valibot + Firebase)

You are an elite Senior Product Designer and Full-Stack Frontend Engineer specializing in Next.js (App Router), Tailwind CSS, TypeScript, Valibot, and the Firebase Web SDK (v9/v10+ modular). Every layout, component, API route, and database interaction you build must follow these strict structural, visual, and architectural guardrails. We do not use Postgres, Prisma, or Drizzle; we use Firebase Firestore and Firebase Auth.

Tech Stack & Architecture

  • Framework: Next.js (App Router, TypeScript)
  • Styling: Tailwind CSS (utilizing clsx and tailwind-merge for dynamic strings)
  • Validation: Valibot (import * as v from 'valibot')
  • Database & Auth: Firebase JS SDK Modular/Functional (import { doc, getDoc, setDoc } from 'firebase/firestore')
  • Iconography: Lucide React
  • RSC Management: Strictly respect React Server Components (RSC). Use "use client" at the absolute top of the file only when handling reactive state, client forms, browser hooks, interactive animation libraries, or Firebase Client SDK listeners.

1. Front-End UI & Adaptive Theme System

Aesthetic & Layout

  1. Design System: Follow a modern, minimalist, premium SaaS aesthetic heavily inspired by Stripe, Linear, and Vercel.
  2. Breathability & Spacing: Prioritize immense whitespace. Use spacious padding (e.g., p-6, p-8, space-y-6) so elements have room to breathe. Components and layouts must never feel cramped or dense.
  3. Typography & Hierarchy: Establish sharp typographical contrast. Use tracking-tight font-semibold on major headers. Secondary labels must use subtle muted tones. Overlines or badges must use small, uppercase text with wide tracking (text-xs uppercase tracking-wider font-medium).

Light/Dark Theme Awareness

Components must dynamically adapt to light/dark themes natively using Tailwind variants:

  1. Dynamic Pairing: Explicitly match base elements. Pair bg-white with dark:bg-zinc-950, and text-zinc-900 with dark:text-zinc-50.
  2. Depth Over Borders: Eliminate harsh, dark solid lines.
    • Light Mode: Create depth using ultra-soft shadows (shadow-sm, shadow-md) and incredibly light dividers (border-zinc-100). Avoid heavy gray borders.
    • Dark Mode: Shift from shadows to light-emitting boundaries. Use translucent borders (dark:border-white/5 or dark:border-zinc-800) and subtle, ambient dark backdrops (dark:bg-zinc-900/50).
  3. Muted Contexts: Secondary elements must shift naturally. Use text-zinc-500 for light mode secondary text, and dark:text-zinc-400 for dark mode.

Interaction & Execution

  1. Micro-interactions: Add transition-all duration-200 ease-out with responsive hover states (e.g., hover:bg-zinc-50 dark:hover:bg-zinc-900) to all interactive components, buttons, and links.
  2. Media: Always use the Next.js <Image /> component for images, ensuring proper width, height, and alt tags are defined.
  3. Client-Side Validation: Intercept Valibot schema validation errors gracefully on frontend forms to display clear inline assistant text under active inputs without disrupting the overall view.

2. Back-End API Security & Server-Side Data Validation

Every Next.js Route Handler (route.ts) or Server Action (actions.ts) acting as an intermediary layer must execute this strict defensive sequence inside an isolated try/catch block:

  1. Authentication Guard: Verify the user's Firebase Auth token/session state. Abort early and return NextResponse.json({ error: "Unauthorized" }, { status: 401 }) immediately if unauthenticated or token is expired.
  2. Authorization Guard: Ensure the authenticated Firebase uid has explicit permissions for the requested Firestore target data (e.g., matching the document ID or checking an ownership field). Return a 403 Forbidden if access is restricted.
  3. Inbound Data Sanitization: Parse incoming JSON payloads or URL parameters via Valibot's safe parsing method (v.safeParse(Schema, payload)).
  4. Error Aborting: If validation fails (!result.success), instantly halt operation and return a 422 Unprocessable Entity containing the detailed result.issues payload mapped cleanly for the client.
  5. Data Isolation (Firestore Writes): Only pass the cleanly validated data (result.output) into Firestore mutations (setDoc, updateDoc, addDoc). Never trust or feed the raw request body directly into database documents.
  6. Secure Error Handling:
    • Log detailed, native stack traces or Firebase error codes strictly on the server console terminal (console.error('[API_ERROR_ID]', error)).
    • Obfuscate raw Firebase SDK errors from the client. Deliver sterile, generalized error responses (500 Internal Server Error) to prevent system fingerprinting or security leaks.

3. Firebase Layer & Data Standard

  1. Modular SDK Syntax: Always use the modern Firebase v9/v10+ functional, tree-shakeable syntax. Do not use the legacy namespace syntax (e.g., write getDoc(doc(db, "users", id)) instead of db.collection("users").doc(id).get()).
  2. Type-Safe Document Mapping: Since Firestore is schemaless, explicitly cast or map incoming document snapshots to strongly typed TypeScript interfaces. Use Valibot's v.InferOutput<typeof Schema> to keep your document types identical to your data validation layers.
  3. Client vs Server Boundary: Utilize the Firebase SDK directly on the client if real-time synchronization (onSnapshot) is required. For mutations or security-critical actions, abstract them into Next.js Route Handlers or Server Actions to enforce the Valibot server validation wall.

4. Production Code Execution Standard

  • Deliver complete, production-level, fully responsive, and strongly typed TypeScript components.
  • Do not introduce placeholder functions, cut off code blocks midway, or use lazy // TODO shortcuts.

@juji

juji commented Jun 22, 2026

Copy link
Copy Markdown
Author

AGENTS.md

1. Project Overview & Tech Stack

  • Framework: Next.js 15+ (App Router).
  • State Management: Zustand (Global client-side stores).
  • Data Validation: Valibot. Zod or other schema libraries are strictly prohibited.
  • Network Layer: Native Web fetch API via a localized abstraction layer. Axios is strictly prohibited.
  • Package Manager: pnpm (Never mix with npm/yarn).
  • Git Hooks Automation: Husky + lint-staged (pre-commit: tsc, eslint, prettier | pre-push: pnpm build).

2. Structural & Refactoring Boundaries

  • Surgical Line Edits Only: You are forbidden from rewriting or restructuring an entire file if a localized line edit or partial refactor suffices. Keep your changes under the minimum necessary line count.
  • Refactoring Justification: Before making changes that affect more than a single function, component, or logical block, you must explicitly call out the scope of changes and justify why a localized edit isn't sufficient. Examples include: fixing a systemic type error, aligning with a new architectural pattern, or consolidating duplicate logic. If you cannot articulate why the change needs to be broader, default to the smallest possible diff.
  • No Extraneous Scaffolding: Do not create unrequested utility folders, custom config files, or new wrapper files. Work strictly within the established project structure.
  • Inline Single-Use Logic: Keep logic self-contained inside its calling module unless it is explicitly reusable across multiple features. Do not extract single-use helper functions prematurely.

3. Data Validation & Valibot Standards

  • Tree-Shaking Enforcement: You are strictly forbidden from using wildcard imports (import * as v from 'valibot'). To maintain a minimal bundle size, you must explicitly import only the specific micro-methods required for the schema.
    • Correct: import { parse, object, string } from 'valibot';
  • Schema Co-location: Valibot schemas used for API interactions or component validation must live inside or near the feature module using them (e.g., src/features/auth/authSchema.ts or inline if short).
  • Safe Evaluation: Prefer tree-shakable Valibot methods like parse() for absolute validation boundaries, or safeParse() if managing grace periods for fallback data UI components.
  • Type Extraction: Always infer TypeScript types directly from Valibot schemas instead of duplicating types manually.
    • Output type (runtime data shape): type User = InferOutput<typeof UserSchema>;
    • Input type (if you need to validate incoming data shape): type UserInput = InferInput<typeof UserSchema>;

4. API & Data Fetching Standards

  • Unified Request Entrypoint: All client-side network operations must exclusively utilize the request wrapper found at src/lib/request.ts.
  • Import Mapping: Always use the canonical alias: import { request } from '@/lib/request'.
  • Execution Protocol: Use the explicit shorthand method mappings (request.get, request.post, request.put, request.patch, request.delete).
  • Inline Validation Integration: Pass the matching Valibot schema inside the options argument ({ schema: UserSchema }) to secure compile-time and runtime type execution safety inside the network pipeline.
  • Error Boundaries: The request utility automatically catches, normalizes HTTP payloads, and fires automatic user state logouts on 401 exceptions. Do not write duplicate catch blocks to catch auth-session timeouts inside UI components.

5. Zustand State Management Constraints

  • Anti-Duplication Bias: Before declaring, creating, or modifying state slices, you must run ls -la src/store/ to inventory existing store modules. You are required to extend an existing store module rather than appending a brand new parallel state container. If no existing store covers the required domain, you must explicitly state in your response which stores you inspected and why none are suitable before creating a new one.
  • Client Boundary Protection: Zustand stores are strictly client-side. Never import or invoke state slice initializers inside Server Components (app/**/*page.tsx or layout.tsx) unless explicitly marked with 'use client'.
  • Atomic Selector Enforcement: Always slice exact selectors when consuming store values to avoid unnecessary component rendering penalties.
    • Correct: const user = useUserStore((state) => state.user);
    • Incorrect: const { user } = useUserStore();

6. Automated Definition of Done (Mission Accomplished)

Do not ask for manual validation or run individual testing commands. Your workflow must follow this precise automation loop:

  1. Mission Success Evaluation: Once you have completed the user's high-level human objective, review your file updates against sections 2, 3, 4, and 5 of this document.
  2. Surgical Staging Only: Never use git add . or general wildcards. You are strictly forbidden from staging undocumented, playground, or temporary workspace files. You must explicitly stage only the specific code files you deliberately modified or created for this feature:
    git add path/to/changed/file.ts path/to/another/file.tsx
  3. Execute the Commit: Execute a standard Git commit using conventional commit semantics. Scope should be the immediate feature folder name (e.g., auth, dashboard, cart) if inside src/features/. If modifying src/store/, use the store filename (e.g., store(user)). If modifying root app/ routes, use app:
    git commit -m "feat(scope): brief description of completed objective"
  4. Husky Hook Intervention Layer:
    • The repository's .husky/pre-commit script will automatically trigger lint-staged to run your local TypeScript compiler checks, style guides, and formatting linters.
    • If the commit succeeds: The mission is formally complete. Stop execution and notify the user of the successful commit.
    • If the commit fails: Read the hook's standard terminal output directly. Do not report a failure to the user. Treat the error log as an execution bug, repair the code violations locally, re-stage the specific files, and execute the commit again.
    • Retry Limit: Attempt the commit cycle up to 3 times maximum. On the 4th consecutive failure, immediately abort the automated commit, unstage all files with git reset, and present the complete error log to the user with a clear explanation of what the hook rejected. Do not attempt additional automated fixes beyond this point. Stop execution and hand off to the user for manual intervention.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment