# AI-Assisted Development with Claude Code Accelerate TelemetryOS application development using Claude Code with a project-specific CLAUDE.md configuration file. # AI-Assisted Development with Claude Code Accelerate TelemetryOS application development using Claude Code, Anthropic's AI coding assistant, with proper project configuration. ## Overview [Claude Code](https://code.claude.com) is a terminal-based AI assistant that reads and writes files, executes commands, and generates code. When configured with a `CLAUDE.md` file in your project root, it understands your TelemetryOS application architecture, SDK APIs, and code patterns. Note that this guide applies equally to other AI Agents like OpenAI's Codex or Cursor. Simple rename CLAUDE.md to AGENTS.md or whatever your agent requires. **What Claude Code Does:** * Reads `CLAUDE.md` automatically on startup * Generates code following project patterns * Debugs issues using project context * Executes builds, tests, and deployments * References files with `@filename` syntax ## CLAUDE.md Template for TelemetryOS Applications Copy this entire template into your project root as `CLAUDE.md`. This is a technical reference for code generation. ````markdown # TelemetryOS SDK Reference **Application:** [Your App Name] **Purpose:** [What this application does] ## Platform Architecture TelemetryOS applications are web apps that run on digital signage devices. Applications have up to 4 components: 1. **Render** (`/render`) - Content displayed on devices (runs on device in Chrome/iframe) 2. **Settings** (`/settings`) - Config UI in Studio admin portal (runs in Studio browser) 3. **Workers** (optional) - Background JavaScript (runs on device, no DOM) 4. **Containers** (optional) - Docker containers for backend services (runs on device) **Runtime Environment:** - Chrome browser (platform-controlled version) - Iframe sandbox execution - Client-side only (no SSR, no Node.js APIs) - Modern web APIs available (Fetch, WebSockets, WebGL, Canvas) - External APIs require CORS proxy **Communication:** - Settings and Render share instance storage - Settings saves config → Render subscribes to config - Device storage only available in Render (not Settings) ## Project Structure ``` project-root/ ├── telemetry.config.json # Platform configuration ├── package.json ├── tsconfig.json ├── vite.config.ts ├── index.html └── src/ ├── main.tsx # Entry point (configure SDK here) ├── App.tsx # Routing logic ├── views/ │ ├── Settings.tsx # /settings mount point │ └── Render.tsx # /render mount point ├── components/ # Reusable components ├── hooks/ # Custom React hooks ├── types/ # TypeScript interfaces └── utils/ # Helper functions ``` ## Configuration Files ### telemetry.config.json (project root) ```json { "name": "app-name", "version": "1.0.0", "mountPoints": { "render": "/render", "settings": "/settings" }, "devServer": { "runCommand": "vite --port 3000", "url": "http://localhost:3000" } } ``` ### package.json scripts ```json { "scripts": { "dev": "vite", "build": "tsc && vite build", "preview": "vite preview" }, "dependencies": { "@telemetryos/sdk": "latest", "react": "latest", "react-dom": "latest" }, "devDependencies": { "@types/react": "latest", "@types/react-dom": "latest", "@vitejs/plugin-react": "latest", "typescript": "latest", "vite": "latest" } } ``` ## Complete File Implementations ### src/main.tsx (Entry Point) ```typescript import { configure } from '@telemetryos/sdk'; import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; import './index.css'; // Configure SDK ONCE before React renders // Name must match telemetry.config.json configure('app-name'); ReactDOM.createRoot(document.getElementById('root')!).render( ); ``` ### src/App.tsx (Routing) ```typescript import Settings from './views/Settings'; import Render from './views/Render'; export default function App() { const path = window.location.pathname; if (path === '/settings') return ; if (path === '/render') return ; return
Invalid mount point: {path}
; } ``` ### src/views/Settings.tsx (Complete Reference) ```typescript import { useEffect, useState, FormEvent } from 'react'; import { store } from '@telemetryos/sdk'; interface Config { city: string; units: 'celsius' | 'fahrenheit'; } export default function Settings() { const [config, setConfig] = useState({ city: '', units: 'celsius' }); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); // Load existing config on mount useEffect(() => { store().instance.get('config') .then(saved => { if (saved) setConfig(saved); }) .catch(err => setError(err.message)); }, []); const handleSave = async (e: FormEvent) => { e.preventDefault(); setLoading(true); setError(null); try { const success = await store().instance.set('config', config); if (!success) throw new Error('Storage operation failed'); } catch (err) { setError(err instanceof Error ? err.message : 'Unknown error'); } finally { setLoading(false); } }; return (

Settings

{error &&
{error}
}
setConfig({ ...config, city: e.target.value })} required />
); } ``` ### src/views/Render.tsx (Complete Reference) ```typescript import { useEffect, useState } from 'react'; import { store, proxy } from '@telemetryos/sdk'; interface Config { city: string; units: 'celsius' | 'fahrenheit'; } interface WeatherData { temperature: number; conditions: string; } export default function Render() { const [config, setConfig] = useState(null); const [weather, setWeather] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); // Subscribe to config changes from Settings useEffect(() => { store().instance.get('config').then(setConfig); const unsubscribe = store().instance.subscribe('config', (newConfig: Config) => { setConfig(newConfig); }); return () => unsubscribe(); }, []); // Fetch weather when config changes useEffect(() => { if (!config?.city) return; const fetchWeather = async () => { setLoading(true); setError(null); try { const response = await proxy().fetch( `https://api.example.com/weather?city=${config.city}&units=${config.units}` ); if (!response.ok) throw new Error(`API error: ${response.status}`); const data = await response.json(); setWeather({ temperature: data.temp, conditions: data.conditions }); // Cache for offline await store().device.set('cached', { data, timestamp: Date.now() }); } catch (err) { setError(err instanceof Error ? err.message : 'Unknown error'); // Try cached data const cached = await store().device.get('cached'); if (cached) setWeather(cached.data); } finally { setLoading(false); } }; fetchWeather(); }, [config]); // States if (!config) return
Configure in Settings
; if (loading && !weather) return
Loading...
; if (error && !weather) return
Error: {error}
; return (

{config.city}

{weather?.temperature}°{config.units === 'celsius' ? 'C' : 'F'}
{weather?.conditions}
{error &&
Showing cached data
}
); } ``` ## SDK API Reference Import from `@telemetryos/sdk`. ### Initialization ```typescript configure(applicationName: string): void ``` - Call once in main.tsx before React renders - Name must match telemetry.config.json - Throws if called multiple times ### Storage API **Type Signatures:** ```typescript store().application.set(key: string, value: any): Promise store().application.get(key: string): Promise store().application.subscribe(key: string, handler: (value: any) => void): () => void store().application.delete(key: string): Promise store().application.keys(): Promise // Same methods for instance, device, shared(namespace) ``` **Four Scopes:** 1. **application** - Shared across all instances of app in account ```typescript await store().application.set('companyLogo', 'https://...'); const logo = await store().application.get('companyLogo'); ``` 2. **instance** - This specific app instance (Settings ↔ Render communication) ```typescript // Settings saves await store().instance.set('config', { city: 'NYC' }); // Render subscribes const unsubscribe = store().instance.subscribe('config', (newConfig) => { updateDisplay(newConfig); }); // Later: unsubscribe(); ``` 3. **device** - This physical device only (NOT available in Settings) ```typescript // Only in Render mount point await store().device.set('cache', data); const cached = await store().device.get('cache'); ``` 4. **shared(namespace)** - Inter-app communication ```typescript // App A publishes await store().shared('weather').set('temp', '72°F'); // App B subscribes store().shared('weather').subscribe('temp', (temp) => console.log(temp)); ``` **Constraints:** - All operations timeout after 30 seconds (throws Error) - Returns Promise for set/delete (true = success) - Returns Promise for get - subscribe() returns unsubscribe function - Device scope throws Error in Settings mount point ### Proxy API ```typescript proxy().fetch(url: string, options?: RequestInit): Promise ``` - Same interface as standard fetch() - Use for ALL external API calls to avoid CORS errors - Returns standard Response object - Handles CORS server-side **Example:** ```typescript import { proxy } from '@telemetryos/sdk'; const response = await proxy().fetch('https://api.example.com/data'); const json = await response.json(); ``` ### Media API ```typescript media().getAllByTag(tag: string): Promise media().getById(id: string): Promise interface MediaContent { id: string; url: string; type: 'image' | 'video'; tags: string[]; metadata: Record; } ``` ### Playlist API ```typescript playlist().nextPage(): Promise playlist().previousPage(): Promise playlist().jumpToPage(index: number): Promise ``` ### Overrides API ```typescript overrides().setOverride(id: string): Promise overrides().clearOverride(): Promise ``` Note: Override IDs must be pre-configured in Freeform Editor. ### Platform Information ```typescript accounts().getCurrent(): Promise users().getCurrent(): Promise devices().getCurrent(): Promise // Render only ``` ## Hard Constraints **These cause runtime errors:** 1. **Device storage in Settings** - Settings runs in Studio browser, not on devices - `store().device.*` throws Error in Settings - Use `store().instance` or `store().application` instead 2. **External API without proxy** - Direct `fetch()` to external domains fails with CORS error - Must use `proxy().fetch()` for all external requests 3. **Missing configure()** - SDK methods throw "SDK not configured" Error - Call `configure()` once in main.tsx before React renders 4. **Subscription memory leaks** - `subscribe()` returns unsubscribe function - Must call unsubscribe on component unmount - Return unsubscribe from useEffect cleanup 5. **Timeout errors** - All SDK operations timeout after 30 seconds - Throws Error with message containing 'timeout' - Handle with try/catch ## TypeScript Patterns **Define interfaces for all configs and data:** ```typescript interface AppConfig { city: string; units: 'celsius' | 'fahrenheit'; refreshInterval: number; } const config = await store().instance.get('config'); if (config) { console.log(config.city); // TypeScript knows this exists } ``` **Component with proper types:** ```typescript interface Props { data: WeatherData; onRefresh: () => void; } export default function WeatherCard({ data, onRefresh }: Props) { return
{data.temperature}
; } ``` ## React Patterns **Error handling:** ```typescript const [error, setError] = useState(null); try { await store().instance.set('key', value); } catch (err) { setError(err instanceof Error ? err.message : 'Unknown error'); } ``` **Loading states:** ```typescript const [loading, setLoading] = useState(false); const handleAction = async () => { setLoading(true); try { await someAsyncOperation(); } finally { setLoading(false); } }; ``` **Subscription cleanup:** ```typescript useEffect(() => { const unsubscribe = store().instance.subscribe('key', handler); return () => unsubscribe(); }, []); ``` **Empty deps for mount-only effects:** ```typescript useEffect(() => { // Runs once on mount store().instance.get('config').then(setConfig); }, []); // Empty deps array ``` ## Code Style **Naming:** - Components: PascalCase (`WeatherCard.tsx`) - Functions: camelCase (`fetchWeatherData`) - Constants: UPPER_SNAKE_CASE (`API_BASE_URL`) - Interfaces: PascalCase (`WeatherData`, `AppConfig`) **Imports order:** ```typescript // 1. SDK imports import { configure, store, proxy } from '@telemetryos/sdk'; // 2. React imports import { useEffect, useState } from 'react'; // 3. Local imports import WeatherCard from '@/components/WeatherCard'; import type { WeatherData } from '@/types'; ``` **TypeScript:** - Use strict mode - Define interfaces for all configs and data - Use generics with storage: `get(key)` - Prefer `interface` over `type` for objects **React:** - Functional components only - Use hooks (useState, useEffect, useMemo, useCallback) - Implement loading, error, empty states - Clean up subscriptions in useEffect return ## Development Commands ```bash # Install dependencies npm install # Start local dev server tos serve # Or: npm run dev # Build for production npm run build # Type check tsc --noEmit ``` **Local testing:** - Settings: http://localhost:3000/settings - Render: http://localhost:3000/render **Deployment:** ```bash git add . git commit -m "Description" git push origin main # GitHub integration auto-deploys ``` ## Common Errors **"SDK not configured"** → Call `configure('app-name')` in main.tsx before React renders **"device storage not available"** → Using `store().device` in Settings - use `store().instance` instead **CORS error** → Using direct `fetch()` - use `proxy().fetch()` instead **"Request timeout"** → SDK operation exceeded 30 seconds - handle with try/catch **Render not updating** → Missing subscription - use `store().instance.subscribe()` in Render **Memory leak** → Not returning unsubscribe from useEffect ## Project-Specific Context [Add your project details here:] **Application Name:** [Your app name] **External APIs:** - [API name]: [endpoint] - Authentication: [method] - Rate limits: [limits] **Custom Components:** - [ComponentName]: [purpose] - Location: [path] - Props: [interface] **Business Logic:** - [Key algorithms or calculations] - [Data transformation rules] ## Technical References **SDK API Documentation:** - [Storage API](https://docs.telemetryos.com/docs/storage-methods) - Complete storage scope reference - [Platform API](https://docs.telemetryos.com/docs/platform-methods) - Proxy, media, accounts, users, devices - [Playlist API](https://docs.telemetryos.com/docs/playlist-methods) - Page navigation methods - [Overrides API](https://docs.telemetryos.com/docs/overrides-methods) - Dynamic content control - [Client API](https://docs.telemetryos.com/docs/client-methods) - Device client interactions - [Media API](https://docs.telemetryos.com/docs/media-methods) - Media content queries **Critical Context:** - [CORS Guide](https://docs.telemetryos.com/docs/cors) - Why proxy().fetch() is required - [Mount Points](https://docs.telemetryos.com/docs/mount-points) - /render vs /settings execution - [Languages Supported](https://docs.telemetryos.com/docs/languages-supported) - Runtime environment constraints - [Configuration](https://docs.telemetryos.com/docs/configuration) - telemetry.config.json schema - [Workers](https://docs.telemetryos.com/docs/workers) - Background JavaScript patterns - [Containers](https://docs.telemetryos.com/docs/containers) - Docker integration patterns **Code Examples:** - [Code Examples](https://docs.telemetryos.com/docs/code-examples) - Real-world implementations - [LLMS.txt](https://docs.telemetryos.com/llms.txt) - Complete documentation index ````