Skip to content

Developer Guide

Quick reference for all APIs, hooks, components, and design tokens available in the Flightdeck web application.

Tech Stack

LayerTechnology
RuntimeNode.js with npm workspaces monorepo
FrontendReact 19.2, TypeScript 5.9, Vite 8, Tailwind CSS 4
State ManagementZustand 5 (stores in src/stores/), TanStack Query 5 (server state)
TestingVitest 4 + @testing-library/react 16, Playwright for E2E
BackendExpress 5, better-sqlite3, Drizzle ORM, WebSocket (ws)
Shared@flightdeck/shared — Zod schemas, shared types (workspace dependency)
Chartsvisx (d3-based)
BuildVite 8 with @vitejs/plugin-react, dev server proxies API/WS to :3001

API Endpoints

Agents

MethodEndpointDescription
GET/agentsList all agents
DELETE/agents/:idTerminate agent
POST/agents/:id/interruptInterrupt agent
POST/agents/:id/restartRestart agent
POST/agents/:id/messageSend message to agent
GET/agents/:id/messages?limit=200Get agent messages
POST/agents/:id/permissionResolve permission request

Sessions & Leads

MethodEndpointDescription
GET/leadList active leads
POST/lead/startStart new lead session
GET/lead/:id/progressGet lead progress
GET/lead/:id/dagGet task DAG
GET/lead/:id/decisionsGet pending decisions
POST/lead/:id/messageSend message to lead
GET/lead/:id/groupsList groups
POST/lead/:id/groupsCreate group
DELETE/lead/:idDelete lead

Decisions

MethodEndpointDescription
POST/decisions/:id/approveApprove decision
POST/decisions/:id/rejectReject decision
POST/decisions/:id/respondRespond with text
POST/decisions/:id/feedbackSend feedback

Natural Language

MethodEndpointDescription
GET/nl/commandsList all 30 NL commands
POST/nl/previewPreview command before executing
POST/nl/executeExecute NL command
POST/nl/undoUndo last command
GET/nl/suggestionsContext-aware suggestions

Onboarding

MethodEndpointDescription
GET/onboarding/statusGet mastery status
POST/onboarding/progressUpdate progress

Predictions (Removed)

Note: The Predictions API has been removed. The endpoints below are no longer active. See Removed Components for details.

Workflows (Removed)

Note: The Workflow Automation API has been removed. This feature was incomplete and is no longer available.

| GET | /commits | List commits | | GET | /commits/by-task/:taskId | Commits for task |

Conflicts

MethodEndpointDescription
GET/conflictsActive conflicts
POST/conflicts/:id/resolveResolve conflict
POST/conflicts/:id/dismissDismiss conflict
GET/conflicts/configGet config
PUT/conflicts/configUpdate config

Intent Rules (Removed)

Note: The Intent Rules API has been removed. Use the Oversight System instead.

Recovery (Removed)

Note: The Recovery/Handoff API has been removed. Agent crash recovery is now handled automatically by the orchestrator.

Oversight

MethodEndpointDescription
GET/config/yamlGet full config (includes oversight section)
PATCH/configUpdate oversight level and custom instructions

Playbooks (Removed)

Note: The Playbooks API has been removed.

Roles

MethodEndpointDescription
GET/rolesList roles
POST/rolesCreate role
PUT/roles/:idUpdate role
DELETE/roles/:idDelete role
POST/roles/testTest role config

Session Replay

MethodEndpointDescription
GET/api/replay/:leadId/keyframesGet keyframes
POST/replay/:leadId/shareCreate share link
GET/api/shared/:tokenGet shared replay

Notifications

MethodEndpointDescription
PUT/notifications/settingsUpdate notification preferences
GET/notifications/routingGet notification routing config

Analytics & Token Usage

MethodEndpointDescription
GET/api/costs/by-agentCosts by agent
GET/api/costs/by-taskCosts by task
GET/api/coordination/statusCoordination status
GET/api/coordination/timelineTimeline events

React Hooks

All hooks are in src/hooks/. Import example: import { useProjects } from '../hooks/useProjects';

Data Fetching Hooks

HookReturnsDescription
useApi(){ spawnAgent, terminateAgent, updateConfig, createRole, ... }Core API client
useFocusAgent(agentId){ data, loading, error, refresh }Polls agent activity, diffs, decisions
useDiffSummary(agentId){ summary, loading }Lightweight diff stats
useProjects(){ projects, loading }Fetch projects from REST API
useHistoricalAgents(projectId)Agent[]Derive agent data from keyframes for historical sessions
useConflicts(){ conflicts, activeConflicts, loading, resolve, dismiss }Conflict alerts
useConflictConfig(){ config, saveConfig }Detection config
useSessionReplay(leadId){ keyframes, worldState, playing, currentTime, seek, setSpeed, ... }Session replay

UI State Hooks

HookReturnsDescription
useCommandPalette(){ isOpen, open, close, toggle }⌘K palette state
useRecentCommands(){ recent, addRecent, clearRecent }Recent command history (localStorage)
useProgressiveRoutes(){ tier, visibleRoutes, hiddenRoutes }Progressive sidebar disclosure
useDashboardLayout(){ panels, allPanels, togglePanel, movePanel, reorderPanels }Dashboard panel config
useAutoScroll(ref, deps)voidAuto-scroll container to bottom
useIdleTimer(timeout){ isIdle }User inactivity detection
useAttachments(){ attachments, addAttachment, removeAttachment }File attachment state
useFileDrop(onDrop){ isDragOver, handleDragOver, handleDrop, ... }Drag-and-drop files
useGlassTooltips()voidGlobal [title] → glass tooltip conversion

WebSocket

typescript
import { useWebSocket } from '../hooks/useWebSocket';
import { sendWsMessage } from '../hooks/useWebSocket';

const ws = useWebSocket(); // Full WS client
sendWsMessage({ type: 'queue_open' }); // Send from anywhere

Shared Components

Import: import { EmptyState, SkeletonCard, SkeletonList, ErrorPage } from '../components/Shared';

EmptyState

tsx
<EmptyState
  icon="📊"
  title="No active sessions"
  description="Sessions appear when you create a project and agents start working."
  action={{ label: "Create Project →", onClick: () => navigate('/') }}
/>
// compact variant for inline use:
<EmptyState icon="📋" title="No items" compact />

Props: icon?: string, title: string, description?: string, action?: { label, onClick }, compact?: boolean, children?: ReactNode

SkeletonCard / SkeletonList

tsx
<SkeletonCard lines={3} showHeader showAvatar />
<SkeletonList count={5} />

SkeletonCard props: lines?: number, showHeader?: boolean, showAvatar?: boolean, className?: string SkeletonList props: count?: number, cardProps?: SkeletonCardProps, className?: string

ErrorPage

tsx
<ErrorPage
  title="Failed to load agents"
  message="The server is unavailable."
  detail="ECONNREFUSED localhost:3001"
  statusCode={503}
  onRetry={() => refetch()}
  onGoHome={() => navigate('/')}
/>

Props: title?: string, message?: string, detail?: string, statusCode?: number, onRetry?: () => void, onGoHome?: () => void


Motion System

Import: styles are global via src/styles/motion.css. Just add class names.

Animation Classes

ClassDurationUse for
motion-fade-in250msUniversal entry
motion-slide-in250msContent entering from left
motion-slide-in-right250msPanels, slide-overs
motion-slide-up250msToasts, bottom sheets
motion-slide-down250msDropdowns, notifications
motion-scale-in250msModals, popovers
motion-scale-in-spring450msPlayful/dramatic entrances
motion-pulse2s ∞Status indicators
motion-pulse-border2s ∞Attention-drawing borders
motion-glow2s ∞Active/selected state
motion-fade-out120msExit animation

Transition Presets

ClassDurationUse for
transition-micro120msHover states, toggles
transition-standard250msPanel transitions
transition-dramatic450msPage transitions

Stagger Pattern

tsx
{items.map((item, i) => (
  <div
    key={item.id}
    className="motion-stagger"
    style={{ '--stagger-index': i } as React.CSSProperties}
  >
    {/* content */}
  </div>
))}

Reduced Motion

All animations respect prefers-reduced-motion: reduce automatically (0ms duration).


Chart Theme

Import: styles are global via src/styles/chart-theme.css. Use CSS custom properties.

Series Colors

--chart-1 through --chart-8 — indigo, cyan, amber, purple, green, rose, blue, orange

Semantic Colors

VariableUse
--chart-successPositive/completed
--chart-warningCaution/amber
--chart-dangerError/red
--chart-infoInformational/blue
--chart-neutralInactive/muted

Agent Status Colors

--chart-running, --chart-idle, --chart-completed, --chart-failed, --chart-creating, --chart-terminated

Communication Edge Colors

--chart-edge-delegation, --chart-edge-message, --chart-edge-group, --chart-edge-broadcast, --chart-edge-report

Structural

--chart-grid, --chart-axis, --chart-tooltip-bg, --chart-tooltip-text, --chart-tooltip-border

Usage with visx

tsx
<LinePath
  stroke={`rgb(var(--chart-1))`}
  // ...
/>
<AxisBottom
  stroke={`rgb(var(--chart-axis))`}
  tickStroke={`rgb(var(--chart-axis))`}
  tickLabelProps={{ fill: `rgb(var(--chart-neutral))` }}
/>

All variables use RGB triplets for opacity support: rgba(var(--chart-1), 0.5).


Key Patterns

TanStack Query (Server State)

Use useQuery from @tanstack/react-query for all server data fetching:

typescript
import { useQuery } from '@tanstack/react-query';
import { apiFetch } from '../hooks/useApi';

const { data, isLoading, error } = useQuery({
  queryKey: ['agents', projectId],
  queryFn: ({ signal }) => apiFetch(`/api/agents?project=${projectId}`, { signal }),
  refetchInterval: 5000,
});

API Fetching (Low-Level)

typescript
import { apiFetch } from '../hooks/useApi';

// GET
const data = await apiFetch<MyType[]>('/projects');

// POST
await apiFetch('/nl/execute', {
  method: 'POST',
  body: JSON.stringify({ commandId: 'nl-pause-all' }),
});

Always handle both response shapes:

typescript
const data = await apiFetch<unknown>('/endpoint');
const items = Array.isArray(data) ? data : data?.items ?? [];

Zustand Store (Client State)

Stores live in src/stores/. Define stores with Zustand 5's create:

typescript
import { create } from 'zustand';

const useAppStore = create<AppState>((set, get) => ({
  agents: [],
  setAgents: (agents) => set({ agents }),
}));

// Testing: useAppStore.getState().setAgents([...])

Use selectors to avoid unnecessary re-renders:

typescript
// ✅ Good — re-renders only when agents changes
const agents = useAppStore(s => s.agents);

// ❌ Bad — re-renders on ANY store change
const { agents, config } = useAppStore();

Theme Classes

Always use th- prefixed classes, never raw colors:

  • Background: bg-th-bg, bg-th-bg-alt
  • Text: text-th-text, text-th-text-muted
  • Border: border-th-border, border-th-border-muted
  • Accent: bg-accent/20 text-accent
Documentation generated by AI

Documentation generated by AI