Example of Claude Code Git Integration A developer shared a bash script that integrates Claude Code with GitHub Issues, enabling automated local processing of issue commands. The script creates a branch, sets up a Node.js environment, and uses the GitHub CLI to comment on issues, demonstrating a practical workflow for AI-assisted development. | /bin/bash | | | | Local Claude Code Handler for GitHub Issues | | Processes GitHub issues by creating branches and calling Claude Code directly | | | | | | set -e | | | | Get environment variables passed from the monitor | | ISSUE NUMBER="${ISSUE NUMBER}" | | ISSUE TITLE="${ISSUE TITLE}" | | ISSUE AUTHOR="${ISSUE AUTHOR}" | | ISSUE COMMAND="${ISSUE COMMAND}" | | REPO OWNER="${REPO OWNER}" | | REPO NAME="${REPO NAME}" | | GITHUB TOKEN="${GITHUB TOKEN}" | | | | Configuration | | REPO="${REPO OWNER}/${REPO NAME}" | | BRANCH NAME="claude-bot/issue-${ISSUE NUMBER}" | | | | Get project root | | SCRIPT DIR="$ cd "$ dirname "${BASH SOURCE 0 }" " && pwd " | | PROJECT ROOT="$ cd "$SCRIPT DIR/../.." && pwd " | | | | Log file location | | LOG DIR="$PROJECT ROOT/logs/claude-handler" | | mkdir -p "$LOG DIR" | | LOG FILE="$LOG DIR/handler-local-$ date +%Y%m%d .log" | | | | Function to log with timestamp | | log { | | echo " $ date '+%Y-%m-%d %H:%M:%S' $1" | tee -a "$LOG FILE" | | } | | | | Function to add a comment to the issue | | add issue comment { | | local comment="$1" | | log "Adding comment to issue $ISSUE NUMBER" | | | | gh issue comment "$ISSUE NUMBER" \ | | --repo "$REPO" \ | | --body "$comment" | | } | | | | Function to get the default branch of the repository | | get default branch { | | gh repo view "$REPO" --json defaultBranchRef --jq '.defaultBranchRef.name' | | } | | | | Set up Node.js environment for Claude Code | | setup node env { | | log "Setting up Node.js environment..." | | | | Load NVM if available | | if -s "$HOME/.nvm/nvm.sh" ; then | | source "$HOME/.nvm/nvm.sh" | | nvm use 22.16.0 /dev/null 2 &1 || { | | log "Installing Node.js 22.16.0..." | | nvm install 22.16.0 | | nvm use 22.16.0 | | } | | elif -s "/usr/local/share/nvm/nvm.sh" ; then | | source "/usr/local/share/nvm/nvm.sh" | | nvm use 22.16.0 /dev/null 2 &1 || { | | log "Installing Node.js 22.16.0..." | | nvm install 22.16.0 | | nvm use 22.16.0 | | } | | fi | | | | NODE VERSION=$ node --version | | log "Using Node.js: $NODE VERSION" | | } | | | | log "=== Processing Issue $ISSUE NUMBER Locally ===" | | log "Title: $ISSUE TITLE" | | log "Author: $ISSUE AUTHOR" | | log "Command: $ISSUE COMMAND" | | log "Branch will be: $BRANCH NAME" | | | | Get the default branch | | DEFAULT BRANCH=$ get default branch | | log "Repository default branch: $DEFAULT BRANCH" | | | | First, acknowledge the issue | | ACKNOWLEDGMENT="👋 Hello @$ISSUE AUTHOR I'm Claude, and I'll help you with this issue. | | | | I'm analyzing your request and will create a branch to work on it locally. Here's what I understand: | | | | Request : $ISSUE COMMAND | | | | I'll start working on this and provide updates as I progress. Creating branch \ $BRANCH NAME\ from \ $DEFAULT BRANCH\ ..." | | | | add issue comment "$ACKNOWLEDGMENT" | | | | Change to project root | | cd "$PROJECT ROOT" | | | | Clean up any stale git state | | log "Cleaning up git state" | | git reset --hard HEAD 2 /dev/null || true | | git clean -fd 2 /dev/null || true | | git checkout "$DEFAULT BRANCH" 2 /dev/null || true | | | | Configure Git for GitHub operations | | log "Configuring Git authentication" | | git config --global user.name "Claude Bot" | | git config --global user.email "claude-bot@anthropic.com" | | | | Clear any existing credential helpers | | git config --global --unset-all credential.helper || true | | | | Set up token-based authentication | | if -n "$GITHUB TOKEN" ; then | | log "Using GITHUB TOKEN for authentication" | | Create credential helper that returns the token | | git config --global credential.helper " f { | | if \"\$1\" = \"get\" ; then | | echo \"username=token\" | | echo \"password=$GITHUB TOKEN\" | | fi | | }; f" | | | | Also set the remote URL to use token authentication | | CURRENT REMOTE=$ git config --get remote.origin.url || echo "" | | if "$CURRENT REMOTE" == "github.com" && "$CURRENT REMOTE" = "@" ; then | | Convert https://github.com/... to https://token:TOKEN@github.com/... | | NEW REMOTE=$ echo "$CURRENT REMOTE" | sed "s|https://github.com/|https://token:$GITHUB TOKEN@github.com/|" | | git remote set-url origin "$NEW REMOTE" | | log "Updated remote URL for token auth" | | fi | | else | | log "Using gh CLI for authentication" | | git config --global credential.helper " gh auth git-credential" | | fi | | | | Create and switch to the branch | | log "Creating branch: $BRANCH NAME" | | | | Clean up ALL existing claude-bot branch references not just current | | log "Cleaning up all claude-bot branch references" | | git branch -D $ git branch | grep "claude-bot" | xargs 2 /dev/null || true | | git branch -d -r $ git branch -r | grep "origin/claude-bot" | xargs 2 /dev/null || true | | rm -rf ".git/refs/remotes/origin/claude-bot" 2 /dev/null || true | | rm -f ".git/refs/remotes/origin/claude-bot" 2 /dev/null || true | | find .git -name " .lock" -delete 2 /dev/null || true | | | | Ensure git directories have proper permissions | | mkdir -p .git/logs/refs/heads .git/refs/remotes/origin | | chmod -R 755 .git/logs .git/refs 2 /dev/null || true | | chown -R $ whoami :$ whoami .git/logs .git/refs 2 /dev/null || true | | | | First switch away from default branch to avoid fetch conflicts | | git checkout HEAD~0 2 /dev/null || true | | | | Fetch updates from origin | | log "Fetching updates from origin" | | git fetch origin || { | | log "Error: Could not fetch from origin. Check GitHub authentication." | | add issue comment "❌ Error: Could not fetch from GitHub repository. Please check authentication setup." | | exit 1 | | } | | | | Switch to default branch first, then create new branch | | git checkout "$DEFAULT BRANCH" || { | | log "Error: Could not switch to default branch $DEFAULT BRANCH" | | add issue comment "❌ Error: Could not switch to default branch \ $DEFAULT BRANCH\ ." | | exit 1 | | } | | | | git checkout -b "$BRANCH NAME" || { | | log "Error: Could not create branch $BRANCH NAME" | | add issue comment "❌ Error: Could not create branch \ $BRANCH NAME\ . Please check for permission issues." | | exit 1 | | } | | | | Update issue with execution status | | EXECUTION COMMENT="🚀 Starting work on branch \ $BRANCH NAME\ | | | | I'm now working on your request locally with Claude Code. I'll implement the changes and run tests before creating a pull request. | | | | Current status : Analyzing request and implementing changes..." | | | | add issue comment "$EXECUTION COMMENT" | | | | Set up Node.js environment | | setup node env | | | | Create a direct command prompt for Claude Code | | CLAUDE PROMPT FILE="/tmp/claude issue ${ISSUE NUMBER} prompt.txt" | | cat "$CLAUDE PROMPT FILE" << EOF | | You are working on GitHub issue $ISSUE NUMBER: "$ISSUE TITLE" within this repository. | | | | REQUEST: $ISSUE COMMAND | | | | I need you to implement this request now. Here's what you should do: | | | | 1. Read the project structure and understand the codebase | | 2. Implement the specific request above | | 3. Follow existing patterns and conventions | | 4. Create or modify files as needed | | 5. Do not create placeholder files - implement actual functionality | | | | The current branch is: $BRANCH NAME | | | | Start by exploring the codebase and then implement the request completely. | | EOF | | | | log "Launching Claude Code with issue prompt..." | | | | Set up environment variables for Claude Code automation | | export CLAUDE PROMPT FILE="$CLAUDE PROMPT FILE" | | export CLAUDE AUTOMODE="true" | | export CI="true" | | export ANTHROPIC AUTO APPROVE="true" | | export CLAUDE NON INTERACTIVE="true" | | | | Run Claude Code with the prompt file | | log "Executing Claude Code in automated mode..." | | CLAUDE EXIT CODE=0 | | | | Try the simplest approach first - just use --print for text generation | | log "Using Claude Code --print for text generation..." | | timeout 960 claude --print --dangerously-skip-permissions < "$CLAUDE PROMPT FILE" "/tmp/claude output ${ISSUE NUMBER}.txt" 2 &1 || CLAUDE EXIT CODE=$? | | | | If that fails, try a simple interactive approach with timeout | | if $CLAUDE EXIT CODE -ne 0 ; then | | log "Text generation failed, trying interactive approach with extended timeout..." | | CLAUDE EXIT CODE=0 | | | | Simple approach: send prompt and exit command with extended timeout | | timeout 1920 bash -c " | | { | | cat '$CLAUDE PROMPT FILE' | | echo '' | | echo 'Please complete this task and implement the changes needed.' | | echo '' | | Give extended time for processing then send exit | | sleep 160 | | echo 'exit' | | } | claude --dangerously-skip-permissions | | " || CLAUDE EXIT CODE=$? | | fi | | | | Check if we got any output from the --print method | | if -s "/tmp/claude output ${ISSUE NUMBER}.txt" ; then | | log "Claude Code --print generated output, creating response file" | | | | Create a response file with the generated content | | echo " Claude Code Response for Issue $ISSUE NUMBER" "CLAUDE RESPONSE ${ISSUE NUMBER}.md" | | echo "" "CLAUDE RESPONSE ${ISSUE NUMBER}.md" | | echo " Original Request : $ISSUE COMMAND" "CLAUDE RESPONSE ${ISSUE NUMBER}.md" | | echo "" "CLAUDE RESPONSE ${ISSUE NUMBER}.md" | | echo " Generated Response :" "CLAUDE RESPONSE ${ISSUE NUMBER}.md" | | echo "" "CLAUDE RESPONSE ${ISSUE NUMBER}.md" | | cat "/tmp/claude output ${ISSUE NUMBER}.txt" "CLAUDE RESPONSE ${ISSUE NUMBER}.md" | | | | git add "CLAUDE RESPONSE ${ISSUE NUMBER}.md" | | | | Clean up temp file | | rm -f "/tmp/claude output ${ISSUE NUMBER}.txt" | | | | Reset exit code since we got output | | CLAUDE EXIT CODE=0 | | | | elif $CLAUDE EXIT CODE -ne 0 ; then | | log "Claude Code execution failed with exit code: $CLAUDE EXIT CODE" | | | | Determine the type of failure | | if $CLAUDE EXIT CODE -eq 124 ; then | | FAILURE REASON="Claude Code execution timed out" | | elif $CLAUDE EXIT CODE -eq 1 ; then | | FAILURE REASON="Claude Code encountered an error during execution" | | else | | FAILURE REASON="Claude Code failed with exit code $CLAUDE EXIT CODE" | | fi | | | | Create a detailed fallback implementation file | | echo " Implementation Status for Issue $ISSUE NUMBER" "IMPLEMENTATION ISSUE ${ISSUE NUMBER}.md" | | echo "" "IMPLEMENTATION ISSUE ${ISSUE NUMBER}.md" | | echo " Original Request : $ISSUE COMMAND" "IMPLEMENTATION ISSUE ${ISSUE NUMBER}.md" | | echo "" "IMPLEMENTATION ISSUE ${ISSUE NUMBER}.md" | | echo " Status : $FAILURE REASON" "IMPLEMENTATION ISSUE ${ISSUE NUMBER}.md" | | echo " Timestamp : $ date " "IMPLEMENTATION ISSUE ${ISSUE NUMBER}.md" | | echo " Branch : \ $BRANCH NAME\ " "IMPLEMENTATION ISSUE ${ISSUE NUMBER}.md" | | echo "" "IMPLEMENTATION ISSUE ${ISSUE NUMBER}.md" | | echo " Next Steps :" "IMPLEMENTATION ISSUE ${ISSUE NUMBER}.md" | | echo "- Check the logs in \ $LOG FILE\ " "IMPLEMENTATION ISSUE ${ISSUE NUMBER}.md" | | echo "- Verify Claude Code is properly installed and configured" "IMPLEMENTATION ISSUE ${ISSUE NUMBER}.md" | | echo "- Consider manual implementation or re-running with different parameters" "IMPLEMENTATION ISSUE ${ISSUE NUMBER}.md" | | | | git add "IMPLEMENTATION ISSUE ${ISSUE NUMBER}.md" | | | | Also notify in the issue comment | | add issue comment "⚠️ Claude Code Execution Failed | | | | $FAILURE REASON | | | | I've created a status file on branch \ $BRANCH NAME\ with details. Please check the logs or try manual implementation." | | | | Clean up temp files | | rm -f "/tmp/claude output ${ISSUE NUMBER}.txt" | | fi | | | | Clean up prompt file | | rm -f "$CLAUDE PROMPT FILE" | | | | Check what changes were made | | log "Checking for changes..." | | if git diff --quiet && git diff --staged --quiet; then | | log "No changes were made by Claude Code" | | | | FINAL COMMENT="⚠️ Implementation Incomplete | | | | I created a branch and ran Claude Code, but no changes were generated. The request was: | | | | $ISSUE COMMAND | | | | This might mean: | | - The request needs more specific details | | - Claude Code encountered an issue during execution | | - Manual implementation is required | | | | Please check the branch \ $BRANCH NAME\ and provide more details if needed, or implement the changes manually." | | | | else | | log "Changes detected, committing and creating PR..." | | | | Add all changes | | git add -A | | | | Commit the changes | | git commit -m "Implement $ISSUE NUMBER: $ISSUE TITLE | | | | $ISSUE COMMAND | | | | 🤖 Implemented locally with Claude Code" || { | | log "Error: Could not commit changes" | | add issue comment "❌ Error: Could not commit changes to branch \ $BRANCH NAME\ ." | | exit 1 | | } | | | | Push the branch | | log "Pushing branch to origin" | | git push origin "$BRANCH NAME" || { | | log "Error: Could not push branch $BRANCH NAME" | | add issue comment "❌ Error: Could not push branch \ $BRANCH NAME\ to GitHub. Please check permissions." | | exit 1 | | } | | | | Create pull request | | log "Creating pull request" | | PR URL=$ gh pr create \ | | --repo "$REPO" \ | | --title "Implement $ISSUE NUMBER: $ISSUE TITLE" \ | | --body "Fixes $ISSUE NUMBER | | | | Original Request : $ISSUE COMMAND | | | | Implementation : This PR was automatically generated by Claude Code running locally in response to the GitHub issue. | | | | 🤖 Implemented locally with Claude Code" \ | | --base "$DEFAULT BRANCH" \ | | --head "$BRANCH NAME" 2 &1 || { | | log "Error creating pull request: $PR URL" | | add issue comment "❌ Error: Could not create pull request. Branch \ $BRANCH NAME\ has been pushed with changes." | | exit 1 | | } | | | | Clean up Claude response file after successful PR creation | | if -f "CLAUDE RESPONSE ${ISSUE NUMBER}.md" ; then | | log "Removing Claude response file after successful PR creation" | | git rm "CLAUDE RESPONSE ${ISSUE NUMBER}.md" | | git commit -m "Clean up Claude response file | | | | 🤖 Automated cleanup after PR creation" || { | | log "Warning: Could not remove Claude response file" | | } | | | | Push the cleanup commit | | git push origin "$BRANCH NAME" || { | | log "Warning: Could not push cleanup commit" | | } | | fi | | | | FINAL COMMENT="✅ Implementation Complete | | | | I've successfully implemented the requested changes using Claude Code and created a pull request: | | | | Pull Request : $PR URL | | Branch : \ $BRANCH NAME\ | | | | The implementation has been completed locally and is ready for review. Please check the PR for details on what was implemented." | | fi | | | | add issue comment "$FINAL COMMENT" | | log "Issue $ISSUE NUMBER processing completed successfully" | | | | exit 0 |