--- description: github-sync allowed-tools: Bash, Read, Edit, Write, Glob, Grep --- # github-sync Two-way sync between AgileFlow stories and GitHub Issues with automatic status updates. ## Prompt ROLE: GitHub Integration Specialist OBJECTIVE Synchronize AgileFlow stories with GitHub Issues bidirectionally, keeping status, labels, assignees, and milestones in sync. INPUTS (optional) - MODE=import|export|sync (default: sync) - EPIC= (filter by specific epic) - STORY= (sync single story) - DRY_RUN=true|false (default: false - preview changes) - DIRECTION=agileflow-to-github|github-to-agileflow|bidirectional (default: bidirectional) PREREQUISITES 1. **GitHub MCP Server** configured in `.mcp.json`: ```json { "mcpServers": { "github": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"], "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_your_token_here" } } } } ``` Token permissions needed: - `repo` (full control) - for issues, PRs, labels - `read:org` - for organization access (if needed) Get token from: https://github.com/settings/tokens 2. **Repository configured** in sync map or provided via GITHUB_REPO parameter 3. **Sync Mapping** (create if missing): `docs/08-project/github-sync-map.json`: ```json { "last_sync": "2025-10-17T14:30:00Z", "mappings": { "US-0030": {"issue_number": 42, "last_synced": "2025-10-17T10:00:00Z"}, "US-0031": {"issue_number": 43, "last_synced": "2025-10-17T11:00:00Z"} }, "config": { "status_mapping": { "ready": "Status: Ready", "in-progress": "Status: In Progress", "in-review": "Status: In Review", "done": "Status: Done" }, "epic_to_milestone": { "EP-0010": "Milestone 1: Authentication", "EP-0011": "Milestone 2: Payments" } } } ``` SYNC WORKFLOW ### 1. Read Current State ```bash # AgileFlow state Read docs/09-agents/status.json Read docs/06-stories/**/*.md # GitHub state (via MCP tools) # Use mcp__github__* tools to list issues, get repo info, etc. # MCP provides: search_repositories, create_or_update_file, push_files, create_issue, # create_pull_request, fork_repository, create_repository, get_file_contents, etc. ``` ### 2. Detect Changes **From AgileFlow to GitHub**: - New stories not in mapping → Create GitHub Issues - Status changes → Update GitHub labels - Story updates (title, description, AC) → Update Issue body - Assignment changes → Update Issue assignees **From GitHub to AgileFlow**: - New Issues with `agileflow:` label → Create stories - Issue closed → Update status to "done" - Label changes → Update status.json - Assignee changes → Update story frontmatter ### 3. Apply Changes (with conflict resolution) If both sides changed: 1. Check timestamps (last_synced vs. GitHub updated_at vs. bus/log.jsonl timestamp) 2. Prefer most recent change 3. Log conflict to docs/09-agents/bus/log.jsonl: ```json {"ts":"2025-10-17T14:30:00Z","type":"sync-conflict","story":"US-0030","github_issue":42,"resolution":"kept_github","reason":"GitHub updated more recently"} ``` AGILEFLOW → GITHUB EXPORT ### Create GitHub Issue from Story For each story in docs/06-stories/**/*.md: ```bash # Read story frontmatter story_id=US-0030 title="User registration endpoint" owner=AG-API epic=EP-0010 status=done # Create issue if not exists if ! in_mapping($story_id); then issue_number=$(gh issue create \ --repo $GITHUB_REPO \ --title "[$story_id] $title" \ --body "$(cat <> docs/09-agents/bus/log.jsonl ``` GITHUB → AGILEFLOW IMPORT ### Create Story from GitHub Issue For each Issue with label `agileflow:story`: ```bash gh issue view $issue_number --json number,title,body,labels,assignees,milestone,state # Extract story metadata from labels epic=$(echo $labels | grep -oP 'epic:\K[A-Z]+-\d+') owner=$(echo $labels | grep -oP 'owner:\K[A-Z]+-[A-Z]+') status_label=$(echo $labels | grep -oP 'Status: \K.*') # Map status case "$status_label" in "Ready") status=ready ;; "In Progress") status=in-progress ;; "In Review") status=in-review ;; "Done") status=done ;; esac # Generate story ID if not in title if [[ $title =~ \[US-([0-9]+)\] ]]; then story_id=US-${BASH_REMATCH[1]} else # Find next available ID story_id=$(find_next_story_id) # Update GitHub issue title gh issue edit $issue_number --title "[$story_id] $title" fi # Create story file if doesn't exist if [ ! -f "docs/06-stories/$epic/$story_id.md" ]; then cat > "docs/06-stories/$epic/$story_id.md" <> docs/09-agents/bus/log.jsonl fi ``` ### Sync Issue Closure ```bash # When GitHub issue is closed if [ "$issue_state" = "CLOSED" ]; then # Update AgileFlow status story_id=$(get_story_from_mapping $issue_number) if [ -n "$story_id" ]; then # Update status.json update_status_json $story_id "done" "$owner" # Log to bus echo "{\"ts\":\"$(date -Iseconds)\",\"type\":\"github-sync\",\"story\":\"$story_id\",\"issue\":$issue_number,\"action\":\"closed\",\"status\":\"done\"}" >> docs/09-agents/bus/log.jsonl fi fi ``` SYNC REPORT After sync completes, generate report: ```markdown # GitHub Sync Report **Generated**: 2025-10-17 14:30 **Mode**: Bidirectional sync **Repository**: owner/repo --- ## 📊 Summary **AgileFlow → GitHub**: 5 changes - ✅ 3 issues created - ✅ 2 statuses updated **GitHub → AgileFlow**: 2 changes - ✅ 1 story created - ✅ 1 status updated (closed) **Conflicts**: 1 resolved - US-0030: GitHub updated more recently (kept GitHub state) --- ## 📤 Exported to GitHub | Story | Issue | Action | Status | |-------|-------|--------|--------| | US-0042 | #45 | Created | ✅ Success | | US-0043 | #46 | Created | ✅ Success | | US-0044 | #47 | Created | ✅ Success | | US-0038 | #40 | Updated status | ✅ Success | | US-0035 | #38 | Updated status | ✅ Success | ## 📥 Imported from GitHub | Issue | Story | Action | Status | |-------|-------|--------|--------| | #48 | US-0050 | Created story | ✅ Success | | #42 | US-0030 | Closed → done | ✅ Success | ## ⚠️ Conflicts Resolved | Story | Issue | Conflict | Resolution | |-------|-------|----------|------------| | US-0030 | #42 | Both updated | Kept GitHub (more recent) | ## 🔗 Mapping Updates Updated `docs/08-project/github-sync-map.json` with 5 new mappings. **Next sync**: Run `/AgileFlow:github-sync` again to keep in sync, or set up GitHub Actions webhook. --- ## 🤖 Automation Recommendation Set up automatic sync with GitHub Actions: `.github/workflows/agileflow-sync.yml`: ```yaml name: AgileFlow Sync on: issues: types: [opened, edited, closed, labeled] schedule: - cron: '0 */6 * * *' # Every 6 hours jobs: sync: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - run: /AgileFlow:github-sync MODE=sync ``` ``` LABEL MANAGEMENT ### Auto-create AgileFlow Labels ```bash # Create standard labels if they don't exist labels=( "agileflow:story|Story tracked in AgileFlow|0366d6" "epic:EP-0010|Epic: User Authentication|d4c5f9" "owner:AG-UI|Owner: UI Agent|fbca04" "owner:AG-API|Owner: API Agent|0e8a16" "Status: Ready|Ready to start|ededed" "Status: In Progress|Work in progress|fbca04" "Status: In Review|Under review|0075ca" "Status: Done|Completed|0e8a16" ) for label_def in "${labels[@]}"; do IFS='|' read -r name description color <<< "$label_def" gh label create "$name" --description "$description" --color "$color" --force done ``` WEBHOOK INTEGRATION (Advanced) For real-time sync, set up GitHub webhook: ```bash # webhook-handler.sh (runs on issue events) payload=$(cat) action=$(echo $payload | jq -r '.action') issue_number=$(echo $payload | jq -r '.issue.number') case $action in opened|edited) # Import/update story /AgileFlow:github-sync MODE=import ISSUE=$issue_number ;; closed) # Mark story done story_id=$(get_story_from_mapping $issue_number) /AgileFlow:status STORY=$story_id STATUS=done ;; labeled) # Sync status if status label changed new_label=$(echo $payload | jq -r '.label.name') if [[ $new_label =~ ^Status: ]]; then /AgileFlow:github-sync MODE=import ISSUE=$issue_number fi ;; esac ``` CONFLICT RESOLUTION STRATEGY 1. **Timestamp comparison**: - AgileFlow: Parse latest timestamp from bus/log.jsonl for story - GitHub: Use `updated_at` from issue - **Winner**: Most recent timestamp 2. **Manual resolution** (if timestamps within 5 minutes): - Show diff to user - Ask which to keep - Log decision to bus 3. **Auto-resolution rules**: - Status changes: Prefer GitHub (closer to source of truth for developers) - Content changes: Prefer AgileFlow (more detailed AC and structure) - Assignment: Prefer GitHub (reflects actual work assignment) DRY RUN MODE Preview changes before applying: ```bash /AgileFlow:github-sync DRY_RUN=true ``` Output: ```markdown # GitHub Sync (DRY RUN) **Would apply 7 changes** (use DRY_RUN=false to apply) ## AgileFlow → GitHub (5 changes) ✏️ **Create** Issue for US-0042 "Login form UI" - Labels: agileflow:story, epic:EP-0010, owner:AG-UI, Status: Ready - Milestone: Milestone 1: Authentication ✏️ **Create** Issue for US-0043 "Profile page" - Labels: agileflow:story, epic:EP-0011, owner:AG-UI, Status: Ready ✏️ **Update** Issue #40 status label - Remove: Status: Ready - Add: Status: In Progress ## GitHub → AgileFlow (2 changes) ✏️ **Create** Story US-0050 from Issue #48 "Add password reset flow" - File: docs/06-stories/EP-0010/US-0050.md - Status: ready - Owner: AG-API ✏️ **Update** US-0030 status to "done" (Issue #42 closed) - Update status.json - Log to bus **Run with DRY_RUN=false to apply these changes.** ``` ERROR HANDLING ```bash # Check for GitHub MCP tools if ! command -v mcp__github__search_repositories &> /dev/null; then echo "❌ GitHub MCP not configured. Add to .mcp.json:" echo ' "github": {' echo ' "command": "npx",' echo ' "args": ["-y", "@modelcontextprotocol/server-github"],' echo ' "env": {"GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_your_token"}' echo ' }' echo "" echo "Then restart Claude Code to load MCP server." exit 1 fi # Validate sync map if [ ! -f "docs/08-project/github-sync-map.json" ]; then echo "⚠️ Sync map not found. Creating new mapping file..." mkdir -p docs/08-project echo '{"last_sync":null,"mappings":{},"config":{}}' > docs/08-project/github-sync-map.json fi ``` USAGE EXAMPLES ### Full bidirectional sync ```bash /AgileFlow:github-sync ``` ### Export all stories to GitHub ```bash /AgileFlow:github-sync MODE=export ``` ### Import GitHub issues to AgileFlow ```bash /AgileFlow:github-sync MODE=import ``` ### Sync single story ```bash /AgileFlow:github-sync STORY=US-0030 ``` ### Sync specific epic ```bash /AgileFlow:github-sync EPIC=EP-0010 ``` ### Preview changes (dry run) ```bash /AgileFlow:github-sync DRY_RUN=true ``` ### One-way sync (AgileFlow → GitHub only) ```bash /AgileFlow:github-sync DIRECTION=agileflow-to-github ``` INTEGRATION WITH OTHER COMMANDS - After `/AgileFlow:story-new`: Optionally prompt to create GitHub issue - After `/AgileFlow:status`: Auto-sync status to GitHub - In `/AgileFlow:board`: Show GitHub issue links - In `/AgileFlow:velocity`: Include GitHub activity metrics RULES - Never create duplicate issues (check mapping first) - Always log sync actions to bus/log.jsonl - Preserve GitHub issue numbers in story frontmatter - Use labels for all metadata (status, epic, owner) - Handle rate limits gracefully (GitHub API: 5000 req/hour) - Validate GitHub token before any write operations OUTPUT - Sync report (markdown) - Updated github-sync-map.json - Updated status.json (if GitHub → AgileFlow changes) - Bus log entries for all sync actions - Optional: Saved report to docs/08-project/sync-reports/sync-YYYYMMDD-HHMMSS.md --- ## GITHUB MCP INTEGRATION This command uses **GitHub MCP** for all GitHub operations, providing: ### Advantages - ✅ **No sudo required** - npx handles installation automatically - ✅ **Consistent with Notion** - Both use MCP with tokens in `.mcp.json` - ✅ **Native Claude Code integration** - Built-in MCP tool support - ✅ **No CLI dependency** - Works in any environment (Docker, codespaces, etc.) - ✅ **Unified configuration** - All integrations in one `.mcp.json` file ### Available MCP Tools The GitHub MCP server provides these tools (prefix: `mcp__github__`): - `search_repositories` - Search for repositories - `create_or_update_file` - Create/update files in repo - `create_issue` - Create GitHub issues - `create_pull_request` - Create PRs - `get_file_contents` - Read file contents - `push_files` - Batch file operations - `fork_repository` - Fork repos - `create_repository` - Create new repos ### Migration from `gh` CLI If you previously used GitHub CLI (`gh`): 1. Remove `gh` CLI (no longer needed) 2. Add GitHub MCP to `.mcp.json` (see Prerequisites above) 3. Restart Claude Code to load MCP server 4. Run `/AgileFlow:github-sync` - it now uses MCP automatically ### Why We Switched - Removes sudo/installation barrier - Consistent security model across all integrations - Better portability across environments - Simpler team onboarding (just copy `.mcp.json.example`) --- ## RELATED COMMANDS - `/AgileFlow:notion-export` - Sync with Notion (uses MCP) - `/AgileFlow:story-new` - Create new story (can auto-create GitHub issue) - `/AgileFlow:board` - Visualize stories with GitHub links - `/AgileFlow:velocity` - Track velocity including GitHub activity