# AGENTS.md Guide for agentic coding assistants working in the Officer monorepo. ## What Is Officer Officer is an **AI-powered intranet server** for small and medium businesses. It's a self-hosted platform that gives each team member a personal AI assistant, file storage, terminal, code editor, workspaces, and project management — all under centralized admin control. **Think of it as**: a self-hosted, AI-native company intranet where every employee gets their own workspace with shared organizational resources and automation. ### Multi-User Architecture - **Role hierarchy**: Member → Admin → Owner → Super Admin - **Bootstrap flow**: First user registers as Super Admin, then invites the team - **Per-user isolation**: Files, sessions, settings, workspaces, and tasks are scoped per user under `$DATA_PATH/{email}/` - **Shared org resources**: Global tasks/skills/processes, server-level settings (SMTP, AI providers, TTS/STT/OCR), pluggable applications and resources - **Multi-scope resolution**: Tasks, skills, and processes resolve user → global → native (built-in), enabling org-wide shared automation ### Core Capabilities 1. **AI Chat** — Multi-provider (Claude, OpenCode, Pi-Mono) with sessions, attachments, speech-to-text, slash commands 2. **File Browser** — Full filesystem access per user (upload, mkdir, copy, move, delete) 3. **File Viewer** — Preview video, images, code, text, markdown 4. **Terminal** — WebSocket-based PTY terminal with Docker sandboxing 5. **Code Editor** — Monaco-based IDE with file tabs 6. **Projects** — Project management with per-project workspace layouts, git init 7. **Workspaces** — Customizable panel-based layouts (split, resize, swap, drag) 8. **Automation/Skills/Tasks/Processes** — Markdown-based capability definitions with YAML frontmatter 9. **Dev Server** — Start/stop project dev servers with auto-port discovery and live proxy 10. **Dashboard Widgets** — Clock, weather, pomodoro, daily goals, quick notes 11. **Settings** — User preferences, server config, resource management ## Quick Start Commands ### Development ```bash bun dev # Dashboard + API server (port 5000) bun dev:emailer # Emailer workspace ``` ### Building ```bash bun run prebuild # Run prebuild tasks bun run build:web # Build web app bun run build:dashboard # Build dashboard bun run build:editor # Build editor (app + extension + runtime) ``` ### Code Quality ```bash bun format # Format all files (Prettier, required before commit) bun format:check # Check formatting without writing bunx tsgo # TypeScript type checking ``` **Note:** No automated tests configured yet. Always run `bun format` before committing. ## Project Structure ``` src/ ├── apps/ │ └── officer-web/ # Main web UI (React 19) │ ├── Screens/ │ │ ├── Authentication/ # Login, verify, reset password │ │ └── Dashboard/ # All main screens (Home, Files, Chat, Terminal, Projects, etc.) │ ├── state/ # App-specific state hooks │ ├── lib/ # Utilities │ └── locales/ # i18n translations │ ├── servers/ │ ├── api/ # REST API (Hono, port 5000) │ │ ├── auth/ # Authentication (JWT + WebAuthn passkeys) │ │ ├── users/ # User management (invite, CRUD) │ │ ├── sessions/ # Multi-provider chat sessions │ │ ├── workspaces/ # Workspace & project state │ │ ├── tasks/ # Task definitions (CRUD + chat) │ │ ├── skills/ # Skill definitions (CRUD + chat) │ │ ├── processes/ # Process definitions (CRUD + chat) │ │ ├── file-browser/ # Filesystem access (multi-root) │ │ ├── terminal/ # WebSocket PTY terminal │ │ ├── dev-server/ # Project dev server management │ │ ├── pi/ # AI agent integration │ │ ├── scrape/ # Web scraping (Playwright) │ │ ├── upload/ # File uploads │ │ ├── settings/ # User settings & state │ │ ├── server-settings/ # Server-wide config (SMTP, AI, TTS, etc.) │ │ ├── dock/ # Dock configuration │ │ ├── plans/ # Markdown plans │ │ ├── task-logs/ # Task execution logs │ │ └── landing-page-data/# Registration status │ └── _middlewares/ # Auth, rate limiting, CORS, body parsing │ ├── databases/ │ └── officer_db/ # JSON file-based auth store (users, passkeys, tokens) │ └── workspaces/ # 13 shared packages ├── types/ # Central type re-exports ├── definitions/ # Constants, enums (roles, statuses, devices) ├── config/ # URL configs, env vars ├── helpers/ # cn(), formatters, slug, debounce, queue ├── hooks/ # 90+ hooks (useClient, useForm, useAuth, etc.) ├── state/ # React Query state hooks (useSettings, useChatSessions, etc.) ├── components/ # 89 components (shadcn/ui base + custom) ├── officerdev/ # Core workspace/panel framework + 11 built-in apps ├── i18n/ # Internationalization ├── injector/ # DOM manipulation for visual editing ├── widgets/ # Dashboard widgets (clock, weather, pomodoro, etc.) ├── emailer/ # React-email templates + SMTP └── sounds/ # Audio feedback library ``` ## Path Aliases - `@/` → `src/apps/officer-web/` - `@@/` → `src/servers/` - `@/components/*` → `src/workspaces/components/*` ## Tech Stack - **Runtime**: Bun - **Language**: TypeScript 5.9 (strict mode, verbatimModuleSyntax) - **Frontend**: React 19, React Router, React Query, Tailwind CSS, shadcn/ui - **Backend**: Hono framework, JWT auth, WebAuthn passkeys - **Storage**: JSON file-based (auth store + user data), no traditional DB for most data - **Build**: Vite - **AI**: Claude Agent SDK, multi-provider support ## Code Style Guide ### Imports Order: **types → external → workspace → relative** ```ts 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'; ``` Type-only imports required (verbatimModuleSyntax): ```ts import { ActionModals, type ActionModalsTypes } from './ActionModals'; import type { FormEvent } from 'react'; ``` ### 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) - Extract params type when signature gets long (no multiline params) ```ts 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) ```tsx type CardProps = { title: string; onClick: () => void }; export const Card = ({ title, onClick }: CardProps) =>
{title}
; ``` ### State Management - **React Query** for server state - **useGlobal()** for UI state (backed by query cache, no Context needed) - **useWorkspacesState()** for persistent workspace layouts (server-synced) - **useQueryState()** for URL-synced state - **usePanelChannel()** for inter-panel pub/sub communication - **Manager pattern** for complex hooks — return object with state + methods - **Derived state** — compute in hook, not in components ### 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) - Always async/await (never .then() chains) ## General Guidelines - **Database-first** approach — schema → API → UI - **Self-documenting code** — clear naming, minimal comments - **Explicit over implicit** — no magic - **Workspace dependencies** — use `workspace:*` - **Multi-user aware** — always consider user isolation and role-based access when adding features - **File-based storage** — user data lives under `$DATA_PATH/{email}/`, respect the per-user boundary