| name | github-flow-for-claude-on-web |
| description | Complete GitHub workflow for Claude Code on the web. ALL GitHub operations MUST use REST API (never gh CLI). Includes branch naming (claude/*-sessionId), push retry logic, PR/issue management via API, and complete workflows. Use for all GitHub interactions in Claude Code web environment. |
| allowed-tools | Bash, Read, Grep |
GitHub Flow for Claude Code on the Web
This skill provides comprehensive Git and GitHub operations optimized for Claude Code on the web environment, including branch management, push operations, and GitHub REST API interactions.
⚠️ CRITICAL: Always Use GitHub REST API
NEVER use gh CLI in Claude Code on the web - it is not available.
All GitHub operations (PRs, issues, comments, reviews) MUST use the REST API via curl:
- ✅
curl -s https://api.github.com/repos/OWNER/REPO/pulls/123
- ❌
gh pr view 123 (NOT AVAILABLE)
When to Use
This skill is automatically activated when running in Claude Code on the web environment (CLAUDE_CODE_REMOTE=true).
Table of Contents
- GitHub API Operations
- Environment Detection
- Branch Naming Requirements
- Git Push Operations
- Pull Request Creation
- Complete Workflows
- Troubleshooting
GitHub API Operations
Core Principle
ALL GitHub operations must use the REST API. The gh CLI is not available in Claude Code on the web environment.
Common GitHub API Endpoints
Get PR Details
curl -s https://api.github.com/repos/OWNER/REPO/pulls/PR_NUMBER
Get PR Review Comments
curl -s https://api.github.com/repos/OWNER/REPO/pulls/PR_NUMBER/comments
curl -s https://api.github.com/repos/OWNER/REPO/issues/PR_NUMBER/comments
Get Repository Info
REMOTE_URL=$(git remote get-url origin)
REPO_FULL=$(echo "$REMOTE_URL" | sed -E 's#.*github\.com[:/]([^/]+/[^/]+)(\.git)?$#\1#')
OWNER=$(echo "$REPO_FULL" | cut -d/ -f1)
REPO=$(echo "$REPO_FULL" | cut -d/ -f2)
curl -s "https://api.github.com/repos/$OWNER/$REPO"
List Issues
curl -s https://api.github.com/repos/OWNER/REPO/issues
curl -s "https://api.github.com/repos/OWNER/REPO/issues?labels=bug"
Get Issue Comments
curl -s https://api.github.com/repos/OWNER/REPO/issues/ISSUE_NUMBER/comments
Authentication
curl -s https://api.github.com/repos/OWNER/REPO/pulls/123
curl -s -H "Authorization: token $GITHUB_TOKEN" \
https://api.github.com/repos/OWNER/REPO/pulls/123
Parsing JSON Responses
curl -s https://api.github.com/repos/OWNER/REPO/pulls/123 | \
jq '{title, state, author: .user.login}'
curl -s https://api.github.com/repos/OWNER/REPO/pulls/123 | \
grep -o '"title": *"[^"]*"' | cut -d'"' -f4
Environment Detection
Always check if running in Claude Code on the web before applying special constraints:
if [ "$CLAUDE_CODE_REMOTE" = "true" ]; then
echo "Running in Claude Code on the web"
else
echo "Running in local environment"
fi
Key Environment Variables:
CLAUDE_CODE_REMOTE - Set to "true" in web environment
CLAUDE_SESSION_ID - Session identifier (may be available)
GITHUB_TOKEN - GitHub personal access token for API operations
Branch Naming Requirements
Critical Constraints
When pushing to remote in Claude Code on the web:
- ✅ Branch names MUST start with
claude/
- ✅ Branch names MUST end with a matching session ID
- ✅ Pattern:
claude/<feature-name>-<sessionId>
- ❌ Pushing to non-compliant branches will fail with HTTP 403
Examples
Valid branch names:
claude/fix-bug-abc123
claude/add-feature-xyz789
claude/create-pull-request-KITjd
Invalid branch names:
main # ❌ Doesn't start with claude/
feature-branch # ❌ Doesn't start with claude/
claude/fix-bug # ❌ Missing session ID
fix-bug-abc123 # ❌ Doesn't start with claude/
Creating Compliant Branches
#!/bin/bash
SESSION_ID="${CLAUDE_SESSION_ID:-9GOGf}"
FEATURE_NAME="fix-matchglob"
BRANCH="claude/${FEATURE_NAME}-${SESSION_ID}"
git checkout -b "$BRANCH"
git checkout "$BRANCH"
Converting Existing Branches
If you're on a non-compliant branch:
#!/bin/bash
CURRENT_BRANCH="$(git branch --show-current)"
SESSION_ID="${CLAUDE_SESSION_ID:-9GOGf}"
if [[ ! "$CURRENT_BRANCH" =~ ^claude/.+-[a-zA-Z0-9]+$ ]]; then
echo "Branch name needs conversion: $CURRENT_BRANCH"
FEATURE_NAME="${CURRENT_BRANCH//[^a-zA-Z0-9-]/-}"
NEW_BRANCH="claude/${FEATURE_NAME}-${SESSION_ID}"
git checkout -b "$NEW_BRANCH"
echo "Created new branch: $NEW_BRANCH"
fi
Git Push Operations
Push with Retry Logic
Claude Code on the web may experience transient network issues. Always use retry logic with exponential backoff:
#!/bin/bash
smart_push() {
local branch="${1:-$(git branch --show-current)}"
if [ "$CLAUDE_CODE_REMOTE" != "true" ]; then
git push -u origin "$branch"
return $?
fi
if [[ ! "$branch" =~ ^claude/.+-[a-zA-Z0-9]+$ ]]; then
echo "❌ Invalid branch name for Claude Code on the web: $branch"
echo " Required pattern: claude/<feature-name>-<sessionId>"
return 1
fi
echo "Pushing branch: $branch"
local max_attempts=4
for attempt in $(seq 1 $max_attempts); do
if [ $attempt -gt 1 ]; then
local delay=$((2 ** (attempt - 1)))
echo "Retry attempt $attempt/$max_attempts after ${delay}s..."
sleep $delay
fi
local output
output=$(git push -u origin "$branch" 2>&1)
local exit_code=$?
if [ $exit_code -eq 0 ]; then
echo "✅ Push successful!"
return 0
fi
if echo "$output" | grep -q "403"; then
echo "❌ HTTP 403 - Branch name validation failed"
echo " Ensure branch follows pattern: claude/*-<sessionId>"
return 1
fi
echo "$output"
done
echo "❌ Push failed after $max_attempts attempts"
return 1
}
smart_push
smart_push "claude/my-feature-abc123"
Quick Push Script
For quick use in bash commands:
BRANCH="$(git branch --show-current)"
for i in 0 1 2 3; do
if [ $i -gt 0 ]; then
delay=$((2 ** i))
echo "Retry $i after ${delay}s..."
sleep $delay
fi
if git push -u origin "$BRANCH" 2>&1; then
echo "✅ Push successful!"
exit 0
fi
done
echo "❌ Push failed after retries"
exit 1
Force Push (Use with Caution)
When you need to force push (e.g., after rebase):
#!/bin/bash
force_push() {
local branch="${1:-$(git branch --show-current)}"
if [[ ! "$branch" =~ ^claude/ ]]; then
echo "❌ Can only force push claude/* branches"
return 1
fi
echo "⚠️ Force pushing to: $branch"
read -p "Continue? (yes/no): " confirm
if [ "$confirm" != "yes" ]; then
echo "Aborted"
return 1
fi
for i in 0 1 2 3; do
if [ $i -gt 0 ]; then
sleep $((2 ** i))
fi
if git push -u origin "$branch" --force 2>&1; then
echo "✅ Force push successful!"
return 0
fi
done
echo "❌ Force push failed"
return 1
}
Pull Request Creation
Using GitHub API
The gh CLI tool is not available in Claude Code on the web. Use the GitHub REST API instead.
Prerequisites
Ensure GITHUB_TOKEN is available:
if [ -z "$GITHUB_TOKEN" ]; then
echo "❌ GITHUB_TOKEN not found"
exit 1
fi
echo "✅ GITHUB_TOKEN available"
Basic PR Creation
#!/bin/bash
create_pr() {
local title="$1"
local body="$2"
local head_branch="${3:-$(git branch --show-current)}"
local base_branch="${4:-main}"
local repo="${5:-owner/repo}"
local response=$(curl -X POST \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${repo}/pulls" \
-d "{
\"title\": \"${title}\",
\"head\": \"${head_branch}\",
\"base\": \"${base_branch}\",
\"body\": \"${body}\"
}")
local pr_url=$(echo "$response" | grep -o '"html_url": *"[^"]*"' | head -1 | cut -d'"' -f4)
if [ -n "$pr_url" ]; then
echo "✅ PR created: $pr_url"
echo "$pr_url"
else
echo "❌ Failed to create PR"
echo "$response"
return 1
fi
}
create_pr \
"fix: improve matchGlob regex escaping" \
"This PR fixes regex escaping in the matchGlob function..." \
"claude/fix-matchglob-abc123" \
"main" \
"shabaraba/vibing.nvim"
Advanced PR Creation with Formatting
#!/bin/bash
create_pr_formatted() {
local title="$1"
local base_branch="$2"
local repo="$3"
local head_branch="$(git branch --show-current)"
local body=$(cat <<'EOF'
Brief description of changes.
- Change 1
- Change 2
- Change 3
- [ ] Unit tests pass
- [ ] Integration tests pass
- [ ] Manual testing completed
Fixes
EOF
)
body=$(echo "$body" | jq -Rs .)
local response=$(curl -s -X POST \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${repo}/pulls" \
-d "{
\"title\": $(echo "$title" | jq -Rs .),
\"head\": \"${head_branch}\",
\"base\": \"${base_branch}\",
\"body\": ${body}
}")
local pr_number=$(echo "$response" | jq -r '.number // empty')
local pr_url=$(echo "$response" | jq -r '.html_url // empty')
if [ -n "$pr_number" ]; then
echo "✅ PR #${pr_number} created: $pr_url"
echo "$pr_url"
else
echo "❌ Failed to create PR"
echo "$response" | jq .
return 1
fi
}
Creating Multiple PRs in Parallel
When you need to create multiple PRs at once:
#!/bin/bash
declare -A prs=(
["claude/fix-pr146-abc123"]="fix: import URL from url module|feat/granular-permissions-123"
["claude/fix-pr144-abc123"]="docs: improve comments in ftplugin|feat/vibing-lsp-133"
["claude/fix-pr142-abc123"]="feat: add language validation|feat/default-language-config-125"
)
REPO="shabaraba/vibing.nvim"
for branch in "${!prs[@]}"; do
IFS='|' read -r title base <<< "${prs[$branch]}"
echo "Creating PR for $branch..."
curl -X POST \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${REPO}/pulls" \
-d "{
\"title\": \"${title}\",
\"head\": \"${branch}\",
\"base\": \"${base}\",
\"body\": \"Auto-generated PR from Claude Code\"
}" | jq -r '.html_url // "Failed"'
sleep 1
done
Updating Existing PR
To update a PR's description:
#!/bin/bash
update_pr() {
local pr_number="$1"
local new_body="$2"
local repo="$3"
curl -X PATCH \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${repo}/pulls/${pr_number}" \
-d "{
\"body\": $(echo "$new_body" | jq -Rs .)
}" | jq -r '.html_url // "Failed"'
}
update_pr 150 "Updated description..." "shabaraba/vibing.nvim"
Complete Workflows
Workflow 1: Feature Development and PR Creation
Complete workflow from feature development to PR:
#!/bin/bash
REPO="shabaraba/vibing.nvim"
SESSION_ID="${CLAUDE_SESSION_ID:-9GOGf}"
FEATURE_NAME="add-new-feature"
BASE_BRANCH="main"
echo "=== Starting feature development workflow ==="
BRANCH="claude/${FEATURE_NAME}-${SESSION_ID}"
echo "Creating branch: $BRANCH"
git checkout -b "$BRANCH"
echo "Making changes..."
git add .
git commit -m "feat: add new feature
This commit adds...
"
echo "Pushing to remote..."
for i in 0 1 2 3; do
if [ $i -gt 0 ]; then
sleep $((2 ** i))
fi
if git push -u origin "$BRANCH"; then
echo "✅ Push successful!"
break
fi
done
echo "Creating pull request..."
PR_BODY=$(cat <<'EOF'
This PR adds a new feature that...
- Added new functionality
- Updated documentation
- Added tests
- [x] Unit tests pass
- [x] Integration tests pass
- [x] Manual testing completed
EOF
)
PR_URL=$(curl -s -X POST \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${REPO}/pulls" \
-d "{
\"title\": \"feat: add new feature\",
\"head\": \"${BRANCH}\",
\"base\": \"${BASE_BRANCH}\",
\"body\": $(echo "$PR_BODY" | jq -Rs .)
}" | jq -r '.html_url // empty')
if [ -n "$PR_URL" ]; then
echo "✅ PR created: $PR_URL"
else
echo "❌ Failed to create PR"
exit 1
fi
echo "=== Workflow complete ==="
Workflow 2: Review Comment Resolution
Workflow for addressing PR review comments:
#!/bin/bash
PR_NUMBER="146"
REPO="shabaraba/vibing.nvim"
SESSION_ID="${CLAUDE_SESSION_ID:-9GOGf}"
echo "=== Addressing review comments for PR #${PR_NUMBER} ==="
echo "Fetching PR details..."
PR_DATA=$(curl -s \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${REPO}/pulls/${PR_NUMBER}")
BASE_BRANCH=$(echo "$PR_DATA" | jq -r '.head.ref')
echo "Base branch: $BASE_BRANCH"
FIX_BRANCH="claude/fix-pr${PR_NUMBER}-${SESSION_ID}"
echo "Creating fix branch: $FIX_BRANCH"
git checkout -b "$FIX_BRANCH"
echo "Making fixes..."
git add .
git commit -m "fix: address review comments on PR #${PR_NUMBER}
- Fixed issue A
- Fixed issue B
"
echo "Pushing fix branch..."
for i in 0 1 2 3; do
if [ $i -gt 0 ]; then sleep $((2 ** i)); fi
if git push -u origin "$FIX_BRANCH"; then
break
fi
done
echo "Creating PR for fixes..."
curl -X POST \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${REPO}/pulls" \
-d "{
\"title\": \"fix: address review comments on PR #${PR_NUMBER}\",
\"head\": \"${FIX_BRANCH}\",
\"base\": \"${BASE_BRANCH}\",
\"body\": \"Addresses review comments on PR #${PR_NUMBER}.\"
}" | jq -r '.html_url // "Failed"'
echo "=== Review comment resolution complete ==="
Workflow 3: Multiple PR Creation
Create multiple PRs in one session:
#!/bin/bash
REPO="shabaraba/vibing.nvim"
SESSION_ID="${CLAUDE_SESSION_ID:-9GOGf}"
declare -a prs=(
"claude/fix-eslint-${SESSION_ID}|fix: import URL from url module|feat/granular-permissions-123|Resolves ESLint error"
"claude/improve-docs-${SESSION_ID}|docs: improve comments in ftplugin|feat/vibing-lsp-133|Clarifies documentation"
"claude/add-validation-${SESSION_ID}|feat: add language validation|feat/default-language-config-125|Adds validation"
)
echo "=== Creating ${#prs[@]} pull requests ==="
for pr_config in "${prs[@]}"; do
IFS='|' read -r branch title base body <<< "$pr_config"
echo ""
echo "Creating PR: $title"
echo " Branch: $branch"
echo " Base: $base"
PR_URL=$(curl -s -X POST \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${REPO}/pulls" \
-d "{
\"title\": \"${title}\",
\"head\": \"${branch}\",
\"base\": \"${base}\",
\"body\": \"${body}\"
}" | jq -r '.html_url // "Failed"')
if [[ "$PR_URL" == https://* ]]; then
echo " ✅ Created: $PR_URL"
else
echo " ❌ Failed"
fi
sleep 1
done
echo ""
echo "=== All PRs created ==="
Troubleshooting
Issue 1: HTTP 403 on Push
Symptom:
error: RPC failed; HTTP 403 curl 22 The requested URL returned error: 403
Cause: Branch name doesn't follow required pattern claude/*-<sessionId>
Solution:
CURRENT_BRANCH="$(git branch --show-current)"
echo "Current branch: $CURRENT_BRANCH"
SESSION_ID="${CLAUDE_SESSION_ID:-9GOGf}"
NEW_BRANCH="claude/${CURRENT_BRANCH}-${SESSION_ID}"
git checkout -b "$NEW_BRANCH"
git push -u origin "$NEW_BRANCH"
Issue 2: Network Timeout/Transient Failures
Symptom:
send-pack: unexpected disconnect while reading sideband packet
fatal: the remote end hung up unexpectedly
Cause: Transient network issues in web environment
Solution: Use retry logic (see Git Push Operations)
Issue 3: "Everything up-to-date" but Push Fails
Symptom:
error: RPC failed; HTTP 403
Everything up-to-date
Cause: Local branch is synced but network/auth issue prevents push confirmation
Solution: Safe to ignore if you see "Everything up-to-date" - your changes are already pushed
Issue 4: Cannot Create PR - No gh Command
Symptom:
gh: command not found
Cause: gh CLI is not available in Claude Code on the web
Solution: Use GitHub API instead (see Pull Request Creation)
Issue 5: Multiple Retry Failures
Symptom: All 4 retry attempts fail
Possible Causes:
- Branch name doesn't follow required pattern
- Network is down (rare)
- Repository permissions issue
Solution:
git branch --show-current
if [[ "$(git branch --show-current)" =~ ^claude/.+-[a-zA-Z0-9]+$ ]]; then
echo "✅ Branch name is valid"
else
echo "❌ Branch name is invalid"
fi
SESSION_ID="${CLAUDE_SESSION_ID:-9GOGf}"
git checkout -b "claude/fresh-branch-${SESSION_ID}"
git push -u origin "claude/fresh-branch-${SESSION_ID}"
Issue 6: PR Creation Returns Error
Symptom: API returns error instead of PR URL
Debug:
RESPONSE=$(curl -s -X POST \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/owner/repo/pulls" \
-d '{
"title": "Test PR",
"head": "claude/test-abc123",
"base": "main",
"body": "Test"
}')
echo "$RESPONSE" | jq .
Quick Reference
Essential Commands
git checkout -b "claude/my-feature-${CLAUDE_SESSION_ID:-9GOGf}"
for i in 0 1 2 3; do
[ $i -gt 0 ] && sleep $((2 ** i))
git push -u origin "$(git branch --show-current)" && break
done
curl -X POST \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/owner/repo/pulls" \
-d '{"title":"My PR","head":"claude/my-feature-abc","base":"main","body":"Description"}'
Validation Checklist
Before pushing:
Before creating PR: