Files
platform/AGENTS.md
T
2026-02-16 19:34:35 +00:00

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 type over interface
  • 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-*.ts or useFeatureName.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.error and 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 editor
  • src/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