From bd81ce92adbcdbc6766dd1f48369c7a20481fcd6 Mon Sep 17 00:00:00 2001 From: millianlmx Date: Fri, 26 Jun 2026 18:30:17 +0000 Subject: [PATCH] docs: add AGENTS.md for Hermes agent context --- AGENTS.md | 593 +++++++++++------------------------------------------- 1 file changed, 122 insertions(+), 471 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 580d37f..cdbba5b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,491 +1,142 @@ -# AGENTS.md +# TabataGo — iOS Tabata Workout App -This file contains optimizations and best practices for working with this TabataFit Expo project. +> Tabata interval training app for iOS + watchOS with HealthKit integration. ---- +## Agent Context -## 🚀 Command Optimizations +This project is part of the **Millian Team** — an AI agent engineering team. +When working here, agents should load the relevant skill: +- `senior-ios` — SwiftUI, Xcode, iOS/watchOS development +- `senior-backend` — Supabase backend +- `senior-devops` — Deploy infrastructure +- `po-pm` — Product vision, specs, validation -Use the following `rtk` commands for optimal performance: +## Tech Stack -| Command | rtk Equivalent | Speedup | Tokens Before | Tokens After | Savings | -|---------|----------------|---------|---------------|--------------|---------| -| `ls` / `tree` | `rtk ls` | 10x | 2,000 | 400 | -80% | -| `cat` / `read` | `rtk read` | 20x | 40,000 | 12,000 | -70% | -| `grep` / `rg` | `rtk grep` | 8x | 16,000 | 3,200 | -80% | -| `git status` | `rtk git status` | 10x | 3,000 | 600 | -80% | -| `git diff` | `rtk git diff` | 5x | 10,000 | 2,500 | -75% | -| `git log` | `rtk git log` | 5x | 2,500 | 500 | -80% | -| `git add/commit/push` | `rtk git` | 8x | 1,600 | 120 | -92% | -| `cargo test` / `npm test` | `rtk test` | 5x | 25,000 | 2,500 | -90% | -| `ruff check` | `rtk lint` | 3x | 3,000 | 600 | -80% | -| `pytest` | `rtk pytest` | 4x | 8,000 | 800 | -90% | -| `go test` | `rtk gotest` | 3x | 6,000 | 600 | -90% | -| `docker ps` | `rtk docker` | - | - | - | - | +| Layer | Tech | +|-------|------| +| App | SwiftUI, iOS 26.0+ | +| Watch | SwiftUI, watchOS 11.0+ | +| Widget | WidgetKit, Live Activities | +| Language | Swift 6.0 (strict concurrency) | +| Architecture | MVVM, @Observable, AppState central | +| Backend | Supabase (PostgreSQL, Auth, Storage) | +| Subscriptions | RevenueCat 5.x | +| Analytics | PostHog 3.x | +| Health | HealthKit (heart rate, calories, workouts) | +| Music | Apple Music integration + YouTube worker | +| Build | XcodeGen (project.yml → .xcodeproj) | +| Package Manager | Swift Package Manager | -### Usage Examples +## Project Structure + +``` +tabatago/ +├── tabatago-swift/ # Main Xcode project +│ ├── project.yml # XcodeGen spec +│ ├── Config/ +│ │ ├── Secrets.xcconfig # API keys (not committed) +│ │ └── Secrets.xcconfig.example +│ ├── TabataGo/ # iOS App +│ │ ├── App/ # App entry, state, root view +│ │ │ ├── TabataGoApp.swift +│ │ │ ├── RootView.swift +│ │ │ └── AppState.swift +│ │ ├── Views/ +│ │ │ ├── Tabs/ # MainTabView, Home, Activity, Programs, Profile +│ │ │ ├── Player/ # Workout player (PlayerView, NowPlaying) +│ │ │ ├── Programs/ # ProgramDetail, BodyZone +│ │ │ ├── Onboarding/ # Onboarding flow +│ │ │ ├── Paywall/ # RevenueCat paywall +│ │ │ ├── Complete/ # Workout completion screen +│ │ │ ├── Settings/ # Settings, policies +│ │ │ └── Components/ # Shared UI components +│ │ ├── ViewModels/ # HomeVM, HealthVM, PlayerVM, PurchaseVM, MusicVM +│ │ ├── Models/ # WorkoutProgram, WorkoutSession, UserProfile, etc. +│ │ ├── Services/ # Supabase, HealthKit, Music, Audio, Purchase, Analytics +│ │ ├── Theme/ # App theme +│ │ ├── Utilities/ # Strings, Environment +│ │ └── Resources/ # Assets, Localizable, entitlements +│ ├── TabataGoWatch/ # watchOS App +│ │ ├── Views/ # WatchRoot, WatchIdle, WatchActivity, WatchPlayer +│ │ ├── Services/ # WatchConnectivity, WatchPlayerEngine +│ │ ├── Complications/ # Watch face complications +│ │ └── Resources/ +│ ├── TabataGoWidget/ # iOS Widget + Live Activities +│ ├── TabataGoTests/ # Unit tests +│ └── TabataGoUITests/ # UI tests +├── supabase/ # Supabase config +│ ├── schema.sql +│ ├── seed.sql +│ ├── setup-admin.sql +│ └── migrations/ # SQL migrations (001-006) +└── youtube-worker/ # Node.js worker for YouTube music + ├── server.js + ├── package.json + └── Dockerfile +``` + +## Dependencies (SPM) + +- **Supabase** 2.5+ — Backend SDK (Auth, Database, Storage) +- **RevenueCat** 5.0+ — In-app purchases +- **PostHog** 3.0+ — Analytics + +## Features + +- Tabata/interval workout player with configurable timers +- Pre-built workout programs by body zone +- HealthKit integration (heart rate, calories, workout saving) +- Apple Watch companion with real-time metrics +- Live Activities + Dynamic Island +- Music integration (Apple Music + YouTube) +- RevenueCat subscriptions +- Onboarding flow +- Activity tracking & workout history + +## Commands ```bash -# Instead of: ls -la src/ -rtk ls src/ +# From tabatago-swift/ +xcodegen generate # Generate .xcodeproj +open TabataGo.xcodeproj # Open in Xcode -# Instead of: cat package.json -rtk read package.json - -# Instead of: grep -r "useEffect" src/ -rtk grep "useEffect" src/ - -# Instead of: git status -rtk git status - -# Instead of: npm test -rtk test - -# Instead of: ruff check . -rtk lint +# In Xcode +Cmd+R → Run on simulator +Cmd+U → Run tests ``` ---- +## Configuration -## 📱 Expo Best Practices +- `Config/Secrets.xcconfig` contains API keys (not committed) +- Template: `Config/Secrets.xcconfig.example` +- Env vars: `SUPABASE_URL`, `SUPABASE_ANON_KEY`, `REVENUECAT_API_KEY`, `POSTHOG_API_KEY` -### Development Workflow +## Current State -**CRITICAL: Always try Expo Go first before creating custom builds.** +- **Version**: 1.0 (build 2) — not yet released +- **State**: App functional, needs finishing work +- **Platforms**: iOS 26.0+, watchOS 11.0+ +- **Requires**: macOS with Xcode 26+ to build -1. **Start with Expo Go**: Run `npx expo start` and scan the QR code with Expo Go -2. **Check if features work**: Test your app thoroughly in Expo Go -3. **Only create custom builds when required** +## Supabase Schema -#### When Custom Builds Are Required +Tables: `profiles`, `workout_sessions`, `workout_programs`, `download_jobs`, `music_genre`, etc. +See `supabase/schema.sql` and `supabase/migrations/` for full schema. -Use `npx expo run:ios/android` or `eas build` ONLY when using: -- **Local Expo modules** (custom native code in `modules/`) -- **Apple targets** (widgets, app clips, extensions via `@bacons/apple-targets`) -- **Third-party native modules** not included in Expo Go -- **Custom native configuration** that can't be expressed in `app.json` +## Team Rules -#### When Expo Go Works +1. **Swift Concurrency** — async/await everywhere, no completion handlers +2. **@Observable** — not @ObservableObject +3. **No force unwrap** — `guard let` always, never `!` +4. **SwiftUI only** — no UIKit unless unavoidable +5. **XcodeGen** — project.yml is source of truth, not .xcodeproj +6. **Secrets** — never commit Secrets.xcconfig +7. **French** — all user-facing strings in French (Localizable.xcstrings) -Expo Go supports a huge range of features out of the box: -- All `expo-*` packages (camera, location, notifications, etc.) -- Expo Router navigation -- Most UI libraries (reanimated, gesture handler, etc.) -- Push notifications, deep links, and more +## Project Context -### Common Commands - -```bash -# Development -npx expo start # Start development server -npx expo start --tunnel # If network issues -npx expo start --clear # Clear cache -npx tsc --noEmit # Type check -npx expo install # Install Expo-compatible packages - -# Building -npx eas-cli@latest build --profile development # Dev build -npx eas-cli@latest build -p ios --profile production --submit # Build and submit iOS -npx testflight # Quick TestFlight shortcut - -# Development Client (when native code changes) -npx expo start --dev-client -``` - -### Code Style Rules - -#### File Naming -- Use kebab-case for file names (e.g., `workout-card.tsx`) -- Never use special characters in file names -- Always remove old route files when moving or restructuring navigation - -#### Imports -- Use path aliases from `tsconfig.json` instead of relative imports -- Prefer aliases over relative imports for refactors -- Always use import statements at the top of the file - -#### Library Preferences -- ✅ `expo-audio` not `expo-av` -- ✅ `expo-video` not `expo-av` -- ✅ `expo-image` with `source="sf:name"` for SF Symbols -- ✅ `react-native-safe-area-context` not react-native SafeAreaView -- ✅ `process.env.EXPO_OS` not `Platform.OS` -- ✅ `React.use` not `React.useContext` -- ❌ Never use modules removed from React Native: Picker, WebView, SafeAreaView, AsyncStorage -- ❌ Never use legacy expo-permissions -- ❌ Never use intrinsic elements like 'img' or 'div' unless in webview - -### Route Structure - -``` -app/ - _layout.tsx # Root layout with tabs - (tabs)/ # Group routes for tabs - _layout.tsx # Tabs layout - index.tsx # Home tab - workouts.tsx # Workouts tab - activity.tsx # Activity tab - browse.tsx # Browse tab - profile.tsx # Profile tab - player/ - [id].tsx # Workout player -``` - -#### Route Rules -- Routes belong in the `app` directory -- Never co-locate components, types, or utilities in the app directory -- Ensure the app always has a route that matches "/" -- Always use `_layout.tsx` files to define stacks - -### UI Guidelines - -#### Responsiveness -- Always wrap root component in a scroll view for responsiveness -- Use `` instead of `` -- `contentInsetAdjustmentBehavior="automatic"` should be applied to FlatList and SectionList -- Use flexbox instead of Dimensions API -- ALWAYS prefer `useWindowDimensions` over `Dimensions.get()` - -#### Styling -- Prefer flex gap over margin and padding styles -- Prefer padding over margin where possible -- Inline styles not StyleSheet.create unless reusing styles is faster -- Use `{ borderCurve: 'continuous' }` for rounded corners -- ALWAYS use a navigation stack title instead of a custom text element -- When padding a ScrollView, use `contentContainerStyle` padding -- Add entering and exiting animations for state changes - -#### Shadows -Use CSS `boxShadow` style prop. NEVER use legacy React Native shadow or elevation styles. - -```tsx - -``` - -#### Text Styling -- Add the `selectable` prop to every `` element displaying important data -- Counters should use `{ fontVariant: 'tabular-nums' }` for alignment - -#### Safe Area -- Always account for safe area with stack headers, tabs, or ScrollView/FlatList `contentInsetAdjustmentBehavior="automatic"` -- Ensure both top and bottom safe area insets are accounted for - -### Navigation Patterns - -#### Stack Configuration - -```tsx -import { Stack } from 'expo-router/stack'; - - - - -``` - -#### Links with Previews - -```tsx -import { Link } from 'expo-router'; - - - - - - - - - - - - - -``` - -#### Modal/Sheet Presentations - -```tsx -// Modal - - -// Form Sheet - -``` - -### Data Fetching - -#### Environment Variables -- Use `EXPO_PUBLIC_` prefix for client-side environment variables -- Never put secrets in `EXPO_PUBLIC_` variables (visible in built app) -- Restart the dev server after changing `.env` files - -```bash -# .env -EXPO_PUBLIC_API_URL=https://api.example.com -EXPO_PUBLIC_SUPABASE_URL=your-supabase-url -``` - -#### API Client Pattern - -```tsx -const BASE_URL = process.env.EXPO_PUBLIC_API_URL; - -export const apiClient = { - get: async (path: string): Promise => { - const response = await fetch(`${BASE_URL}${path}`); - if (!response.ok) throw new Error(`HTTP ${response.status}`); - return response.json(); - }, -}; -``` - -#### React Query Setup - -```tsx -// app/_layout.tsx -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; - -const queryClient = new QueryClient({ - defaultOptions: { - queries: { - staleTime: 1000 * 60 * 5, // 5 minutes - retry: 2, - }, - }, -}); -``` - -### EAS Build Configuration - -```json -{ - "cli": { - "version": ">= 16.0.1", - "appVersionSource": "remote" - }, - "build": { - "production": { - "autoIncrement": true, - "ios": { - "resourceClass": "m-medium" - } - }, - "development": { - "developmentClient": true, - "distribution": "internal" - } - }, - "submit": { - "production": {} - } -} -``` - -### Testing & Type Checking - -```bash -# TypeScript -npx tsc --noEmit - -# Run unit tests (Vitest) -npm test - -# Run tests in watch mode -npm run test:watch - -# Run tests with coverage report -npm run test:coverage - -# Run Maestro E2E tests -npm run test:maestro - -# Lint -npx eslint . -``` - -#### Test Structure -``` -src/__tests__/ - setup.ts # Mocks and test configuration - stores/ # Zustand store tests - hooks/ # React hooks tests - services/ # Service layer tests - components/ # Component logic tests - data/ # Data validation tests -``` - -#### Coverage Goals -- **Stores**: 80%+ (business logic) -- **Services**: 80%+ (API integration) -- **Hooks**: 70%+ (timer, purchases) -- **Components**: 50%+ (critical UI) - -### Key Takeaways - -1. **Start simple**: Always test in Expo Go before creating custom builds -2. **Follow conventions**: Use Expo Router patterns, kebab-case filenames -3. **Use modern APIs**: Prefer `expo-audio`, `expo-video`, `expo-image` -4. **Handle safe areas**: Use `contentInsetAdjustmentBehavior="automatic"` -5. **Style with CSS**: Use `boxShadow` instead of legacy shadow props -6. **Type everything**: Use TypeScript strict mode, no `any` -7. **Secure tokens**: Use `expo-secure-store` for sensitive data -8. **Environment config**: Use `EXPO_PUBLIC_` prefix for client env vars - ---- - -## 📝 Project Context - -**TabataFit** — "Apple Fitness+ for Tabata" - -- **Framework**: Expo SDK 52 (managed) -- **Navigation**: Expo Router v3 -- **State**: Zustand + AsyncStorage -- **Video**: expo-av → HLS streaming -- **Audio**: expo-av (coaching + music) -- **Animations**: React Native Animated -- **Payments**: RevenueCat -- **Analytics**: PostHog - -### Design System - -```typescript -BACKGROUND: '#000000' // Pure black -SURFACE: '#1C1C1E' // Charcoal -BRAND: '#FF6B35' // Flame orange -REST: '#5AC8FA' // Ice blue -SUCCESS: '#30D158' // Energy green -``` - -### Phase Colors (Critical) - -```typescript -PREP: '#FF9500' // Orange-yellow -WORK: '#FF6B35' // Flame orange -REST: '#5AC8FA' // Ice blue -COMPLETE: '#30D158' // Green -``` - ---- - -*Last updated: March 14, 2026* - -# context-mode — MANDATORY routing rules - -You have context-mode MCP tools available. These rules are NOT optional — they protect your context window from flooding. A single unrouted command can dump 56 KB into context and waste the entire session. - -## BLOCKED commands — do NOT attempt these - -### curl / wget — BLOCKED -Any shell command containing `curl` or `wget` will be intercepted and blocked by the context-mode plugin. Do NOT retry. -Instead use: -- `context-mode_ctx_fetch_and_index(url, source)` to fetch and index web pages -- `context-mode_ctx_execute(language: "javascript", code: "const r = await fetch(...)")` to run HTTP calls in sandbox - -### Inline HTTP — BLOCKED -Any shell command containing `fetch('http`, `requests.get(`, `requests.post(`, `http.get(`, or `http.request(` will be intercepted and blocked. Do NOT retry with shell. -Instead use: -- `context-mode_ctx_execute(language, code)` to run HTTP calls in sandbox — only stdout enters context - -### Direct web fetching — BLOCKED -Do NOT use any direct URL fetching tool. Use the sandbox equivalent. -Instead use: -- `context-mode_ctx_fetch_and_index(url, source)` then `context-mode_ctx_search(queries)` to query the indexed content - -## REDIRECTED tools — use sandbox equivalents - -### Shell (>20 lines output) -Shell is ONLY for: `git`, `mkdir`, `rm`, `mv`, `cd`, `ls`, `npm install`, `pip install`, and other short-output commands. -For everything else, use: -- `context-mode_ctx_batch_execute(commands, queries)` — run multiple commands + search in ONE call -- `context-mode_ctx_execute(language: "shell", code: "...")` — run in sandbox, only stdout enters context - -### File reading (for analysis) -If you are reading a file to **edit** it → reading is correct (edit needs content in context). -If you are reading to **analyze, explore, or summarize** → use `context-mode_ctx_execute_file(path, language, code)` instead. Only your printed summary enters context. - -### grep / search (large results) -Search results can flood context. Use `context-mode_ctx_execute(language: "shell", code: "grep ...")` to run searches in sandbox. Only your printed summary enters context. - -## Tool selection hierarchy - -1. **GATHER**: `context-mode_ctx_batch_execute(commands, queries)` — Primary tool. Runs all commands, auto-indexes output, returns search results. ONE call replaces 30+ individual calls. -2. **FOLLOW-UP**: `context-mode_ctx_search(queries: ["q1", "q2", ...])` — Query indexed content. Pass ALL questions as array in ONE call. -3. **PROCESSING**: `context-mode_ctx_execute(language, code)` | `context-mode_ctx_execute_file(path, language, code)` — Sandbox execution. Only stdout enters context. -4. **WEB**: `context-mode_ctx_fetch_and_index(url, source)` then `context-mode_ctx_search(queries)` — Fetch, chunk, index, query. Raw HTML never enters context. -5. **INDEX**: `context-mode_ctx_index(content, source)` — Store content in FTS5 knowledge base for later search. - -## Output constraints - -- Keep responses under 500 words. -- Write artifacts (code, configs, PRDs) to FILES — never return them as inline text. Return only: file path + 1-line description. -- When indexing content, use descriptive source labels so others can `search(source: "label")` later. - -## ctx commands - -| Command | Action | -|---------|--------| -| `ctx stats` | Call the `stats` MCP tool and display the full output verbatim | -| `ctx doctor` | Call the `doctor` MCP tool, run the returned shell command, display as checklist | -| `ctx upgrade` | Call the `upgrade` MCP tool, run the returned shell command, display as checklist | - - -# GitNexus — Code Intelligence - -This project is indexed by GitNexus as **tabatago** (3362 symbols, 9407 relationships, 129 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely. - -> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first. - -## Always Do - -- **MUST run impact analysis before editing any symbol.** Before modifying a function, class, or method, run `gitnexus_impact({target: "symbolName", direction: "upstream"})` and report the blast radius (direct callers, affected processes, risk level) to the user. -- **MUST run `gitnexus_detect_changes()` before committing** to verify your changes only affect expected symbols and execution flows. -- **MUST warn the user** if impact analysis returns HIGH or CRITICAL risk before proceeding with edits. -- When exploring unfamiliar code, use `gitnexus_query({query: "concept"})` to find execution flows instead of grepping. It returns process-grouped results ranked by relevance. -- When you need full context on a specific symbol — callers, callees, which execution flows it participates in — use `gitnexus_context({name: "symbolName"})`. - -## Never Do - -- NEVER edit a function, class, or method without first running `gitnexus_impact` on it. -- NEVER ignore HIGH or CRITICAL risk warnings from impact analysis. -- NEVER rename symbols with find-and-replace — use `gitnexus_rename` which understands the call graph. -- NEVER commit changes without running `gitnexus_detect_changes()` to check affected scope. - -## Resources - -| Resource | Use for | -|----------|---------| -| `gitnexus://repo/tabatago/context` | Codebase overview, check index freshness | -| `gitnexus://repo/tabatago/clusters` | All functional areas | -| `gitnexus://repo/tabatago/processes` | All execution flows | -| `gitnexus://repo/tabatago/process/{name}` | Step-by-step execution trace | - -## CLI - -| Task | Read this skill file | -|------|---------------------| -| Understand architecture / "How does X work?" | `.claude/skills/gitnexus/gitnexus-exploring/SKILL.md` | -| Blast radius / "What breaks if I change X?" | `.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md` | -| Trace bugs / "Why is X failing?" | `.claude/skills/gitnexus/gitnexus-debugging/SKILL.md` | -| Rename / extract / split / refactor | `.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md` | -| Tools, resources, schema reference | `.claude/skills/gitnexus/gitnexus-guide/SKILL.md` | -| Index, status, clean, wiki CLI commands | `.claude/skills/gitnexus/gitnexus-cli/SKILL.md` | - - +- **User**: Millian LMX (CEO) +- **Gitea**: https://gitea.1000co.fr/millianlmx/tabatago +- **Supabase**: Managed instance (URL in secrets) +- **App Store**: Not yet published