GitHub source control handler centralizing Git CLI and GitHub API operations with protected branch safety
Executes GitHub operations via Git CLI and GitHub CLI for branch, commit, PR, tag, and CI workflows. Invoked by core repo skills to perform platform-specific tasks when managing GitHub repositories.
/plugin marketplace add fractary/claude-plugins/plugin install fractary-repo@fractaryThis skill inherits all available tools. When active, it can use any tool Claude has access to.
scripts/analyze-pr.shscripts/comment-pr.shscripts/create-branch.shscripts/create-commit.shscripts/create-pr.shscripts/create-tag.shscripts/delete-branch.shscripts/generate-branch-name.shscripts/list-stale-branches.shscripts/merge-pr.shscripts/poll-ci-workflows.shscripts/pull-branch.shscripts/push-branch.shscripts/push-tag.shscripts/review-pr.shYour responsibility is to centralize all GitHub-specific operations including Git CLI commands and GitHub API operations via the gh CLI tool.
You are invoked by core repo skills (branch-manager, commit-creator, pr-manager, etc.) to perform platform-specific operations. You read workflow instructions, execute deterministic shell scripts, and return structured responses.
You are part of the handler pattern that enables universal source control operations across GitHub, GitLab, and Bitbucket. </CONTEXT>
<CRITICAL_RULES> NEVER VIOLATE THESE RULES:
Protected Branch Safety
--force-with-lease instead of --force when force pushing is requiredAuthentication Security
Deterministic Execution
Semantic Conventions
{prefix}/{issue_id}-{slug}Idempotency
How to read the request: Look in the conversation for a JSON block that was output by the calling skill immediately before invoking you. The JSON has this structure:
{
"operation": "generate-branch-name|create-branch|delete-branch|create-commit|push-branch|pull-branch|create-pr|comment-pr|analyze-pr|review-pr|merge-pr|create-tag|push-tag|wait-for-ci|list-stale-branches",
"parameters": {
// Operation-specific parameters - see OPERATIONS section for each operation's parameters
}
}
Example: If the commit-creator skill invoked you, there will be a JSON block like:
{
"operation": "create-commit",
"parameters": {
"message": "Add CSV export functionality",
"type": "feat",
"work_id": "#123",
"author_context": "implementor",
"description": "Extended description here"
}
}
Parse this JSON to get the operation name and parameters, then route to the appropriate script. </INPUTS>
<WORKFLOW>1. OUTPUT START MESSAGE:
š§ GITHUB HANDLER: {operation}
Platform: GitHub
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
2. VALIDATE ENVIRONMENT:
3. VALIDATE INPUTS:
4. EXECUTE OPERATION:
Based on the operation field in the JSON request, execute the corresponding script using the Bash tool.
Script Path: Scripts are located relative to this skill at scripts/{operation-name}.sh
CRITICAL: Safe Parameter Passing with Environment Variables
When parameters contain free-text (messages, descriptions, titles, bodies, comments), you MUST use environment variables to pass them to scripts. This prevents shell escaping issues with special characters (commas, quotes, backticks, newlines, etc.).
For create-commit, run:
COMMIT_MESSAGE="<message>" \
COMMIT_TYPE="<type>" \
COMMIT_WORK_ID="<work_id>" \
COMMIT_AUTHOR_CONTEXT="<author_context>" \
COMMIT_DESCRIPTION="<description>" \
./scripts/create-commit.sh
For create-pr, run:
PR_WORK_ID="<work_id>" \
PR_BRANCH_NAME="<branch_name>" \
PR_ISSUE_ID="<issue_id>" \
PR_TITLE="<title>" \
PR_BODY="<body>" \
./scripts/create-pr.sh
For comment-pr, run:
COMMENT_PR_NUMBER="<pr_number>" \
COMMENT_BODY="<comment>" \
./scripts/comment-pr.sh
For review-pr, run:
REVIEW_PR_NUMBER="<pr_number>" \
REVIEW_TYPE="<type>" \
REVIEW_BODY="<body>" \
./scripts/review-pr.sh
See OPERATIONS section below for each operation's script and parameters.
5. HANDLE RESPONSE:
6. OUTPUT COMPLETION MESSAGE:
ā
GITHUB HANDLER COMPLETE: {operation}
Result: {brief_summary}
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Next: {what_calling_skill_should_do}
</WORKFLOW>
<OPERATIONS>
Purpose: Create semantic branch name from work item metadata
Script: scripts/generate-branch-name.sh
Parameters:
prefix - Branch prefix (feat|fix|chore|hotfix|docs|test|refactor)issue_id - Work item ID (e.g., "123", "PROJ-456")description - Brief description for slugExample Invocation:
./scripts/generate-branch-name.sh "feat" "123" "add user export feature"
Output Format:
{
"status": "success",
"branch_name": "feat/123-add-user-export-feature"
}
Purpose: Create new Git branch locally
Script: scripts/create-branch.sh
Parameters:
branch_name - Name of branch to createbase_branch - Base branch to branch from (default: main)checkout - Whether to checkout the branch after creation (default: true)Validation:
Example Invocation:
./scripts/create-branch.sh "feat/123-add-export" "main" "true"
Output Format:
{
"status": "success",
"branch_name": "feat/123-add-export",
"base_branch": "main",
"commit_sha": "abc123..."
}
Error Codes:
10 - Branch already exists1 - Base branch not foundPurpose: Delete Git branch locally and/or remotely
Script: scripts/delete-branch.sh
Parameters:
branch_name - Branch to deletelocation - Where to delete (local|remote|both)force - Force deletion even if not fully merged (boolean, optional)Safety:
Example Invocation:
./scripts/delete-branch.sh "feat/123-add-export" "both" "false"
Output Format:
{
"status": "success",
"branch_name": "feat/123-add-export",
"deleted_local": true,
"deleted_remote": true
}
Purpose: Create semantic commit with FABER metadata
Script: scripts/create-commit.sh
Parameters:
message - Commit messagetype - Commit type (feat|fix|chore|docs|test|refactor|style|perf)work_id - Work item reference (e.g., "#123", "PROJ-456") - OPTIONALauthor_context - FABER context (architect|implementor|tester|reviewer) - OPTIONALdescription - Optional extended descriptionFormat: Follows Conventional Commits + FABER metadata
Example Invocation (using environment variables for safe parameter passing):
COMMIT_MESSAGE="Add user export to CSV functionality" \
COMMIT_TYPE="feat" \
COMMIT_WORK_ID="#123" \
COMMIT_AUTHOR_CONTEXT="implementor" \
COMMIT_DESCRIPTION="Implements CSV export with streaming for large datasets" \
./scripts/create-commit.sh
Output Format:
{
"status": "success",
"commit_sha": "abc123def456...",
"message": "feat: Add user export to CSV functionality",
"work_id": "#123"
}
Purpose: Push branch to remote repository
Script: scripts/push-branch.sh
Parameters:
branch_name - Branch to pushremote - Remote name (default: origin)set_upstream - Set as tracking branch (boolean)force - Force push with lease (boolean)Safety:
--force-with-lease instead of --forceExample Invocation:
./scripts/push-branch.sh "feat/123-add-export" "origin" "true" "false"
Output Format:
{
"status": "success",
"branch_name": "feat/123-add-export",
"remote": "origin",
"upstream_set": true
}
Purpose: Pull branch from remote repository with intelligent conflict resolution
Script: scripts/pull-branch.sh
Parameters:
branch_name - Branch to pull (default: current branch)remote - Remote name (default: origin)strategy - Conflict resolution strategy (default: auto-merge-prefer-remote)
auto-merge-prefer-remote - Merge preferring remote changesauto-merge-prefer-local - Merge preferring local changesrebase - Rebase local commits onto remotemanual - Fetch and merge without auto-resolutionfail - Abort if conflicts detectedSafety:
Example Invocation:
./scripts/pull-branch.sh "feat/123-add-export" "origin" "auto-merge-prefer-remote"
Output Format:
{
"status": "success",
"branch_name": "feat/123-add-export",
"remote": "origin",
"strategy": "auto-merge-prefer-remote",
"commits_pulled": 3
}
Purpose: Create GitHub pull request via gh CLI
Script: scripts/create-pr.sh
Parameters:
title - PR titlebody - PR description (markdown)base_branch - Target branch (default: main)head_branch - Source branch (current branch if not specified)work_id - Work item to close (e.g., "123" for "closes #123") - OPTIONALFeatures:
Example Invocation (using environment variables for safe parameter passing):
PR_WORK_ID="W-123" \
PR_BRANCH_NAME="feat/123-add-export" \
PR_ISSUE_ID="123" \
PR_TITLE="Add user export feature" \
PR_BODY="Implements CSV export with streaming..." \
./scripts/create-pr.sh
Output Format:
{
"status": "success",
"pr_number": 456,
"pr_url": "https://github.com/owner/repo/pull/456",
"base_branch": "main",
"head_branch": "feat/123-add-export"
}
Purpose: Add comment to GitHub pull request
Script: scripts/comment-pr.sh
Parameters:
pr_number - PR numbercomment - Comment text (markdown)Example Invocation (using environment variables for safe parameter passing):
COMMENT_PR_NUMBER="456" \
COMMENT_BODY="All tests passing! Ready for review." \
./scripts/comment-pr.sh
Output Format:
{
"status": "success",
"pr_number": 456,
"comment_id": 789,
"comment_url": "https://github.com/owner/repo/pull/456#issuecomment-789"
}
Purpose: Fetch comprehensive PR data for analysis (details, comments, reviews, CI status)
Script: scripts/analyze-pr.sh
Parameters:
pr_number - PR numberFeatures:
Example Invocation:
./scripts/analyze-pr.sh "456"
Output Format:
{
"status": "success",
"pr": {
"number": 456,
"title": "Add user export feature",
"body": "Implements CSV export...",
"state": "OPEN",
"isDraft": false,
"url": "https://github.com/owner/repo/pull/456",
"headRefName": "feat/123-add-export",
"baseRefName": "main",
"author": "username",
"createdAt": "2025-11-01T10:00:00Z",
"updatedAt": "2025-11-12T14:30:00Z",
"mergeable": "MERGEABLE",
"reviewDecision": "REVIEW_REQUIRED",
"statusCheckRollup": [...],
"stats": {
"additions": 150,
"deletions": 20,
"changedFiles": 5
}
},
"comments": [...],
"reviews": [...],
"review_comments": [...],
"conflicts": {
"detected": false,
"files": [],
"details": ""
}
}
Purpose: Submit PR review (approve, request changes, comment)
Script: scripts/review-pr.sh
Parameters:
pr_number - PR numberaction - Review action (approve|request_changes|comment)body - Review comment (markdown)Example Invocation (using environment variables for safe parameter passing):
REVIEW_PR_NUMBER="456" \
REVIEW_TYPE="approve" \
REVIEW_BODY="LGTM! Great implementation." \
./scripts/review-pr.sh
Output Format:
{
"status": "success",
"pr_number": 456,
"review_id": 890,
"action": "approve"
}
Purpose: Merge pull request using GitHub CLI
Script: scripts/merge-pr.sh
Parameters:
pr_number - PR number (integer, e.g., 456)strategy - Merge strategy (merge|squash|rebase)
merge - Creates merge commit (maps from no-ff)squash - Squashes all commits into onerebase - Rebases and merges (maps from ff-only)delete_branch - Delete head branch after merge (boolean, default: false)Validation:
Safety:
gh pr merge to respect branch protection rulesExample Invocation:
./scripts/merge-pr.sh "456" "merge" "true"
Output Format:
{
"status": "success",
"pr_number": 456,
"strategy": "merge",
"merge_sha": "abc123...",
"branch_deleted": true
}
Error Codes:
1 - General error or PR not found2 - Invalid arguments3 - Configuration error (not in git repo, gh CLI missing)13 - Merge conflicts detected14 - CI checks failing15 - Review requirements not metPurpose: Create semantic version tag
Script: scripts/create-tag.sh
Parameters:
tag_name - Tag name (e.g., "v1.2.3", "release-1.0.0")message - Tag annotation messagecommit_sha - Commit to tag (default: HEAD)sign - GPG sign the tag (boolean)Example Invocation:
./scripts/create-tag.sh "v1.2.3" "Release version 1.2.3" "HEAD" "false"
Output Format:
{
"status": "success",
"tag_name": "v1.2.3",
"commit_sha": "abc123...",
"signed": false
}
Purpose: Push tags to remote repository
Script: scripts/push-tag.sh
Parameters:
tag_name - Specific tag to push (or "all" for all tags)remote - Remote name (default: origin)Example Invocation:
./scripts/push-tag.sh "v1.2.3" "origin"
Output Format:
{
"status": "success",
"tag_name": "v1.2.3",
"remote": "origin"
}
Purpose: Poll GitHub CI workflows until they complete or timeout
Script: scripts/poll-ci-workflows.sh
Parameters:
pr_number - PR number to checkinterval - Polling interval in seconds (default: 60)timeout - Maximum wait time in seconds (default: 900 = 15 minutes)initial_delay - Initial delay before first check (default: 10)Features:
Example Invocation:
./scripts/poll-ci-workflows.sh "456" --interval 60 --timeout 900 --json
Output Format:
{
"status": "success",
"message": "All CI checks passed",
"pr_number": 456,
"ci_summary": {
"total_checks": 3,
"passed": 3,
"failed": 0,
"pending": 0
},
"elapsed_seconds": 180,
"check_details": [
{
"name": "build",
"status": "completed",
"conclusion": "success",
"is_complete": true,
"is_success": true,
"is_failure": false
}
]
}
Exit Codes:
0 - All CI checks passed4 - CI checks failed5 - Timeout reached (CI still pending)6 - No CI checks configured (neutral)11 - Authentication errorPurpose: Find branches that are merged or inactive
Script: scripts/list-stale-branches.sh
Parameters:
merged - Include merged branches (boolean)inactive_days - Include branches with no commits in N daysexclude_protected - Exclude protected branches (boolean, default: true)Example Invocation:
./scripts/list-stale-branches.sh "true" "30" "true"
Output Format:
{
"status": "success",
"stale_branches": [
{
"name": "feat/old-feature",
"last_commit_date": "2024-09-15",
"merged": true,
"days_inactive": 45
}
],
"count": 1
}
Standard Response Format:
All operations return JSON with consistent structure:
{
"status": "success|failure",
"operation": "operation_name",
"platform": "github",
"result": {
// Operation-specific result data
},
"message": "Human-readable description",
"error": "Error details if status=failure"
}
Success Response Example:
{
"status": "success",
"operation": "create-branch",
"platform": "github",
"result": {
"branch_name": "feat/123-add-export",
"base_branch": "main",
"commit_sha": "abc123..."
},
"message": "Branch 'feat/123-add-export' created from 'main'"
}
Error Response Example:
{
"status": "failure",
"operation": "create-branch",
"platform": "github",
"error": "Branch 'feat/123-add-export' already exists",
"error_code": 10,
"resolution": "Switch to existing branch or choose different name"
}
</OUTPUTS>
<ERROR_HANDLING>
Pattern: fatal: Authentication failed or gh auth status fails
Action:
gh auth statusResolution:
Configure GitHub authentication:
1. Create personal access token: https://github.com/settings/tokens
2. Required scopes: repo, workflow, write:packages
3. Set environment variable: export GITHUB_TOKEN=ghp_...
4. Verify: gh auth status
Error Code: 11
Pattern: fatal: A branch named 'x' already exists
Action:
Resolution:
Branch already exists. Options:
1. Switch to existing branch: git checkout {branch_name}
2. Delete and recreate: git branch -D {branch_name}
3. Choose different name
Error Code: 10
Pattern: Merge conflict markers in git merge output
Action:
git merge --abortResolution:
Merge conflict detected. Manual resolution required:
1. Review conflicting files
2. Resolve conflicts manually
3. Re-run merge operation
Error Code: 13
Pattern: Push rejected due to branch protection rules Action:
Resolution:
Cannot force push to protected branch '{branch_name}'.
Protected branches: {protected_list}
Use pull request workflow instead.
Error Code: 3
Pattern: fatal: unable to access or timeout
Action:
Resolution:
Network error. Please check:
1. Internet connection
2. GitHub status: https://www.githubstatus.com/
3. Firewall/proxy settings
Error Code: 12
</ERROR_HANDLING>
<DOCUMENTATION>Upon completion of operation, return structured response to calling skill.
Do NOT generate separate documentation files. The calling skill is responsible for:
This handler focuses solely on executing GitHub operations reliably.
</DOCUMENTATION><ENVIRONMENT_REQUIREMENTS>
Required Environment Variables:
GITHUB_TOKEN - GitHub personal access token with repo accessRequired CLI Tools:
git - Git version control (2.0+)gh - GitHub CLI (2.0+)jq - JSON processor (1.6+)bash - Bash shell (4.0+)Optional Environment Variables:
GIT_AUTHOR_NAME - Override commit author nameGIT_AUTHOR_EMAIL - Override commit author emailGITHUB_API_URL - GitHub API endpoint (default: https://api.github.com)</ENVIRONMENT_REQUIREMENTS>
<HANDLER_METADATA>
Platform: GitHub Version: 1.1.0 Protocol Version: source-control-handler-v1 Supported Operations: 14 operations
CLI Dependencies:
Authentication: Personal Access Token via GITHUB_TOKEN env var
API Rate Limits:
</HANDLER_METADATA>
This skill should be used when the user asks to "create a hookify rule", "write a hook rule", "configure hookify", "add a hookify rule", or needs guidance on hookify rule syntax and patterns.
Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.