Research Branch Merge Overview Handles the complete workflow for processing research branches created during Claude Code Web sessions: 1. Detect research branches 2. Preview content for user approval 3. Squash-merge to main branch 4. Move docs to standardized location 5. Create GitHub issue from findings 6. Clean up remote branch Trigger: Called by skill when research branches detected, or directly via . User Interaction Pattern ALWAYS use AskUserQuestion for merge decisions: Processing Workflow Step 1: Detect Research Branches Use the utility: Step 2: Preview Content For each branch, show a…

, content, re.MULTILINE):\n statements.append({\n \"text\": match.group(1).strip(),\n \"type\": \"bullet\"\n })\n\n # Extract sentences from paragraphs (simplified)\n paragraphs = re.split(r'\\n\\n+', content)\n for para in paragraphs:\n if para.strip() and not para.strip().startswith('#'):\n sentences = re.split(r'(?\u003c=[.!?])\\s+', para)\n for sent in sentences:\n if len(sent) > 20: # Skip very short sentences\n statements.append({\n \"text\": sent.strip(),\n \"type\": \"sentence\"\n })\n\n return statements\n\n\ndef find_duplicates(files: List[Path], threshold: float = 0.7) -> List[Dict[str, Any]]:\n \"\"\"Find duplicate content across files.\"\"\"\n duplicates = []\n file_statements = {}\n\n # Extract statements from each file\n for file_path in files:\n if file_path.exists():\n content = file_path.read_text()\n file_statements[str(file_path)] = extract_statements(content)\n\n # Compare statements between files\n file_paths = list(file_statements.keys())\n for i, file1 in enumerate(file_paths):\n for file2 in file_paths[i+1:]:\n for stmt1 in file_statements[file1]:\n tokens1 = tokenize(stmt1[\"text\"])\n for stmt2 in file_statements[file2]:\n tokens2 = tokenize(stmt2[\"text\"])\n similarity = jaccard_similarity(tokens1, tokens2)\n\n if similarity >= threshold:\n duplicates.append({\n \"file1\": file1,\n \"statement1\": stmt1[\"text\"][:100],\n \"file2\": file2,\n \"statement2\": stmt2[\"text\"][:100],\n \"similarity\": round(similarity, 2)\n })\n\n return duplicates\n\n\ndef find_conflicts(files: List[Path]) -> List[Dict[str, Any]]:\n \"\"\"Find potentially conflicting statements.\"\"\"\n conflicts = []\n\n # Patterns that might indicate conflicting statements\n contradiction_pairs = [\n (r'\\bshould\\b', r'\\bshould not\\b'),\n (r'\\bmust\\b', r'\\bmust not\\b'),\n (r'\\balways\\b', r'\\bnever\\b'),\n (r'\\brecommended\\b', r'\\bnot recommended\\b'),\n (r'\\bbest practice\\b', r'\\banti-pattern\\b'),\n (r'\\bincrease\\b', r'\\bdecrease\\b'),\n (r'\\bfaster\\b', r'\\bslower\\b'),\n (r'\\bbetter\\b', r'\\bworse\\b'),\n ]\n\n file_statements = {}\n for file_path in files:\n if file_path.exists():\n content = file_path.read_text()\n file_statements[str(file_path)] = extract_statements(content)\n\n # Look for contradictions\n file_paths = list(file_statements.keys())\n for i, file1 in enumerate(file_paths):\n for file2 in file_paths[i+1:]:\n for stmt1 in file_statements[file1]:\n text1 = stmt1[\"text\"].lower()\n for stmt2 in file_statements[file2]:\n text2 = stmt2[\"text\"].lower()\n\n # Check for contradiction patterns\n for pattern1, pattern2 in contradiction_pairs:\n if (re.search(pattern1, text1) and re.search(pattern2, text2)) or \\\n (re.search(pattern2, text1) and re.search(pattern1, text2)):\n # Check if they're about the same topic\n tokens1 = tokenize(text1)\n tokens2 = tokenize(text2)\n topic_overlap = jaccard_similarity(tokens1, tokens2)\n\n if topic_overlap > 0.3: # Same topic\n conflicts.append({\n \"file1\": file1,\n \"statement1\": stmt1[\"text\"][:100],\n \"file2\": file2,\n \"statement2\": stmt2[\"text\"][:100],\n \"topic_overlap\": round(topic_overlap, 2),\n \"type\": \"potential_contradiction\"\n })\n\n return conflicts\n\n\ndef main():\n import argparse\n parser = argparse.ArgumentParser(description=\"Detect research conflicts\")\n parser.add_argument(\"files\", nargs=\"+\", help=\"Research files to analyze\")\n parser.add_argument(\"--mode\", choices=[\"duplicates\", \"conflicts\", \"all\"], default=\"all\",\n help=\"Detection mode\")\n parser.add_argument(\"--threshold\", type=float, default=0.7,\n help=\"Similarity threshold for duplicates\")\n args = parser.parse_args()\n\n files = [Path(f) for f in args.files]\n\n # Validate files exist\n missing = [f for f in files if not f.exists()]\n if missing:\n print(json.dumps({\n \"success\": False,\n \"error\": f\"Files not found: {[str(f) for f in missing]}\"\n }, indent=2))\n return 1\n\n result = {\n \"operation\": \"detect_conflicts\",\n \"files_analyzed\": len(files),\n \"mode\": args.mode\n }\n\n if args.mode in [\"duplicates\", \"all\"]:\n duplicates = find_duplicates(files, args.threshold)\n result[\"duplicates\"] = {\n \"count\": len(duplicates),\n \"items\": duplicates[:20] # Limit output\n }\n\n if args.mode in [\"conflicts\", \"all\"]:\n conflicts = find_conflicts(files)\n result[\"conflicts\"] = {\n \"count\": len(conflicts),\n \"items\": conflicts[:20] # Limit output\n }\n\n result[\"success\"] = True\n\n print(json.dumps(result, indent=2))\n return 0\n\n\nif __name__ == \"__main__\":\n sys.exit(main())\n","content_type":"text/x-python; charset=utf-8","language":"python","size":7640,"content_sha256":"d0db12db77056b2ba1b0fb3a6f90d70f762b87f484f2ad201e571256e3aa8f7a"},{"filename":"scripts/merge_findings.py","content":"#!/usr/bin/env python3\n\"\"\"\nResearch Findings Merge Script.\n\nMerge findings from multiple research notes into a unified document.\n\nUsage:\n python merge_findings.py FILE1 FILE2 [FILE3...] [--output OUTPUT]\n\nOutput:\n Merged research document\n\"\"\"\n\nimport json\nimport re\nimport sys\nfrom datetime import datetime\nfrom pathlib import Path\nfrom typing import Any, Dict, List, Optional, Set\n\n\ndef parse_frontmatter(content: str) -> tuple:\n \"\"\"Parse YAML frontmatter and content.\"\"\"\n if content.startswith('---'):\n parts = content.split('---', 2)\n if len(parts) >= 3:\n return parts[1].strip(), parts[2].strip()\n return '', content\n\n\ndef extract_metadata(frontmatter: str) -> Dict[str, Any]:\n \"\"\"Extract metadata from frontmatter.\"\"\"\n metadata = {}\n\n # Simple YAML parsing\n for line in frontmatter.split('\\n'):\n if ':' in line:\n key, value = line.split(':', 1)\n key = key.strip()\n value = value.strip()\n\n # Handle arrays\n if value.startswith('['):\n value = [v.strip().strip('\"\\'') for v in value[1:-1].split(',')]\n\n metadata[key] = value\n\n return metadata\n\n\ndef extract_sections(content: str) -> Dict[str, str]:\n \"\"\"Extract sections from markdown content.\"\"\"\n sections = {}\n current_section = None\n current_content = []\n\n for line in content.split('\\n'):\n if line.startswith('## '):\n if current_section:\n sections[current_section] = '\\n'.join(current_content).strip()\n current_section = line[3:].strip()\n current_content = []\n elif current_section:\n current_content.append(line)\n\n if current_section:\n sections[current_section] = '\\n'.join(current_content).strip()\n\n return sections\n\n\ndef extract_bullet_points(content: str) -> List[str]:\n \"\"\"Extract bullet points from content.\"\"\"\n points = []\n for line in content.split('\\n'):\n line = line.strip()\n if line.startswith('- ') or line.startswith('* '):\n points.append(line[2:].strip())\n return points\n\n\ndef dedupe_points(points: List[str], threshold: float = 0.8) -> List[str]:\n \"\"\"Remove duplicate or very similar points.\"\"\"\n unique = []\n\n for point in points:\n is_dup = False\n point_words = set(point.lower().split())\n\n for existing in unique:\n existing_words = set(existing.lower().split())\n if not point_words or not existing_words:\n continue\n\n # Calculate Jaccard similarity\n intersection = len(point_words & existing_words)\n union = len(point_words | existing_words)\n similarity = intersection / union if union > 0 else 0\n\n if similarity > threshold:\n is_dup = True\n # Keep longer version\n if len(point) > len(existing):\n unique.remove(existing)\n unique.append(point)\n break\n\n if not is_dup:\n unique.append(point)\n\n return unique\n\n\ndef merge_research_notes(files: List[Path]) -> Dict[str, Any]:\n \"\"\"Merge multiple research notes.\"\"\"\n merged = {\n \"title\": \"\",\n \"sources\": [],\n \"tags\": set(),\n \"findings\": [],\n \"code_examples\": [],\n \"references\": [],\n \"questions\": []\n }\n\n all_sections = {}\n\n for file_path in files:\n if not file_path.exists():\n continue\n\n content = file_path.read_text()\n frontmatter, body = parse_frontmatter(content)\n metadata = extract_metadata(frontmatter)\n sections = extract_sections(body)\n\n # Collect metadata\n merged[\"sources\"].append(str(file_path))\n\n if metadata.get(\"tags\"):\n if isinstance(metadata[\"tags\"], list):\n merged[\"tags\"].update(metadata[\"tags\"])\n else:\n merged[\"tags\"].add(metadata[\"tags\"])\n\n # Merge sections\n for section_name, section_content in sections.items():\n if section_name not in all_sections:\n all_sections[section_name] = []\n all_sections[section_name].append(section_content)\n\n # Process merged sections\n if \"Key Findings\" in all_sections:\n all_findings = []\n for content in all_sections[\"Key Findings\"]:\n all_findings.extend(extract_bullet_points(content))\n merged[\"findings\"] = dedupe_points(all_findings)\n\n if \"Questions & Follow-ups\" in all_sections:\n all_questions = []\n for content in all_sections[\"Questions & Follow-ups\"]:\n all_questions.extend(extract_bullet_points(content))\n merged[\"questions\"] = dedupe_points(all_questions)\n\n if \"References\" in all_sections:\n all_refs = []\n for content in all_sections[\"References\"]:\n all_refs.extend(extract_bullet_points(content))\n merged[\"references\"] = dedupe_points(all_refs)\n\n # Convert set to list\n merged[\"tags\"] = list(merged[\"tags\"])\n\n return merged\n\n\ndef generate_merged_document(merged: Dict[str, Any], title: str = None) -> str:\n \"\"\"Generate merged research document.\"\"\"\n lines = [\n \"---\",\n f\"title: \\\"{title or 'Merged Research'}\\\"\",\n f\"date: {datetime.now().strftime('%Y-%m-%d')}\",\n f\"tags: [{', '.join(merged['tags'])}]\",\n f\"sources: [{', '.join(merged['sources'])}]\",\n \"status: draft\",\n \"---\",\n \"\",\n f\"# {title or 'Merged Research'}\",\n \"\",\n \"## Overview\",\n \"\",\n f\"This document merges research from {len(merged['sources'])} source(s).\",\n \"\",\n \"## Key Findings\",\n \"\"\n ]\n\n for finding in merged[\"findings\"]:\n lines.append(f\"- {finding}\")\n\n if merged[\"questions\"]:\n lines.extend([\n \"\",\n \"## Questions & Follow-ups\",\n \"\"\n ])\n for question in merged[\"questions\"]:\n lines.append(f\"- [ ] {question}\")\n\n if merged[\"references\"]:\n lines.extend([\n \"\",\n \"## References\",\n \"\"\n ])\n for ref in merged[\"references\"]:\n lines.append(f\"- {ref}\")\n\n lines.extend([\n \"\",\n \"## Sources Merged\",\n \"\"\n ])\n for source in merged[\"sources\"]:\n lines.append(f\"- {source}\")\n\n return \"\\n\".join(lines)\n\n\ndef main():\n import argparse\n parser = argparse.ArgumentParser(description=\"Merge research findings\")\n parser.add_argument(\"files\", nargs=\"+\", help=\"Research files to merge\")\n parser.add_argument(\"--output\", \"-o\", help=\"Output file path\")\n parser.add_argument(\"--title\", \"-t\", help=\"Title for merged document\")\n parser.add_argument(\"--format\", choices=[\"json\", \"markdown\"], default=\"markdown\", help=\"Output format\")\n parser.add_argument(\"--dry-run\", action=\"store_true\", help=\"Show what would be merged\")\n args = parser.parse_args()\n\n files = [Path(f) for f in args.files]\n\n # Validate files exist\n missing = [f for f in files if not f.exists()]\n if missing:\n print(json.dumps({\n \"success\": False,\n \"error\": f\"Files not found: {[str(f) for f in missing]}\"\n }, indent=2))\n return 1\n\n if args.dry_run:\n print(json.dumps({\n \"operation\": \"merge_findings\",\n \"dry_run\": True,\n \"files\": [str(f) for f in files],\n \"output\": args.output or \"stdout\"\n }, indent=2))\n return 0\n\n # Merge\n merged = merge_research_notes(files)\n\n # Output\n if args.format == \"json\":\n output = json.dumps({\n \"operation\": \"merge_findings\",\n \"success\": True,\n \"files_merged\": len(files),\n **merged\n }, indent=2)\n else:\n output = generate_merged_document(merged, args.title)\n\n if args.output:\n Path(args.output).write_text(output)\n print(json.dumps({\n \"operation\": \"merge_findings\",\n \"success\": True,\n \"files_merged\": len(files),\n \"output_file\": args.output\n }, indent=2))\n else:\n print(output)\n\n return 0\n\n\nif __name__ == \"__main__\":\n sys.exit(main())\n","content_type":"text/x-python; charset=utf-8","language":"python","size":8237,"content_sha256":"af6ad417d2d0431ee724b4ac6990f1747416ab1bcf3210a5a27efc0d29897fe1"},{"filename":"skill-report.json","content":"{\n \"schema_version\": \"2.0\",\n \"meta\": {\n \"generated_at\": \"2026-01-17T06:45:19.841Z\",\n \"slug\": \"jrc1883-research-merge\",\n \"source_url\": \"https://github.com/jrc1883/popkit-claude/tree/main/packages/popkit-research/skills/pop-research-merge/\",\n \"source_ref\": \"main\",\n \"model\": \"claude\",\n \"analysis_version\": \"3.0.0\",\n \"source_type\": \"community\",\n \"content_hash\": \"a60ad8698f177797d418afb86496e17ce4d1cd6bc1e1f2830a92cda7717ac5ff\",\n \"tree_hash\": \"e562b249a09ddbf3556db9662ec675f81f66d9d1750406e009b6741077c6eb71\"\n },\n \"skill\": {\n \"name\": \"research-merge\",\n \"description\": \"Processes research branches from Claude Code Web sessions - merges content, moves docs to docs/research/, and creates GitHub issues. Use when /popkit:next detects research branches or when manually processing research from mobile sessions. Do NOT use for regular feature branches - only for branches matching claude/research-* or containing research documentation.\",\n \"summary\": \"Processes research branches from Claude Code Web sessions - merges content, moves docs to docs/resea...\",\n \"icon\": \"🔬\",\n \"version\": \"1.0.0\",\n \"author\": \"jrc1883\",\n \"license\": \"MIT\",\n \"category\": \"research\",\n \"tags\": [\n \"research\",\n \"git\",\n \"github\",\n \"documentation\",\n \"merge\"\n ],\n \"supported_tools\": [\n \"claude\",\n \"codex\",\n \"claude-code\"\n ],\n \"risk_factors\": [\n \"external_commands\",\n \"filesystem\"\n ]\n },\n \"security_audit\": {\n \"risk_level\": \"low\",\n \"is_blocked\": false,\n \"safe_to_publish\": true,\n \"summary\": \"This is a legitimate research management skill that handles git operations for research branches. The static scanner produced numerous false positives due to pattern matching heuristics that do not apply to this context. All git commands are hardcoded strings for legitimate repository operations. File system access is limited to reading markdown research documents and writing merged output. No credentials are accessed or exfiltrated. The skill is safe for publication.\",\n \"risk_factor_evidence\": [\n {\n \"factor\": \"external_commands\",\n \"evidence\": [\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 122,\n \"line_end\": 150\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 175,\n \"line_end\": 180\n }\n ]\n },\n {\n \"factor\": \"filesystem\",\n \"evidence\": [\n {\n \"file\": \"scripts/detect_conflicts.py\",\n \"line_start\": 81,\n \"line_end\": 83\n },\n {\n \"file\": \"scripts/detect_conflicts.py\",\n \"line_start\": 124,\n \"line_end\": 127\n }\n ]\n }\n ],\n \"critical_findings\": [],\n \"high_findings\": [],\n \"medium_findings\": [],\n \"low_findings\": [],\n \"dangerous_patterns\": [],\n \"files_scanned\": 5,\n \"total_lines\": 1188,\n \"audit_model\": \"claude\",\n \"audited_at\": \"2026-01-17T06:45:19.841Z\"\n },\n \"content\": {\n \"user_title\": \"Merge Research Branches Automatically\",\n \"value_statement\": \"Research branches pile up and become difficult to manage. This skill automatically detects, merges, and organizes research findings from Claude Code Web sessions into actionable GitHub issues.\",\n \"seo_keywords\": [\n \"Claude Code\",\n \"research management\",\n \"git merge\",\n \"GitHub issues\",\n \"documentation\",\n \"branch cleanup\",\n \"Claude\",\n \"research workflow\",\n \"knowledge management\",\n \"PopKit\"\n ],\n \"actual_capabilities\": [\n \"Detects research branches matching claude/research-* pattern\",\n \"Squash-merges research content to main branch\",\n \"Moves research docs to docs/research/ directory\",\n \"Creates GitHub issues from research findings\",\n \"Cleans up remote branches after processing\",\n \"Detects duplicate and conflicting research findings\"\n ],\n \"limitations\": [\n \"Requires GitHub CLI (gh) for issue creation\",\n \"Only processes branches with research documentation\",\n \"Cannot handle merge conflicts automatically\",\n \"Needs clean working directory before merging\"\n ],\n \"use_cases\": [\n {\n \"target_user\": \"Developers using Claude Code Web\",\n \"title\": \"Process Research from Mobile Sessions\",\n \"description\": \"Merge research branches created during mobile coding sessions into organized documentation with GitHub tracking\"\n },\n {\n \"target_user\": \"Research teams\",\n \"title\": \"Consolidate Research Findings\",\n \"description\": \"Combine multiple research notes into unified documents while detecting duplicates and conflicts\"\n },\n {\n \"target_user\": \"Project managers\",\n \"title\": \"Track Research Progress\",\n \"description\": \"Automatically create GitHub issues from research findings to ensure insights are acted upon\"\n }\n ],\n \"prompt_templates\": [\n {\n \"title\": \"Basic Research Merge\",\n \"scenario\": \"You have research branches to process\",\n \"prompt\": \"Use the research-merge skill to detect and process any research branches in my repository\"\n },\n {\n \"title\": \"Merge Specific Research\",\n \"scenario\": \"You know which research branch to merge\",\n \"prompt\": \"Merge the research branch about [topic] and create a GitHub issue with the findings\"\n },\n {\n \"title\": \"Research Cleanup\",\n \"scenario\": \"Clean up old research branches\",\n \"prompt\": \"Scan for research branches older than 30 days and help me decide which to merge or delete\"\n },\n {\n \"title\": \"Conflict Resolution\",\n \"scenario\": \"Multiple research notes have conflicting findings\",\n \"prompt\": \"Detect conflicts between these research files and help resolve them before merging\"\n }\n ],\n \"output_examples\": [\n {\n \"input\": \"Process my research branches\",\n \"output\": [\n \"Found 3 research branches:\",\n \"- research-claude-code-v2 (5 commits, 2 docs)\",\n \"- research-performance (3 commits, 1 doc)\",\n \"- research-ui-components (8 commits, 3 docs)\",\n \"\",\n \"Created GitHub issue #142: [Research] Claude Code v2.0.65 Features\",\n \"Moved 2 docs to docs/research/\",\n \"Deleted remote branch: research-claude-code-v2\"\n ]\n },\n {\n \"input\": \"Merge research about database optimization\",\n \"output\": [\n \"Detected branch: claude/research-db-optimization-abc123\",\n \"Research topic: Database Query Optimization\",\n \"1 documentation file found\",\n \"\",\n \"Merged content to main branch\",\n \"Created issue #89: [Research] Database Query Optimization\",\n \"Branch deleted successfully\"\n ]\n }\n ],\n \"best_practices\": [\n \"Review research content before merging to ensure quality and accuracy\",\n \"Use descriptive titles in research documents for better issue generation\",\n \"Include implementation tasks in research docs to create actionable issues\"\n ],\n \"anti_patterns\": [\n \"Merging research without reviewing the content first\",\n \"Creating research branches without proper documentation\",\n \"Ignoring merge conflicts instead of resolving them manually\"\n ],\n \"faq\": [\n {\n \"question\": \"What triggers research branch detection?\",\n \"answer\": \"The skill runs when /popkit:next detects branches matching claude/research-* pattern, or when invoked manually\"\n },\n {\n \"question\": \"Can I merge research without creating GitHub issues?\",\n \"answer\": \"Yes, choose Merge only option to squash-merge content without creating an issue\"\n },\n {\n \"question\": \"What happens to the original branch after merging?\",\n \"answer\": \"The remote branch is automatically deleted, but you can skip this step if needed\"\n },\n {\n \"question\": \"How does conflict detection work?\",\n \"answer\": \"The skill analyzes text similarity and looks for contradictory statements like should vs should not\"\n },\n {\n \"question\": \"Where are research documents moved?\",\n \"answer\": \"Research docs are organized into docs/research/ directory with standardized naming\"\n },\n {\n \"question\": \"What if I do not have GitHub CLI installed?\",\n \"answer\": \"The skill will skip issue creation and notify you - the merge will still complete successfully\"\n }\n ]\n },\n \"file_structure\": [\n {\n \"name\": \"scripts\",\n \"type\": \"dir\",\n \"path\": \"scripts\",\n \"children\": [\n {\n \"name\": \"detect_conflicts.py\",\n \"type\": \"file\",\n \"path\": \"scripts/detect_conflicts.py\",\n \"lines\": 209\n },\n {\n \"name\": \"merge_findings.py\",\n \"type\": \"file\",\n \"path\": \"scripts/merge_findings.py\",\n \"lines\": 290\n }\n ]\n },\n {\n \"name\": \"workflows\",\n \"type\": \"dir\",\n \"path\": \"workflows\",\n \"children\": [\n {\n \"name\": \"merge-workflow.json\",\n \"type\": \"file\",\n \"path\": \"workflows/merge-workflow.json\",\n \"lines\": 119\n }\n ]\n },\n {\n \"name\": \"SKILL.md\",\n \"type\": \"file\",\n \"path\": \"SKILL.md\",\n \"lines\": 304\n }\n ]\n}\n","content_type":"application/json; charset=utf-8","language":"json","size":9413,"content_sha256":"370f2a54888b98bd7497d192e2dc1bc216b87088375eaad35f015b66914881e7"},{"filename":"workflows/merge-workflow.json","content":"{\n \"name\": \"Research Merge Workflow\",\n \"version\": \"1.0.0\",\n \"description\": \"Guided workflow for merging research from multiple sources\",\n \"phases\": [\n {\n \"id\": \"collect\",\n \"name\": \"Collect Sources\",\n \"description\": \"Gather research notes to merge\",\n \"steps\": [\n {\n \"id\": \"select_sources\",\n \"name\": \"Select Research Sources\",\n \"prompt\": \"Which research notes should be merged?\",\n \"type\": \"multiselect\",\n \"data_source\": \"docs/research/*.md\"\n },\n {\n \"id\": \"load_content\",\n \"name\": \"Load Content\",\n \"type\": \"automated\",\n \"action\": \"Read selected research notes\"\n },\n {\n \"id\": \"parse_findings\",\n \"name\": \"Parse Findings\",\n \"type\": \"automated\",\n \"action\": \"Extract structured findings from each source\"\n }\n ]\n },\n {\n \"id\": \"dedupe\",\n \"name\": \"Deduplicate\",\n \"description\": \"Identify and handle duplicate findings\",\n \"steps\": [\n {\n \"id\": \"detect_duplicates\",\n \"name\": \"Detect Duplicates\",\n \"type\": \"automated\",\n \"script\": \"scripts/detect_conflicts.py --mode=duplicates\"\n },\n {\n \"id\": \"resolve_duplicates\",\n \"name\": \"Resolve Duplicates\",\n \"prompt\": \"How should duplicates be handled?\",\n \"type\": \"selection\",\n \"options\": [\n {\"label\": \"Keep most recent\", \"value\": \"recent\", \"description\": \"Use the most recent version\"},\n {\"label\": \"Keep most detailed\", \"value\": \"detailed\", \"description\": \"Use the version with more content\"},\n {\"label\": \"Merge all\", \"value\": \"merge\", \"description\": \"Combine information from all versions\"},\n {\"label\": \"Manual review\", \"value\": \"manual\", \"description\": \"Review each duplicate manually\"}\n ]\n },\n {\n \"id\": \"detect_conflicts\",\n \"name\": \"Detect Conflicts\",\n \"type\": \"automated\",\n \"script\": \"scripts/detect_conflicts.py --mode=conflicts\"\n },\n {\n \"id\": \"resolve_conflicts\",\n \"name\": \"Resolve Conflicts\",\n \"type\": \"interactive\",\n \"conditional\": \"conflicts_found\",\n \"action\": \"Present each conflict for user resolution\"\n }\n ]\n },\n {\n \"id\": \"synthesize\",\n \"name\": \"Synthesize\",\n \"description\": \"Combine findings into unified document\",\n \"steps\": [\n {\n \"id\": \"merge_findings\",\n \"name\": \"Merge Findings\",\n \"type\": \"automated\",\n \"script\": \"scripts/merge_findings.py\"\n },\n {\n \"id\": \"organize_sections\",\n \"name\": \"Organize Sections\",\n \"prompt\": \"How should the merged research be organized?\",\n \"type\": \"selection\",\n \"options\": [\n {\"label\": \"By topic\", \"value\": \"topic\", \"description\": \"Group by subject matter\"},\n {\"label\": \"By importance\", \"value\": \"importance\", \"description\": \"Most important findings first\"},\n {\"label\": \"Chronological\", \"value\": \"chronological\", \"description\": \"By discovery date\"},\n {\"label\": \"By source\", \"value\": \"source\", \"description\": \"Preserve original groupings\"}\n ]\n },\n {\n \"id\": \"generate_summary\",\n \"name\": \"Generate Summary\",\n \"type\": \"automated\",\n \"action\": \"Create unified summary from merged findings\"\n },\n {\n \"id\": \"save_merged\",\n \"name\": \"Save Merged Research\",\n \"type\": \"automated\",\n \"action\": \"Write merged document to docs/research/\"\n }\n ]\n }\n ],\n \"triggers\": {\n \"automatic\": [],\n \"manual\": [\n \"Invoke pop-research-merge skill\",\n \"Combine multiple research notes\"\n ]\n },\n \"output\": {\n \"primary\": \"docs/research/YYYY-MM-DD-\u003ctopic>-merged.md\"\n }\n}\n","content_type":"application/json; charset=utf-8","language":"json","size":3915,"content_sha256":"2d551f701a23b24ee19f0d4e7d68a616ea8ec855380648cd4e3d8a70e654034c"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Research Branch Merge","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Overview","type":"text"}]},{"type":"paragraph","content":[{"text":"Handles the complete workflow for processing research branches created during Claude Code Web sessions:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Detect research branches","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Preview content for user approval","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Squash-merge to main branch","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Move docs to standardized location","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Create GitHub issue from findings","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Clean up remote branch","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Trigger:","type":"text","marks":[{"type":"strong"}]},{"text":" Called by ","type":"text"},{"text":"pop-next-action","type":"text","marks":[{"type":"code_inline"}]},{"text":" skill when research branches detected, or directly via ","type":"text"},{"text":"/popkit:research merge","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"User Interaction Pattern","type":"text"}]},{"type":"paragraph","content":[{"text":"ALWAYS use AskUserQuestion","type":"text","marks":[{"type":"strong"}]},{"text":" for merge decisions:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"Use AskUserQuestion tool with:\n- question: \"Found research branch: [topic]. How should we process it?\"\n- header: \"Research\"\n- options:\n - label: \"Merge and create issue\"\n description: \"Squash-merge, move docs, create GitHub issue, delete branch\"\n - label: \"Merge only\"\n description: \"Squash-merge content without creating issue\"\n - label: \"Skip for now\"\n description: \"Leave branch for later processing\"\n - label: \"Delete branch\"\n description: \"Discard research (cannot be undone)\"\n- multiSelect: false","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Processing Workflow","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 1: Detect Research Branches","type":"text"}]},{"type":"paragraph","content":[{"text":"Use the ","type":"text"},{"text":"research_branch_detector.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" utility:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"import sys\n# No longer needed - install popkit-shared instead\nfrom research_branch_detector import (\n fetch_remotes,\n get_research_branches,\n format_branch_table,\n get_branch_content_preview,\n parse_research_doc,\n generate_issue_body\n)\n\n# Fetch and detect\nfetch_remotes()\nbranches = get_research_branches()\n\nif not branches:\n print(\"No research branches detected.\")\n return\n\n# Show table\nprint(\"## Research Branches Detected\\n\")\nprint(format_branch_table(branches))","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 2: Preview Content","type":"text"}]},{"type":"paragraph","content":[{"text":"For each branch, show a preview before prompting:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"for branch in branches:\n print(f\"\\n### {branch.short_name}\")\n print(f\"**Topic:** {branch.topic}\")\n print(f\"**Created:** {branch.created_ago}\")\n print(f\"**Commits:** {branch.commit_count} ahead of master\")\n\n if branch.doc_paths:\n print(f\"\\n**Documentation:**\")\n for path in branch.doc_paths:\n print(f\"- `{path}`\")\n\n # Show summary preview\n previews = get_branch_content_preview(branch, max_lines=20)\n for path, content in previews.items():\n parsed = parse_research_doc(content)\n if parsed.get(\"summary\"):\n print(f\"\\n**Summary:** {parsed['summary'][:200]}...\")","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 3: User Decision","type":"text"}]},{"type":"paragraph","content":[{"text":"Use AskUserQuestion for each branch:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"Use AskUserQuestion tool with:\n- question: f\"Process '{branch.topic}' research? ({branch.commit_count} commits, {len(branch.doc_paths)} docs)\"\n- header: \"Merge\"\n- options:\n - label: \"Merge + Issue\"\n description: \"Full processing: merge, organize docs, create issue\"\n - label: \"Merge Only\"\n description: \"Just merge the content\"\n - label: \"Skip\"\n description: \"Process later\"\n - label: \"Delete\"\n description: \"Discard this research\"\n- multiSelect: false","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 4: Execute Merge","type":"text"}]},{"type":"paragraph","content":[{"text":"Based on user choice:","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Option A: Merge + Issue (Full Processing)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# 1. Ensure clean working directory\ngit status --porcelain\n# If dirty, prompt user to commit or stash first\n\n# 2. Squash merge the research branch\ngit merge --squash origin/claude/research-[topic]-[session-id]\n\n# 3. Organize docs (if not already in docs/research/)\nmkdir -p docs/research\n# Move any root-level research docs\ngit mv RESEARCH*.md docs/research/ 2>/dev/null || true\ngit mv *_RESEARCH.md docs/research/ 2>/dev/null || true\n\n# 4. Commit with standard message\ngit commit -m \"docs(research): merge [topic] research from web session\n\nMerged from: [branch-name]\nCreated: [created-ago]\n\n🤖 Generated with [Claude Code](https://claude.ai/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 \[email protected]>\"\n\n# 5. Create GitHub issue\ngh issue create --title \"[Research] [Topic Title]\" --body \"[generated-body]\" --label \"research,documentation\"\n\n# 6. Delete remote branch\ngit push origin --delete claude/research-[topic]-[session-id]","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Option B: Merge Only","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"git merge --squash origin/claude/research-[topic]-[session-id]\ngit commit -m \"docs(research): merge [topic] research\n\nMerged from: [branch-name]\n\n🤖 Generated with [Claude Code](https://claude.ai/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 \[email protected]>\"\n\n# Optionally delete branch\n# Ask: \"Delete the remote branch?\"","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Option C: Skip","type":"text"}]},{"type":"paragraph","content":[{"text":"No action - branch remains for future processing.","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Option D: Delete","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Confirm deletion\n# \"Are you sure? This research will be permanently lost.\"\n\ngit push origin --delete claude/research-[topic]-[session-id]","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 5: Summary Report","type":"text"}]},{"type":"paragraph","content":[{"text":"After processing all branches:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"markdown"},"content":[{"text":"## Research Processing Complete\n\n| Branch | Action | Result |\n|--------|--------|--------|\n| research-claude-code | Merged + Issue | Issue #182 created |\n| research-audio-hooks | Skipped | - |\n| research-old-test | Deleted | - |\n\n**Next Steps:**\n- Review created issues\n- Run `/popkit:next` to see updated recommendations","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Issue Generation","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Title Format","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"[Research] {Topic Title}","type":"text"}]},{"type":"paragraph","content":[{"text":"Examples:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"[Research] Claude Code v2.0.65 Features Integration","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"[Research] Audio Feedback Hooks Architecture","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Body Format","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"markdown"},"content":[{"text":"## Summary\n\n{Executive summary from research doc}\n\n## Source\n\n- **Branch:** `{full_branch_name}`\n- **Created:** {created_ago}\n- **Files:** {file_count} changed\n\n## Documentation\n\n- `docs/research/{doc_name}.md`\n\n## Implementation Tasks\n\n- [ ] {Task 1 from research}\n- [ ] {Task 2 from research}\n\n---\n*Auto-generated from research branch by PopKit*","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Labels","type":"text"}]},{"type":"paragraph","content":[{"text":"Automatically apply:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"research","type":"text","marks":[{"type":"code_inline"}]},{"text":" - Marks as research output","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"documentation","type":"text","marks":[{"type":"code_inline"}]},{"text":" - Contains documentation","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Optionally detect from content:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"enhancement","type":"text","marks":[{"type":"code_inline"}]},{"text":" - If implementation tasks found","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"P1-high","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"P2-medium","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"P3-low","type":"text","marks":[{"type":"code_inline"}]},{"text":" - From priority metadata","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Error Handling","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Situation","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Response","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Dirty working directory","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Prompt to commit/stash first","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Merge conflicts","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Show conflicts, offer manual resolution","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"gh CLI unavailable","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Skip issue creation, note in output","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"No doc files","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Merge anyway, create minimal issue","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Branch already merged","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Skip, note in output","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Research Document Standard","type":"text"}]},{"type":"paragraph","content":[{"text":"For best results, research docs should follow this format:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"markdown"},"content":[{"text":"# Research: [Topic Name]\n\n**Research Date:** YYYY-MM-DD\n**Status:** Research Document\n**Priority:** P1-high | P2-medium | P3-low\n\n## Executive Summary\n\n[Brief summary of findings - becomes issue body]\n\n## Key Findings\n\n[Main research content]\n\n## Implementation Tasks\n\n- [ ] Task 1 [becomes checklist in issue]\n- [ ] Task 2\n- [ ] Task 3\n\n## References\n\n[Links and sources]","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Integration Points","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Component","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Role","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"pop-next-action","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Calls this skill when branches detected","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"research_branch_detector.py","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Core detection logic","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"/popkit:next","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Entry point for auto-detection","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"/popkit:routine morning","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Can include in morning routine","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"GitHub Issues","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Output destination for findings","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Related","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"/popkit:next","type":"text","marks":[{"type":"code_inline"}]},{"text":" - Primary entry point","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"/popkit:routine morning","type":"text","marks":[{"type":"code_inline"}]},{"text":" - Can detect in morning check","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"hooks/utils/research_branch_detector.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" - Detection utility","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"output-styles/research-summary.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" - Output formatting","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}}]},"metadata":{"date":"2026-06-05","name":"research-merge","author":"@skillopedia","source":{"stars":336,"repo_name":"marketplace","origin_url":"https://github.com/aiskillstore/marketplace/blob/HEAD/skills/jrc1883/research-merge/SKILL.md","repo_owner":"aiskillstore","body_sha256":"d3b62ae8a1282fa377dd7f71869e9ac43e491e2f3298724c1d5dcec450840795","cluster_key":"ede6b90f1ae075d57eb8eb217961d26dd967b2eacfb3acad1b253dc4f71ca0ae","clean_bundle":{"format":"clean-skill-bundle-v1","source":"aiskillstore/marketplace/skills/jrc1883/research-merge/SKILL.md","attachments":[{"id":"7b75dbc0-ad9e-584e-b341-565820f4f9d3","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/7b75dbc0-ad9e-584e-b341-565820f4f9d3/attachment.py","path":"scripts/detect_conflicts.py","size":7640,"sha256":"d0db12db77056b2ba1b0fb3a6f90d70f762b87f484f2ad201e571256e3aa8f7a","contentType":"text/x-python; charset=utf-8"},{"id":"554ba3a8-4cc1-582c-86a9-6d12472a2a49","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/554ba3a8-4cc1-582c-86a9-6d12472a2a49/attachment.py","path":"scripts/merge_findings.py","size":8237,"sha256":"af6ad417d2d0431ee724b4ac6990f1747416ab1bcf3210a5a27efc0d29897fe1","contentType":"text/x-python; charset=utf-8"},{"id":"c06efa4f-4794-58aa-8a17-dce9c3bf0136","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/c06efa4f-4794-58aa-8a17-dce9c3bf0136/attachment.json","path":"skill-report.json","size":9413,"sha256":"370f2a54888b98bd7497d192e2dc1bc216b87088375eaad35f015b66914881e7","contentType":"application/json; charset=utf-8"},{"id":"938bd01d-71ff-5f19-8dc9-b2dcc01b9e77","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/938bd01d-71ff-5f19-8dc9-b2dcc01b9e77/attachment.json","path":"workflows/merge-workflow.json","size":3915,"sha256":"2d551f701a23b24ee19f0d4e7d68a616ea8ec855380648cd4e3d8a70e654034c","contentType":"application/json; charset=utf-8"}],"bundle_sha256":"0b3db52b912eed04dfd9816c8f8c1b0ad545532256c72d9665fa50d77a0e749a","attachment_count":4,"text_attachments":4,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":0,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":"skills/jrc1883/research-merge/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"documents-office","category_label":"Documents"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"documents-office","import_tag":"clean-skills-v1","description":"Processes research branches from Claude Code Web sessions - merges content, moves docs to docs/research/, and creates GitHub issues. Use when /popkit:next detects research branches or when manually processing research from mobile sessions. Do NOT use for regular feature branches - only for branches matching claude/research-* or containing research documentation."}},"renderedAt":1782988828347}

Research Branch Merge Overview Handles the complete workflow for processing research branches created during Claude Code Web sessions: 1. Detect research branches 2. Preview content for user approval 3. Squash-merge to main branch 4. Move docs to standardized location 5. Create GitHub issue from findings 6. Clean up remote branch Trigger: Called by skill when research branches detected, or directly via . User Interaction Pattern ALWAYS use AskUserQuestion for merge decisions: Processing Workflow Step 1: Detect Research Branches Use the utility: Step 2: Preview Content For each branch, show a…