4.3 KiB
4.3 KiB
AGENTS.md
Guide for agentic coding assistants working in the Officer monorepo.
Quick Start Commands
Development
bun dev # Dashboard + API server (port 5000)
bun dev:tracking # Tracking server (port 5001)
bun dev:experiments # Experiments server
bun dev:emailer # Emailer workspace
Building & Database
bun run prebuild # Run prebuild tasks
bun run build:dashboard # Build dashboard
bun run build:editor # Build editor (app + extension + runtime)
bun run build:runtime # Build all runtime scripts
bun run db:gen && db:push # Generate & push officer_db migrations
bun run db:gen:stats && db:push:stats # Generate & push statistics_db
Code Quality
bun format # Format all files (Prettier, required before commit)
bun format:check # Check formatting without writing
bunx tsgo # TypeScript type checking (comprehensive, slow)
Note: No automated tests configured yet. Always run bun format before committing.
Code Style Guide
Imports
Order: types → external → workspace → relative
import type { Experiment } from 'types';
import { useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { useExperiment } from 'hooks/use-experiment';
import { formatDate } from '../helpers';
TypeScript
- Strict mode always - no
any - Prefer
typeoverinterface - Colocate prop types with components as named exports
- Early returns for null/undefined guards
- Use optional chaining and nullish coalescing:
obj?.prop ?? fallback
Functions
- Arrow functions for simple/one-liners
- Regular functions for complex multi-line logic
- Named exports only (never default exports)
export const formatDate = (ts: number) => new Date(ts).toLocaleDateString();
export function calculateStats(data: DataPoint[]) {
/* ... */
}
React Components
- Functional components with named prop types
- Arrow function syntax
- No useMemo/useCallback (React 19 compiler handles optimization)
type CardProps = { title: string; onClick: () => void };
export const Card = ({ title, onClick }: CardProps) => <div onClick={onClick}>{title}</div>;
State Management
- Manager pattern for complex hooks - return object with state + methods
- Colocation - all feature state in one hook
- Derived state - compute in hook, not in components
export const useExperimentManager = (id: number) => {
const [exp, setExp] = useState<Experiment | null>(null);
const isActive = exp?.status === 'running';
return {
exp,
isActive,
update: (data) => {
/* ... */
},
};
};
Naming Conventions
- Components:
PascalCase.tsx(e.g.,ExperimentCard.tsx) - Everything else:
kebab-case.ts(e.g.,use-experiment.ts,format-date.ts) - Hooks:
use-*.tsoruseFeatureName.ts
Formatting (Prettier)
- Semicolons: always
- Quotes: single (JS/TS), double (JSX)
- Trailing commas: all
- Indent: 2 spaces
- Line width: 120 characters
Error Handling
- Use try/catch for async operations
- Include context in error messages (IDs, resource names)
- Log with
console.errorand re-throw appropriately - Handle database connection errors explicitly
Async/Await
- Always use async/await (never .then() chains)
- Minimize nesting
Project Structure
src/apps/dashboard/- Admin UI (React 19)src/apps/editor/- Visual editorsrc/servers/api/- REST API (Hono, port 5000)src/servers/tracking/- Event collection (port 5001)src/databases/- PostgreSQL schemas (3 DBs: officer_db, statistics_db, ephemeral_db)src/workspaces/- Shared: components, hooks, helpers, types
Path Aliases
@/→src/apps/dashboard/@@/→src/servers/
Tech Stack
- Runtime: Bun
- Language: TypeScript 5.9 (strict mode)
- Frontend: React 19, React Router, React Query, Tailwind CSS, shadcn/ui
- Backend: Hono, PostgreSQL, Drizzle ORM
- Build: Vite
General Guidelines
- Database-first approach - schema → API → UI
- Self-documenting code - clear naming, minimal comments
- Explicit over implicit - no magic
- Workspace dependencies - use
workspace:* - Environment variables - use
.env, access directly in code