diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..66c3375
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,200 @@
+# AGENTS.md - AI Coding Agent Guidelines
+
+Guidelines for AI agents working in this Bun monorepo.
+
+## Project Overview
+
+- **Monorepo**: Bun workspaces + Turborepo orchestration
+- **Runtime**: Bun (see `mise.toml` for version)
+- **Apps**:
+ - `apps/server` - TanStack Start fullstack web app (see `apps/server/AGENTS.md`)
+ - `apps/desktop` - Tauri v2 desktop shell, loads server via sidecar (see `apps/desktop/AGENTS.md`)
+- **Packages**: `packages/utils`, `packages/tsconfig` (shared configs)
+
+## Build / Lint / Test Commands
+
+### Root Commands (via Turbo)
+```bash
+bun dev # Start all apps in dev mode
+bun build # Build all apps
+bun fix # Lint + format (Biome auto-fix)
+bun typecheck # TypeScript check across monorepo
+```
+
+### Server App (`apps/server`)
+```bash
+bun dev # Vite dev server (localhost:3000)
+bun build # Production build → .output/
+bun fix # Biome auto-fix
+bun typecheck # TypeScript check
+
+# Database (Drizzle)
+bun db:generate # Generate migrations from schema
+bun db:migrate # Run migrations
+bun db:push # Push schema (dev only)
+bun db:studio # Open Drizzle Studio
+```
+
+### Desktop App (`apps/desktop`)
+```bash
+bun dev # Copy sidecar + start Tauri dev
+bun build # Copy sidecar + build installer
+
+# Rust (from apps/desktop/src-tauri/)
+cargo check # Compile check
+cargo clippy # Linter
+cargo fmt # Formatter
+```
+
+### Testing
+No test framework configured yet. When adding tests:
+```bash
+bun test path/to/test.ts # Run single test file
+bun test -t "pattern" # Run tests matching pattern
+cargo test test_name -- --nocapture # Rust single test with output
+```
+
+## Code Style (TypeScript)
+
+### Formatting (Biome)
+- **Indent**: 2 spaces
+- **Line endings**: LF
+- **Quotes**: Single `'`
+- **Semicolons**: Omit (ASI)
+- **Arrow parentheses**: Always `(x) => x`
+
+### Imports
+Biome auto-organizes. Order:
+1. External packages
+2. Internal `@/*` aliases
+3. Type imports (`import type { ... }`)
+
+```typescript
+import { createFileRoute } from '@tanstack/react-router'
+import { z } from 'zod'
+import { db } from '@/server/db'
+import type { ReactNode } from 'react'
+```
+
+### TypeScript Strictness
+- `strict: true`
+- `noUncheckedIndexedAccess: true` - array/object access returns `T | undefined`
+- `noImplicitOverride: true`
+- `verbatimModuleSyntax: true`
+- Use `@/*` path aliases (maps to `src/*`)
+
+### Naming Conventions
+| Type | Convention | Example |
+|------|------------|---------|
+| Files (utils) | kebab-case | `auth-utils.ts` |
+| Files (components) | PascalCase | `UserProfile.tsx` |
+| Components | PascalCase arrow | `const Button = () => {}` |
+| Functions | camelCase | `getUserById` |
+| Constants | UPPER_SNAKE | `MAX_RETRIES` |
+| Types/Interfaces | PascalCase | `UserProfile` |
+
+### React Patterns
+```typescript
+// Components: arrow functions (enforced by Biome)
+const MyComponent = ({ title }: { title: string }) => {
+ return
{title}
+}
+
+// Routes: TanStack Router file conventions
+export const Route = createFileRoute('/')({
+ component: Home,
+})
+
+// Data fetching: TanStack Query
+const { data } = useSuspenseQuery(orpc.todo.list.queryOptions())
+```
+
+### Error Handling
+- Use `try-catch` for async operations
+- Throw descriptive errors
+- ORPC: Use `ORPCError` with proper codes (`NOT_FOUND`, `INPUT_VALIDATION_FAILED`)
+- Never use empty catch blocks
+
+## Code Style (Rust - Tauri)
+
+- **Indent**: 4 spaces
+- **Naming**: snake_case (functions), PascalCase (types), SCREAMING_SNAKE (consts)
+- Use `expect("中文消息")` over `unwrap()`
+- Async: `tokio` runtime, `tauri::async_runtime::spawn`
+- Run `cargo fmt` and `cargo clippy` before commit
+
+## Database (Drizzle ORM)
+
+```typescript
+import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core'
+import { sql } from 'drizzle-orm'
+
+export const myTable = pgTable('my_table', {
+ id: uuid().primaryKey().default(sql`uuidv7()`),
+ name: text().notNull(),
+ createdAt: timestamp({ withTimezone: true }).notNull().defaultNow(),
+ updatedAt: timestamp({ withTimezone: true }).notNull().defaultNow().$onUpdateFn(() => new Date()),
+})
+```
+
+## Environment Variables
+
+- Use `@t3-oss/env-core` with Zod validation in `src/env.ts`
+- Server vars: no prefix
+- Client vars: `VITE_` prefix required
+- Never commit `.env` files
+
+## Critical Rules
+
+**DO:**
+- Run `bun fix` before committing
+- Use `@/*` path aliases (not relative imports)
+- Let React Compiler handle memoization (no manual `useMemo`/`useCallback`)
+- Include `createdAt`/`updatedAt` on all tables
+
+**DON'T:**
+- Edit `src/routeTree.gen.ts` (auto-generated)
+- Use `as any`, `@ts-ignore`, `@ts-expect-error`
+- Commit `.env` files
+- Use empty catch blocks `catch(e) {}`
+- Use `unwrap()` in Rust without `expect()`
+
+## Git Workflow
+
+1. Make changes following style guide
+2. `bun fix` - auto-format and lint
+3. `bun typecheck` - verify types
+4. `bun dev` - test locally
+5. Commit with descriptive message
+
+## Directory Structure
+
+```
+.
+├── apps/
+│ ├── server/ # TanStack Start fullstack app
+│ │ ├── src/
+│ │ │ ├── client/ # ORPC client, Query client
+│ │ │ ├── components/
+│ │ │ ├── routes/ # File-based routing
+│ │ │ └── server/ # API layer + database
+│ │ │ ├── api/ # ORPC contracts, routers, middlewares
+│ │ │ └── db/ # Drizzle schema
+│ │ └── AGENTS.md
+│ └── desktop/ # Tauri v2 shell (no frontend src)
+│ ├── src-tauri/ # Rust Tauri code
+│ │ ├── src/ # Rust source
+│ │ └── binaries/ # Sidecar binaries
+│ └── AGENTS.md
+├── packages/
+│ ├── tsconfig/ # Shared TS configs
+│ └── utils/ # Shared utilities
+├── biome.json # Linting/formatting config
+├── turbo.json # Turbo task orchestration
+└── package.json # Workspace root
+```
+
+## See Also
+
+- `apps/server/AGENTS.md` - Detailed TanStack Start / ORPC patterns
+- `apps/desktop/AGENTS.md` - Rust / Tauri development guide
diff --git a/apps/desktop/AGENTS.md b/apps/desktop/AGENTS.md
new file mode 100644
index 0000000..eaa0206
--- /dev/null
+++ b/apps/desktop/AGENTS.md
@@ -0,0 +1,171 @@
+# AGENTS.md - Desktop App Guidelines
+
+Tauri v2 desktop shell - a lightweight wrapper that loads the server app via sidecar.
+
+## Architecture
+
+- **Type**: Tauri v2 desktop application (shell only)
+- **Design**: Tauri provides native desktop APIs; all web logic handled by sidecar
+- **Sidecar**: The compiled server binary runs as a child process
+- **Dev mode**: Connects to `localhost:3000` (requires server dev running)
+- **Prod mode**: Automatically starts sidecar binary
+
+**This app has NO frontend src** - it loads the server app entirely.
+
+## Commands
+
+```bash
+# Development (from apps/desktop/)
+bun dev # Copy sidecar + start Tauri dev
+
+# Build
+bun build # Copy sidecar + build Tauri installer
+
+# Rust Commands (from src-tauri/)
+cargo check # Compile check
+cargo clippy # Linter
+cargo fmt # Formatter
+cargo test # Run tests
+cargo test test_name -- --nocapture # Single test with output
+```
+
+## Directory Structure
+
+```
+apps/desktop/
+├── src-tauri/ # Rust Tauri code
+│ ├── src/
+│ │ ├── main.rs # Entry point (calls lib::run)
+│ │ ├── lib.rs # Core app logic (plugins, commands, state)
+│ │ ├── commands/
+│ │ │ └── mod.rs # Native desktop commands
+│ │ └── sidecar.rs # Sidecar process management
+│ ├── binaries/ # Sidecar binaries (copied from server build)
+│ ├── capabilities/ # Tauri v2 permission config
+│ ├── icons/ # App icons
+│ ├── Cargo.toml # Rust dependencies
+│ └── tauri.conf.json # Tauri configuration
+├── copy.ts # Script to copy server binary to binaries/
+├── package.json
+└── tsconfig.json
+```
+
+## Development Workflow
+
+1. **Start server dev first**: `cd ../server && bun dev`
+2. **Start Tauri**: `bun dev` (from apps/desktop/)
+3. Tauri connects to localhost:3000 with HMR support
+
+## Rust Code Style
+
+### Formatting
+- **Indent**: 4 spaces
+- **Line width**: 100 chars
+- Run `cargo fmt` before commit
+
+### Naming
+| Type | Convention | Example |
+|------|------------|---------|
+| Functions/variables | snake_case | `find_available_port` |
+| Types/structs/enums | PascalCase | `SidecarProcess` |
+| Constants | SCREAMING_SNAKE | `DEFAULT_PORT` |
+
+### Imports
+```rust
+// Order: std → external crates → internal modules (separated by blank lines)
+use std::sync::Mutex;
+
+use tauri::Manager;
+use tauri_plugin_shell::ShellExt;
+
+use crate::sidecar::SidecarProcess;
+```
+
+### Error Handling
+```rust
+// Use expect() with Chinese error messages
+let sidecar = app_handle
+ .shell()
+ .sidecar("server")
+ .expect("无法找到 server sidecar");
+
+// Log with emoji for clear feedback
+println!("✓ Sidecar 启动成功!");
+eprintln!("✗ Sidecar 启动失败");
+```
+
+### Async Code
+```rust
+// Use Tauri's async runtime for spawning
+tauri::async_runtime::spawn(async move {
+ let port = find_available_port(3000).await;
+ // ...
+});
+```
+
+## Tauri Patterns
+
+### Command Definition
+```rust
+#[tauri::command]
+fn greet(name: &str) -> String {
+ format!("Hello, {}!", name)
+}
+
+// Register in Builder
+.invoke_handler(tauri::generate_handler![commands::greet])
+```
+
+### State Management
+```rust
+struct SidecarProcess(Mutex