From 378163ad5c1f1c2d180f1abfd674c9853f5a8752 Mon Sep 17 00:00:00 2001 From: Vova Ignatov Date: Tue, 4 Nov 2025 13:03:16 +0000 Subject: [PATCH] IOS-5420 Implement progressive disclosure documentation system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Created 3-level architecture: CLAUDE.md (overview) β†’ Skills (routers) β†’ Specialized guides (comprehensive) - Added 6 smart router skills with auto-activation via hooks - Consolidated code review docs: CODE_REVIEW_GUIDE.md + pr-review-automation.md - Slimmed CLAUDE.md from 457 to 310 lines - Created specialized guides: IOS_DEVELOPMENT_GUIDE.md, LOCALIZATION_GUIDE.md, CODE_GENERATION_GUIDE.md, SKILLS_MANAGEMENT_GUIDE.md - Updated GitHub workflow to use progressive disclosure system --- .../CODE_REVIEW_GUIDE.md | 4 +- .claude/SKILLS_MANAGEMENT_GUIDE.md | 694 ++++++++++++++++++ .claude/hooks/README.md | 548 ++++++++++++++ .claude/hooks/post-tool-use-tracker.sh | 84 +++ .claude/hooks/skill-activation-prompt.sh | 116 +++ .claude/hooks/skill-rules.json | 290 ++++++++ .claude/hooks/swiftformat-auto.sh | 108 +++ .claude/logs/.gitignore | 5 + .claude/skills/README.md | 534 ++++++++++++++ .../skills/code-generation-developer/SKILL.md | 192 +++++ .claude/skills/code-review-developer/SKILL.md | 263 +++++++ .../skills/design-system-developer/SKILL.md | 207 ++++++ .claude/skills/ios-dev-guidelines/SKILL.md | 127 ++++ .../skills/localization-developer/SKILL.md | 178 +++++ .claude/skills/skills-manager/SKILL.md | 243 ++++++ .github/workflows/claude-code-review.yml | 18 +- ...view-prompt.md => pr-review-automation.md} | 0 Anytype/Sources/IOS_DEVELOPMENT_GUIDE.md | 550 ++++++++++++++ .../Common/LOCALIZATION_GUIDE.md | 313 ++++++++ CLAUDE.md | 377 +++------- Modules/AnytypeCore/CODE_GENERATION_GUIDE.md | 407 ++++++++++ 21 files changed, 4999 insertions(+), 259 deletions(-) rename .github/workflows/code-review-guidelines.md => .claude/CODE_REVIEW_GUIDE.md (97%) create mode 100644 .claude/SKILLS_MANAGEMENT_GUIDE.md create mode 100644 .claude/hooks/README.md create mode 100755 .claude/hooks/post-tool-use-tracker.sh create mode 100755 .claude/hooks/skill-activation-prompt.sh create mode 100644 .claude/hooks/skill-rules.json create mode 100755 .claude/hooks/swiftformat-auto.sh create mode 100644 .claude/logs/.gitignore create mode 100644 .claude/skills/README.md create mode 100644 .claude/skills/code-generation-developer/SKILL.md create mode 100644 .claude/skills/code-review-developer/SKILL.md create mode 100644 .claude/skills/design-system-developer/SKILL.md create mode 100644 .claude/skills/ios-dev-guidelines/SKILL.md create mode 100644 .claude/skills/localization-developer/SKILL.md create mode 100644 .claude/skills/skills-manager/SKILL.md rename .github/workflows/{claude-code-review-prompt.md => pr-review-automation.md} (100%) create mode 100644 Anytype/Sources/IOS_DEVELOPMENT_GUIDE.md create mode 100644 Anytype/Sources/PresentationLayer/Common/LOCALIZATION_GUIDE.md create mode 100644 Modules/AnytypeCore/CODE_GENERATION_GUIDE.md diff --git a/.github/workflows/code-review-guidelines.md b/.claude/CODE_REVIEW_GUIDE.md similarity index 97% rename from .github/workflows/code-review-guidelines.md rename to .claude/CODE_REVIEW_GUIDE.md index 3a21031ce5..f9b6d2be37 100644 --- a/.github/workflows/code-review-guidelines.md +++ b/.claude/CODE_REVIEW_GUIDE.md @@ -1,6 +1,6 @@ -# Code Review Guidelines +# Code Review Guide -Shared review standards for both local reviews and automated CI reviews. +Comprehensive review standards for both local reviews and automated CI reviews. ## Core Review Rules diff --git a/.claude/SKILLS_MANAGEMENT_GUIDE.md b/.claude/SKILLS_MANAGEMENT_GUIDE.md new file mode 100644 index 0000000000..a78c1fc8f8 --- /dev/null +++ b/.claude/SKILLS_MANAGEMENT_GUIDE.md @@ -0,0 +1,694 @@ +# Skills & Hooks Management Guide + +Complete guide to managing, troubleshooting, and fine-tuning the progressive disclosure documentation system. + +*Last updated: 2025-01-30* + +## Overview + +This guide explains how to manage the **automated documentation system** that suggests relevant skills based on your prompts and file context. + +## 🎯 System Components + +### 1. Hooks (The Automation Layer) + +**What**: Shell scripts that run automatically at specific events +**Where**: `.claude/hooks/` +**Purpose**: Analyze prompts and suggest relevant skills + +**The 3 hooks**: +- `skill-activation-prompt.sh` - **UserPromptSubmit event** - Analyzes your prompt BEFORE Claude sees it, suggests relevant skills +- `post-tool-use-tracker.sh` - **PostToolUse event** - Tracks file edits after Claude uses Edit/Write tools +- `swiftformat-auto.sh` - **Stop event** - Auto-formats Swift files after Claude finishes + +**Configuration**: +- `skill-rules.json` - Defines keywords and patterns for skill matching + +### 2. Skills (The Documentation Routers) + +**What**: Short markdown files (~100-200 lines) that act as "smart routers" +**Where**: `.claude/skills/*/SKILL.md` +**Purpose**: Provide critical rules + quick patterns + point to comprehensive guides + +**The 4 skills**: +1. `ios-dev-guidelines` - Swift/iOS patterns β†’ `IOS_DEVELOPMENT_GUIDE.md` +2. `localization-developer` - Localization workflow β†’ `LOCALIZATION_GUIDE.md` +3. `code-generation-developer` - Feature flags, make generate β†’ `CODE_GENERATION_GUIDE.md` +4. `design-system-developer` - Icons, typography, colors β†’ `DESIGN_SYSTEM_MAPPING.md` + +### 3. Specialized Guides (The Deep Knowledge) + +**What**: Comprehensive documentation files (300-550 lines each) +**Where**: Various locations in the project +**Purpose**: Single source of truth for deep technical knowledge + +## πŸ”„ How the System Works + +### The Activation Flow + +``` +You type: "Add a feature flag for chat" + ↓ +[UserPromptSubmit hook runs - happens automatically] + ↓ +skill-activation-prompt.sh executes + ↓ +Reads skill-rules.json + ↓ +Checks keywords: "feature flag" βœ“ matches code-generation-developer + ↓ +Outputs suggestion (Claude Code displays this): +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +🎯 SKILL ACTIVATION CHECK +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +πŸ“š Relevant Skill: code-generation-developer + Description: Smart router to code generation... + +πŸ’‘ Consider using these skills if relevant to this task. +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ↓ +Claude sees the suggestion and can read the skill + ↓ +Claude uses skill to route you to CODE_GENERATION_GUIDE.md if needed +``` + +### What Gets Matched + +**skill-rules.json** contains matching rules for each skill: + +```json +{ + "skills": { + "code-generation-developer": { + "promptTriggers": { + "keywords": ["feature flag", "make generate", "swiftgen"], + "intentPatterns": ["(create|add|enable).*?(feature flag|flag)"] + }, + "fileTriggers": { + "pathPatterns": ["**/FeatureDescription+Flags.swift"], + "contentPatterns": ["FeatureFlags\\."] + } + } + } +} +``` + +**Matching logic**: +1. **Keywords**: Simple word/phrase matching in your prompt +2. **Intent patterns**: Regex patterns for detecting user intent (e.g., "add.*feature flag") +3. **File path patterns**: Matches when editing specific files +4. **Content patterns**: Matches when file contains specific code patterns + +## πŸ”§ Troubleshooting & Fine-Tuning + +### Scenario 1: Skill Didn't Activate (False Negative) + +**Symptom**: You expected a skill to activate but it didn't + +**How to diagnose**: + +1. **Check the activation logs**: + ```bash + tail -20 .claude/logs/skill-activations.log + ``` + + Look for your prompt and see what matched: + ``` + [2025-01-30 14:23:45] Analyzing prompt: "export SVG from Figma" + No matches found + ``` + +2. **Check current keywords for the expected skill**: + ```bash + cat .claude/hooks/skill-rules.json | jq '.skills."design-system-developer".promptTriggers.keywords' + ``` + +3. **Identify missing keywords**: + - Your prompt: "export SVG from Figma" + - Current keywords: icon, figma, typography, color + - Missing: "svg", "export" + +**How to fix**: + +**Ask Claude**: +``` +"The design-system skill didn't activate when I asked about exporting SVG. +Can you add 'svg' and 'export' as keywords?" +``` + +**Or edit yourself**: +```bash +# Edit .claude/hooks/skill-rules.json +# Find design-system-developer section +# Add to keywords array: +"keywords": [ + "icon", + "figma", + "svg", // ← Add this + "export" // ← Add this +] +``` + +### Scenario 2: Skill Activated When Not Relevant (False Positive) + +**Symptom**: A skill activates too often or in wrong contexts + +**Example**: Every time you mention "text", localization-developer activates + +**How to diagnose**: + +1. **Check which keyword is causing it**: + ```bash + cat .claude/hooks/skill-rules.json | jq '.skills."localization-developer".promptTriggers.keywords' + ``` + + Result shows: `"text"` is in the keywords array + +2. **Determine if keyword is too broad**: + - "text" matches: "add text to UI", "text file", "raw text", etc. + - Too broad! Should be more specific + +**How to fix**: + +**Ask Claude**: +``` +"The word 'text' in localization-developer is too broad. +Replace it with 'localized text' and 'user-facing text'." +``` + +**Or edit yourself**: +```bash +# Edit .claude/hooks/skill-rules.json +# Before: +"keywords": ["localization", "text", "Loc."] + +# After: +"keywords": ["localization", "localized text", "user-facing text", "Loc."] +``` + +### Scenario 3: Testing Changes + +After modifying `skill-rules.json`, verify it works: + +**Method 1: Try the prompt again in conversation** +``` +"Add an SVG icon from Figma" +# Should now trigger design-system-developer +``` + +**Method 2: Check activation logs** +```bash +tail .claude/logs/skill-activations.log +# Look for: Matched: design-system-developer +``` + +**Method 3: Manual test (advanced)** +```bash +echo '{"prompt":"Add SVG from Figma"}' | .claude/hooks/skill-activation-prompt.sh +# Should output skill suggestion +``` + +## πŸ“‹ Common Adjustments + +### Add a Keyword + +**When**: You use a term that should trigger a skill but doesn't + +**Example**: Add "component" to ios-dev-guidelines + +```json +// .claude/hooks/skill-rules.json +{ + "skills": { + "ios-dev-guidelines": { + "promptTriggers": { + "keywords": [ + "swift", + "swiftui", + "viewmodel", + "component" // ← Add here + ] + } + } + } +} +``` + +**Ask Claude**: "Add 'component' as a keyword for ios-dev-guidelines" + +### Remove a Too-Broad Keyword + +**When**: A skill activates too often due to a common word + +**Example**: Remove "text" from localization-developer + +```json +// Before +"keywords": ["localization", "text", "Loc."] + +// After +"keywords": ["localization", "Loc."] +``` + +**Ask Claude**: "Remove 'text' from localization-developer keywords, it's too broad" + +### Add an Intent Pattern (Advanced) + +**When**: You want to match user actions/intents, not just keywords + +**Example**: Trigger design-system when implementing from Figma + +```json +{ + "skills": { + "design-system-developer": { + "promptTriggers": { + "intentPatterns": [ + "(add|create|use).*?(icon|image|asset)", + "(implement|build|create).*?from figma" // ← Add regex pattern + ] + } + } + } +} +``` + +**Regex explanation**: +- `(implement|build|create)` - Matches any of these action words +- `.*?` - Matches any characters in between (non-greedy) +- `from figma` - Matches this phrase + +**Ask Claude**: "When I say 'implement X from Figma', trigger design-system skill" + +### Adjust Priority + +**When**: Multiple skills match, you want to control which is suggested first + +```json +{ + "skills": { + "ios-dev-guidelines": { + "priority": "high" // Suggested first + }, + "design-system-developer": { + "priority": "medium" // Suggested second + } + } +} +``` + +**Values**: `"high"`, `"medium"`, `"low"` + +## πŸ” Diagnostic Commands + +### View Activation Logs + +```bash +# Last 20 activations +tail -20 .claude/logs/skill-activations.log + +# Watch in real-time +tail -f .claude/logs/skill-activations.log + +# Search for specific skill +grep "design-system-developer" .claude/logs/skill-activations.log +``` + +**Log format**: +``` +[2025-01-30 14:23:45] Analyzing prompt: "add feature flag" + βœ“ Matched: code-generation-developer + Suggested skills: code-generation-developer +``` + +### View Current Configuration + +```bash +# All skills configuration +cat .claude/hooks/skill-rules.json + +# Pretty print +cat .claude/hooks/skill-rules.json | jq . + +# Specific skill keywords +cat .claude/hooks/skill-rules.json | jq '.skills."ios-dev-guidelines".promptTriggers.keywords' + +# All keywords for all skills +cat .claude/hooks/skill-rules.json | jq '.skills[].promptTriggers.keywords' +``` + +### Test Skill Activation Manually + +```bash +# Test a specific prompt +echo '{"prompt":"add a feature flag"}' | .claude/hooks/skill-activation-prompt.sh + +# Should output: +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# 🎯 SKILL ACTIVATION CHECK +# ... +# πŸ“š Relevant Skill: code-generation-developer +``` + +### Verify Hook Permissions + +```bash +# Hooks should be executable +ls -l .claude/hooks/*.sh + +# Should show: -rwxr-xr-x +# If not, fix with: +chmod +x .claude/hooks/*.sh +``` + +## πŸŽ“ Advanced: Understanding skill-rules.json + +### Full Structure + +```json +{ + "skills": { + "skill-name": { + "type": "domain", // Type of skill + "priority": "high", // Suggestion priority + "description": "...", // Shown in activation message + "promptTriggers": { + "keywords": [...], // Simple word matching + "intentPatterns": [...] // Regex for intent matching + }, + "fileTriggers": { + "pathPatterns": [...], // File path glob patterns + "contentPatterns": [...] // Code pattern matching + } + } + }, + "config": { + "maxSkillsPerPrompt": 2, // Max skills to suggest at once + "logActivations": true, // Enable logging + "logPath": ".claude/logs/skill-activations.log" + } +} +``` + +### Keyword Matching (Simple) + +**Keywords**: Array of words/phrases to match in prompt + +```json +"keywords": [ + "swift", // Matches: "swift code", "Swift programming" + "feature flag", // Matches: "add a feature flag" + "Loc." // Matches: "use Loc.title" +] +``` + +**Case insensitive**: "Swift" = "swift" = "SWIFT" + +### Intent Pattern Matching (Advanced) + +**Intent patterns**: Regex for matching user actions/intents + +```json +"intentPatterns": [ + "(create|add|implement).*?(view|viewmodel|coordinator)", + "(how to|best practice).*?(swift|ios|architecture)" +] +``` + +**Examples**: +- `"(create|add).*?view"` matches: + - "create a new view" + - "add view for settings" + - "create chat view" + +**Regex cheatsheet**: +- `(word1|word2)` - Match either word +- `.*?` - Match any characters (non-greedy) +- `\\.` - Match literal dot (escaped) +- `\\(` - Match literal parenthesis (escaped) + +### File Trigger Matching + +**Path patterns**: Glob patterns for file paths + +```json +"pathPatterns": [ + "**/*.swift", // Any .swift file + "**/PresentationLayer/**", // Any file in PresentationLayer + "**/FeatureDescription+Flags.swift" // Specific file +] +``` + +**Content patterns**: Regex for code content + +```json +"contentPatterns": [ + "class.*ViewModel", // Classes ending in ViewModel + "@Published", // @Published property wrapper + "FeatureFlags\\.", // FeatureFlags usage + "import SwiftUI" // SwiftUI import +] +``` + +## πŸ› οΈ Creating a New Skill + +### When to Create a New Skill + +Create a new skill when: +- βœ… You have a distinct domain of knowledge (e.g., testing, CI/CD, performance) +- βœ… There's comprehensive documentation to route to +- βœ… The topic comes up frequently +- ❌ DON'T create for one-off topics or rarely-used info + +### Steps to Create a New Skill + +**1. Create the specialized guide** (Level 3): +```bash +# Example: Create testing guide +touch Anytype/Sources/TESTING_GUIDE.md +# Fill with comprehensive testing documentation +``` + +**2. Create the skill** (Level 2): +```bash +mkdir -p .claude/skills/testing-developer +touch .claude/skills/testing-developer/SKILL.md +``` + +**3. Use the smart router template**: +```markdown +# Testing Developer (Smart Router) + +## Purpose +Context-aware routing to testing patterns and practices. + +## When Auto-Activated +- Working with test files +- Keywords: test, mock, unittest, xctest + +## 🚨 CRITICAL RULES +1. ALWAYS update tests when refactoring +2. NEVER skip test execution + +## πŸ“‹ Quick Reference +[Quick testing patterns] + +## πŸ“š Complete Documentation +**Full Guide**: `Anytype/Sources/TESTING_GUIDE.md` + +--- +**Navigation**: This is a smart router. For details, refer to TESTING_GUIDE.md. +``` + +**4. Add to skill-rules.json**: +```json +{ + "skills": { + "testing-developer": { + "type": "domain", + "priority": "medium", + "description": "Smart router to testing guide. Unit tests, mocks, XCTest patterns", + "promptTriggers": { + "keywords": ["test", "unittest", "mock", "xctest", "testing"], + "intentPatterns": ["(write|add|create).*?test"] + }, + "fileTriggers": { + "pathPatterns": ["**/*Tests.swift", "**/Mocks/**"], + "contentPatterns": ["XCTestCase", "import XCTest"] + } + } + } +} +``` + +**5. Test the new skill**: +```bash +echo '{"prompt":"write unit tests for this"}' | .claude/hooks/skill-activation-prompt.sh +# Should suggest: testing-developer +``` + +## 🚨 Common Issues & Fixes + +### Issue: Hook Not Executing + +**Symptoms**: No skill suggestions appear, logs empty + +**Diagnosis**: +```bash +# Check if hook exists +ls -l .claude/hooks/skill-activation-prompt.sh + +# Check if executable +# Should show: -rwxr-xr-x +``` + +**Fix**: +```bash +chmod +x .claude/hooks/skill-activation-prompt.sh +``` + +### Issue: Invalid JSON in skill-rules.json + +**Symptoms**: Hook fails silently, no activations + +**Diagnosis**: +```bash +# Validate JSON +jq . .claude/hooks/skill-rules.json + +# If error shown, there's invalid JSON +``` + +**Fix**: +- Check for missing commas +- Check for trailing commas in arrays/objects +- Use a JSON validator or `jq` to find the error +- Ask Claude: "Validate and fix my skill-rules.json" + +### Issue: Skill Activates But Content Not Helpful + +**Symptoms**: Right skill activates but doesn't help + +**Diagnosis**: The skill might be outdated or routing to wrong guide + +**Fix**: +1. Check the skill file: `cat .claude/skills/SKILL-NAME/SKILL.md` +2. Verify it points to the correct guide +3. Check if the guide exists and is up-to-date +4. Ask Claude: "Update the X skill to route to Y guide" + +### Issue: Too Many Skills Suggested + +**Symptoms**: Multiple skills activate for same prompt + +**Diagnosis**: Keywords overlap between skills + +**Fix**: +1. Check `maxSkillsPerPrompt` in skill-rules.json config +2. Make keywords more specific +3. Adjust priorities so most relevant skill appears first + +```json +"config": { + "maxSkillsPerPrompt": 2 // Limit to 2 skills max +} +``` + +## πŸ“Š Monitoring & Maintenance + +### Regular Checks + +**Weekly**: +- Review activation logs for false positives/negatives +- Check if new common terms should be added as keywords + +```bash +# See most recent activations +tail -50 .claude/logs/skill-activations.log + +# Count activations by skill +grep "Matched:" .claude/logs/skill-activations.log | sort | uniq -c +``` + +**Monthly**: +- Review and update skill content +- Verify specialized guides are current +- Clean up outdated keywords + +### Log Rotation + +Logs can grow large over time: + +```bash +# Archive old logs +cd .claude/logs +tar -czf logs-$(date +%Y%m%d).tar.gz skill-activations.log +rm skill-activations.log +``` + +## 🎯 Quick Reference + +### I Want To... + +**Add a keyword**: +```bash +# Ask Claude: +"Add 'architecture' to ios-dev-guidelines keywords" + +# Or edit: +vim .claude/hooks/skill-rules.json +# Add to keywords array +``` + +**See what activated**: +```bash +tail -20 .claude/logs/skill-activations.log +``` + +**Test a prompt**: +```bash +echo '{"prompt":"your prompt here"}' | .claude/hooks/skill-activation-prompt.sh +``` + +**Check current keywords**: +```bash +cat .claude/hooks/skill-rules.json | jq '.skills."SKILL-NAME".promptTriggers.keywords' +``` + +**Fix permissions**: +```bash +chmod +x .claude/hooks/*.sh +``` + +**Validate JSON**: +```bash +jq . .claude/hooks/skill-rules.json +``` + +## πŸ“š Related Documentation + +- `.claude/hooks/README.md` - Complete hooks system documentation +- `.claude/skills/README.md` - Skills system overview +- `CLAUDE.md` - Main project documentation (Level 1) + +## πŸ’‘ Pro Tips + +1. **Start broad, then narrow**: Add broad keywords first, remove if too many false positives +2. **Use logs for data**: Check logs regularly to see what's activating +3. **Ask Claude for help**: Let Claude analyze logs and suggest improvements +4. **Test changes**: Always test after modifying skill-rules.json +5. **Document custom keywords**: Add comments in skill-rules.json explaining why you added specific terms + +## βœ… Checklist: System Health + +- [ ] All hooks are executable (`ls -l .claude/hooks/*.sh` shows `rwx`) +- [ ] skill-rules.json is valid JSON (`jq . .claude/hooks/skill-rules.json`) +- [ ] Logs directory exists (`.claude/logs/`) +- [ ] Recent activations visible in logs (`tail .claude/logs/skill-activations.log`) +- [ ] All 4 skills exist and are readable +- [ ] Specialized guides exist and link correctly from skills + +--- + +**Need help?** Just ask: "Check my skills system health" or "Help me troubleshoot skill activation" diff --git a/.claude/hooks/README.md b/.claude/hooks/README.md new file mode 100644 index 0000000000..fe262bbdec --- /dev/null +++ b/.claude/hooks/README.md @@ -0,0 +1,548 @@ +# Claude Code Hooks System + +Automated hooks for the Anytype iOS project that enhance Claude Code's capabilities with skill auto-activation, tool tracking, and code formatting. + +## Overview + +Hooks are shell scripts that run at specific points during Claude Code execution: +- **UserPromptSubmit**: Before Claude sees your message +- **PostToolUse**: After Claude uses a tool (Edit, Write, etc.) +- **Stop**: After Claude finishes responding + +These hooks enable: +- Automatic skill suggestions +- Tool usage logging +- Automatic Swift code formatting +- Real-time monitoring + +## πŸͺ Installed Hooks + +### 1. skill-activation-prompt.sh (UserPromptSubmit) + +**Purpose**: Automatically suggest relevant skills based on prompt and context + +**Event**: `UserPromptSubmit` (before Claude sees your message) + +**What it does**: +1. Analyzes your prompt for keywords (e.g., "swift", "localization", "icon") +2. Checks file paths if you're editing files +3. Matches against patterns in `skill-rules.json` +4. Injects skill suggestions into Claude's context + +**Example Output**: +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +🎯 SKILL ACTIVATION CHECK +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +πŸ“š Relevant Skill: ios-dev-guidelines + Description: Swift/iOS development patterns... + +πŸ’‘ Consider using these skills if relevant to this task. +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +**Logs**: `.claude/logs/skill-activations.log` + +**Configuration**: `.claude/hooks/skill-rules.json` + +--- + +### 2. post-tool-use-tracker.sh (PostToolUse) + +**Purpose**: Track all file modifications for monitoring and debugging + +**Event**: `PostToolUse` (after Edit/Write/MultiEdit/NotebookEdit) + +**What it does**: +1. Logs which files were edited with timestamps +2. Categorizes by codebase area (UI/Presentation, Services, Models, etc.) +3. Creates detailed usage log for debugging +4. Enables other hooks to know what was modified + +**Example Log Entry**: +``` +[2025-01-30 14:23:45] Edit: Anytype/Sources/PresentationLayer/ChatView.swift + └─ Area: UI/Presentation, File: Anytype/Sources/PresentationLayer/ChatView.swift +``` + +**Logs**: `.claude/logs/tool-usage.log` + +--- + +### 3. swiftformat-auto.sh (Stop) + +**Purpose**: Automatically format Swift files after Claude finishes + +**Event**: `Stop` (after Claude finishes responding) + +**What it does**: +1. Reads recently edited Swift files from tool-usage.log +2. Runs SwiftFormat on each file +3. Logs formatting results +4. Displays summary with token usage warning + +**⚠️ Token Usage Warning**: + +File modifications trigger `` notifications that consume context tokens. Based on research from the showcase repository: +- Large files with many changes = more tokens consumed +- Strict formatting rules = more changes = more tokens +- Each change generates a system-reminder with full diff + +**Enabled by default**: `ENABLED=true` (can be disabled in script) + +**To disable**: +```bash +# Edit the script +vim .claude/hooks/swiftformat-auto.sh + +# Change line: +ENABLED=false # Set to false +``` + +**Or rename to disable**: +```bash +mv .claude/hooks/swiftformat-auto.sh .claude/hooks/swiftformat-auto.sh.disabled +``` + +**Logs**: `.claude/logs/swiftformat.log` + +**Example Output**: +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +✨ SwiftFormat Auto-Formatter +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +Automatically formatted 3 Swift file(s) + +⚠️ Note: File formatting consumes context tokens... +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +## πŸ“‚ Directory Structure + +``` +.claude/hooks/ +β”œβ”€β”€ README.md (this file) +β”œβ”€β”€ skill-rules.json # Skill activation configuration +β”œβ”€β”€ skill-activation-prompt.sh # UserPromptSubmit hook +β”œβ”€β”€ post-tool-use-tracker.sh # PostToolUse hook +└── swiftformat-auto.sh # Stop hook + +.claude/logs/ # Generated logs (gitignored) +β”œβ”€β”€ skill-activations.log +β”œβ”€β”€ tool-usage.log +└── swiftformat.log +``` + +## βš™οΈ Configuration + +### skill-rules.json + +Defines which skills activate for which patterns: + +```json +{ + "skills": { + "ios-dev-guidelines": { + "type": "domain", + "priority": "high", + "description": "Swift/iOS development patterns...", + "promptTriggers": { + "keywords": ["swift", "viewmodel", "refactor"], + "intentPatterns": [ + "(create|add).*?(view|viewmodel|coordinator)" + ] + }, + "fileTriggers": { + "pathPatterns": ["**/*.swift"], + "contentPatterns": ["class.*ViewModel", "@Published"] + } + }, + ... + }, + "config": { + "maxSkillsPerPrompt": 2, + "logActivations": true, + "logPath": ".claude/logs/skill-activations.log" + } +} +``` + +**Key Fields**: +- `keywords`: Terms that trigger skill suggestion +- `intentPatterns`: Regex for action patterns +- `pathPatterns`: File paths that activate skill +- `contentPatterns`: Code patterns to match +- `maxSkillsPerPrompt`: Limit suggestions (default: 2) + +### Hook Configuration + +Each hook script has configuration at the top: + +**skill-activation-prompt.sh**: +```bash +# Paths +SKILL_RULES="$SCRIPT_DIR/skill-rules.json" +LOG_FILE="$LOG_DIR/skill-activations.log" +``` + +**swiftformat-auto.sh**: +```bash +# Configuration +ENABLED=true # Set to false to disable +``` + +## πŸ” Monitoring & Debugging + +### View Activation Logs + +```bash +# Skill activations +tail -f .claude/logs/skill-activations.log + +# Tool usage +tail -f .claude/logs/tool-usage.log + +# SwiftFormat results +tail -f .claude/logs/swiftformat.log +``` + +### Check Hook Execution + +```bash +# List hooks +ls -lh .claude/hooks/*.sh + +# Verify executability +ls -l .claude/hooks/*.sh | grep -E "^-rwx" +``` + +### Test Hook Manually + +```bash +# Test skill-activation-prompt +echo '{"prompt":"add a feature flag for chat"}' | .claude/hooks/skill-activation-prompt.sh + +# Should output skill suggestion +``` + +## πŸš€ Hook Lifecycle + +### UserPromptSubmit Flow + +``` +User types prompt + ↓ +Claude Code calls hook + ↓ +skill-activation-prompt.sh runs + ↓ +Analyzes prompt + files + ↓ +Matches against skill-rules.json + ↓ +Outputs skill suggestions + ↓ +Claude sees prompt + suggestions +``` + +### PostToolUse Flow + +``` +Claude uses Edit/Write + ↓ +Tool completes + ↓ +post-tool-use-tracker.sh runs + ↓ +Logs file path + timestamp + ↓ +Categorizes by codebase area + ↓ +Updates tool-usage.log +``` + +### Stop Flow + +``` +Claude finishes response + ↓ +swiftformat-auto.sh runs + ↓ +Reads recently edited Swift files + ↓ +Runs SwiftFormat on each + ↓ +Logs results to swiftformat.log + ↓ +Displays summary to user +``` + +## πŸ› οΈ Managing Hooks + +### Enabling/Disabling Hooks + +**To disable a hook temporarily**: +```bash +# Rename with .disabled extension +mv .claude/hooks/swiftformat-auto.sh .claude/hooks/swiftformat-auto.sh.disabled +``` + +**To re-enable**: +```bash +mv .claude/hooks/swiftformat-auto.sh.disabled .claude/hooks/swiftformat-auto.sh +``` + +**To disable via configuration** (swiftformat-auto.sh only): +```bash +# Edit the script +vim .claude/hooks/swiftformat-auto.sh + +# Change ENABLED=true to ENABLED=false +``` + +### Adding New Hooks + +1. **Create hook script**: +```bash +touch .claude/hooks/my-new-hook.sh +chmod +x .claude/hooks/my-new-hook.sh +``` + +2. **Add shebang and setup**: +```bash +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +LOG_DIR="$SCRIPT_DIR/../logs" +mkdir -p "$LOG_DIR" +``` + +3. **Read event data**: +```bash +EVENT_DATA=$(cat) +# Parse JSON with jq +``` + +4. **Implement logic**: +```bash +# Your hook logic here +echo "Hook executed successfully" +``` + +5. **Test**: +```bash +echo '{"test":"data"}' | .claude/hooks/my-new-hook.sh +``` + +## ⚠️ Important Warnings + +### Token Usage with SwiftFormat + +**From Research** (showcase repository + community feedback): + +File formatting can consume significant context tokens: +- Each file change triggers a `` +- System-reminders include full file diffs +- Can consume 160k+ tokens in 3 rounds for large files with strict formatting + +**Recommendation**: +- Monitor your context usage +- Disable swiftformat-auto.sh if context depletes too quickly +- Alternative: Run SwiftFormat manually between Claude sessions + +**How to check token usage**: +- Watch the context indicator in Claude Code +- Review system-reminders in conversation +- Check if context auto-compacts frequently + +**If problematic**: +```bash +# Disable SwiftFormat hook +mv .claude/hooks/swiftformat-auto.sh .claude/hooks/swiftformat-auto.sh.disabled +``` + +### Hook Failures + +If a hook fails: +1. Check logs for error messages +2. Test hook manually with sample input +3. Verify jq is installed (required for JSON parsing) +4. Check file permissions (should be executable) +5. Look for syntax errors in shell script + +## πŸ“Š Log Management + +### Log Rotation + +Logs can grow large over time. Rotate them periodically: + +```bash +# Archive old logs +cd .claude/logs +tar -czf logs-$(date +%Y%m%d).tar.gz *.log +rm *.log +``` + +### Clear Logs + +```bash +# Clear all logs +rm .claude/logs/*.log + +# Or truncate without deleting +truncate -s 0 .claude/logs/*.log +``` + +### Git Ignore + +Logs are gitignored by default (`.claude/logs/.gitignore`): +``` +*.log +!.gitignore +``` + +## πŸ”§ Troubleshooting + +### Hook Not Running + +**Problem**: Hook doesn't seem to execute + +**Solutions**: +1. Verify hook is executable: + ```bash + chmod +x .claude/hooks/skill-activation-prompt.sh + ``` + +2. Check for syntax errors: + ```bash + bash -n .claude/hooks/skill-activation-prompt.sh + ``` + +3. Test manually: + ```bash + echo '{"prompt":"test"}' | .claude/hooks/skill-activation-prompt.sh + ``` + +### Skills Not Activating + +**Problem**: No skill suggestions appear + +**Solutions**: +1. Check activation log: + ```bash + tail .claude/logs/skill-activations.log + ``` + +2. Verify skill-rules.json is valid: + ```bash + jq . .claude/hooks/skill-rules.json + ``` + +3. Use more specific keywords in prompts + +### SwiftFormat Not Running + +**Problem**: Swift files not being formatted + +**Solutions**: +1. Verify SwiftFormat is installed: + ```bash + which swiftformat + ``` + +2. Install if missing: + ```bash + brew install swiftformat + ``` + +3. Check if hook is enabled: + ```bash + grep "ENABLED" .claude/hooks/swiftformat-auto.sh + ``` + +4. Check logs: + ```bash + tail .claude/logs/swiftformat.log + ``` + +## πŸ“š Related Documentation + +- **Skills System**: `.claude/skills/README.md` - What skills are available +- **Showcase Repository**: https://github.com/diet103/claude-code-infrastructure-showcase - Original inspiration +- **CLAUDE.md**: Main project documentation + +## πŸŽ“ Best Practices + +### For Hook Usage + +1. **Monitor logs regularly** - Check for errors and unusual patterns +2. **Keep skill-rules.json updated** - Add keywords as you discover them +3. **Watch token usage** - Disable SwiftFormat if context consumption is high +4. **Test hooks after updates** - Verify they still work correctly +5. **Keep hooks simple** - Complex logic should be in skills, not hooks + +### For Hook Development + +1. **Use set -euo pipefail** - Catch errors early +2. **Log extensively** - Makes debugging easier +3. **Handle edge cases** - Check for missing files, invalid JSON, etc. +4. **Test with sample data** - Don't just test in live Claude sessions +5. **Document configuration** - Explain what each setting does + +## πŸ“– Hook Template + +When creating a new hook: + +```bash +#!/bin/bash + +# [Hook Name] - [Description] +# Event: [UserPromptSubmit/PostToolUse/Stop] +# Purpose: [What this hook does] + +set -euo pipefail + +# Configuration +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +LOG_DIR="$SCRIPT_DIR/../logs" +LOG_FILE="$LOG_DIR/my-hook.log" + +# Ensure log directory exists +mkdir -p "$LOG_DIR" + +# Read event data from stdin +EVENT_DATA=$(cat) + +# Parse event data +FIELD=$(echo "$EVENT_DATA" | jq -r '.field // empty') + +# Exit if no data +if [ -z "$FIELD" ]; then + exit 0 +fi + +# Log activity +echo "[$(date '+%Y-%m-%d %H:%M:%S')] Hook executed" >> "$LOG_FILE" + +# Your logic here +# ... + +# Output to Claude (if UserPromptSubmit hook) +# echo "Your message to Claude" + +exit 0 +``` + +## Summary + +The hooks system provides: +- βœ… **Automatic skill activation** - No manual skill loading needed +- βœ… **Tool usage tracking** - Know what files were modified +- βœ… **Code formatting** - Keep Swift files formatted (with token awareness) +- βœ… **Comprehensive logging** - Debug issues and monitor activity +- βœ… **Easy configuration** - skill-rules.json for fine-tuning + +**Usage**: Hooks run automatically - you don't need to do anything. Just monitor logs and adjust configuration as needed. \ No newline at end of file diff --git a/.claude/hooks/post-tool-use-tracker.sh b/.claude/hooks/post-tool-use-tracker.sh new file mode 100755 index 0000000000..449ce508d2 --- /dev/null +++ b/.claude/hooks/post-tool-use-tracker.sh @@ -0,0 +1,84 @@ +#!/bin/bash + +# Post-Tool-Use Tracker Hook +# Logs all Edit/Write/MultiEdit operations for monitoring and debugging +# Based on: https://github.com/diet103/claude-code-infrastructure-showcase + +set -euo pipefail + +# Get the directory where this script is located +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +LOG_DIR="$SCRIPT_DIR/../logs" +LOG_FILE="$LOG_DIR/tool-usage.log" + +# Ensure log directory exists +mkdir -p "$LOG_DIR" + +# Read event data from stdin +EVENT_DATA=$(cat) + +# Extract tool name and parameters +TOOL_NAME=$(echo "$EVENT_DATA" | jq -r '.tool // "unknown"') + +# Only track file modification tools +case "$TOOL_NAME" in + Edit|Write|MultiEdit|NotebookEdit) + ;; + *) + # Not a file modification tool, exit silently + exit 0 + ;; +esac + +# Get timestamp +TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') + +# Extract file path(s) based on tool type +FILE_PATHS="" + +case "$TOOL_NAME" in + Edit|Write|NotebookEdit) + FILE_PATH=$(echo "$EVENT_DATA" | jq -r '.parameters.file_path // .parameters.notebook_path // "unknown"') + FILE_PATHS="$FILE_PATH" + ;; + MultiEdit) + # MultiEdit has an array of edits + FILE_PATHS=$(echo "$EVENT_DATA" | jq -r '.parameters.edits[]?.file_path // empty' | tr '\n' ', ' | sed 's/,$//') + ;; +esac + +# If no files found, exit +if [ -z "$FILE_PATHS" ]; then + exit 0 +fi + +# Log the tool usage +echo "[$TIMESTAMP] $TOOL_NAME: $FILE_PATHS" >> "$LOG_FILE" + +# Extract repo/directory context (helps identify which part of the project was modified) +for file in $(echo "$FILE_PATHS" | tr ',' '\n'); do + # Remove leading/trailing whitespace + file=$(echo "$file" | xargs) + + # Determine which area of the codebase + AREA="unknown" + if echo "$file" | grep -q "PresentationLayer"; then + AREA="UI/Presentation" + elif echo "$file" | grep -q "ServiceLayer"; then + AREA="Services" + elif echo "$file" | grep -q "ApplicationLayer"; then + AREA="Application" + elif echo "$file" | grep -q "Models"; then + AREA="Models" + elif echo "$file" | grep -q "\.claude/"; then + AREA="Claude Config" + elif echo "$file" | grep -q "Modules/"; then + AREA="Modules" + elif echo "$file" | grep -q "\.xcstrings"; then + AREA="Localization" + fi + + echo " └─ Area: $AREA, File: $file" >> "$LOG_FILE" +done + +exit 0 diff --git a/.claude/hooks/skill-activation-prompt.sh b/.claude/hooks/skill-activation-prompt.sh new file mode 100755 index 0000000000..d9fbfb57c8 --- /dev/null +++ b/.claude/hooks/skill-activation-prompt.sh @@ -0,0 +1,116 @@ +#!/bin/bash + +# Skill Auto-Activation Hook (UserPromptSubmit) +# This hook analyzes user prompts and suggests relevant skills automatically +# Based on: https://github.com/diet103/claude-code-infrastructure-showcase + +set -euo pipefail + +# Get the directory where this script is located +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SKILL_RULES="$SCRIPT_DIR/skill-rules.json" +LOG_DIR="$SCRIPT_DIR/../logs" +LOG_FILE="$LOG_DIR/skill-activations.log" + +# Ensure log directory exists +mkdir -p "$LOG_DIR" + +# Read event data from stdin +EVENT_DATA=$(cat) + +# Extract user prompt from event data +USER_PROMPT=$(echo "$EVENT_DATA" | jq -r '.prompt // empty') + +# Exit silently if no prompt +if [ -z "$USER_PROMPT" ]; then + exit 0 +fi + +# Log timestamp +echo "[$(date '+%Y-%m-%d %H:%M:%S')] Analyzing prompt..." >> "$LOG_FILE" + +# Convert prompt to lowercase for case-insensitive matching +PROMPT_LOWER=$(echo "$USER_PROMPT" | tr '[:upper:]' '[:lower:]') + +# Array to hold matched skills +MATCHED_SKILLS=() + +# Function to check if prompt contains any keyword +contains_keyword() { + local skill_name=$1 + local keywords=$(jq -r ".skills[\"$skill_name\"].promptTriggers.keywords[]" "$SKILL_RULES") + + while IFS= read -r keyword; do + keyword_lower=$(echo "$keyword" | tr '[:upper:]' '[:lower:]') + if echo "$PROMPT_LOWER" | grep -qi "$keyword_lower"; then + return 0 # Found match + fi + done <<< "$keywords" + + return 1 # No match +} + +# Function to check if prompt matches any intent pattern +matches_intent() { + local skill_name=$1 + local patterns=$(jq -r ".skills[\"$skill_name\"].promptTriggers.intentPatterns[]" "$SKILL_RULES" 2>/dev/null) + + if [ -z "$patterns" ]; then + return 1 + fi + + while IFS= read -r pattern; do + if echo "$PROMPT_LOWER" | grep -qiE "$pattern"; then + return 0 # Found match + fi + done <<< "$patterns" + + return 1 # No match +} + +# Check each skill for matches +for skill in $(jq -r '.skills | keys[]' "$SKILL_RULES"); do + if contains_keyword "$skill" || matches_intent "$skill"; then + MATCHED_SKILLS+=("$skill") + echo " βœ“ Matched: $skill" >> "$LOG_FILE" + fi +done + +# If no skills matched, exit silently +if [ ${#MATCHED_SKILLS[@]} -eq 0 ]; then + echo " No skills matched" >> "$LOG_FILE" + exit 0 +fi + +# Get max skills per prompt from config (default: 2) +MAX_SKILLS=$(jq -r '.config.maxSkillsPerPrompt // 2' "$SKILL_RULES") + +# Limit to max skills +if [ ${#MATCHED_SKILLS[@]} -gt $MAX_SKILLS ]; then + MATCHED_SKILLS=("${MATCHED_SKILLS[@]:0:$MAX_SKILLS}") +fi + +# Build skill activation message +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "🎯 SKILL ACTIVATION CHECK" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +for skill in "${MATCHED_SKILLS[@]}"; do + description=$(jq -r ".skills[\"$skill\"].description" "$SKILL_RULES") + echo "πŸ“š Relevant Skill: $skill" + echo " Description: $description" + echo "" +done + +echo "πŸ’‘ Consider using these skills if they're relevant to this task." +echo " You can manually load a skill by reading its SKILL.md file." +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +# Log successful activation +echo " Suggested skills: ${MATCHED_SKILLS[*]}" >> "$LOG_FILE" + +exit 0 diff --git a/.claude/hooks/skill-rules.json b/.claude/hooks/skill-rules.json new file mode 100644 index 0000000000..c983fa4b7e --- /dev/null +++ b/.claude/hooks/skill-rules.json @@ -0,0 +1,290 @@ +{ + "skills": { + "ios-dev-guidelines": { + "type": "domain", + "priority": "high", + "description": "Smart router to Swift/iOS development patterns (β†’ IOS_DEVELOPMENT_GUIDE.md). Critical rules, MVVM/Coordinator patterns, code style", + "promptTriggers": { + "keywords": [ + "swift", + "swiftui", + "viewmodel", + "coordinator", + "repository", + "refactor", + "architecture", + "mvvm", + "combine", + "async", + "await", + "@Published", + "@MainActor", + "protocol", + "extension", + "formatting", + "whitespace", + "indentation", + "code style", + "best practice" + ], + "intentPatterns": [ + "(create|add|implement|build).*?(view|viewmodel|coordinator|service|repository)", + "(refactor|restructure|reorganize).*?(code|class|struct|module)", + "(how to|best practice|correct way).*?(swift|ios|architecture|pattern)", + "(format|style|organize).*?(code|file|property)" + ] + }, + "fileTriggers": { + "pathPatterns": [ + "**/*.swift", + "**/PresentationLayer/**", + "**/ServiceLayer/**", + "**/ApplicationLayer/**", + "**/Models/**" + ], + "contentPatterns": [ + "class.*ViewModel", + "class.*Coordinator", + "protocol.*Repository", + "@Published", + "@MainActor", + "import SwiftUI", + "import Combine" + ] + } + }, + "localization-developer": { + "type": "domain", + "priority": "high", + "description": "Smart router to localization system (β†’ LOCALIZATION_GUIDE.md). 3-file .xcstrings workflow, Loc constants, format specifiers", + "promptTriggers": { + "keywords": [ + "localization", + "localiz", + "Loc.", + "xcstrings", + "translation", + "strings", + "text", + "label", + "title", + "hardcoded", + "string literal", + "user-facing text", + "crowdin", + "Auth.xcstrings", + "Workspace.xcstrings", + "UI.xcstrings", + "make generate" + ], + "intentPatterns": [ + "(add|create|update).*?(localization|string|text|label)", + "(hardcoded|hard-coded|literal).*?(string|text)", + "(remove|delete).*?(localization|string|key)", + "(search|find).*?(localization|string|key)", + "(how to|where).*?(localization|string|text)" + ] + }, + "fileTriggers": { + "pathPatterns": [ + "**/Loc/**/*.xcstrings", + "**/Loc/**/*.swift", + "**/Resources/**/*.xcstrings" + ], + "contentPatterns": [ + "import Loc", + "Loc\\.", + "\\.xcstrings", + "AnytypeText\\(", + "localization" + ] + } + }, + "code-generation-developer": { + "type": "domain", + "priority": "medium", + "description": "Smart router to code generation (β†’ CODE_GENERATION_GUIDE.md). Feature flags, SwiftGen, Sourcery, make generate workflows", + "promptTriggers": { + "keywords": [ + "make generate", + "swiftgen", + "sourcery", + "generate", + "codegen", + "code generation", + "feature flag", + "FeatureFlags", + "FeatureDescription", + "protobuf", + "generated", + "// Generated using", + "Assets.xcassets", + "imageset" + ], + "intentPatterns": [ + "(run|execute).*?(make generate|swiftgen|sourcery)", + "(create|add|enable).*?(feature flag|flag)", + "(generate|regenerate).*?(code|assets|localization|protobuf)", + "(update|modify).*?(feature flag|generated)", + "(how to|best practice).*?(generate|feature flag|codegen)" + ] + }, + "fileTriggers": { + "pathPatterns": [ + "**/FeatureDescription+Flags.swift", + "**/Assets.xcassets/**", + "**/.xcassets/**", + "**/swiftgen.yml", + "**/sourcery.yml", + "**/anytypeGen.yml", + "**/Generated/**" + ], + "contentPatterns": [ + "// Generated using Sourcery", + "// Generated using SwiftGen", + "FeatureFlags\\.", + "FeatureDescription\\(", + "static let.*=.*FeatureDescription" + ] + } + }, + "design-system-developer": { + "type": "domain", + "priority": "medium", + "description": "Smart router to design system (β†’ DESIGN_SYSTEM_MAPPING.md, TYPOGRAPHY_MAPPING.md). Icons (x18-x40), typography mapping, spacing formula", + "promptTriggers": { + "keywords": [ + "icon", + "image asset", + "x18", + "x24", + "x32", + "x40", + "typography", + "font", + "text style", + "design system", + "color", + "UI component", + "figma", + "design token", + "AnytypeText", + "DESIGN_SYSTEM_MAPPING", + "TYPOGRAPHY_MAPPING" + ], + "intentPatterns": [ + "(add|create|use).*?(icon|image|asset)", + "(update|change).*?(typography|font|text style)", + "(how to|where).*?(icon|image|asset|typography|font)", + "(design system|ui component).*?(pattern|usage|guide)", + "(export|add).*?(figma|svg)" + ] + }, + "fileTriggers": { + "pathPatterns": [ + "**/Assets.xcassets/**/*.imageset/**", + "**/DesignSystem/**", + "**/PresentationLayer/Common/**", + "**/DESIGN_SYSTEM_MAPPING.md", + "**/TYPOGRAPHY_MAPPING.md" + ], + "contentPatterns": [ + "Image\\(asset:", + "\\.X18\\.", + "\\.X24\\.", + "\\.X32\\.", + "\\.X40\\.", + "AnytypeText\\(", + "style:.*\\.ux" + ] + } + }, + "skills-manager": { + "type": "meta", + "priority": "medium", + "description": "Smart router to skills/hooks management (β†’ SKILLS_MANAGEMENT_GUIDE.md). Troubleshoot activation, add keywords, fine-tune system", + "promptTriggers": { + "keywords": [ + "skill activation", + "skill didn't activate", + "hook", + "troubleshoot skill", + "fine-tune", + "add keyword", + "skill-rules.json", + "activation log", + "why didn't", + "false positive", + "false negative", + "check logs", + "skills system", + "hooks system", + "skill not working" + ], + "intentPatterns": [ + "(check|view|show).*?(activation|log|skill)", + "(add|remove).*?keyword", + "(troubleshoot|debug|fix).*?(skill|hook|activation)", + "why (didn't|did).*?(activate|trigger)", + "(how to|how do I).*?(add|modify|change).*?(skill|hook|keyword)" + ] + }, + "fileTriggers": { + "pathPatterns": [ + "**/.claude/hooks/**", + "**/.claude/skills/**", + "**/skill-rules.json", + "**/SKILLS_MANAGEMENT_GUIDE.md" + ], + "contentPatterns": [ + "skill-rules.json", + "promptTriggers", + "fileTriggers" + ] + } + }, + "code-review-developer": { + "type": "domain", + "priority": "high", + "description": "Smart router to code review guidelines (β†’ code-review-guidelines.md). Review standards, common mistakes, actionable feedback only", + "promptTriggers": { + "keywords": [ + "code review", + "review code", + "PR review", + "pull request review", + "review PR", + "approve", + "review changes", + "review diff", + "feedback", + "code feedback", + "review guidelines", + "review standards" + ], + "intentPatterns": [ + "(review|check|analyze).*?(code|pr|pull request|changes|diff)", + "(approve|reject).*?(pr|pull request)", + "(provide|give).*?(review|feedback)", + "(how to|best practice).*?review" + ] + }, + "fileTriggers": { + "pathPatterns": [ + "**/.github/workflows/code-review-guidelines.md", + "**/.github/workflows/claude-code-review-prompt.md" + ], + "contentPatterns": [ + "Review using CLAUDE.md", + "Review Sections", + "gh pr comment" + ] + } + } + }, + "config": { + "maxSkillsPerPrompt": 2, + "logActivations": true, + "logPath": ".claude/logs/skill-activations.log" + } +} diff --git a/.claude/hooks/swiftformat-auto.sh b/.claude/hooks/swiftformat-auto.sh new file mode 100755 index 0000000000..84e410d3ac --- /dev/null +++ b/.claude/hooks/swiftformat-auto.sh @@ -0,0 +1,108 @@ +#!/bin/bash + +# SwiftFormat Auto-Formatter Hook (Stop Event) +# Automatically formats Swift files after Claude finishes responding +# +# ⚠️ WARNING - CONTEXT TOKEN USAGE CONCERN ⚠️ +# Based on research from https://github.com/diet103/claude-code-infrastructure-showcase +# and community feedback: +# +# File modifications trigger notifications that consume context tokens. +# In some cases, auto-formatting can lead to significant token usage: +# - Large files with many formatting changes = more tokens consumed +# - Strict formatting rules = more changes = more tokens +# - Each file change generates a system-reminder with full diff context +# +# RECOMMENDATION: +# - Monitor your context usage after enabling this hook +# - If you notice rapid context depletion, consider disabling this hook +# - Alternative: Run SwiftFormat manually between Claude sessions instead +# +# TO DISABLE THIS HOOK: +# 1. Rename this file to add .disabled extension: swiftformat-auto.sh.disabled +# 2. Or delete this file entirely +# +# Based on: https://github.com/diet103/claude-code-infrastructure-showcase + +set -euo pipefail + +# Configuration +ENABLED=true # Set to false to disable without deleting the file +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +LOG_DIR="$SCRIPT_DIR/../logs" +TOOL_LOG="$LOG_DIR/tool-usage.log" +FORMAT_LOG="$LOG_DIR/swiftformat.log" + +# Exit if disabled +if [ "$ENABLED" != "true" ]; then + exit 0 +fi + +# Ensure log directory exists +mkdir -p "$LOG_DIR" + +# Check if SwiftFormat is installed +if ! command -v swiftformat &> /dev/null; then + echo "[$(date '+%Y-%m-%d %H:%M:%S')] SwiftFormat not installed. Skipping auto-format." >> "$FORMAT_LOG" + exit 0 +fi + +# Check if tool usage log exists +if [ ! -f "$TOOL_LOG" ]; then + exit 0 +fi + +# Get timestamp for this run +TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') + +# Extract Swift files that were edited in the last minute +# (Stop hook runs after Claude finishes, so recent edits are relevant) +SWIFT_FILES=$(grep -E "\.(swift|Swift)" "$TOOL_LOG" 2>/dev/null | \ + tail -20 | \ + grep -oE '[^ ]+\.swift' | \ + sort -u || true) + +# If no Swift files, exit +if [ -z "$SWIFT_FILES" ]; then + exit 0 +fi + +# Log formatting session +echo "[$TIMESTAMP] Auto-formatting Swift files..." >> "$FORMAT_LOG" + +# Format each Swift file +FORMATTED_COUNT=0 +while IFS= read -r file; do + # Skip if file doesn't exist (might have been deleted) + if [ ! -f "$file" ]; then + continue + fi + + # Run SwiftFormat + if swiftformat "$file" --quiet 2>/dev/null; then + echo " βœ“ Formatted: $file" >> "$FORMAT_LOG" + ((FORMATTED_COUNT++)) + else + echo " βœ— Failed: $file" >> "$FORMAT_LOG" + fi +done <<< "$SWIFT_FILES" + +# Log summary +if [ $FORMATTED_COUNT -gt 0 ]; then + echo " Summary: Formatted $FORMATTED_COUNT Swift file(s)" >> "$FORMAT_LOG" + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "✨ SwiftFormat Auto-Formatter" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "" + echo "Automatically formatted $FORMATTED_COUNT Swift file(s)" + echo "" + echo "⚠️ Note: File formatting consumes context tokens via diffs." + echo " If context usage is too high, disable this hook by setting ENABLED=false" + echo " in .claude/hooks/swiftformat-auto.sh" + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "" +fi + +exit 0 diff --git a/.claude/logs/.gitignore b/.claude/logs/.gitignore new file mode 100644 index 0000000000..db82191f5c --- /dev/null +++ b/.claude/logs/.gitignore @@ -0,0 +1,5 @@ +# Ignore all log files generated by hooks +*.log + +# But keep this directory in git +!.gitignore diff --git a/.claude/skills/README.md b/.claude/skills/README.md new file mode 100644 index 0000000000..96aa99e65a --- /dev/null +++ b/.claude/skills/README.md @@ -0,0 +1,534 @@ +# Claude Code Skills System + +Smart routing system for the Anytype iOS project using **progressive disclosure** architecture. Skills act as lightweight routers that provide critical rules and point you to comprehensive documentation. + +## Overview + +This skills system uses a **3-level progressive disclosure** pattern: +- **Level 1**: CLAUDE.md - Lightweight overview + quick reference +- **Level 2**: Skills (this directory) - Smart routers with critical rules + navigation +- **Level 3**: Specialized guides - Deep technical documentation + +Skills provide **automatic activation** based on your prompts and file context, eliminating the need to manually load documentation. + +## 🎯 Available Skills + +### 1. **ios-dev-guidelines** (Smart Router) +**Purpose**: Routes to Swift/iOS development patterns, architecture, and best practices + +**Auto-activates when**: +- Working with `.swift` files +- Discussing ViewModels, Coordinators, or architecture +- Refactoring or formatting code +- Using keywords: swift, swiftui, mvvm, async, await + +**Provides**: +- Critical rules (NEVER trim whitespace, update tests/mocks, etc.) +- Quick patterns (MVVM ViewModel, Coordinator, DI) +- Project structure overview +- Common historical mistakes +- **β†’ Routes to**: `Anytype/Sources/IOS_DEVELOPMENT_GUIDE.md` for comprehensive details + +**Location**: `.claude/skills/ios-dev-guidelines/SKILL.md` + +--- + +### 2. **localization-developer** (Smart Router) +**Purpose**: Routes to localization system for managing .xcstrings files and Loc constants + +**Auto-activates when**: +- Working with `.xcstrings` files +- Using Loc constants +- Discussing hardcoded strings or user-facing text +- Using keywords: localization, strings, text, Loc. + +**Provides**: +- Critical rules (NEVER duplicate keys, only edit English, etc.) +- 3-file decision tree (Auth/Workspace/UI) +- Quick workflow + key naming patterns +- Dynamic localization (format specifiers) +- **β†’ Routes to**: `Anytype/Sources/PresentationLayer/Common/LOCALIZATION_GUIDE.md` for comprehensive details + +**Location**: `.claude/skills/localization-developer/SKILL.md` + +--- + +### 3. **code-generation-developer** (Smart Router) +**Purpose**: Routes to code generation workflows (SwiftGen, Sourcery, Feature Flags, Protobuf) + +**Auto-activates when**: +- Running or discussing `make generate` +- Adding feature flags +- Working with generated files +- Using keywords: swiftgen, sourcery, feature flags, FeatureFlags + +**Provides**: +- Critical rules (NEVER edit generated files, always run make generate) +- Feature flags quick workflow (define β†’ generate β†’ use) +- When to run make generate table +- Quick SwiftGen, Sourcery, Middleware overviews +- **β†’ Routes to**: `Modules/AnytypeCore/CODE_GENERATION_GUIDE.md` for comprehensive details + +**Location**: `.claude/skills/code-generation-developer/SKILL.md` + +--- + +### 4. **design-system-developer** (Smart Router) +**Purpose**: Routes to design system patterns (icons, typography, colors, Figma-to-code) + +**Auto-activates when**: +- Working with icons or typography +- Using keywords: icon, typography, design system, figma +- Editing files in DesignSystem/ or Assets.xcassets +- Discussing colors or UI components + +**Provides**: +- Critical rules (use design system constants, spacing formula) +- Icon quick reference (x18/x24/x32/x40) +- Typography mapping (Figma β†’ Swift) with caption exceptions +- Critical spacing formula: `Next.Y - (Current.Y + Current.Height)` +- **β†’ Routes to**: `DESIGN_SYSTEM_MAPPING.md` & `TYPOGRAPHY_MAPPING.md` for comprehensive details + +**Location**: `.claude/skills/design-system-developer/SKILL.md` + +--- + +### 5. **skills-manager** (Smart Router - Meta!) +**Purpose**: Routes to skills/hooks management and troubleshooting + +**Auto-activates when**: +- Discussing skill activation or hooks +- Troubleshooting why a skill didn't activate +- Using keywords: skill activation, hook, troubleshoot, fine-tune, add keyword + +**Provides**: +- Critical rules for managing the system +- Quick diagnostic workflows +- How to add/remove keywords +- Health check commands +- Common issues and fixes +- **β†’ Routes to**: `.claude/SKILLS_MANAGEMENT_GUIDE.md` for comprehensive management + +**Location**: `.claude/skills/skills-manager/SKILL.md` + +**Note**: This is a meta-skill - it helps you manage the skills system itself! + +--- + +### 6. **code-review-developer** (Smart Router) +**Purpose**: Routes to code review guidelines for conducting thorough, actionable reviews + +**Auto-activates when**: +- Reviewing pull requests or code changes +- Keywords: code review, PR review, review code, pull request, approve, issues +- Discussing review comments or feedback + +**Provides**: +- Critical rules (be lean, no praise sections, no design suggestions) +- Quick review workflow (read changes β†’ check CLAUDE.md β†’ find issues β†’ format review) +- Common analysis mistakes (assuming unused code, not understanding flags) +- Review sections format (bugs, best practices, performance, security) +- **β†’ Routes to**: `.claude/CODE_REVIEW_GUIDE.md` for complete review standards +- **β†’ Routes to**: `.github/workflows/pr-review-automation.md` for CI/GitHub Actions integration + +**Location**: `.claude/skills/code-review-developer/SKILL.md` + +## πŸ“Š Progressive Disclosure Architecture + +This documentation system follows the principle of **progressive disclosure** - load only what's needed, when it's needed. + +### 3-Level Information Architecture + +``` +Level 1: CLAUDE.md +β”œβ”€ Quick start + critical rules +β”œβ”€ Essential commands +β”œβ”€ Quick workflows with "β†’ See [GUIDE]" pointers +└─ Links to Level 2 (Skills) and Level 3 (Specialized Docs) + +Level 2: Skills +β”œβ”€ Critical rules worth duplicating +β”œβ”€ Quick reference patterns +β”œβ”€ Decision trees and checklists +β”œβ”€ Common mistakes +└─ "β†’ Routes to" pointers to Level 3 + +Level 3: Specialized Guides (Comprehensive documentation) +β”œβ”€ IOS_DEVELOPMENT_GUIDE.md +β”œβ”€ LOCALIZATION_GUIDE.md +β”œβ”€ CODE_GENERATION_GUIDE.md +β”œβ”€ SKILLS_MANAGEMENT_GUIDE.md [meta!] +β”œβ”€ DESIGN_SYSTEM_MAPPING.md +└─ TYPOGRAPHY_MAPPING.md +``` + +### Why This Architecture? + +**Single Source of Truth**: Each piece of knowledge lives in exactly one place +- Critical rules duplicated in skills for visibility +- Everything else lives in Level 3 specialized docs +- Skills act as routers with clear navigation paths + +**Context Token Efficiency**: Load only what's needed +- CLAUDE.md: Always loaded, lightweight overview +- Skills: Auto-activated based on context +- Specialized docs: Referenced when deep knowledge needed + +**Maintainability**: Easy to update without duplication +- Update specialized docs once +- Skills reference docs, don't duplicate content +- Clear separation of concerns + +## πŸ”„ How Auto-Activation Works + +### Automatic Suggestion + +When you start a conversation, the system: + +1. **Analyzes your prompt** for keywords and patterns +2. **Checks file paths** if you're editing files +3. **Matches against skill rules** (defined in `.claude/hooks/skill-rules.json`) +4. **Suggests relevant skills** with a formatted message: + +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +🎯 SKILL ACTIVATION CHECK +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +πŸ“š Relevant Skill: ios-dev-guidelines + Description: Swift/iOS development patterns, architecture, and best practices + +πŸ’‘ Consider using these skills if they're relevant to this task. + You can manually load a skill by reading its SKILL.md file. + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +### Manual Loading + +You can also manually load a skill: + +``` +Read the file .claude/skills/ios-dev-guidelines/SKILL.md +``` + +## πŸ“‚ Directory Structure + +``` +.claude/skills/ +β”œβ”€β”€ README.md (this file) +β”‚ +β”œβ”€β”€ ios-dev-guidelines/ +β”‚ └── SKILL.md (smart router) +β”‚ +β”œβ”€β”€ localization-developer/ +β”‚ └── SKILL.md (smart router) +β”‚ +β”œβ”€β”€ code-generation-developer/ +β”‚ └── SKILL.md (smart router) +β”‚ +β”œβ”€β”€ design-system-developer/ +β”‚ └── SKILL.md (smart router) +β”‚ +β”œβ”€β”€ skills-manager/ +β”‚ └── SKILL.md (smart router - meta!) +β”‚ +└── code-review-developer/ + └── SKILL.md (smart router) +``` + +**Note**: Resource files removed in favor of specialized documentation at Level 3. + +## βš™οΈ Configuration + +### Skill Rules + +**Location**: `.claude/hooks/skill-rules.json` + +Defines activation patterns for each skill: +- **Keywords**: Terms that trigger skill suggestion +- **Intent Patterns**: Regex patterns for actions (e.g., "create.*feature") +- **File Triggers**: Path patterns that activate skills +- **Content Patterns**: Code patterns that match skills + +### Example Configuration + +```json +{ + "skills": { + "ios-dev-guidelines": { + "type": "domain", + "priority": "high", + "promptTriggers": { + "keywords": ["swift", "viewmodel", "refactor"], + "intentPatterns": [ + "(create|add).*?(view|viewmodel|coordinator)" + ] + }, + "fileTriggers": { + "pathPatterns": ["**/*.swift"], + "contentPatterns": ["class.*ViewModel", "@Published"] + } + } + } +} +``` + +## πŸͺ Hooks Integration + +The skills system uses hooks for auto-activation: + +### UserPromptSubmit Hook + +**File**: `.claude/hooks/skill-activation-prompt.sh` + +- Runs before Claude sees your message +- Analyzes prompt and file context +- Injects skill suggestions into conversation +- Logs activations to `.claude/logs/skill-activations.log` + +### Activation Flow + +``` +User Prompt β†’ Hook Analyzes β†’ Matches Skills β†’ Suggests to Claude +``` + +## 🎨 Best Practices + +### For Users + +1. **Trust the suggestions** - If a skill is suggested, it's likely relevant +2. **Don't manually load skills repeatedly** - Auto-activation handles it +3. **Use specific keywords** - Helps trigger the right skills +4. **Check activation logs** - See which skills were suggested + +### For Skill Authors (Smart Router Pattern) + +1. **Keep SKILL.md** - Skills are routers, not comprehensive guides +2. **Add clear "Critical Rules" section** - Worth duplicating for visibility +3. **Provide quick reference only** - Tables, examples, common patterns +4. **Point to Level 3 docs** - Use "**β†’ Routes to**: path/to/GUIDE.md" pattern +5. **No resource files** - All comprehensive content lives in Level 3 specialized docs +6. **Update skill-rules.json** - Add relevant keywords and patterns + +## πŸ“Š Monitoring + +### Activation Logs + +**Location**: `.claude/logs/skill-activations.log` + +Shows which skills were suggested and when: + +``` +[2025-01-30 14:23:45] Analyzing prompt... + βœ“ Matched: ios-dev-guidelines + Suggested skills: ios-dev-guidelines +``` + +### Tool Usage Logs + +**Location**: `.claude/logs/tool-usage.log` + +Tracks file modifications: + +``` +[2025-01-30 14:24:12] Edit: Anytype/Sources/PresentationLayer/ChatView.swift + └─ Area: UI/Presentation, File: ... +``` + +## πŸš€ Usage Examples + +### Example 1: Adding a Feature Flag + +**Your Prompt**: "Add a feature flag for the new chat interface" + +**Auto-Activated**: `code-generation-developer` + +**Why**: Keyword "feature flag" matches code-generation-developer rules + +**What You Get**: Guidance on: +- Where to add FeatureDescription +- How to run `make generate` +- How to use FeatureFlags in code + +### Example 2: Implementing Figma Design + +**Your Prompt**: "Implement the empty state design with icons and typography" + +**Auto-Activated**: `design-system-developer` + +**Why**: Keywords "icons", "typography" match design-system-developer + +**What You Get**: Guidance on: +- Icon size selection +- Typography mapping +- Spacing extraction from Figma +- Color constants usage + +### Example 3: Refactoring ViewModel + +**Your Prompt**: "Refactor ChatViewModel to use async/await" + +**Auto-Activated**: `ios-dev-guidelines` + +**Why**: Keywords "ViewModel", "async/await", "refactor" match ios-dev-guidelines + +**What You Get**: Guidance on: +- ViewModel patterns +- Async/await best practices +- Property organization +- Code formatting rules + +## πŸ”§ Troubleshooting + +### Skills Not Activating + +**Problem**: Expected skill not suggested + +**Solutions**: +1. Check `.claude/logs/skill-activations.log` for activation attempts +2. Verify keywords in your prompt match `skill-rules.json` +3. Use more specific keywords (e.g., "localization" instead of "text") +4. Manually load skill if auto-activation fails + +### Wrong Skill Suggested + +**Problem**: Irrelevant skill suggested + +**Solutions**: +1. Ignore the suggestion (it's just a recommendation) +2. Be more specific in your prompt +3. Update `skill-rules.json` to refine matching rules + +### Multiple Skills Suggested + +**Problem**: Too many skills suggested + +**Solution**: This is normal - system limits to 2 skills max (configured in skill-rules.json) + +## πŸ“š Related Documentation + +- **Hooks System**: `.claude/hooks/README.md` - How hooks work +- **CLAUDE.md**: Main project documentation - Quick start and workflows +- **skill-rules.json**: Skill activation configuration + +## πŸŽ“ Learning Path + +**New to the project?** Read skills in this order: + +1. **ios-dev-guidelines** - Understand Swift/iOS patterns +2. **localization-developer** - Learn localization workflow +3. **code-generation-developer** - Master `make generate` workflows +4. **design-system-developer** - Understand design system usage + +## πŸ”„ Updating Skills + +### Adding a New Skill + +1. Create directory: `.claude/skills/new-skill-name/` +2. Create `SKILL.md` with clear structure +3. Add resources to `resources/` subdirectory +4. Update `skill-rules.json` with activation patterns +5. Test activation with sample prompts +6. Update this README + +### Modifying Existing Skill + +1. Edit the SKILL.md file +2. Keep under 500 lines (move details to resources) +3. Update activation rules if keywords change +4. Test that auto-activation still works + +## πŸ“– Smart Router Skill Template + +When creating a new skill, follow this **smart router** pattern: + +```markdown +# Skill Name (Smart Router) + +## Purpose +Context-aware routing to [topic]. Helps you navigate [what it helps with]. + +## When Auto-Activated +- [File types or contexts] +- Keywords: [keyword1, keyword2, ...] + +## 🚨 CRITICAL RULES (NEVER VIOLATE) + +1. Must-follow rule 1 (worth duplicating for visibility) +2. Must-follow rule 2 +3. Must-follow rule 3 + +## πŸ“‹ Quick Reference + +[Tables, examples, common patterns - QUICK ONLY] + +### Example Pattern +```swift +// Quick code example +``` + +## 🎯 Quick Workflow + +1. Step 1 +2. Step 2 +3. Step 3 + +## ⚠️ Common Mistakes + +### Mistake 1 +```swift +// ❌ WRONG +... + +// βœ… CORRECT +... +``` + +## πŸ“š Complete Documentation + +**Full Guide**: `path/to/SPECIALIZED_GUIDE.md` + +For comprehensive coverage of: +- Detailed topic 1 +- Detailed topic 2 +- Complete examples +- Troubleshooting + +## βœ… Checklist + +- [ ] Item 1 +- [ ] Item 2 + +## πŸ”— Related Skills & Docs + +- **other-skill** β†’ `path/to/OTHER_GUIDE.md` - How they relate +- **another-skill** β†’ How they integrate + +--- + +**Navigation**: This is a smart router. For deep technical details, always refer to `SPECIALIZED_GUIDE.md`. +``` + +**Key principles**: +- ~100-200 lines total +- Critical rules duplicated for visibility +- Quick reference only (no comprehensive guides) +- Clear "β†’ Routes to" pointers to Level 3 docs +- No resource files - all comprehensive content in Level 3 + +## Summary + +The skills system provides: +- βœ… **Progressive disclosure architecture** - 3 levels of documentation +- βœ… **Automatic skill suggestions** based on context - Zero friction +- βœ… **6 smart router skills** - Lightweight and fast +- βœ… **Hook-based activation** - Analyzed prompts trigger relevant skills +- βœ… **Context token efficiency** - Load only what's needed +- βœ… **Single Source of Truth** - Each piece of knowledge lives in one place +- βœ… **Self-documenting** - skills-manager skill helps you manage the system +- βœ… **Logging and monitoring** for debugging + +**Start using it**: Just work normally - skills auto-activate when relevant and route you to comprehensive docs! + +**Need help managing the system?** The skills-manager skill auto-activates when you discuss troubleshooting or fine-tuning! \ No newline at end of file diff --git a/.claude/skills/code-generation-developer/SKILL.md b/.claude/skills/code-generation-developer/SKILL.md new file mode 100644 index 0000000000..18fe9f9c31 --- /dev/null +++ b/.claude/skills/code-generation-developer/SKILL.md @@ -0,0 +1,192 @@ +# Code Generation Developer (Smart Router) + +## Purpose +Context-aware routing to code generation workflows: SwiftGen, Sourcery, Feature Flags, and Protobuf. Helps you navigate when and how to run generators. + +## When Auto-Activated +- Running or discussing `make generate` +- Adding feature flags +- Working with generated files +- Keywords: swiftgen, sourcery, feature flags, FeatureFlags, make generate + +## 🚨 CRITICAL RULES (NEVER VIOLATE) + +1. **NEVER edit generated files** - Files marked with `// Generated using Sourcery/SwiftGen` are auto-generated +2. **ALWAYS run `make generate` after changes** - When updating templates, flags, assets, or localization +3. **Feature flags for all new features** - Wrap experimental code for safe rollouts +4. **Update source, not generated code** - Edit templates/configurations, then regenerate + +## πŸ“‹ Essential Commands + +```bash +make generate # Run all generators (SwiftGen, Sourcery, assets, localization) +make generate-middle # Regenerate middleware and protobuf (when dependencies change) +make setup-middle # Initial middleware setup +``` + +## 🚩 Feature Flags Quick Workflow + +### 1. Define Flag + +**File**: `/Modules/AnytypeCore/AnytypeCore/Utils/FeatureFlags/FeatureDescription+Flags.swift` + +```swift +extension FeatureDescription { + static let newChatInterface = FeatureDescription( + title: "New Chat Interface", + type: .feature(author: "Your Name", releaseVersion: "0.42.0"), + defaultValue: false, // Off in production + debugValue: true // On in debug builds for testing + ) +} +``` + +### 2. Generate + +```bash +make generate +``` + +This creates: `Modules/AnytypeCore/AnytypeCore/Generated/FeatureFlags.swift` + +### 3. Use in Code + +```swift +import AnytypeCore + +if FeatureFlags.newChatInterface { + NewChatView() +} else { + LegacyChatView() +} +``` + +### Flag Types + +- **`.debug`**: Debug-only (not available in production) +- **`.feature(author:releaseVersion:)`**: Production feature with metadata + +### Best Practices + +- `defaultValue: false` for unreleased features +- `debugValue: true` for easier developer testing +- Remove flags after full rollout + +## 🎯 When to Run `make generate` + +| You Did This | Run This | Why | +|--------------|----------|-----| +| Added/updated .xcstrings | `make generate` | Regenerate Loc constants | +| Added feature flag | `make generate` | Generate FeatureFlags enum | +| Added icon to Assets.xcassets | `make generate` | Generate Image asset constants | +| Modified Sourcery template | `make generate` | Regenerate code from templates | +| Updated middleware version | `make generate-middle` | Regenerate protobuf bindings | + +## 🎨 SwiftGen - Assets & Localization + +### Adding Icons + +1. Export SVG from Figma (e.g., "32/qr code" β†’ `QRCode.svg`) +2. Add to `/Modules/Assets/.../Assets.xcassets/DesignSystem/x32/QRCode.imageset/` +3. Run `make generate` +4. Use: `Image(asset: .X32.qrCode)` + +**Icon Sizes**: x18, x24, x32, x40 (pt) + +### Localization + +SwiftGen generates Loc constants from .xcstrings files. + +See **localization-developer** skill for complete workflow. + +## πŸ”§ Sourcery - Template-Based Generation + +Sourcery generates Swift code from templates based on source file annotations. + +**Common uses**: +- Protocol conformance +- Mock implementations +- Dependency injection +- Enum helpers + +**Workflow**: +1. Add annotation to source file: `// sourcery: AutoEquatable` +2. Run `make generate` +3. Use generated code (don't edit generated files!) + +## πŸ”Œ Middleware & Protobuf + +### When to Regenerate + +- Middleware version updated +- `Dependencies/Middleware/Lib.xcframework` missing binaries +- Build errors related to middleware symbols + +### Commands + +```bash +make setup-middle # Initial setup +make generate-middle # Regenerate middleware + protobuf +``` + +## ⚠️ Common Mistakes + +### Editing Generated Files + +```swift +// In FeatureFlags.swift (GENERATED) +static let myFlag: Bool = true // ❌ DON'T DO THIS +// Your changes will be overwritten +``` + +**βœ… Correct**: Edit `FeatureDescription+Flags.swift`, then `make generate` + +### Forgetting to Generate + +```swift +// Added FeatureDescription but didn't generate +if FeatureFlags.myNewFlag { // ❌ Error: unresolved identifier + ... +} +``` + +**βœ… Correct**: Run `make generate` first + +### Missing Middleware Binaries + +**Symptoms**: "Lib.xcframework missing binaries" + +**Solution**: `make setup-middle` or `make generate` + +## πŸ“š Complete Documentation + +**Full Guide**: `Modules/AnytypeCore/CODE_GENERATION_GUIDE.md` + +For comprehensive coverage of: +- Feature Flags lifecycle (Development β†’ Beta β†’ Rollout β†’ Cleanup) +- SwiftGen configuration files and workflows +- Sourcery templates and annotations +- Protobuf splitting configuration +- Complete troubleshooting guide +- Generated file locations + +## βœ… Checklist: Before Committing + +- [ ] Ran `make generate` if you added/updated: + - [ ] Feature flags + - [ ] Icons/assets + - [ ] Localization strings + - [ ] Sourcery annotations +- [ ] Did NOT manually edit files with "// Generated using" header +- [ ] Committed both source AND generated files +- [ ] Verified build succeeds + +## πŸ”— Related Skills & Docs + +- **localization-developer** β†’ `LOCALIZATION_GUIDE.md` - Localization keys generated by SwiftGen +- **ios-dev-guidelines** β†’ `IOS_DEVELOPMENT_GUIDE.md` - Never edit generated files +- **design-system-developer** β†’ Icons generated by SwiftGen + +--- + +**Navigation**: This is a smart router. For deep technical details, always refer to `CODE_GENERATION_GUIDE.md`. diff --git a/.claude/skills/code-review-developer/SKILL.md b/.claude/skills/code-review-developer/SKILL.md new file mode 100644 index 0000000000..8ad143ada3 --- /dev/null +++ b/.claude/skills/code-review-developer/SKILL.md @@ -0,0 +1,263 @@ +# Code Review Developer (Smart Router) + +## Purpose +Context-aware routing to code review guidelines. Helps you conduct thorough, actionable code reviews following project standards. + +## When Auto-Activated +- Reviewing pull requests or code changes +- Keywords: code review, PR review, review code, pull request, approve, issues +- Discussing review comments or feedback + +## 🚨 CRITICAL RULES (NEVER VIOLATE) + +1. **Be LEAN and ACTIONABLE** - Only report actual issues, no noise +2. **NO praise sections** - No "Strengths", no "no concerns" statements +3. **NO design suggestions** - You cannot see visual design (padding, margins, colors) +4. **Reference file:line** - Always include specific locations for issues +5. **If clean, just approve** - "βœ… **Approved** - No issues found" (nothing else!) +6. **Check CLAUDE.md** - Review against project conventions + +## πŸ“‹ Quick Review Workflow + +### 1. Read the Changes +- Understand what the PR is trying to do +- Check file diffs thoroughly + +### 2. Check Against CLAUDE.md +- Localization: Using `Loc` constants? +- Generated files: Not editing generated code? +- Code style: Following Swift best practices? +- Tests: Updated when refactoring? + +### 3. Look for Real Issues +**ONLY include sections if issues exist:** +- **Bugs/Issues** - Logic errors, potential bugs +- **Best Practices** - Violations of CLAUDE.md guidelines +- **Performance** - Actual performance problems +- **Security** - Real security vulnerabilities + +### 4. Format Your Review + +**If clean**: +``` +βœ… **Approved** - No issues found +``` + +**If issues found**: +``` +## Bugs/Issues + +**ChatView.swift:45** +Potential race condition when... + +--- + +⚠️ **Minor Issues** - Fix race condition +``` + +## ⚠️ Common Mistakes to Avoid + +### Assuming Code is Unused After UI Removal + +**Scenario**: PR removes a menu button but leaves the `menu` parameter + +**❌ WRONG**: +``` +"The menu parameter is now unused and should be removed" +``` + +**βœ… CORRECT**: +``` +Check if menu is used elsewhere: +- Long-press context menu? +- Dual UX pattern (button + long-press)? +- Multiple consumers? +``` + +**Example**: +```swift +// menu() is used in BOTH places +.toolbar { Menu { menu() } } // Visible button (removed) +.contextMenu { menu() } // Long-press (still there!) +``` + +**Before suggesting removal**: +- [ ] Searched ALL usages in the file +- [ ] Checked for dual UX patterns +- [ ] Understood purpose of each flag +- [ ] Asked about design intent if unsure + +### Not Understanding Conditional Flags + +**Scenario**: Component has `allowMenuContent` and `allowContextMenuItems` + +**❌ WRONG**: +``` +"These flags serve the same purpose, consolidate them" +``` + +**βœ… CORRECT**: +``` +They control DIFFERENT UI elements: +- allowMenuContent: Visible button +- allowContextMenuItems: Long-press menu +- Can be independently enabled/disabled +``` + +## 🎯 Review Sections (Include ONLY If Issues Exist) + +### Bugs/Issues +Logic errors, potential bugs that need fixing + +**Format**: +``` +**FileName.swift:123** +Description of the bug and why it's a problem. +``` + +### Best Practices +Violations of Swift/SwiftUI conventions or CLAUDE.md guidelines (code quality only, not design) + +**Format**: +``` +**FileName.swift:45** +Using hardcoded strings instead of Loc constants. +``` + +### Performance +Actual performance problems (not theoretical) + +**Format**: +``` +**ViewModel.swift:89** +N+1 query in loop - will cause performance issues with large datasets. +``` + +### Security +Real security vulnerabilities + +**Format**: +``` +**AuthService.swift:34** +Storing credentials in UserDefaults - should use Keychain. +``` + +## πŸ“Š Summary Format + +**End with ONE sentence with status emoji**: + +``` +βœ… **Approved** - Clean implementation following guidelines +⚠️ **Minor Issues** - Fix hardcoded strings and race condition +🚨 **Major Issues** - Critical security vulnerability in auth flow +``` + +## πŸ” Analysis Checklist + +Before finalizing your review: +- [ ] Checked against CLAUDE.md conventions +- [ ] Verified localization (no hardcoded strings) +- [ ] Checked for generated file edits +- [ ] Looked for race conditions +- [ ] Verified tests/mocks updated if refactoring +- [ ] Searched for ALL usages before suggesting removal +- [ ] Only included sections with actual issues +- [ ] No design/UI suggestions (padding, margins, colors) +- [ ] Referenced specific file:line for each issue +- [ ] Ended with status emoji summary + +## πŸ“š Complete Documentation + +**Full Guide**: `.claude/CODE_REVIEW_GUIDE.md` + +For comprehensive coverage of: +- Core review rules +- Common analysis mistakes (with examples) +- Review sections and formats +- Complete checklist + +**CI/Automation**: `.github/workflows/pr-review-automation.md` + +For GitHub Actions integration: +- Context variables (REPO, PR_NUMBER, COMMIT_SHA) +- Valid runners and Xcode versions +- Review comment strategies +- How to post reviews via `gh` CLI + +## πŸ’‘ Quick Reference + +### What to Check + +**From CLAUDE.md**: +- [ ] No hardcoded strings (use `Loc` constants) +- [ ] No generated file edits (`// Generated using...`) +- [ ] Tests/mocks updated when refactoring +- [ ] Feature flags for new features +- [ ] No whitespace trimming +- [ ] Async/await over completion handlers + +**Code Quality**: +- [ ] Swift best practices (guard, @MainActor) +- [ ] Proper error handling +- [ ] No force unwraps in production code +- [ ] Memory leaks (weak/unowned where needed) + +### What NOT to Comment On + +- ❌ Design/UI spacing (padding, margins) +- ❌ Colors or visual appearance +- ❌ Praise or "Strengths" sections +- ❌ "No concerns" statements +- ❌ Theoretical performance issues +- ❌ Style preferences not in CLAUDE.md + +## πŸŽ“ Example Reviews + +### Example 1: Clean PR +``` +βœ… **Approved** - No issues found +``` + +**That's it! Don't add explanations, don't list changes.** + +### Example 2: Minor Issues +``` +## Best Practices + +**ChatView.swift:34** +Using hardcoded string "Send Message" instead of localization constant. +Should be: `Text(Loc.sendMessage)` + +**ChatViewModel.swift:89** +Tests not updated after renaming `sendMessage()` to `send()`. +Update `ChatViewModelTests.swift` to use new method name. + +--- + +⚠️ **Minor Issues** - Fix hardcoded string and update tests +``` + +### Example 3: Critical Issue +``` +## Bugs/Issues + +**AuthService.swift:45** +Storing password in UserDefaults (line 45). This is a security vulnerability. +Should use Keychain instead: `KeychainService.store(password, for: key)` + +--- + +🚨 **Major Issues** - Fix password storage security vulnerability +``` + +## πŸ”— Related Skills & Docs + +- **ios-dev-guidelines** β†’ `IOS_DEVELOPMENT_GUIDE.md` - Swift/iOS patterns to check against +- **localization-developer** β†’ `LOCALIZATION_GUIDE.md` - Verify no hardcoded strings +- **code-generation-developer** β†’ `CODE_GENERATION_GUIDE.md` - Verify no generated file edits + +--- + +**Navigation**: This is a smart router. For detailed review standards and common mistakes, always refer to `.claude/CODE_REVIEW_GUIDE.md`. + +**For CI/automation**: See `.github/workflows/pr-review-automation.md` for GitHub Actions integration. diff --git a/.claude/skills/design-system-developer/SKILL.md b/.claude/skills/design-system-developer/SKILL.md new file mode 100644 index 0000000000..629f038810 --- /dev/null +++ b/.claude/skills/design-system-developer/SKILL.md @@ -0,0 +1,207 @@ +# Design System Developer (Smart Router) + +## Purpose +Context-aware routing to the Anytype iOS design system: icons, typography, colors, spacing. Helps you navigate Figma-to-code translation. + +## When Auto-Activated +- Working with icons or typography +- Keywords: icon, typography, design system, figma, color, spacing +- Editing files in DesignSystem/ or Assets.xcassets +- Discussing colors or UI components + +## 🚨 CRITICAL RULES (NEVER VIOLATE) + +1. **ALWAYS use design system constants** - Never hardcode hex colors, font sizes, or asset names +2. **ALWAYS run `make generate` after adding assets** - Icons and assets must be code-generated +3. **Icons are organized by size** - x18, x24, x32, x40 (use correct size for context) +4. **Typography follows strict mapping** - Figma style names map to specific Swift enum cases +5. **Spacing formula** - `NextElement.Y - (CurrentElement.Y + CurrentElement.Height)` + +## πŸ“‹ Quick Reference + +### Icon Usage + +```swift +// 18pt - Toolbar/nav bar icons +Image(asset: .X18.search) + +// 24pt - List row icons +Image(asset: .X24.camera) + +// 32pt - Buttons, main UI (most common) +Image(asset: .X32.qrCode) + +// 40pt - Large features +Image(asset: .X40.profile) +``` + +### Adding Icons + +1. Export SVG from Figma ("32/qr code" β†’ `QRCode.svg`) +2. Add to `/Modules/Assets/.../Assets.xcassets/DesignSystem/x32/QRCode.imageset/` +3. Run `make generate` +4. Use: `Image(asset: .X32.qrCode)` + +### Typography Usage + +```swift +// Screen titles +AnytypeText("Settings", style: .uxTitle1Semibold) + +// Section headers +AnytypeText("Recent", style: .uxTitle2Semibold) + +// Body text +Text("Description").anytypeStyle(.bodyRegular) + +// Small labels +Text("Add Member").anytypeStyle(.caption1Medium) // Note: no "ux" prefix! +``` + +### Typography Mapping (Figma β†’ Swift) + +**Content Styles** (remove "Content/" prefix): +- "Content/Body/Semibold" β†’ `.bodySemibold` +- "Content/Preview Title 2/Regular" β†’ `.previewTitle2Regular` + +**UX Styles - Title/Body/Callout** (keep "ux" prefix lowercase): +- "UX/Title 1/Semibold" β†’ `.uxTitle1Semibold` +- "UX/Body/Regular" β†’ `.uxBodyRegular` + +**UX Styles - Captions** (DROP "ux" prefix - EXCEPTION!): +- "UX/Caption 1/Medium" β†’ `.caption1Medium` (no "ux") +- "UX/Caption 2/Regular" β†’ `.caption2Regular` (no "ux") + +### Common Typography Styles + +| Use Case | Figma Style | Swift Constant | Size | +|----------|-------------|----------------|------| +| Screen titles | UX/Title 1/Semibold | `.uxTitle1Semibold` | 28pt | +| Section headers | UX/Title 2/Semibold | `.uxTitle2Semibold` | 17pt | +| Body text | Content/Body/Regular | `.bodyRegular` | 17pt | +| Small labels | UX/Caption 1/Medium | `.caption1Medium` | 13pt | + +### Color Usage + +```swift +// Backgrounds +.background(Color.Shape.transperentSecondary) +.background(Color.Background.primary) + +// Text colors +.foregroundColor(Color.Text.primary) +.foregroundColor(Color.Text.secondary) + +// Control colors +.foregroundColor(Color.Control.active) +``` + +## πŸ“ Spacing from Figma (CRITICAL FORMULA) + +**CRITICAL**: Spacing is the GAP between elements, not top-to-top distance. + +**Formula**: +``` +Spacing = NextElement.Y - (CurrentElement.Y + CurrentElement.Height) +``` + +**Example**: +1. First element: Y=326px, Height=24px β†’ Bottom edge = 350px +2. Second element: Y=374px +3. **Spacing = 374 - 350 = 24px** βœ… + +**Common mistake**: +``` +❌ WRONG: 374 - 326 = 48px (includes first element's height!) +βœ… CORRECT: 374 - (326 + 24) = 24px (actual gap) +``` + +**SwiftUI usage**: +```swift +Text("Title") +Spacer.fixedHeight(24) // βœ… Correct spacing +Text("Feature") +``` + +## ⚠️ Common Mistakes + +### Typography Style Doesn't Exist + +```swift +// ❌ WRONG +Text("Button").anytypeStyle(.uxCaption1Medium) // Doesn't exist! + +// βœ… CORRECT +Text("Button").anytypeStyle(.caption1Medium) // Captions drop "ux" prefix +``` + +### Hardcoded Colors + +```swift +// ❌ WRONG +.background(Color(hex: "#FF0000")) + +// βœ… CORRECT +.background(Color.Pure.red) +``` + +### Wrong Icon Size + +```swift +// ❌ WRONG - Upscaling looks bad +Image(asset: .X18.qrCode) + .frame(width: 32, height: 32) + +// βœ… CORRECT - Use native size +Image(asset: .X32.qrCode) + .frame(width: 32, height: 32) +``` + +### Spacing Calculation + +```swift +// ❌ WRONG - Top-to-top (includes height) +Spacing = NextElement.Y - CurrentElement.Y + +// βœ… CORRECT - Actual gap +Spacing = NextElement.Y - (CurrentElement.Y + CurrentElement.Height) +``` + +## πŸ“š Complete Documentation + +**Full Guides**: +- **Design System**: `Anytype/Sources/PresentationLayer/Common/DESIGN_SYSTEM_MAPPING.md` +- **Typography**: `Anytype/Sources/PresentationLayer/Common/TYPOGRAPHY_MAPPING.md` + +For comprehensive coverage of: +- Complete typography mapping table +- All color categories and constants +- Icon organization and workflows +- Corner radius standards +- Dimension standards (whole numbers only) +- Design verification workflow +- Dark/light mode considerations + +**Figma References**: +- Typography: https://www.figma.com/file/vgXV7x2v20vJajc7clYJ7a/Typography-Mobile + +## βœ… Design Implementation Checklist + +- [ ] All icons use `.X*` constants, no hardcoded asset names +- [ ] All typography uses `.anytypeStyle()` or `AnytypeText` +- [ ] All colors use `Color.*` constants, no hex values +- [ ] Spacing extracted from Figma using correct formula +- [ ] All dimensions are whole numbers (or documented if rounded) +- [ ] Ran `make generate` after adding new assets +- [ ] Verified against Figma design visually +- [ ] Checked dark/light mode appearance + +## πŸ”— Related Skills & Docs + +- **code-generation-developer** β†’ `CODE_GENERATION_GUIDE.md` - Run make generate after adding icons +- **ios-dev-guidelines** β†’ `IOS_DEVELOPMENT_GUIDE.md` - SwiftUI patterns for design system +- **localization-developer** β†’ Combine typography with localized text + +--- + +**Navigation**: This is a smart router. For deep technical details, always refer to `DESIGN_SYSTEM_MAPPING.md` and `TYPOGRAPHY_MAPPING.md`. diff --git a/.claude/skills/ios-dev-guidelines/SKILL.md b/.claude/skills/ios-dev-guidelines/SKILL.md new file mode 100644 index 0000000000..81b7d16536 --- /dev/null +++ b/.claude/skills/ios-dev-guidelines/SKILL.md @@ -0,0 +1,127 @@ +# iOS Development Guidelines (Smart Router) + +## Purpose +Context-aware routing to iOS development patterns, code style, and architecture guidelines. This skill provides critical rules and points you to comprehensive documentation. + +## When Auto-Activated +- Working with `.swift` files +- Discussing ViewModels, Coordinators, architecture +- Refactoring or formatting code +- Keywords: swift, swiftui, mvvm, async, await, refactor + +## 🚨 CRITICAL RULES (NEVER VIOLATE) + +1. **NEVER trim whitespace-only lines** - Preserve blank lines with spaces/tabs exactly as they appear +2. **NEVER edit generated files** - Files marked with `// Generated using Sourcery/SwiftGen` +3. **NEVER use hardcoded strings in UI** - Always use localization constants (`Loc.*`) +4. **NEVER add comments** unless explicitly requested +5. **ALWAYS update tests and mocks when refactoring** - Search for all references and update +6. **Use feature flags for new features** - Wrap experimental code for safe rollouts + +## πŸ“‹ Quick Checklist + +Before completing any task: +- [ ] Whitespace-only lines preserved (not trimmed) +- [ ] No hardcoded strings (use `Loc` constants) +- [ ] Tests and mocks updated if dependencies changed +- [ ] Generated files not edited +- [ ] Feature flags applied to new features +- [ ] No comments added (unless requested) + +## 🎯 Common Patterns + +### MVVM ViewModel +```swift +@MainActor +final class ChatViewModel: ObservableObject { + @Published var messages: [Message] = [] + @Injected(\.chatService) private var chatService + + func sendMessage(_ text: String) async { + // Business logic here + } +} +``` + +### Coordinator +```swift +@MainActor +final class ChatCoordinator: ObservableObject { + @Published var route: Route? + + enum Route { + case settings + case memberList + } +} +``` + +### Dependency Injection +```swift +extension Container { + var chatService: Factory { + Factory(self) { ChatService() } + } +} + +// Usage in ViewModel +@Injected(\.chatService) private var chatService +``` + +## πŸ—‚οΈ Project Structure + +``` +Anytype/Sources/ +β”œβ”€β”€ ApplicationLayer/ # App lifecycle, coordinators +β”œβ”€β”€ PresentationLayer/ # UI components, ViewModels +β”œβ”€β”€ ServiceLayer/ # Business logic, data services +β”œβ”€β”€ Models/ # Data models, entities +└── CoreLayer/ # Core utilities, networking +``` + +## πŸ”§ Code Style Quick Reference + +- **Indentation**: 4 spaces (no tabs) +- **Naming**: PascalCase (types), camelCase (variables/functions) +- **Extensions**: `TypeName+Feature.swift` +- **Property order**: @Published/@Injected β†’ public β†’ private β†’ computed β†’ init β†’ methods +- **Avoid nested types** - Extract to top-level with descriptive names +- **Enum exhaustiveness** - Use explicit switch statements (enables compiler warnings) + +## πŸ“š Complete Documentation + +**Full Guide**: `Anytype/Sources/IOS_DEVELOPMENT_GUIDE.md` + +For comprehensive coverage of: +- Detailed formatting rules +- Swift best practices (guard, @MainActor, async/await) +- Architecture patterns (MVVM, Coordinator, Repository) +- Property organization +- Common mistakes from past incidents +- Testing & mock management +- Complete code examples + +## 🚨 Common Mistakes (Historical) + +### Autonomous Committing (2025-01-28) +**NEVER commit without explicit user request** - Committing is destructive + +### Wildcard File Deletion (2025-01-24) +Used `rm -f .../PublishingPreview*.swift` - deleted main UI component +- Always check with `ls` first +- Delete files individually + +### Incomplete Mock Updates (2025-01-16) +Refactored dependencies but forgot `MockView.swift` +- Search: `rg "oldName" --type swift` +- Update: tests, mocks, DI registrations + +## πŸ”— Related Skills & Docs + +- **localization-developer** β†’ `LOCALIZATION_GUIDE.md` - Localization system +- **code-generation-developer** β†’ `CODE_GENERATION_GUIDE.md` - Feature flags, make generate +- **design-system-developer** β†’ `DESIGN_SYSTEM_MAPPING.md` - Icons, typography + +--- + +**Navigation**: This is a smart router. For deep technical details, always refer to `IOS_DEVELOPMENT_GUIDE.md`. diff --git a/.claude/skills/localization-developer/SKILL.md b/.claude/skills/localization-developer/SKILL.md new file mode 100644 index 0000000000..edc0985d23 --- /dev/null +++ b/.claude/skills/localization-developer/SKILL.md @@ -0,0 +1,178 @@ +# Localization Developer (Smart Router) + +## Purpose +Context-aware routing to the Anytype iOS localization system. Helps you navigate the 3-file .xcstrings structure and use Loc constants correctly. + +## When Auto-Activated +- Working with `.xcstrings` files +- Using `Loc` constants +- Discussing hardcoded strings or user-facing text +- Keywords: localization, strings, text, Loc., .xcstrings + +## 🚨 CRITICAL RULES (NEVER VIOLATE) + +1. **NEVER use hardcoded strings in UI** - Always use `Loc` constants +2. **NEVER create duplicate keys** across the 3 .xcstrings files - Breaks code generation +3. **NEVER edit non-English translations** - Only update English (`en`), Crowdin handles others +4. **ALWAYS search for existing keys first** - Reuse before creating new +5. **ALWAYS run `make generate`** after editing .xcstrings files + +## πŸ“‹ Quick Workflow + +1. **Search existing**: `rg "yourSearchTerm" Modules/Loc/Sources/Loc/Generated/Strings.swift` +2. **If found**: Reuse existing key +3. **If not found**: Add to appropriate .xcstrings file (see decision tree below) +4. **Generate**: `make generate` +5. **Use**: `AnytypeText(Loc.yourKey, style: .uxCalloutMedium)` + +## πŸ—‚οΈ The 3-File System + +### Decision Tree + +``` +Is this text for authentication/login/vault? + YES β†’ Auth.xcstrings (86 keys) + NO β†’ Continue + +Is this text for spaces/objects/collaboration? + YES β†’ Workspace.xcstrings (493 keys) + NO β†’ Continue + +Is this text for settings/widgets/general UI? + YES β†’ UI.xcstrings (667 keys) +``` + +### File Locations + +- **Auth.xcstrings**: `Modules/Loc/Sources/Loc/Resources/Auth.xcstrings` +- **Workspace.xcstrings**: `Modules/Loc/Sources/Loc/Resources/Workspace.xcstrings` +- **UI.xcstrings**: `Modules/Loc/Sources/Loc/Resources/UI.xcstrings` + +**Generated output**: All 3 files β†’ single `Strings.swift` (~5,000 lines, 1,246 total keys) + +## 🎯 Adding Keys + +### Format (add to appropriate .xcstrings file) + +```json +"Your localization key" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Your English text here" + } + } + } +} +``` + +**Key naming**: +- Short keys: `"No properties yet"` βœ… +- Not full sentences: `"No properties yet. Add some."` ❌ +- Hierarchical: `"QR.join.title"` β†’ `Loc.Qr.Join.title` + +## πŸ”’ Dynamic Localization (Parameters) + +### βœ… CORRECT - Use generated functions + +```swift +// String: "You've reached the limit of %lld editors" +Loc.SpaceLimit.Editors.title(4) + +// String: "Welcome, %@!" +Loc.welcomeMessage("John") +``` + +### ❌ WRONG - Never use String(format:) + +```swift +String(format: Loc.limitReached, 10) // DON'T DO THIS +``` + +**Why**: SwiftGen auto-generates parameterized functions for format specifiers (%lld, %d, %@). + +**Format specifiers**: +- `%lld` β†’ Int parameter +- `%d` β†’ Int parameter +- `%@` β†’ String parameter +- `%.1f` β†’ Double parameter + +## πŸ—‘οΈ Removing Unused Keys + +1. **Search**: `rg "keyName" --type swift` +2. **If only in Strings.swift**: Key is orphaned +3. **Remove** from source .xcstrings file +4. **Generate**: `make generate` + +## ⚠️ Common Mistakes + +### Hardcoded Strings +```swift +// ❌ WRONG +Text("Delete") + +// βœ… CORRECT +Text(Loc.delete) +``` + +### Duplicate Keys Across Files +```json +// In Auth.xcstrings +"Settings" : { ... } + +// In UI.xcstrings +"Settings" : { ... } // ❌ DUPLICATE! Breaks generation +``` + +### Using String(format:) +```swift +// ❌ WRONG +String(format: Loc.limitReached, 10) + +// βœ… CORRECT +Loc.limitReached(10) +``` + +### Editing Non-English +```json +// ❌ WRONG - Crowdin will overwrite +"de" : { "value" : "Meine Übersetzung" } + +// βœ… CORRECT - Only edit English +"en" : { "value" : "My translation" } +``` + +## πŸ“š Complete Documentation + +**Full Guide**: `Anytype/Sources/PresentationLayer/Common/LOCALIZATION_GUIDE.md` + +For comprehensive coverage of: +- Detailed 3-file system explanation +- Key naming patterns and conventions +- Dynamic localization with all format specifiers +- Translation workflow with Crowdin +- Removing orphaned keys +- Generated file structure +- Complete examples and troubleshooting + +## βœ… Workflow Checklist + +- [ ] Searched for existing keys (`rg` in Strings.swift) +- [ ] Added to correct .xcstrings file (Auth/Workspace/UI) +- [ ] No duplicate keys across files +- [ ] Only updated English (`en`) +- [ ] Ran `make generate` +- [ ] Used generated key: `Loc.yourKey` +- [ ] No hardcoded strings in UI + +## πŸ”— Related Skills & Docs + +- **ios-dev-guidelines** β†’ `IOS_DEVELOPMENT_GUIDE.md` - Never use hardcoded strings +- **code-generation-developer** β†’ `CODE_GENERATION_GUIDE.md` - Understanding make generate +- **design-system-developer** β†’ Using Loc constants in UI components + +--- + +**Navigation**: This is a smart router. For deep details, always refer to `LOCALIZATION_GUIDE.md`. diff --git a/.claude/skills/skills-manager/SKILL.md b/.claude/skills/skills-manager/SKILL.md new file mode 100644 index 0000000000..ae1ed3b7d2 --- /dev/null +++ b/.claude/skills/skills-manager/SKILL.md @@ -0,0 +1,243 @@ +# Skills Manager (Smart Router) + +## Purpose +Context-aware routing to skills and hooks management. Helps you troubleshoot, fine-tune, and manage the automated documentation system. + +## When Auto-Activated +- Discussing skills activation or hooks +- Keywords: skill activation, hook, troubleshoot, fine-tune, keyword, skill-rules.json +- Debugging why a skill didn't activate or activated incorrectly + +## 🚨 CRITICAL RULES + +1. **Logs are your friend** - Always check `.claude/logs/skill-activations.log` first +2. **Test after changes** - Always verify modifications to `skill-rules.json` work +3. **Validate JSON** - Use `jq` to validate skill-rules.json before committing +4. **Keywords should be specific** - Too-broad keywords cause false positives + +## πŸ“‹ Quick Diagnostic Workflow + +### Problem: Skill Didn't Activate + +1. **Check logs**: + ```bash + tail -20 .claude/logs/skill-activations.log + ``` + +2. **Check current keywords**: + ```bash + cat .claude/hooks/skill-rules.json | jq '.skills."SKILL-NAME".promptTriggers.keywords' + ``` + +3. **Add missing keyword**: + - Ask Claude: "Add 'KEYWORD' to SKILL-NAME" + - Or edit `.claude/hooks/skill-rules.json` directly + +4. **Test**: + ```bash + echo '{"prompt":"test prompt"}' | .claude/hooks/skill-activation-prompt.sh + ``` + +### Problem: Skill Activated When Shouldn't + +1. **Identify the trigger** - Check logs to see which keyword matched + +2. **Remove or make more specific**: + - Remove: "Remove 'text' from localization-developer" + - Make specific: Replace "text" with "localized text" + +3. **Verify**: + ```bash + tail .claude/logs/skill-activations.log + ``` + +## 🎯 Common Tasks + +### Add a Keyword + +**Quick**: Ask Claude +``` +"Add 'refactoring' to ios-dev-guidelines keywords" +``` + +**Manual**: Edit `.claude/hooks/skill-rules.json` +```json +"keywords": [ + "swift", + "refactoring" // ← Add here +] +``` + +### Remove a Keyword + +**Quick**: Ask Claude +``` +"Remove 'text' from localization-developer, it's too broad" +``` + +**Manual**: Edit and remove from keywords array + +### Check What Activated + +```bash +tail -20 .claude/logs/skill-activations.log +``` + +Look for: +``` +βœ“ Matched: skill-name # ← This skill activated +No matches found # ← Nothing activated +``` + +### Test Activation Manually + +```bash +echo '{"prompt":"add feature flag"}' | .claude/hooks/skill-activation-prompt.sh +``` + +Should output skill suggestion if match found. + +## πŸ”§ The System Components + +### Hooks (Automation) + +**Location**: `.claude/hooks/` + +**What they do**: +- `skill-activation-prompt.sh` - Suggests skills based on your prompt +- `post-tool-use-tracker.sh` - Tracks file edits +- `swiftformat-auto.sh` - Auto-formats Swift files + +### Skills (Routers) + +**Location**: `.claude/skills/*/SKILL.md` + +**The 5 skills**: +1. `ios-dev-guidelines` - Swift/iOS patterns +2. `localization-developer` - Localization +3. `code-generation-developer` - Feature flags, make generate +4. `design-system-developer` - Icons, typography, colors +5. `skills-manager` - This skill (meta!) + +### Configuration + +**Location**: `.claude/hooks/skill-rules.json` + +**What it contains**: +- Keywords for each skill +- Intent patterns (regex) +- File path patterns +- Priority settings + +## πŸ“Š Configuration Structure + +```json +{ + "skills": { + "skill-name": { + "type": "domain", + "priority": "high", // or "medium", "low" + "description": "Smart router to...", + "promptTriggers": { + "keywords": ["keyword1", "keyword2"], + "intentPatterns": ["(create|add).*?something"] + }, + "fileTriggers": { + "pathPatterns": ["**/*.swift"], + "contentPatterns": ["SomePattern"] + } + } + }, + "config": { + "maxSkillsPerPrompt": 2, + "logActivations": true + } +} +``` + +## ⚠️ Common Issues + +### Hook Not Executing + +**Symptom**: No activation messages, empty logs + +**Fix**: +```bash +# Make hooks executable +chmod +x .claude/hooks/*.sh + +# Verify +ls -l .claude/hooks/*.sh # Should show rwx +``` + +### Invalid JSON + +**Symptom**: Hook fails silently + +**Fix**: +```bash +# Validate +jq . .claude/hooks/skill-rules.json + +# If error, ask Claude to fix it +``` + +### Too Many False Positives + +**Symptom**: Skill activates too often + +**Fix**: Make keywords more specific +- ❌ "text" β†’ activates for everything +- βœ… "localized text" β†’ more specific + +## πŸ“š Complete Documentation + +**Full Guide**: `.claude/SKILLS_MANAGEMENT_GUIDE.md` + +For comprehensive coverage of: +- Detailed troubleshooting workflows +- Advanced regex patterns for intent matching +- Creating new skills from scratch +- Monitoring and maintenance +- Log rotation and cleanup +- Complete skill-rules.json reference +- Examples for every scenario + +## βœ… Health Check Commands + +```bash +# Check hook permissions +ls -l .claude/hooks/*.sh + +# Validate configuration +jq . .claude/hooks/skill-rules.json + +# View recent activations +tail -20 .claude/logs/skill-activations.log + +# Count activations by skill +grep "Matched:" .claude/logs/skill-activations.log | sort | uniq -c + +# Test specific prompt +echo '{"prompt":"your test"}' | .claude/hooks/skill-activation-prompt.sh +``` + +## πŸ’‘ Pro Tips + +1. **Ask Claude to check logs** - "Check the logs for my last prompt" +2. **Use logs for tuning** - Review regularly to spot patterns +3. **Start broad** - Add broad keywords, narrow if too many false positives +4. **Test everything** - Always test after modifying skill-rules.json +5. **Document changes** - Add comments in skill-rules.json + +## πŸ”— Related Docs + +- `.claude/hooks/README.md` - Complete hooks documentation +- `.claude/skills/README.md` - Skills system overview +- `CLAUDE.md` - Main documentation + +--- + +**Navigation**: This is a smart router. For deep troubleshooting and management details, always refer to `SKILLS_MANAGEMENT_GUIDE.md`. + +**Quick help**: Just ask "Check skills system health" or "Why didn't X skill activate?" diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index be636d0faf..d7d9fc7a52 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -31,10 +31,24 @@ jobs: with: fetch-depth: 1 - - name: Load review prompt + - name: Load review skill and CI automation id: load-prompt run: | - PROMPT_CONTENT=$(cat .github/workflows/claude-code-review-prompt.md) + # Load the code-review-developer skill (routes to general standards) + SKILL_CONTENT=$(cat .claude/skills/code-review-developer/SKILL.md) + + # Load CI-specific automation instructions + CI_AUTOMATION=$(cat .github/workflows/pr-review-automation.md) + + # Combine both for the prompt + PROMPT_CONTENT="${SKILL_CONTENT} + + --- + + # CI/PR-Specific Instructions + + ${CI_AUTOMATION}" + echo "prompt_content<> $GITHUB_OUTPUT echo "$PROMPT_CONTENT" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT diff --git a/.github/workflows/claude-code-review-prompt.md b/.github/workflows/pr-review-automation.md similarity index 100% rename from .github/workflows/claude-code-review-prompt.md rename to .github/workflows/pr-review-automation.md diff --git a/Anytype/Sources/IOS_DEVELOPMENT_GUIDE.md b/Anytype/Sources/IOS_DEVELOPMENT_GUIDE.md new file mode 100644 index 0000000000..b1bf0c7cae --- /dev/null +++ b/Anytype/Sources/IOS_DEVELOPMENT_GUIDE.md @@ -0,0 +1,550 @@ +# iOS Development Guide + +Complete guide to iOS development patterns, architecture, and best practices for the Anytype iOS app. + +*Last updated: 2025-01-30* + +## Overview + +The Anytype iOS app is built with Swift and SwiftUI, following MVVM architecture with Coordinator pattern for navigation. This guide covers the patterns, code style, and best practices used throughout the project. + +## ⚠️ CRITICAL RULES + +1. **NEVER trim whitespace-only lines** - Preserve blank lines with spaces/tabs exactly as they appear +2. **NEVER edit generated files** - Files marked with `// Generated using Sourcery/SwiftGen` +3. **NEVER use hardcoded strings** - Always use localization constants (`Loc.*`) +4. **ALWAYS update tests and mocks** - When refactoring, update all references +5. **Use feature flags for new features** - Wrap experimental code for safe rollouts +6. **Follow MVVM pattern** - ViewModels handle business logic, Views are lightweight + +## πŸ—οΈ Architecture + +### Technologies + +- **Swift & SwiftUI** - Primary language and UI framework +- **Combine** - Reactive programming +- **Factory** - Dependency injection +- **Middleware** - Custom binary framework for core functionality +- **Protobuf** - Middleware communication + +### Project Structure + +``` +Anytype/Sources/ +β”œβ”€β”€ ApplicationLayer/ # App lifecycle, coordinators +β”œβ”€β”€ PresentationLayer/ # UI components, ViewModels +β”œβ”€β”€ ServiceLayer/ # Business logic, data services +β”œβ”€β”€ Models/ # Data models, entities +β”œβ”€β”€ CoreLayer/ # Core utilities, networking +└── DesignSystem/ # Reusable UI components + +Modules/ # Swift packages +β”œβ”€β”€ Services/ # Core services +β”œβ”€β”€ AnytypeCore/ # Core utilities +β”œβ”€β”€ ProtobufMessages/ # Generated protobuf code +β”œβ”€β”€ Loc/ # Localization +└── Assets/ # Design assets +``` + +### Key Architectural Patterns + +#### 1. MVVM (Model-View-ViewModel) + +**View** (SwiftUI): +```swift +struct ChatView: View { + @StateObject private var model: ChatViewModel + + var body: some View { + // UI only, no business logic + } +} +``` + +**ViewModel**: +```swift +@MainActor +final class ChatViewModel: ObservableObject { + @Published var messages: [Message] = [] + @Injected(\.chatService) private var chatService + + func sendMessage(_ text: String) async { + // Business logic here + } +} +``` + +#### 2. Coordinator Pattern + +Coordinators handle navigation: + +```swift +@MainActor +final class ChatCoordinator: ObservableObject { + @Published var route: Route? + + enum Route { + case settings + case memberList + } + + func showSettings() { + route = .settings + } +} +``` + +#### 3. Repository Pattern + +Data access abstracted through services: + +```swift +protocol ChatRepository { + func fetchMessages() async throws -> [Message] + func sendMessage(_ message: Message) async throws +} + +final class ChatRepositoryImpl: ChatRepository { + // Implementation +} +``` + +#### 4. Dependency Injection (Factory) + +```swift +extension Container { + var chatService: Factory { + Factory(self) { ChatService() } + } +} + +// Usage in ViewModel +@Injected(\.chatService) private var chatService +``` + +## πŸ”§ Code Style + +### Formatting + +- **Indentation**: 4 spaces (no tabs) +- **Bracket style**: K&R (opening bracket on same line) +- **Line length**: 120-140 characters +- **Blank lines**: One between functions, two between sections +- **Whitespace-only lines**: NEVER trim - preserve exactly as is + +```swift +// βœ… CORRECT +class ChatViewModel { + @Published var messages: [Message] = [] + // ← Preserve blank line with spaces + func sendMessage() { + // Implementation + } +} + +// ❌ WRONG +class ChatViewModel { + @Published var messages: [Message] = [] +// ← Trimmed whitespace - breaks formatting consistency + func sendMessage() { +``` + +### Naming Conventions + +| Type | Convention | Example | +|------|------------|---------| +| Classes, Structs, Protocols | PascalCase | `ChatViewModel`, `UserService` | +| Variables, Functions | camelCase | `objectDetails`, `updateRows()` | +| Extensions | `TypeName+Feature.swift` | `ChatView+Actions.swift` | +| Protocols | Often suffixed with `Protocol` | `ChatServiceProtocol` | + +### Import Order + +```swift +// System frameworks +import Foundation +import SwiftUI +import Combine + +// Third-party +import Factory + +// Internal +import AnytypeCore +import Services +``` + +### Property Organization + +```swift +class ViewModel: ObservableObject { + // 1. Property wrappers + @Published var data: [Item] = [] + @Injected(\.service) private var service + + // 2. Public properties + let title: String + + // 3. Private properties + private var cancellables = Set() + + // 4. Constants + private let maxItems = 100 + + // 5. Computed properties + var isEmpty: Bool { data.isEmpty } + + // 6. Init + init(title: String) { + self.title = title + } + + // 7. Public methods + func loadData() async { } + + // 8. Private methods + private func processData() { } +} +``` + +## 🎯 Swift Best Practices + +### Use Guard for Early Returns + +```swift +// βœ… CORRECT +func processUser(_ user: User?) { + guard let user else { return } + // Continue with user +} + +// ❌ WRONG +func processUser(_ user: User?) { + if let user = user { + // Deep nesting + } +} +``` + +### Use @MainActor for UI Classes + +```swift +// βœ… CORRECT - Ensures UI updates on main thread +@MainActor +final class ChatViewModel: ObservableObject { + @Published var messages: [Message] = [] +} + +// ❌ WRONG - Can cause UI threading issues +final class ChatViewModel: ObservableObject { + @Published var messages: [Message] = [] +} +``` + +### Async/Await over Completion Handlers + +```swift +// βœ… CORRECT - Modern async/await +func fetchData() async throws -> [Item] { + try await service.fetch() +} + +// ❌ WRONG - Old completion handler style +func fetchData(completion: @escaping (Result<[Item], Error>) -> Void) { + service.fetch(completion: completion) +} +``` + +### Avoid Nested Types + +```swift +// ❌ WRONG - Nested type +struct ChatView: View { + enum MessageType { // Nested in View + case text, image + } +} + +// βœ… CORRECT - Top-level with descriptive name +enum ChatMessageType { + case text, image +} + +struct ChatView: View { + // Use ChatMessageType +} +``` + +### Enum Exhaustiveness + +Always use explicit switch statements to enable compiler warnings when new cases are added: + +```swift +// βœ… CORRECT - Compiler warns if new case added +var showManageButton: Bool { + switch self { + case .sharedSpaces: + return true + case .editors: + return false + } +} + +// ❌ WRONG - Default fallback prevents warnings +var showManageButton: Bool { + if case .sharedSpaces = self { return true } + return false // Won't warn about new cases +} +``` + +**Exception**: Only use default fallback for super obvious single-case checks: +```swift +var isSharedSpaces: Bool { + if case .sharedSpaces = self { return true } + return false +} +``` + +### SwiftUI Property Wrappers + +Use appropriate property wrappers: + +```swift +// State management +@State private var isLoading = false // Local view state +@StateObject private var model = ViewModel() // Own the ViewModel +@ObservedObject var model: ViewModel // Passed from parent + +// Published (in ObservableObject) +@Published var data: [Item] = [] + +// Dependency injection +@Injected(\.service) private var service + +// Environment +@Environment(\.dismiss) private var dismiss +``` + +### Trailing Closures + +```swift +// βœ… CORRECT +Button("Submit") { + submit() +} + +// ❌ WRONG - Unnecessary parentheses +Button("Submit", action: { + submit() +}) +``` + +### Type Inference + +```swift +// βœ… CORRECT - Infer when obvious +let items = [1, 2, 3] +let name = "Chat" + +// βœ… CORRECT - Explicit when needed +let items: [Item] = fetchItems() +let callback: (String) -> Void = handle +``` + +## πŸ§ͺ Testing & Mocks + +### Always Update Tests When Refactoring + +When renaming properties or dependencies: + +**1. Search for all references**: +```bash +rg "oldName" --type swift +``` + +**2. Update all locations**: +- Unit tests: `AnyTypeTests/` +- Preview mocks: `Anytype/Sources/PreviewMocks/` +- Mock implementations: `Anytype/Sources/PreviewMocks/Mocks/` +- DI registrations: `MockView.swift`, test setup files + +**Common mistake** (2025-01-16): Refactored `spaceViewStorage` β†’ `spaceViewsStorage` in production code but forgot to update `MockView.swift`, causing test failures. + +### Mock Generation + +Use Sourcery for automatic mock generation: + +```swift +// sourcery: AutoMockable +protocol ChatService { + func fetchMessages() async throws -> [Message] +} + +// After make generate: +// ChatServiceMock automatically created +``` + +## πŸ—‘οΈ Code Cleanup + +### Remove Unused Code + +After refactoring, always delete: +- Unused properties +- Unused functions +- Entire files that are no longer referenced + +**Example**: If removing a feature, delete: +1. ViewModel file +2. View file +3. Service implementation +4. Tests +5. Mocks +6. Localization keys (see LOCALIZATION_GUIDE.md) + +### Search Before Deleting + +```bash +# Check if type is still used +rg "MyOldViewModel" --type swift + +# Check if file is imported +rg "import MyOldModule" --type swift +``` + +## 🚨 Common Mistakes to Avoid + +### ❌ Autonomous Committing (2025-01-28) + +**NEVER commit without explicit user request**. Committing is destructive and should only happen when user approves. + +### ❌ Wildcard File Deletion (2025-01-24) + +```bash +# WRONG - Used wildcard +rm -f .../PublishingPreview*.swift # Accidentally deleted main UI component + +# CORRECT - Check first, delete individually +ls .../PublishingPreview*.swift # Verify what will be deleted +rm .../PublishingPreviewViewModel.swift # Delete specific file +``` + +### ❌ Incomplete Mock Updates (2025-01-16) + +Refactored production code but forgot to update `MockView.swift`. Always search for ALL references: + +```bash +rg "spaceViewStorage" --type swift # Find all uses +# Update all: production, tests, mocks, DI +``` + +### ❌ Trimming Whitespace-Only Lines + +This breaks formatting consistency. NEVER trim blank lines that contain spaces/tabs. + +### ❌ Hardcoded Strings + +```swift +// WRONG +Text("Add Member") + +// CORRECT +Text(Loc.addMember) +``` + +### ❌ Editing Generated Files + +```swift +// File: Generated/FeatureFlags.swift +// ❌ Don't edit this file - changes will be overwritten +``` + +## πŸ“š Integration with Other Guides + +- **Localization**: See `LOCALIZATION_GUIDE.md` for using `Loc.*` constants +- **Code Generation**: See `CODE_GENERATION_GUIDE.md` for feature flags and `make generate` +- **Design System**: See `DESIGN_SYSTEM_MAPPING.md` for icons, typography, colors + +## πŸ’‘ Best Practices Summary + +### Code Organization + +βœ… **DO**: +- Use MVVM pattern (View β†’ ViewModel β†’ Service β†’ Repository) +- Inject dependencies with `@Injected` +- Mark UI classes with `@MainActor` +- Use async/await for asynchronous code +- Use `guard` for early returns +- Organize properties: wrappers β†’ public β†’ private β†’ computed β†’ init β†’ methods + +❌ **DON'T**: +- Put business logic in Views +- Use nested types (extract to top-level) +- Use completion handlers (use async/await) +- Trim whitespace-only lines +- Hardcode strings (use Loc.*) + +### Testing + +βœ… **DO**: +- Update tests when refactoring +- Use Sourcery for mock generation +- Search for all references before renaming + +❌ **DON'T**: +- Forget to update mocks +- Skip test updates during refactoring + +### File Management + +βœ… **DO**: +- Use descriptive file names +- Follow extension naming: `Type+Feature.swift` +- Delete unused files +- Search before deleting + +❌ **DON'T**: +- Use wildcard deletion +- Leave orphaned files +- Keep unused code "just in case" + +## πŸ“– Quick Reference + +**Create ViewModel**: +```swift +@MainActor +final class FeatureViewModel: ObservableObject { + @Published var data: [Item] = [] + @Injected(\.service) private var service + + func loadData() async throws { + data = try await service.fetch() + } +} +``` + +**Create Coordinator**: +```swift +@MainActor +final class FeatureCoordinator: ObservableObject { + @Published var route: Route? + + enum Route { case detail, settings } +} +``` + +**Dependency Injection**: +```swift +// Register in Container +extension Container { + var myService: Factory { + Factory(self) { MyService() } + } +} + +// Use in ViewModel +@Injected(\.myService) private var service +``` + +--- + +*This guide is the single source of truth for iOS development patterns. For quick reference, see CLAUDE.md.* \ No newline at end of file diff --git a/Anytype/Sources/PresentationLayer/Common/LOCALIZATION_GUIDE.md b/Anytype/Sources/PresentationLayer/Common/LOCALIZATION_GUIDE.md new file mode 100644 index 0000000000..c6cd73b81a --- /dev/null +++ b/Anytype/Sources/PresentationLayer/Common/LOCALIZATION_GUIDE.md @@ -0,0 +1,313 @@ +# Localization System Guide + +Complete guide to the Anytype iOS localization system using SwiftGen and .xcstrings files. + +*Last updated: 2025-01-30* + +## Overview + +The Anytype iOS app uses a 3-file localization system with SwiftGen code generation: +- **Auth.xcstrings** (86 keys): Authentication, login/join flows, keychain, vault, onboarding, migration +- **Workspace.xcstrings** (493 keys): Spaces, objects, relations, collections, sets, types, templates, collaboration +- **UI.xcstrings** (667 keys): Settings, widgets, alerts, common UI elements, general app strings + +All three files generate into a single `Strings.swift` file (~5,000 lines) with type-safe constants. + +## ⚠️ CRITICAL RULES + +1. **NEVER use hardcoded strings in UI** - Always use localization constants +2. **Keys must be unique across ALL three .xcstrings files** - Duplicate keys break code generation +3. **Only update English (`en`) translations** - All other languages handled by Crowdin +4. **Always run `make generate` after changes** - Regenerates Strings.swift constants + +## πŸ“‹ Quick Workflow + +### 1. Search Existing Keys First + +```bash +rg "yourSearchTerm" Modules/Loc/Sources/Loc/Generated/Strings.swift +``` + +**Use existing patterns**: +- Block titles: `[feature]BlockTitle` +- Block subtitles: `[feature]BlockSubtitle` +- Common words: `camera`, `photo`, `picture`, `video(1)` + +### 2. Choose the Right .xcstrings File + +| File | Count | Use For | +|------|-------|---------| +| **Auth.xcstrings** | 86 keys | Authentication, login/join flows, keychain, vault, onboarding, migration | +| **Workspace.xcstrings** | 493 keys | Spaces, objects, relations, collections, sets, types, templates, collaboration | +| **UI.xcstrings** | 667 keys | Settings, widgets, alerts, common UI elements, general app strings | + +### 3. Add Key (If Doesn't Exist) + +**Location**: `Modules/Loc/Sources/Loc/Resources/[File].xcstrings` + +**Format**: +```json +"Your localization key" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Your English text here" + } + } + } +} +``` + +**⚠️ IMPORTANT**: Only edit the `"en"` (English) translation. Do not manually edit translations for other languages (de, es, fr, ja, etc.) - the localization team manages non-English translations through Crowdin workflow. + +### 4. Generate Constants + +```bash +make generate +``` + +This runs SwiftGen to generate type-safe constants in `Modules/Loc/Sources/Loc/Generated/Strings.swift`. + +### 5. Use in Code + +```swift +import Loc + +// Simple text +AnytypeText(Loc.yourLocalizationKey, style: .uxCalloutMedium) + +// Or with Text +Text(Loc.yourLocalizationKey) + .anytypeStyle(.bodyRegular) +``` + +## πŸ”€ Key Naming Patterns + +### Short, Descriptive Keys + +βœ… **CORRECT**: `"No properties yet"` +❌ **WRONG**: `"No properties yet. Add some to this type."` + +**Why**: Keys should be concise. Full sentences belong in the value, not the key name. + +### Hierarchical Organization + +Use dots for organization. SwiftGen creates nested enums: + +**Input** (in .xcstrings): +```json +"QR.join.title": { "en": "Join with QR" } +"QR.join.subtitle": { "en": "Scan code to join" } +``` + +**Generated** (in Strings.swift): +```swift +enum Loc { + enum Qr { + enum Join { + static let title = "Join with QR" + static let subtitle = "Scan code to join" + } + } +} +``` + +**Usage**: +```swift +Text(Loc.Qr.Join.title) +Text(Loc.Qr.Join.subtitle) +``` + +## πŸ”§ Dynamic Localization (with Parameters) + +For strings with format specifiers (%lld, %d, %@), SwiftGen automatically generates functions with parameters. + +### Format Specifiers + +| Specifier | Type | Example | +|-----------|------|---------| +| `%lld` | Integer (long long) | "You've reached the limit of %lld editors" | +| `%d` | Integer | "Pin limit reached: %d pinned spaces" | +| `%@` | String | "Hello %@" | +| `%f` | Float/Double | "Progress: %.2f%%" | + +### Example + +**Input** (Workspace.xcstrings): +```json +"You've reached the limit of %lld editors": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "You've reached the limit of %lld editors" + } + } + } +} +``` + +**Generated** (Strings.swift): +```swift +static func youVeReachedTheLimitOfEditors(_ value: Int) -> String { + return String(format: "You've reached the limit of %lld editors", value) +} +``` + +**Usage**: + +βœ… **CORRECT** - Use generated function: +```swift +Text(Loc.youVeReachedTheLimitOfEditors(4)) +``` + +❌ **WRONG** - Don't use String(format:): +```swift +String(format: Loc.youVeReachedTheLimitOfEditors, 4) // Compile error! +``` + +**Why**: SwiftGen generates type-safe functions. Always use the generated function directly. + +## πŸ—‘οΈ Removing Unused Localization Keys + +When removing code that uses localization keys, clean up the .xcstrings files: + +### Workflow + +**1. Search for usage**: +```bash +rg "keyName" --type swift +``` + +**2. If only found in Generated/Strings.swift**, the key is unused: +- Remove the entire key entry from the source `.xcstrings` file +- Run `make generate` to regenerate Strings.swift + +**3. Example**: +- Removed `MembershipParticipantUpgradeReason.numberOfSpaceReaders` from code +- Search: `rg "noMoreMembers" --type swift` β†’ only in Strings.swift +- Remove `"Membership.Upgrade.NoMoreMembers"` from Workspace.xcstrings +- Run `make generate` + +**Important**: Never leave orphaned localization keys in .xcstrings files - they bloat the codebase and confuse translators. + +## πŸ“ File Locations + +- **Source .xcstrings files**: `Modules/Loc/Sources/Loc/Resources/` + - Auth.xcstrings + - Workspace.xcstrings + - UI.xcstrings +- **Generated constants**: `Modules/Loc/Sources/Loc/Generated/Strings.swift` +- **SwiftGen config**: `Modules/Loc/swiftgen.yml` + +## πŸŽ“ Common Mistakes + +### ❌ Using String(format:) + +```swift +// WRONG +String(format: Loc.someKey, value) + +// CORRECT +Loc.someKey(value) +``` + +### ❌ Hardcoded Strings + +```swift +// WRONG +Text("Add Member") + +// CORRECT +Text(Loc.addMember) +``` + +### ❌ Duplicate Keys Across Files + +```swift +// If "Settings.Title" exists in both UI.xcstrings and Workspace.xcstrings +// β†’ make generate will fail +``` + +**Solution**: Keys must be globally unique across all 3 files. + +### ❌ Forgetting to Generate + +```bash +# After adding key to .xcstrings +# WRONG: Try to use immediately +Text(Loc.myNewKey) // Error: unresolved identifier + +# CORRECT: Generate first +make generate +Text(Loc.myNewKey) // Success! +``` + +### ❌ Editing Non-English Translations + +```json +// WRONG - Don't edit other languages +"localizations": { + "en": { ... }, + "de": { "value": "Meine Übersetzung" } // Don't do this! +} + +// CORRECT - Only edit English +"localizations": { + "en": { "value": "My translation" } + // Crowdin handles other languages +} +``` + +## πŸ” Troubleshooting + +### Issue: Key not generating + +**Symptom**: Added key to .xcstrings but `Loc.myKey` doesn't exist + +**Solution**: +1. Check JSON syntax is valid: `jq . Modules/Loc/Sources/Loc/Resources/UI.xcstrings` +2. Verify key doesn't exist in other files (duplicate keys break generation) +3. Run `make generate` +4. Check for errors in generation output + +### Issue: Duplicate key error + +**Symptom**: `make generate` fails with duplicate key error + +**Solution**: +```bash +# Find duplicates across all files +rg "\"My Key\"" Modules/Loc/Sources/Loc/Resources/*.xcstrings + +# Should appear only once total across all 3 files +``` + +### Issue: Format specifier not working + +**Symptom**: `Loc.myKey(value)` doesn't exist, only `Loc.myKey` (string) + +**Solution**: Check the .xcstrings value includes format specifier: +- With `%lld` or `%d` β†’ generates function with Int parameter +- Without format specifier β†’ generates plain string constant + +## πŸ“š Additional Resources + +- **Quick Reference**: See CLAUDE.md for condensed workflow +- **Skills System**: `.claude/skills/localization-developer/` for auto-activation +- **SwiftGen Docs**: https://github.com/SwiftGen/SwiftGen + +## πŸ’‘ Best Practices + +1. **Search before adding** - Reuse existing keys when possible +2. **Use hierarchical naming** - `Feature.Section.Item` for organization +3. **Keep keys short** - Full text goes in value, not key name +4. **Clean up unused keys** - Prevents bloat and translator confusion +5. **Only edit English** - Let Crowdin handle other languages +6. **Always generate** - Run `make generate` after any .xcstrings change + +--- + +*This guide is the single source of truth for localization. For quick reference, see CLAUDE.md.* \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index 9ab0a18856..3248826525 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -39,9 +39,41 @@ make setup-middle # Initial setup ### AI Assistance - **Always present a detailed action plan before implementing multi-step changes and await approval before proceeding** +### πŸ“š Skills System & Documentation (Progressive Disclosure) + +**Level 1 - This File**: Quick start, critical rules, high-level overview +**Level 2 - Skills**: Context-aware guides that auto-activate β†’ `.claude/skills/` +**Level 3 - Specialized Docs**: Deep knowledge for specific domains + +#### Auto-Activating Skills + +The skills system provides context-aware guidance that auto-activates based on your work: +- **ios-dev-guidelines** β†’ Auto-activates when working with `.swift` files +- **localization-developer** β†’ Auto-activates for localization work +- **code-generation-developer** β†’ Auto-activates for code generation +- **design-system-developer** β†’ Auto-activates for UI/design work +- **code-review-developer** β†’ Auto-activates when reviewing PRs or code changes + +**How it works**: When you start a task, the system analyzes your prompt and file context, then automatically suggests relevant skills. No manual loading needed. + +**Learn more**: See `.claude/skills/README.md` for system overview and `.claude/hooks/README.md` for automation details. + +#### Specialized Documentation + +For deep knowledge, see these guides: + +| Topic | Quick Reference (Skills) | Complete Guide (Specialized Docs) | +|-------|-------------------------|-----------------------------------| +| **iOS Development** | `.claude/skills/ios-dev-guidelines/` | `Anytype/Sources/IOS_DEVELOPMENT_GUIDE.md` | +| **Localization** | `.claude/skills/localization-developer/` | `Anytype/Sources/PresentationLayer/Common/LOCALIZATION_GUIDE.md` | +| **Code Generation** | `.claude/skills/code-generation-developer/` | `Modules/AnytypeCore/CODE_GENERATION_GUIDE.md` | +| **Design System** | `.claude/skills/design-system-developer/` | `Anytype/Sources/PresentationLayer/Common/DESIGN_SYSTEM_MAPPING.md` | +| **Typography** | `.claude/skills/design-system-developer/` | `Anytype/Sources/PresentationLayer/Common/TYPOGRAPHY_MAPPING.md` | +| **Code Review** | `.claude/skills/code-review-developer/` | `.claude/CODE_REVIEW_GUIDE.md` | + ### Code Quality - **Never edit files marked with `// Generated using Sourcery/SwiftGen`** - These are automatically generated -- **Never use hardcoded strings in UI** - Always use localization constants +- **Never use hardcoded strings in UI** - Always use localization constants (see LOCALIZATION_GUIDE.md) - **All user-facing text must be localized** for international support - **Do not add comments** unless explicitly requested - **We only work in feature branches** - never push directly to develop/main @@ -52,228 +84,125 @@ make setup-middle # Initial setup - Mock implementations (`Anytype/Sources/PreviewMocks/Mocks/`) - Dependency injection registrations (`MockView.swift`, test setup files) -## πŸ“ Localization System +## πŸ“ Localization System (Quick Reference) + +**Full Guide**: `Anytype/Sources/PresentationLayer/Common/LOCALIZATION_GUIDE.md` ### Quick Workflow -1. **Search existing keys first**: - ```bash - rg "yourSearchTerm" Modules/Loc/Sources/Loc/Generated/Strings.swift - ``` +1. Search existing: `rg "yourSearchTerm" Modules/Loc/Sources/Loc/Generated/Strings.swift` +2. Choose file: Auth (86 keys), Workspace (493 keys), or UI (667 keys) +3. Add to appropriate `.xcstrings` file if missing +4. Run: `make generate` +5. Use: `Loc.yourKey` or `AnytypeText(Loc.yourKey, style: .uxBodyRegular)` -2. **Use existing patterns**: - - Block titles: `[feature]BlockTitle` - - Block subtitles: `[feature]BlockSubtitle` - - Common words: `camera`, `photo`, `picture`, `video(1)` - -3. **Choosing the Right File**: - Localization is split into 3 files - select based on your feature: - - **Auth.xcstrings** (86 keys): Authentication, login/join flows, keychain, vault, onboarding, migration - - **Workspace.xcstrings** (493 keys): Spaces, objects, relations, collections, sets, types, templates, collaboration - - **UI.xcstrings** (667 keys): Settings, widgets, alerts, common UI elements, general app strings - - **⚠️ CRITICAL**: Keys must be unique across ALL three files. Duplicate keys will break code generation. - -4. **Only if key doesn't exist**, add to the appropriate file in `Modules/Loc/Sources/Loc/Resources/`: - ```json - "Your localization key" : { - "extractionState" : "manual", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Your English text here" - } - } - } - } - ``` +### Critical Rules +- ❌ Never use hardcoded strings +- ❌ Never use `String(format: Loc.key, value)` β†’ βœ… Use `Loc.key(value)` +- ⚠️ Keys must be unique across ALL 3 .xcstrings files +- ⚠️ Only edit English (`en`) - Crowdin handles other languages - **⚠️ IMPORTANT**: When adding or updating localization strings: - - **Only update the English (`en`) translation** - All other language translations are handled automatically via Crowdin - - Do not manually edit translations for other languages (de, es, fr, ja, etc.) - - The localization team manages non-English translations through Crowdin workflow +## 🎨 Design System (Quick Reference) -5. **Generate and use**: - ```bash - make generate - ``` - ```swift - import Loc - AnytypeText(Loc.yourLocalizationKey, style: .uxCalloutMedium) - ``` +**Full Guides**: +- `Anytype/Sources/PresentationLayer/Common/DESIGN_SYSTEM_MAPPING.md` +- `Anytype/Sources/PresentationLayer/Common/TYPOGRAPHY_MAPPING.md` -### Key Patterns -- **Naming**: Use short, descriptive keys β†’ `"No properties yet"` βœ…, `"No properties yet. Add some to this type."` ❌ -- **Hierarchical**: Use dots for organization β†’ `"QR.join.title"` creates `Loc.Qr.Join.title` -- **Generated file**: All 3 localization files (Auth, Workspace, UI) generate into a single `Strings.swift` file (~5,000 lines). Use `rg` for searching -- **Always import**: `import Loc` when using localization +### Icons +Icons organized by size (x18, x24, x32, x40): +```swift +Image(asset: .X32.qrCode) // 32pt icon +Image(asset: .X24.search) // 24pt icon +``` -### Dynamic Localization (with Parameters) +**Adding**: Export SVG from Figma β†’ Add to Assets.xcassets β†’ `make generate` β†’ Use constant -**βœ… CORRECT** - Generated function with parameters: +### Typography +Figma styles map to Swift constants: ```swift -// For string: "You've reached the limit of %lld editors" -Loc.SpaceLimit.Editors.title(4) // Proper way - -// For string: "Pin limit reached: %d pinned spaces" -Loc.pinLimitReached(10) // Proper way +AnytypeText("Title", style: .uxTitle1Semibold) // Screen titles +AnytypeText("Body", style: .bodyRegular) // Body text ``` -**❌ WRONG** - Never use String(format:): +### Colors +Always use design system constants: ```swift -String(format: Loc.SpaceLimit.Editors.title, 4) // DON'T DO THIS -String(format: Loc.pinLimitReached, 10) // DON'T DO THIS +.foregroundColor(Color.Text.primary) +.background(Color.Shape.transperentSecondary) ``` -**Why**: SwiftGen automatically generates parameterized functions for strings with format specifiers (%lld, %d, %@). Always use the generated function directly. - -### Removing Unused Localization Keys - -When removing code that uses localization keys, **always check if the key is still used elsewhere**: - -1. **Search for usage**: - ```bash - rg "keyName" --type swift - ``` - -2. **If only found in Generated/Strings.swift**, the key is unused: - - Remove the entire key entry from the source `.xcstrings` file - - Run `make generate` to regenerate Strings.swift - -3. **Example workflow**: - - Removed `MembershipParticipantUpgradeReason.numberOfSpaceReaders` - - Search: `rg "noMoreMembers" --type swift` β†’ only in Strings.swift - - Remove `"Membership.Upgrade.NoMoreMembers"` from Workspace.xcstrings - - Run `make generate` +## πŸ”§ Code Generation (Quick Reference) -**Important**: Never leave orphaned localization keys in .xcstrings files - they bloat the codebase and confuse translators. - -## 🎨 Design System & Common UI Components - -### Quick Reference -- **Search Patterns**: `/PresentationLayer/Common/SwiftUI/Search/SEARCH_PATTERNS.md` -- **Design System Mapping**: `/PresentationLayer/Common/DESIGN_SYSTEM_MAPPING.md` -- **Typography Mapping**: `/PresentationLayer/Common/TYPOGRAPHY_MAPPING.md` - Maps Figma text styles to Swift constants -- **Analytics Patterns**: `/PresentationLayer/Common/Analytics/ANALYTICS_PATTERNS.md` -- **Code Review Guidelines**: `/.github/workflows/code-review-guidelines.md` - Shared review standards for local and automated CI reviews - -### Icons -Icons are code-generated from assets organized by size (x18, x24, x32, x40). +**Full Guide**: `Modules/AnytypeCore/CODE_GENERATION_GUIDE.md` -**Usage**: -```swift -Image(asset: .X32.qrCode) // 32pt QR code icon -Image(asset: .X24.search) // 24pt search icon +### Quick Workflow +```bash +make generate # After adding flags, assets, or localization +make generate-middle # After middleware/protobuf changes ``` -**Adding new icons**: -1. Export SVG from Figma ("32/qr code" format) -2. Add to `/Modules/Assets/.../Assets.xcassets/DesignSystem/x32/QRCode.imageset/` -3. Run `make generate` -4. Use: `Image(asset: .X32.qrCode)` - ### Feature Flags -Wrap new features in boolean toggles for safe rollouts. - -**Adding**: -1. Edit `/Modules/AnytypeCore/AnytypeCore/Utils/FeatureFlags/FeatureDescription+Flags.swift`: - ```swift - static let yourFeatureName = FeatureDescription( - title: "Your Feature Name", - type: .feature(author: "Your Name", releaseVersion: "X.X.X"), - defaultValue: false, - debugValue: true - ) - ``` - -2. Generate: `make generate` +1. Add to `/Modules/AnytypeCore/.../FeatureDescription+Flags.swift` +2. Run `make generate` +3. Use: `if FeatureFlags.yourFlag { ... }` -3. Use: - ```swift - import AnytypeCore - - if FeatureFlags.yourFeatureName { - // Your feature code - } - ``` +### Tools +- **SwiftGen**: Assets & localization β†’ type-safe constants +- **Sourcery**: Swift code from templates β†’ boilerplate reduction +- **Protobuf**: Middleware message generation -**Types**: `.debug` (debug-only), `.feature(author:releaseVersion:)` (production) +## πŸ—οΈ Architecture (High-Level) -## πŸ—οΈ Architecture +**Full Guide**: `Anytype/Sources/IOS_DEVELOPMENT_GUIDE.md` ### Technologies - **Swift & SwiftUI** - Primary language and UI framework - **Combine** - Reactive programming - **Factory** - Dependency injection -- **Middleware** - Custom binary framework for core functionality -- **Protobuf** - Middleware communication +- **Middleware** - Custom binary framework (Protobuf communication) -### Structure +### Project Structure ``` Anytype/Sources/ β”œβ”€β”€ ApplicationLayer/ # App lifecycle, coordinators β”œβ”€β”€ PresentationLayer/ # UI components, ViewModels β”œβ”€β”€ ServiceLayer/ # Business logic, data services β”œβ”€β”€ Models/ # Data models, entities -β”œβ”€β”€ CoreLayer/ # Core utilities, networking -└── DesignSystem/ # Reusable UI components +└── CoreLayer/ # Core utilities, networking Modules/ # Swift packages -β”œβ”€β”€ Services/ # Core services -β”œβ”€β”€ AnytypeCore/ # Core utilities -β”œβ”€β”€ ProtobufMessages/ # Generated protobuf code -└── ... +β”œβ”€β”€ AnytypeCore/ # Core utilities, feature flags +β”œβ”€β”€ Loc/ # Localization +β”œβ”€β”€ Assets/ # Design assets +└── Services/ # Core services ``` ### Key Patterns -- **MVVM**: ViewModels handle business logic for SwiftUI views +- **MVVM**: ViewModels handle business logic, Views are lightweight - **Coordinator**: Navigation handled by coordinators - **Repository**: Data access abstracted through services -- **Protocol-Oriented**: Heavy use of protocols for testability -- **Dependency Injection**: Factory pattern in `ServiceLayer/ServicesDI.swift` +- **Dependency Injection**: Factory pattern with `@Injected` + +## πŸ”§ Code Style (Quick Reference) -## πŸ”§ Code Style +**Full Guide**: `Anytype/Sources/IOS_DEVELOPMENT_GUIDE.md` ### Formatting - 4 spaces indentation (no tabs) - K&R style (opening brackets on same line) - 120-140 character lines -- One blank line between functions, two between sections -- **NEVER trim whitespace-only lines** - Preserve blank lines with spaces or tabs exactly as they appear in the original file +- **NEVER trim whitespace-only lines** - Preserve blank lines with spaces/tabs exactly ### Naming - **PascalCase**: Classes, Structs, Protocols (`ChatViewModel`) - **camelCase**: Variables, Functions (`objectDetails`, `updateRows()`) - **Extensions**: `TypeName+Feature.swift` -- **Protocols**: Often suffixed with `Protocol` ### Swift Best Practices -- Prefer `guard` for early returns - Use `@MainActor` for UI classes -- Import order: system β†’ third-party β†’ internal -- Property organization: @Published/@Injected β†’ public β†’ private β†’ constants β†’ variables β†’ methods -- Use async/await, SwiftUI property wrappers, trailing closures, type inference -- **Avoid nested types** - Extract enums/structs to top-level with descriptive names (e.g., `SpaceLimitBannerLimitType` instead of `SpaceLimitBannerView.LimitType`) -- **Enum exhaustiveness**: Always use explicit switch statements for enum pattern matching to enable compiler warnings when new cases are added - - βœ… **CORRECT**: - ```swift - var showManageButton: Bool { - switch self { - case .sharedSpaces: - return true - case .editors: - return false - } - } - ``` - - ❌ **WRONG**: - ```swift - var showManageButton: Bool { - if case .sharedSpaces = self { return true } - return false // Default fallback prevents compiler warnings - } - ``` - - **Exception**: Only use default fallback for super obvious single-case checks (e.g., `isSharedSpaces`, `isEditor`) +- Prefer `guard` for early returns +- Use async/await over completion handlers +- Avoid nested types (extract to top-level) +- Use explicit switch for enums (enables compiler warnings) ## πŸ”„ Development Workflow @@ -290,30 +219,15 @@ Modules/ # Swift packages **⚠️ CRITICAL: This is the FIRST thing to do when starting any task** When receiving a Linear task ID (e.g., `IOS-5292`): -1. **Identify the task branch**: The branch name follows the format `ios-XXXX-description` - - Example: `ios-5292-update-space-hub-loading-state` - - You can retrieve the branch name from Linear issue details - -2. **Switch to the task branch IMMEDIATELY** before doing ANY other work: - ```bash - git checkout ios-5292-update-space-hub-loading-state - ``` - +1. **Identify the task branch**: Format is `ios-XXXX-description` +2. **Switch to the task branch IMMEDIATELY**: `git checkout ios-5292-update-space-hub-loading-state` 3. **All work for the task must be done in this dedicated branch** - - Never work on tasks in the wrong branch - - Verify you're on the correct branch: `git branch --show-current` ### Git & GitHub - **Main branch**: `develop` - **Feature branches**: `ios-XXXX-description` - **⚠️ CRITICAL: NEVER commit without explicit user request** - - Wait for user to explicitly ask you to commit - - Do NOT commit automatically after making changes - - Do NOT assume commits are expected -- **Commit messages**: - - Single line only - - **NO AI signatures** (no "Generated with Claude", no co-author attribution) - - Professional and concise +- **Commit messages**: Single line, no AI signatures - **GitHub CLI**: Use `gh` tool for all GitHub operations - `gh pr view --repo anyproto/anytype-swift` - `gh pr diff --repo anyproto/anytype-swift` @@ -322,38 +236,21 @@ When receiving a Linear task ID (e.g., `IOS-5292`): For comprehensive documentation on GitHub workflows, actions, and automation (including auto-merge behavior), see `.github/WORKFLOWS_REFERENCE.md` ### Release Branch Workflow -- **Branches from release**: When creating a branch from a release branch (e.g., `release/0.42.0`): - - Target the **release branch** in your PR, not `develop` - - Always add the **"Release"** label to the PR - - Example: `gh pr create --base release/0.42.0 --label "Release" --title "..." --body "..."` +When creating a branch from a release branch (e.g., `release/0.42.0`): +- Target the **release branch** in your PR, not `develop` +- Always add the **"Release"** label to the PR +- Example: `gh pr create --base release/0.42.0 --label "Release" --title "..." --body "..."` ### ❌ FORBIDDEN Git Practices **ABSOLUTELY NEVER run destructive git operations** unless you have explicit, written approval: - `git reset --hard` - Discards all local changes permanently -- `git checkout ` or `git restore` to revert to older commits - Can lose work +- `git checkout ` or `git restore` to revert to older commits - `git clean -fd` - Removes untracked files permanently - `git push --force` to main/develop - Rewrites shared history **If you are even slightly unsure about a git command, STOP and ask the user first.** -**NEVER do this:** -```bash -# ❌ WRONG - Contains AI attribution -git commit -m "Fix pinned spaces limit - -Co-Authored-By: Claude " - -# ❌ WRONG - Contains AI signature -git commit -m "Add feature πŸ€– Generated with Claude Code" -``` - -**ALWAYS do this:** -```bash -# βœ… CORRECT - Clean, professional, single line -git commit -m "IOS-4852 Add limit check for pinned spaces" -``` - ### Pull Requests **Format**: ``` @@ -363,28 +260,23 @@ git commit -m "IOS-4852 Add limit check for pinned spaces" **Note**: PRs are for programmers, not testers - **NO test plan needed** -**IMPORTANT**: +**IMPORTANT**: - **NEVER add AI signatures** like "πŸ€– Generated with Claude Code" to pull requests -- **NEVER add AI signatures** to commit messages - Keep commits and PRs professional without AI attribution **Incremental Strategy** (for related changes): - Sequential branches: `ios-XXXX-description-1`, `ios-XXXX-description-2` - Chain PRs: `branch-1` β†’ `develop`, `branch-2` β†’ `branch-1` -- Atomic changes per branch ### πŸ”§ Git Technical Tips **Quoting paths with special characters**: -- Always quote git paths containing brackets, parentheses, or spaces -- Prevents shell from treating them as globs or subshells - +Always quote git paths containing brackets, parentheses, or spaces: ```bash # βœ… CORRECT git add "Anytype/Sources/[Feature]/Component.swift" -git commit -m "Update component" -- "path/with spaces/file.swift" -# ❌ WRONG - Shell interprets brackets as glob pattern +# ❌ WRONG - Shell interprets brackets as glob git add Anytype/Sources/[Feature]/Component.swift ``` @@ -394,52 +286,27 @@ git add Anytype/Sources/[Feature]/Component.swift 3. **Check PRs**: Use `gh` tool to examine related PRs 4. **Update progress**: Add comments and check off completed items -## πŸ› οΈ Code Generation - -### Tools & Locations -- **SwiftGen**: Assets, localization strings (`/Modules/*/swiftgen.yml`) -- **Sourcery**: Swift code from templates (`/Modules/*/sourcery.yml`) -- **Custom**: Protobuf splitting (`anytypeGen.yml`) - -### Important Notes -- Generated files marked with `// Generated using Sourcery/SwiftGen` -- Never edit generated files directly -- Update source templates/configurations instead -- Always run `make generate` after template changes - -## πŸ“š Common Tasks - -### Adding Features -1. Create models in `Models/` (if needed) -2. Add service logic in `ServiceLayer/` -3. Create ViewModel in `PresentationLayer/` -4. Build UI with SwiftUI -5. Add tests in `AnyTypeTests/` -6. Wrap in feature flags - -### Working with Middleware -- Pre-compiled binary framework -- Communication via Protobuf messages -- Message definitions in `Modules/ProtobufMessages/` - ## πŸ“‹ Memories & Tips - For trivial PRs, add GitHub label "🧠 No brainer" (not in title) - Use `rg` for searching large files -- Check existing keys before adding new localization - Feature flags for all new features -- **NO need to import `Loc` manually** - it's pre-imported by default in shared header +- **NO need to import `Loc` manually** - it's pre-imported by default - Import `AnytypeCore` for feature flags -### ⚠️ Common Mistakes to Avoid +## ⚠️ Common Mistakes to Avoid -#### Git Operations -**Autonomous Committing (2025-01-28):** Committed changes without explicit user request. NEVER commit unless user explicitly asks. This is a CRITICAL rule - committing is a destructive operation that should only happen when user approves. +### Git Operations +**Autonomous Committing (2025-01-28):** Committed changes without explicit user request. NEVER commit unless user explicitly asks. This is a CRITICAL rule. -#### File Operations & Architecture -**Wildcard File Deletion (2025-01-24):** Used `rm -f .../PublishingPreview*.swift` - accidentally deleted main UI component. Always check with `ls` first, remove files individually, keep UI in PresentationLayer. +### File Operations & Architecture +**Wildcard File Deletion (2025-01-24):** Used `rm -f .../PublishingPreview*.swift` - accidentally deleted main UI component. Always check with `ls` first, remove files individually. -#### Refactoring & Testing -**Incomplete Mock Updates (2025-01-16):** Refactored `spaceViewStorage` β†’ `spaceViewsStorage` and `participantSpaceStorage` β†’ `participantSpacesStorage` in production code, but forgot to update `MockView.swift` causing test failures. When renaming dependencies: -1. Search for old names across entire codebase: `rg "oldName" --type swift` +### Refactoring & Testing +**Incomplete Mock Updates (2025-01-16):** Refactored properties in production code but forgot to update `MockView.swift` causing test failures. When renaming dependencies: +1. Search for old names: `rg "oldName" --type swift` 2. Update all references in tests, mocks, and DI registrations -3. Report changes to user for compilation verification \ No newline at end of file +3. Report changes to user for compilation verification + +--- + +**Remember**: This file provides quick reference and overview. For detailed guidance, see the specialized documentation guides linked above. \ No newline at end of file diff --git a/Modules/AnytypeCore/CODE_GENERATION_GUIDE.md b/Modules/AnytypeCore/CODE_GENERATION_GUIDE.md new file mode 100644 index 0000000000..65aa2539f6 --- /dev/null +++ b/Modules/AnytypeCore/CODE_GENERATION_GUIDE.md @@ -0,0 +1,407 @@ +# Code Generation Guide + +Complete guide to code generation workflows in the Anytype iOS app: SwiftGen, Sourcery, Feature Flags, and Protobuf. + +*Last updated: 2025-01-30* + +## Overview + +The Anytype iOS app uses multiple code generation tools to reduce boilerplate and ensure type safety: + +- **SwiftGen**: Generates constants for assets (icons, colors) and localization strings +- **Sourcery**: Generates Swift code from templates based on source file annotations +- **Feature Flags**: Boolean toggles for safe feature rollouts (Sourcery-generated) +- **Protobuf**: Middleware message definitions + +## ⚠️ CRITICAL RULES + +1. **NEVER edit generated files** - Files marked with `// Generated using Sourcery/SwiftGen` are auto-generated +2. **ALWAYS run `make generate` after changes** - Updates templates, flags, assets, or localization +3. **Feature flags for all new features** - Wrap experimental features for safe rollouts +4. **Update source, not generated code** - Edit templates/configurations, then regenerate + +## πŸ“‹ Essential Commands + +```bash +make generate # Run all generators (SwiftGen, Sourcery, assets, localization) +make generate-middle # Regenerate middleware and protobuf (when dependencies change) +make setup-middle # Initial middleware setup +``` + +### When to Run `make generate` + +| You Did This | Run This | Why | +|--------------|----------|-----| +| Added/updated .xcstrings | `make generate` | Regenerate Loc constants | +| Added feature flag | `make generate` | Generate FeatureFlags enum | +| Added icon to Assets.xcassets | `make generate` | Generate Image asset constants | +| Modified Sourcery template | `make generate` | Regenerate code from templates | +| Updated middleware version | `make generate-middle` | Regenerate protobuf bindings | + +## 🚩 Feature Flags System + +Feature flags enable safe rollout of new features by wrapping them in boolean toggles. + +### Quick Workflow + +**1. Define the flag** in `/Modules/AnytypeCore/AnytypeCore/Utils/FeatureFlags/FeatureDescription+Flags.swift`: + +```swift +extension FeatureDescription { + static let newChatInterface = FeatureDescription( + title: "New Chat Interface", + type: .feature(author: "Your Name", releaseVersion: "0.42.0"), + defaultValue: false, // Off in production + debugValue: true // On in debug builds for testing + ) +} +``` + +**2. Generate**: + +```bash +make generate +``` + +This generates `Modules/AnytypeCore/AnytypeCore/Generated/FeatureFlags.swift`: + +```swift +// Generated using Sourcery +enum FeatureFlags { + static let newChatInterface: Bool = /* value based on build config */ +} +``` + +**3. Use in code**: + +```swift +import AnytypeCore + +if FeatureFlags.newChatInterface { + NewChatView() +} else { + LegacyChatView() +} +``` + +### Feature Flag Types + +```swift +// Debug-only (not available in production builds) +type: .debug + +// Production feature with metadata +type: .feature(author: "Dev Name", releaseVersion: "0.42.0") +``` + +### Best Practices + +βœ… **DO**: +- Set `defaultValue: false` for unreleased features +- Set `debugValue: true` for easier developer testing +- Include author and release version metadata +- Remove flags after feature is fully rolled out + +❌ **DON'T**: +- Deploy features without feature flags +- Forget to run `make generate` after adding flags +- Leave old flags in codebase indefinitely + +### Feature Flag Lifecycle + +**1. Development** (defaultValue: false, debugValue: true) +- Flag off in production +- Flag on in debug builds for testing + +**2. Beta** (defaultValue: false, debugValue: true) +- Still off in production +- Enable for beta testers via remote config (if available) + +**3. Rollout** (defaultValue: true, debugValue: true) +- Change defaultValue to true +- Deploy - feature now enabled for all users + +**4. Cleanup** +- Feature stable and enabled everywhere +- Remove FeatureDescription +- Remove all `if FeatureFlags.x` checks +- Make new behavior the default +- Run `make generate` + +## 🎨 SwiftGen - Assets & Localization + +SwiftGen generates type-safe constants for resources. + +### Configuration Files + +- Assets: `/Modules/Assets/swiftgen.yml` +- Localization: `/Modules/Loc/swiftgen.yml` + +### Icon Generation + +**Input** (Assets.xcassets): +``` +DesignSystem/ +└── x32/ + └── QRCode.imageset/ + β”œβ”€β”€ QRCode.svg + └── Contents.json +``` + +**Generated** (after `make generate`): +```swift +enum ImageAsset { + enum X32 { + static let qrCode = ImageAsset(name: "DesignSystem/x32/QRCode") + } +} +``` + +**Usage**: +```swift +Image(asset: .X32.qrCode) +``` + +### Adding Icons + +1. Export SVG from Figma (e.g., "32/qr code" β†’ `QRCode.svg`) +2. Add to `/Modules/Assets/.../Assets.xcassets/DesignSystem/x32/QRCode.imageset/` +3. Run `make generate` +4. Use: `Image(asset: .X32.qrCode)` + +**Icon Sizes**: +- `x18` - 18pt icons (small UI) +- `x24` - 24pt icons (medium UI) +- `x32` - 32pt icons (large UI, most common) +- `x40` - 40pt icons (extra large) + +### Localization Generation + +SwiftGen also generates constants for localization keys from .xcstrings files. + +**See**: `LOCALIZATION_GUIDE.md` for complete localization workflow. + +## πŸ”§ Sourcery - Template-Based Generation + +Sourcery generates Swift code from templates based on source file annotations. + +### Configuration + +Multiple `sourcery.yml` files across modules: +- `/Modules/AnytypeCore/sourcery.yml` +- `/Modules/Services/sourcery.yml` +- etc. + +### Generated File Markers + +All Sourcery-generated files include: +```swift +// Generated using Sourcery X.X.X β€” https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT +``` + +### Common Use Cases + +**1. Protocol conformance** (Equatable, Hashable) +```swift +// sourcery: AutoEquatable +struct User { + let id: String + let name: String +} + +// After make generate: +// User conforms to Equatable automatically +``` + +**2. Mock implementations for testing** +```swift +// sourcery: AutoMockable +protocol UserService { + func fetchUser(id: String) async throws -> User +} + +// After make generate: +// UserServiceMock class created automatically +``` + +**3. Enum helpers** +```swift +// sourcery: AutoCases +enum UserRole { + case admin, editor, viewer +} + +// After make generate: +// CaseIterable conformance added +``` + +### Workflow + +1. Add annotation to source file: `// sourcery: AutoEquatable` +2. Run: `make generate` +3. Sourcery scans files, applies templates, generates code +4. Use generated code (don't edit generated files!) + +### Important + +βœ… Update source file annotations, not generated files +βœ… Run `make generate` after changing templates +βœ… Commit both source and generated files to git + +❌ Don't manually edit generated files +❌ Don't ignore "DO NOT EDIT" warnings + +## πŸ”Œ Middleware & Protobuf + +The Anytype middleware is a pre-compiled binary framework communicating via Protobuf. + +### Commands + +```bash +make setup-middle # Initial setup (downloads middleware) +make generate-middle # Regenerate middleware + protobuf bindings +``` + +### When to Regenerate + +- Middleware version updated in dependencies +- `Dependencies/Middleware/Lib.xcframework` missing binaries +- Protobuf message definitions changed +- Build errors related to middleware symbols + +### Locations + +- **Middleware**: `Dependencies/Middleware/Lib.xcframework` +- **Protobuf messages**: `Modules/ProtobufMessages/` +- **Generated code**: `Modules/ProtobufMessages/Generated/` +- **Custom config**: `anytypeGen.yml` (protobuf splitting) + +## πŸ“ Generated File Locations + +| Generator | Output Location | +|-----------|-----------------| +| SwiftGen (Localization) | `Modules/Loc/Sources/Loc/Generated/Strings.swift` | +| SwiftGen (Assets) | `Modules/Assets/Generated/ImageAssets.swift` | +| SwiftGen (Colors) | `Modules/Assets/Sources/Assets/Generated/Color+Assets.swift` | +| Sourcery (Feature Flags) | `Modules/AnytypeCore/AnytypeCore/Generated/FeatureFlags.swift` | +| Sourcery (Various) | `Modules/*/Generated/` | +| Protobuf | `Modules/ProtobufMessages/Generated/` | + +## 🚨 Common Mistakes + +### ❌ Editing Generated Files + +```swift +// In Generated/FeatureFlags.swift +static let myFlag: Bool = true // ❌ Don't edit this! +// Your changes will be overwritten on next make generate +``` + +**βœ… Correct**: Edit source file (`FeatureDescription+Flags.swift`), then regenerate. + +### ❌ Forgetting to Generate + +```swift +// Added FeatureDescription but didn't generate +if FeatureFlags.myNewFlag { // ❌ Error: unresolved identifier + ... +} +``` + +**βœ… Correct**: Run `make generate` first. + +### ❌ Not Committing Generated Files + +Generated files should be committed to git for reproducibility: + +```bash +git add Modules/AnytypeCore/AnytypeCore/Generated/FeatureFlags.swift +git commit -m "Add new feature flag" +``` + +## πŸ” Troubleshooting + +### Issue: `make generate` fails + +**Common causes**: +- Malformed JSON in .xcstrings files +- Duplicate keys across localization files +- Invalid Sourcery annotations +- Syntax errors in templates + +**Solution**: +```bash +# Validate JSON +jq . Modules/Loc/Sources/Loc/Resources/UI.xcstrings + +# Check for duplicate localization keys +rg "\"My Key\"" Modules/Loc/Sources/Loc/Resources/*.xcstrings | wc -l +# Should be 1, not 2+ + +# Check Sourcery annotations +rg "// sourcery:" --type swift +``` + +### Issue: Generated constant not found + +**Symptom**: `FeatureFlags.myFlag` doesn't exist after adding FeatureDescription + +**Solution**: +1. Verify flag definition in `FeatureDescription+Flags.swift` +2. Run `make generate` +3. Check generated file: `rg "myFlag" Modules/AnytypeCore/AnytypeCore/Generated/` +4. Clean build if needed + +### Issue: Middleware binaries missing + +**Symptom**: Build error: "Lib.xcframework missing binaries" + +**Solution**: +```bash +make setup-middle # Initial setup +# Or +make generate # May trigger middleware generation +``` + +## πŸ“š Integration with Other Systems + +- **Localization**: See `LOCALIZATION_GUIDE.md` for complete `.xcstrings` workflow +- **Design System**: Icons generated by SwiftGen after adding to Assets.xcassets +- **iOS Development**: Generated code follows patterns in `IOS_DEVELOPMENT_GUIDE.md` + +## πŸ’‘ Best Practices + +1. **Run `make generate` frequently** - After any asset, localization, or flag changes +2. **Never edit generated files** - Always update source, then regenerate +3. **Commit generated files** - Ensures everyone has same code without requiring generators +4. **Use feature flags for new features** - Safe rollouts, easy rollback +5. **Keep flags temporary** - Remove after full rollout to avoid technical debt +6. **Check generated code into git** - Don't rely on everyone running generators + +## πŸ“– Quick Reference + +**Add feature flag**: +```bash +vim Modules/AnytypeCore/.../FeatureDescription+Flags.swift +make generate +# Use FeatureFlags.yourFlag in code +``` + +**Add icon**: +```bash +cp icon.svg Modules/Assets/.../x32/Icon.imageset/ +make generate +# Use Image(asset: .X32.icon) +``` + +**Add localization**: +```bash +# Edit .xcstrings file +make generate +# Use Loc.yourKey +``` + +--- + +*This guide is the single source of truth for code generation. For quick reference, see CLAUDE.md.* \ No newline at end of file