replace the stale AGENTS.md with a pointer to CLAUDE.md
It described a product that no longer exists: a multi-user intranet for small businesses, a user-invitation API, bun dev serving a separate dashboard on port 5000, and a closing rule to "always consider user isolation and role-based access" — the opposite of how this codebase now works. An agent opening this repo read that before anything accurate. Now mirrors the deployment root: AGENTS.md points at CLAUDE.md so the two cannot drift, and lists which of the remaining root documents are current. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
fe6f1fc095
commit
f08179606b
@@ -1,220 +1,32 @@
|
|||||||
# AGENTS.md
|
# AGENTS.md
|
||||||
|
|
||||||
Guide for agentic coding assistants working in the Officer monorepo.
|
Guidance for any coding agent working in the Officer platform repo.
|
||||||
|
|
||||||
## What Is Officer
|
**The instructions live in [`CLAUDE.md`](CLAUDE.md). Read it first — this file only points there.**
|
||||||
|
|
||||||
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.
|
Kept separate so agents that look for `AGENTS.md` by convention find the same guidance as those that
|
||||||
|
look for `CLAUDE.md`, without the two drifting apart. The previous contents of this file had drifted
|
||||||
|
badly: they described Officer as a multi-user intranet for small businesses, with a user-invitation
|
||||||
|
API, a `bun dev` serving a separate dashboard on port 5000, and a closing instruction to be
|
||||||
|
"multi-user aware — always consider user isolation and role-based access". None of that is true.
|
||||||
|
|
||||||
**Think of it as**: a self-hosted, AI-native company intranet where every employee gets their own workspace with shared organizational resources and automation.
|
## Orientation
|
||||||
|
|
||||||
### Multi-User Architecture
|
Officer is a self-hosted personal platform that **serves exactly one person — the owner of the
|
||||||
|
server**. There is no tenancy, no roles, no user management. If a design question turns on "which
|
||||||
|
user", the answer is the owner.
|
||||||
|
|
||||||
- **Role hierarchy**: Member → Admin → Owner → Super Admin
|
This repo is one of two. The other, `capabilities/`, holds the agent's tasks, tools and skills as
|
||||||
- **Bootstrap flow**: First user registers as Super Admin, then invites the team
|
plain files, and is where most changes belong — adding or changing a task needs no code change here
|
||||||
- **Per-user isolation**: Files, sessions, settings, workspaces, and tasks are scoped per user under `$DATA_PATH/{email}/`
|
and no restart.
|
||||||
- **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
|
- [`CLAUDE.md`](CLAUDE.md) — this repo's architecture, conventions and code style
|
||||||
|
- [`docs/working-on-officer.md`](docs/working-on-officer.md) — the deployment-wide guide: which
|
||||||
|
directory a change belongs in, how to run and verify it, the task system, and the failure modes
|
||||||
|
worth knowing about
|
||||||
|
- `CONVENTIONS.md` — component organisation and React patterns, with rationale
|
||||||
|
- `TODO.md` — current direction; takes precedence where it disagrees with anything else
|
||||||
|
|
||||||
1. **AI Chat** — Multi-provider (Claude, OpenCode, Pi-Mono) with sessions, attachments, speech-to-text, slash commands
|
The other Markdown files in this repo root (`OFFICERDEV_*.md`, `MARKETING_WEBSITE.md`,
|
||||||
2. **File Browser** — Full filesystem access per user (upload, mkdir, copy, move, delete)
|
`PHONE_APP.md`, `SECURITY_AUDIT.md`, `SETUP_*.md`, …) are older design notes and have not been kept
|
||||||
3. **File Viewer** — Preview video, images, code, text, markdown
|
current. Treat the code as the source of truth.
|
||||||
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) => <div onClick={onClick}>{title}</div>;
|
|
||||||
```
|
|
||||||
|
|
||||||
### 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
|
|
||||||
|
|||||||
Reference in New Issue
Block a user