# Convert Code Analysis to Linear Tasks Convert code analysis to Linear tasks ## Purpose This command scans your codebase for TODO/FIXME comments, technical debt markers, deprecated code, and other indicators that should be tracked as tasks. It automatically creates organized, prioritized Linear tasks to ensure important code improvements aren't forgotten. ## Usage ```bash # Scan entire codebase for TODOs and create tasks claude "Create tasks from all TODO comments in the codebase" # Scan specific directory or module claude "Find TODOs in src/api and create Linear tasks" # Create tasks from specific patterns claude "Create tasks for all deprecated functions" # Generate technical debt report claude "Analyze technical debt in the project and create improvement tasks" ``` ## Instructions ### 1. Scan for Task Markers Search for common patterns indicating needed work: ```bash # Find TODO comments rg "TODO|FIXME|HACK|XXX|OPTIMIZE|REFACTOR" --type-add 'code:*.{js,ts,py,java,go,rb,php}' -t code # Find deprecated markers rg "@deprecated|DEPRECATED|@obsolete" -t code # Find temporary code rg "TEMPORARY|TEMP|REMOVE BEFORE|DELETE ME" -t code -i # Find technical debt markers rg "TECHNICAL DEBT|TECH DEBT|REFACTOR|NEEDS REFACTORING" -t code -i # Find security concerns rg "SECURITY|INSECURE|VULNERABILITY|CVE-" -t code -i # Find performance issues rg "SLOW|PERFORMANCE|OPTIMIZE|BOTTLENECK" -t code -i ``` ### 2. Parse Comment Context Extract meaningful information from comments: ```javascript class CommentParser { parseComment(file, lineNumber, comment) { const parsed = { type: 'todo', priority: 'medium', title: '', description: '', author: null, date: null, tags: [], code_context: '', file_path: file, line_number: lineNumber }; // Detect comment type if (comment.match(/FIXME/i)) { parsed.type = 'fixme'; parsed.priority = 'high'; } else if (comment.match(/HACK|XXX/i)) { parsed.type = 'hack'; parsed.priority = 'high'; } else if (comment.match(/OPTIMIZE|PERFORMANCE/i)) { parsed.type = 'optimization'; } else if (comment.match(/DEPRECATED/i)) { parsed.type = 'deprecation'; parsed.priority = 'high'; } else if (comment.match(/SECURITY/i)) { parsed.type = 'security'; parsed.priority = 'urgent'; } // Extract author and date const authorMatch = comment.match(/@(\w+)|by (\w+)/i); if (authorMatch) { parsed.author = authorMatch[1] || authorMatch[2]; } const dateMatch = comment.match(/(\d{4}-\d{2}-\d{2})|(\d{1,2}\/\d{1,2}\/\d{2,4})/); if (dateMatch) { parsed.date = dateMatch[0]; } // Extract title and description const cleanComment = comment .replace(/^\/\/\s*|^\/\*\s*|\*\/\s*$|^#\s*/g, '') .replace(/TODO|FIXME|HACK|XXX/i, '') .trim(); const parts = cleanComment.split(/[:\-–—]/); if (parts.length > 1) { parsed.title = parts[0].trim(); parsed.description = parts.slice(1).join(':').trim(); } else { parsed.title = cleanComment; } // Extract tags const tagMatch = comment.match(/#(\w+)/g); if (tagMatch) { parsed.tags = tagMatch.map(tag => tag.substring(1)); } return parsed; } getCodeContext(file, lineNumber, contextLines = 5) { const lines = readFileLines(file); const start = Math.max(0, lineNumber - contextLines); const end = Math.min(lines.length, lineNumber + contextLines); return lines.slice(start, end).map((line, i) => ({ number: start + i + 1, content: line, isTarget: start + i + 1 === lineNumber })); } } ``` ### 3. Group and Deduplicate Organize found issues intelligently: ```javascript class TaskGrouper { groupTasks(parsedComments) { const groups = { byFile: new Map(), byType: new Map(), byAuthor: new Map(), byModule: new Map() }; for (const comment of parsedComments) { // Group by file if (!groups.byFile.has(comment.file_path)) { groups.byFile.set(comment.file_path, []); } groups.byFile.get(comment.file_path).push(comment); // Group by type if (!groups.byType.has(comment.type)) { groups.byType.set(comment.type, []); } groups.byType.get(comment.type).push(comment); // Group by module const module = this.extractModule(comment.file_path); if (!groups.byModule.has(module)) { groups.byModule.set(module, []); } groups.byModule.get(module).push(comment); } return groups; } mergeSimilarTasks(tasks) { const merged = []; const seen = new Set(); for (const task of tasks) { if (seen.has(task)) continue; // Find similar tasks const similar = tasks.filter(t => t !== task && !seen.has(t) && this.areSimilar(task, t) ); if (similar.length > 0) { // Merge into one task const mergedTask = { ...task, title: this.generateMergedTitle(task, similar), description: this.generateMergedDescription(task, similar), locations: [task, ...similar].map(t => ({ file: t.file_path, line: t.line_number })) }; merged.push(mergedTask); seen.add(task); similar.forEach(t => seen.add(t)); } else { merged.push(task); seen.add(task); } } return merged; } } ``` ### 4. Analyze Technical Debt Identify code quality issues: ```javascript class TechnicalDebtAnalyzer { async analyzeFile(filePath) { const issues = []; const content = await readFile(filePath); const lines = content.split('\n'); // Check for long functions const functionMatches = content.matchAll(/function\s+(\w+)|(\w+)\s*=\s*\(.*?\)\s*=>/g); for (const match of functionMatches) { const functionName = match[1] || match[2]; const startLine = getLineNumber(content, match.index); const functionLength = this.getFunctionLength(lines, startLine); if (functionLength > 50) { issues.push({ type: 'long_function', severity: functionLength > 100 ? 'high' : 'medium', title: `Refactor long function: ${functionName}`, description: `Function ${functionName} is ${functionLength} lines long. Consider breaking it into smaller functions.`, file_path: filePath, line_number: startLine }); } } // Check for duplicate code const duplicates = await this.findDuplicateCode(filePath); for (const dup of duplicates) { issues.push({ type: 'duplicate_code', severity: 'medium', title: 'Remove duplicate code', description: `Similar code found in ${dup.otherFile}:${dup.otherLine}`, file_path: filePath, line_number: dup.line }); } // Check for complex conditionals const complexConditions = content.matchAll(/if\s*\([^)]{50,}\)/g); for (const match of complexConditions) { issues.push({ type: 'complex_condition', severity: 'low', title: 'Simplify complex conditional', description: 'Consider extracting conditional logic into named variables or functions', file_path: filePath, line_number: getLineNumber(content, match.index) }); } // Check for outdated dependencies if (filePath.endsWith('package.json')) { const outdated = await this.checkOutdatedDependencies(filePath); for (const dep of outdated) { issues.push({ type: 'outdated_dependency', severity: dep.major ? 'high' : 'low', title: `Update ${dep.name} from ${dep.current} to ${dep.latest}`, description: dep.major ? 'Major version update available' : 'Minor update available', file_path: filePath }); } } return issues; } } ``` ### 5. Create Linear Tasks Convert findings into actionable tasks: ```javascript async function createLinearTasks(groupedTasks, options = {}) { const created = []; const skipped = []; // Check for existing tasks to avoid duplicates const existingTasks = await linear.searchTasks('TODO OR FIXME'); const existingTitles = new Set(existingTasks.map(t => t.title)); // Create parent task for large groups if (options.createEpic && groupedTasks.length > 10) { const epic = await linear.createTask({ title: `Technical Debt: ${options.module || 'Codebase'} Cleanup`, description: `Parent task for ${groupedTasks.length} code improvements`, priority: 2, labels: ['technical-debt', 'code-quality'] }); options.parentId = epic.id; } for (const task of groupedTasks) { // Skip if similar task exists if (existingTitles.has(task.title)) { skipped.push({ task, reason: 'duplicate' }); continue; } // Build task description const description = buildTaskDescription(task); // Map priority const priorityMap = { urgent: 1, high: 2, medium: 3, low: 4 }; try { const linearTask = await linear.createTask({ title: task.title, description, priority: priorityMap[task.priority] || 3, labels: getLabelsForTask(task), parentId: options.parentId, estimate: estimateTaskSize(task) }); created.push({ linear: linearTask, source: task }); // Add code link as comment await linear.createComment({ issueId: linearTask.id, body: `📍 Code location: \`${task.file_path}:${task.line_number}\`` }); } catch (error) { skipped.push({ task, reason: error.message }); } } return { created, skipped }; } function buildTaskDescription(task) { let description = task.description || ''; // Add code context if (task.code_context) { description += '\n\n### Code Context\n```\n'; task.code_context.forEach(line => { const prefix = line.isTarget ? '>>> ' : ' '; description += `${prefix}${line.number}: ${line.content}\n`; }); description += '```\n'; } // Add metadata description += '\n\n### Details\n'; description += `- **Type**: ${task.type}\n`; description += `- **File**: \`${task.file_path}\`\n`; description += `- **Line**: ${task.line_number}\n`; if (task.author) { description += `- **Author**: @${task.author}\n`; } if (task.date) { description += `- **Date**: ${task.date}\n`; } if (task.tags.length > 0) { description += `- **Tags**: ${task.tags.join(', ')}\n`; } // Add suggestions if (task.type === 'deprecated') { description += '\n### Suggested Actions\n'; description += '1. Identify all usages of this deprecated code\n'; description += '2. Update to use the recommended alternative\n'; description += '3. Add deprecation warnings if not present\n'; description += '4. Schedule for removal in next major version\n'; } return description; } ``` ### 6. Generate Summary Report Create overview of findings: ```javascript function generateReport(scanResults, createdTasks) { const report = { summary: { totalFound: scanResults.length, tasksCreated: createdTasks.created.length, tasksSkipped: createdTasks.skipped.length, byType: {}, byPriority: {}, byFile: {} }, details: [], recommendations: [] }; // Analyze distribution for (const result of scanResults) { report.summary.byType[result.type] = (report.summary.byType[result.type] || 0) + 1; report.summary.byPriority[result.priority] = (report.summary.byPriority[result.priority] || 0) + 1; } // Generate recommendations if (report.summary.byType.security > 0) { report.recommendations.push({ priority: 'urgent', action: 'Address security-related TODOs immediately', tasks: scanResults.filter(r => r.type === 'security').length }); } if (report.summary.byType.deprecated > 5) { report.recommendations.push({ priority: 'high', action: 'Create deprecation removal sprint', tasks: report.summary.byType.deprecated }); } return report; } ``` ### 7. Error Handling ```javascript // Handle access errors try { await scanDirectory(path); } catch (error) { if (error.code === 'EACCES') { console.warn(`Skipping ${path} - permission denied`); } } // Handle Linear API limits const rateLimiter = { tasksCreated: 0, resetTime: Date.now() + 3600000, async createTask(taskData) { if (this.tasksCreated >= 50) { console.log('Rate limit approaching, batching remaining tasks...'); // Create single task with list of TODOs return this.createBatchTask(remainingTasks); } this.tasksCreated++; return linear.createTask(taskData); } }; // Handle malformed comments const safeParser = { parse(comment) { try { return this.parseComment(comment); } catch (error) { return { type: 'todo', title: comment.substring(0, 50) + '...', priority: 'low', parseError: true }; } } }; ``` ## Example Output ``` Scanning codebase for TODOs and technical debt... 📊 Scan Results: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Found 47 items across 23 files: • 24 TODOs • 8 FIXMEs • 5 Deprecated functions • 3 Security concerns • 7 Performance optimizations 🔍 Breakdown by Priority: 🔴 Urgent: 3 (security related) 🟠 High: 13 (FIXMEs + deprecations) 🟡 Medium: 24 (standard TODOs) 🟢 Low: 7 (optimizations) 📁 Hotspot Files: 1. src/api/auth.js - 8 items 2. src/utils/validation.js - 6 items 3. src/models/User.js - 5 items 🚨 Critical Findings: 1. SECURITY: Hardcoded API key File: src/config/api.js:45 TODO: Remove hardcoded key and use env variable → Creating task with URGENT priority 2. DEPRECATED: Legacy authentication method File: src/api/auth.js:120 Multiple usages found in 4 files → Creating migration task 3. FIXME: Race condition in concurrent updates File: src/services/sync.js:78 Author: @alice (2024-01-03) → Creating high-priority bug task 📝 Task Creation Summary: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ✅ Created 32 Linear tasks: - Epic: "Q1 Technical Debt Cleanup" (LIN-456) - 3 urgent security tasks - 10 high-priority fixes - 19 medium-priority improvements ⏭️ Skipped 15 items: - 8 duplicates (tasks already exist) - 4 low-value comments (e.g., "TODO: think about this") - 3 external dependencies (waiting on upstream) 📊 Estimates: - Total story points: 89 - Estimated effort: 2-3 sprints - Recommended team size: 2-3 developers 🎯 Recommended Actions: 1. Schedule security sprint immediately (3 urgent items) 2. Assign deprecation removal to next sprint (5 items) 3. Create coding standards to reduce future TODOs 4. Set up pre-commit hook to limit new TODOs View all created tasks: https://linear.app/yourteam/project/q1-technical-debt-cleanup ``` ## Advanced Features ### Custom Patterns Define project-specific patterns: ```bash # Add custom markers to scan claude "Scan for REVIEW, QUESTION, and ASSUMPTION comments" ``` ### Integration with CI/CD ```bash # Fail build if critical TODOs found claude "Check for SECURITY or FIXME comments and exit with error if found" ``` ### Scheduled Scans ```bash # Weekly technical debt report claude "Generate weekly technical debt report and create tasks for new items" ``` ## Tips - Run regularly to prevent TODO accumulation - Use consistent comment formats across the team - Include author and date in TODOs - Link TODOs to existing Linear issues when possible - Set up IDE snippets for properly formatted TODOs - Review and close completed TODO tasks - Use TODO comments as a quality gate in PR reviews