What I Do
Enforce AGENTS.md rules during PR review (architecture layering, TypeScript discipline, DB safety, auth, MCP protocol, tests).
Core Checklist (Must Enforce)
Architecture / Boundaries
- •Layering: Routes/Handlers (
routes/) → Service Facade (services/articles.ts) → DB Services (databaseArticles.ts,databaseVersionHistory.ts,databaseEmbedding.ts) → PostgreSQL - •Single server:
src/backend/server.tshandles API, MCP, and static serving - •Routes = orchestration only (auth check → validate input → call service → format response)
- •Services throw descriptive errors; handlers catch and return HTTP status codes
- •Use the facade: handlers call
articleService, never import DB services directly - •Filenames are virtual:
slug+.md(useslugToFilename/filenameToSlug)
TypeScript / Imports (CRITICAL)
- •Strict mode: no
any, no@ts-ignore, no@ts-expect-error - •Explicit interfaces for all data structures
- •ESM only with
.tsextensions in imports (e.g.,from './file.ts') - •Node built-ins via bare specifiers (
fs/promises,path) - •Naming:
camelCasefunctions/vars,PascalCaseComponents/Interfaces,SCREAMING_SNAKE_CASEconstants - •If you see type suppression: block the review until fixed
Database Operations
- •Parameterized queries only (
$1, $2placeholders) — never string interpolation in SQL - •Connection pooling: use
databaseService.getClient(), never createPoolinstances - •Always
client.release()infinallyblocks — no resource leaks - •Wrap DB operations in try-catch, use
handleDatabaseError()
Authentication & Security
- •All write endpoints:
requireAuth(request, 'write')with scope check - •All read endpoints:
requireAuth(request)(read-only scope minimum) - •Web-only endpoints (token management):
useWebAuth: true - •Bearer tokens:
Authorization: Bearer <token>— never log full tokens - •Input validation via
mcp/validation.tshelpers - •Path traversal prevention (no
../in filenames/slugs) - •DOMPurify for user content on frontend
Frontend (React)
- •State:
useState,useContext, custom hooks — no Redux/Zustand/MobX - •API calls: use
apiClient— never rawfetch()with hardcoded paths - •Theming: CSS variables +
data-themeattribute — no inline theme colors - •Functional components with hooks only — no class components
- •URL paths: use
buildRouteUrl/buildApiUrl— never hardcode paths (breaks subpath deployment)
MCP Protocol
- •Tool definitions in
mcp/server.ts, handlers inmcp/handlers.ts - •Filter tools by token scope (read-only vs write)
- •Validate ALL tool arguments via
validation.ts - •Return format:
{ content: [{ type: 'text', text: JSON.stringify(data) }] }
Embeddings / Performance
- •Embedding operations must not block article CRUD — use
safelyHandleEmbeddingOperation() - •Queue via
embeddingQueueService.enqueue()with priority levels - •Article operations succeed even if embeddings fail (graceful degradation)
Explicit Anti-patterns (Flag)
- •
as any,@ts-ignore,@ts-expect-error(type suppression) - •String concatenation in SQL queries (injection risk)
- •
client.query()withouttry/finallywithclient.release()(resource leak) - •Direct import of
databaseArticles.tsfrom routes/handlers (bypass facade) - •Raw
fetch('/api/...')in frontend (bypasses apiClient + base path) - •Hardcoded URL paths in frontend (breaks nginx subpath deployment)
- •
await upsertArticleChunks()synchronously blocking article CRUD - •Empty catch blocks
catch(e) {}(swallowed errors) - •Unauthenticated write operations
- •Unwanted files in git (logs, traces,
.env, credentials)
Review Flow (Fast)
- •Identify layer by path (Route / Service / DB Service / Frontend / MCP)
- •Apply the layer checks below + cross-cutting checks (TypeScript, auth, errors)
- •Report using the template; require
bun run typecheckandbun run precommitfor approval
Layer Checks
Routes/Handlers (routes/): Auth check with correct scope; input validation; call articleService only; proper HTTP status codes; no business logic; no DB imports.
Service Facade (services/articles.ts): Throw descriptive errors; orchestrate DB services + embeddings; no HTTP objects; no raw DB queries.
DB Services (database*.ts): Parameterized queries only; client.release() in finally; handleDatabaseError() on catch; return domain objects.
Frontend (.tsx): React hooks only; apiClient for requests; CSS variables for theming; buildRouteUrl/buildApiUrl for paths; no state management libraries.
MCP (mcp/): Validate all args via validation.ts; scope-filtered tools; proper MCP response format; delegate to articleService.
Review Output Template
## Summary [Critical/High/Medium/Low] + 1-2 sentences ## Critical (Must Fix) 1. [file:line] problem → fix → AGENTS.md ref ## Recommendations - ... ## Action Items - [ ] ... ## Required Checks - bun run typecheck - bun run precommit (- bun run build if frontend changed) (- bun scripts/verify-mcp.ts <TOKEN> if MCP changed)