name: "Claude Code Action Official" description: "General-purpose Claude agent for GitHub PRs and issues. Can answer questions and implement code changes." branding: icon: "at-sign" color: "orange" inputs: trigger_phrase: description: "The trigger phrase to look for in comments or issue body" required: false default: "@claude" assignee_trigger: description: "The assignee username that triggers the action (e.g. @claude)" required: false label_trigger: description: "The label that triggers the action (e.g. claude)" required: false default: "claude" base_branch: description: "The branch to use as the base/source when creating new branches (defaults to repository default branch)" required: false branch_prefix: description: "The prefix to use for Claude branches (defaults to 'claude/', use 'claude-' for dash format)" required: false default: "claude/" allowed_bots: description: "Comma-separated list of allowed bot usernames, or '*' to allow all bots. Empty string (default) allows no bots." required: false default: "" # Mode configuration mode: description: "Execution mode for the action. Valid modes: 'tag' (default - triggered by mentions/assignments), 'agent' (for automation with no trigger checking), 'experimental-review' (experimental mode for code reviews with inline comments and suggestions)" required: false default: "tag" # Claude Code configuration model: description: "Model to use (provider-specific format required for Bedrock/Vertex)" required: false anthropic_model: description: "DEPRECATED: Use 'model' instead. Model to use (provider-specific format required for Bedrock/Vertex)" required: false fallback_model: description: "Enable automatic fallback to specified model when primary model is unavailable" required: false allowed_tools: description: "Additional tools for Claude to use (the base GitHub tools will always be included)" required: false default: "" disallowed_tools: description: "Tools that Claude should never use" required: false default: "" custom_instructions: description: "Additional custom instructions to include in the prompt for Claude" required: false default: "" direct_prompt: description: "Direct instruction for Claude (bypasses normal trigger detection)" required: false default: "" override_prompt: description: "Complete replacement of Claude's prompt with custom template (supports variable substitution)" required: false default: "" mcp_config: description: "Additional MCP configuration (JSON string) that merges with the built-in GitHub MCP servers" additional_permissions: description: "Additional permissions to enable. Currently supports 'actions: read' for viewing workflow results" required: false default: "" claude_env: description: "Custom environment variables to pass to Claude Code execution (YAML format)" required: false default: "" settings: description: "Claude Code settings as JSON string or path to settings JSON file" required: false default: "" # Auth configuration anthropic_api_key: description: "Anthropic API key (required for direct API, not needed for Bedrock/Vertex)" required: false claude_code_oauth_token: description: "Claude Code OAuth token (alternative to anthropic_api_key)" required: false github_token: description: "GitHub token with repo and pull request permissions (optional if using GitHub App)" required: false use_bedrock: description: "Use Amazon Bedrock with OIDC authentication instead of direct Anthropic API" required: false default: "false" use_vertex: description: "Use Google Vertex AI with OIDC authentication instead of direct Anthropic API" required: false default: "false" max_turns: description: "Maximum number of conversation turns" required: false default: "" timeout_minutes: description: "Timeout in minutes for execution" required: false default: "30" use_sticky_comment: description: "Use just one comment to deliver issue/PR comments" required: false default: "false" use_commit_signing: description: "Enable commit signing using GitHub's commit signature verification. When false, Claude uses standard git commands" required: false default: "false" experimental_allowed_domains: description: "Restrict network access to these domains only (newline-separated). If not set, no restrictions are applied. Provider domains are auto-detected." required: false default: "" path_to_claude_code_executable: description: "Optional path to a custom Claude Code executable. If provided, skips automatic installation and uses this executable instead. WARNING: Using an older version may cause problems if the action begins taking advantage of new Claude Code features. This input is typically not needed unless you're debugging something specific or have unique needs in your environment." required: false default: "" path_to_bun_executable: description: "Optional path to a custom Bun executable. If provided, skips automatic Bun installation and uses this executable instead. WARNING: Using an incompatible version may cause problems if the action requires specific Bun features. This input is typically not needed unless you're debugging something specific or have unique needs in your environment." required: false default: "" outputs: execution_file: description: "Path to the Claude Code execution output file" value: ${{ steps.claude-code.outputs.execution_file }} branch_name: description: "The branch created by Claude Code for this execution" value: ${{ steps.prepare.outputs.CLAUDE_BRANCH }} runs: using: "composite" steps: - name: Install Bun if: inputs.path_to_bun_executable == '' uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # https://github.com/oven-sh/setup-bun/releases/tag/v2.0.2 with: bun-version: 1.2.11 - name: Setup Custom Bun Path if: inputs.path_to_bun_executable != '' shell: bash run: | echo "Using custom Bun executable: ${{ inputs.path_to_bun_executable }}" # Add the directory containing the custom executable to PATH BUN_DIR=$(dirname "${{ inputs.path_to_bun_executable }}") echo "$BUN_DIR" >> "$GITHUB_PATH" - name: Install Dependencies shell: bash run: | cd ${GITHUB_ACTION_PATH} bun install - name: Prepare action id: prepare shell: bash run: | bun run ${GITHUB_ACTION_PATH}/src/entrypoints/prepare.ts env: MODE: ${{ inputs.mode }} TRIGGER_PHRASE: ${{ inputs.trigger_phrase }} ASSIGNEE_TRIGGER: ${{ inputs.assignee_trigger }} LABEL_TRIGGER: ${{ inputs.label_trigger }} BASE_BRANCH: ${{ inputs.base_branch }} BRANCH_PREFIX: ${{ inputs.branch_prefix }} ALLOWED_TOOLS: ${{ inputs.allowed_tools }} DISALLOWED_TOOLS: ${{ inputs.disallowed_tools }} CUSTOM_INSTRUCTIONS: ${{ inputs.custom_instructions }} DIRECT_PROMPT: ${{ inputs.direct_prompt }} OVERRIDE_PROMPT: ${{ inputs.override_prompt }} MCP_CONFIG: ${{ inputs.mcp_config }} OVERRIDE_GITHUB_TOKEN: ${{ inputs.github_token }} ALLOWED_BOTS: ${{ inputs.allowed_bots }} GITHUB_RUN_ID: ${{ github.run_id }} USE_STICKY_COMMENT: ${{ inputs.use_sticky_comment }} DEFAULT_WORKFLOW_TOKEN: ${{ github.token }} ADDITIONAL_PERMISSIONS: ${{ inputs.additional_permissions }} USE_COMMIT_SIGNING: ${{ inputs.use_commit_signing }} ALL_INPUTS: ${{ toJson(inputs) }} - name: Install Base Action Dependencies if: steps.prepare.outputs.contains_trigger == 'true' shell: bash run: | echo "Installing base-action dependencies..." cd ${GITHUB_ACTION_PATH}/base-action bun install echo "Base-action dependencies installed" cd - # Install Claude Code if no custom executable is provided if [ -z "${{ inputs.path_to_claude_code_executable }}" ]; then echo "Installing Claude Code..." curl -fsSL https://claude.ai/install.sh | bash -s 1.0.90 echo "$HOME/.local/bin" >> "$GITHUB_PATH" else echo "Using custom Claude Code executable: ${{ inputs.path_to_claude_code_executable }}" # Add the directory containing the custom executable to PATH CLAUDE_DIR=$(dirname "${{ inputs.path_to_claude_code_executable }}") echo "$CLAUDE_DIR" >> "$GITHUB_PATH" fi - name: Setup Network Restrictions if: steps.prepare.outputs.contains_trigger == 'true' && inputs.experimental_allowed_domains != '' shell: bash run: | chmod +x ${GITHUB_ACTION_PATH}/scripts/setup-network-restrictions.sh ${GITHUB_ACTION_PATH}/scripts/setup-network-restrictions.sh env: EXPERIMENTAL_ALLOWED_DOMAINS: ${{ inputs.experimental_allowed_domains }} - name: Run Claude Code id: claude-code if: steps.prepare.outputs.contains_trigger == 'true' shell: bash run: | # Run the base-action bun run ${GITHUB_ACTION_PATH}/base-action/src/index.ts env: # Base-action inputs CLAUDE_CODE_ACTION: "1" INPUT_PROMPT_FILE: ${{ runner.temp }}/claude-prompts/claude-prompt.txt INPUT_ALLOWED_TOOLS: ${{ env.ALLOWED_TOOLS }} INPUT_DISALLOWED_TOOLS: ${{ env.DISALLOWED_TOOLS }} INPUT_MAX_TURNS: ${{ inputs.max_turns }} INPUT_MCP_CONFIG: ${{ steps.prepare.outputs.mcp_config }} INPUT_SETTINGS: ${{ inputs.settings }} INPUT_SYSTEM_PROMPT: "" INPUT_APPEND_SYSTEM_PROMPT: ${{ env.APPEND_SYSTEM_PROMPT }} INPUT_TIMEOUT_MINUTES: ${{ inputs.timeout_minutes }} INPUT_CLAUDE_ENV: ${{ inputs.claude_env }} INPUT_FALLBACK_MODEL: ${{ inputs.fallback_model }} INPUT_EXPERIMENTAL_SLASH_COMMANDS_DIR: ${{ github.action_path }}/slash-commands INPUT_ACTION_INPUTS_PRESENT: ${{ steps.prepare.outputs.action_inputs_present }} INPUT_PATH_TO_CLAUDE_CODE_EXECUTABLE: ${{ inputs.path_to_claude_code_executable }} INPUT_PATH_TO_BUN_EXECUTABLE: ${{ inputs.path_to_bun_executable }} # Model configuration ANTHROPIC_MODEL: ${{ inputs.model || inputs.anthropic_model }} GITHUB_TOKEN: ${{ steps.prepare.outputs.GITHUB_TOKEN }} NODE_VERSION: ${{ env.NODE_VERSION }} DETAILED_PERMISSION_MESSAGES: "1" # Provider configuration ANTHROPIC_API_KEY: ${{ inputs.anthropic_api_key }} CLAUDE_CODE_OAUTH_TOKEN: ${{ inputs.claude_code_oauth_token }} ANTHROPIC_BASE_URL: ${{ env.ANTHROPIC_BASE_URL }} CLAUDE_CODE_USE_BEDROCK: ${{ inputs.use_bedrock == 'true' && '1' || '' }} CLAUDE_CODE_USE_VERTEX: ${{ inputs.use_vertex == 'true' && '1' || '' }} # AWS configuration AWS_REGION: ${{ env.AWS_REGION }} AWS_ACCESS_KEY_ID: ${{ env.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ env.AWS_SECRET_ACCESS_KEY }} AWS_SESSION_TOKEN: ${{ env.AWS_SESSION_TOKEN }} ANTHROPIC_BEDROCK_BASE_URL: ${{ env.ANTHROPIC_BEDROCK_BASE_URL || (env.AWS_REGION && format('https://bedrock-runtime.{0}.amazonaws.com', env.AWS_REGION)) }} # GCP configuration ANTHROPIC_VERTEX_PROJECT_ID: ${{ env.ANTHROPIC_VERTEX_PROJECT_ID }} CLOUD_ML_REGION: ${{ env.CLOUD_ML_REGION }} GOOGLE_APPLICATION_CREDENTIALS: ${{ env.GOOGLE_APPLICATION_CREDENTIALS }} ANTHROPIC_VERTEX_BASE_URL: ${{ env.ANTHROPIC_VERTEX_BASE_URL }} # Model-specific regions for Vertex VERTEX_REGION_CLAUDE_3_5_HAIKU: ${{ env.VERTEX_REGION_CLAUDE_3_5_HAIKU }} VERTEX_REGION_CLAUDE_3_5_SONNET: ${{ env.VERTEX_REGION_CLAUDE_3_5_SONNET }} VERTEX_REGION_CLAUDE_3_7_SONNET: ${{ env.VERTEX_REGION_CLAUDE_3_7_SONNET }} - name: Update comment with job link if: steps.prepare.outputs.contains_trigger == 'true' && steps.prepare.outputs.claude_comment_id && always() shell: bash run: | bun run ${GITHUB_ACTION_PATH}/src/entrypoints/update-comment-link.ts env: REPOSITORY: ${{ github.repository }} PR_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }} CLAUDE_COMMENT_ID: ${{ steps.prepare.outputs.claude_comment_id }} GITHUB_RUN_ID: ${{ github.run_id }} GITHUB_TOKEN: ${{ steps.prepare.outputs.GITHUB_TOKEN }} GITHUB_EVENT_NAME: ${{ github.event_name }} TRIGGER_COMMENT_ID: ${{ github.event.comment.id }} CLAUDE_BRANCH: ${{ steps.prepare.outputs.CLAUDE_BRANCH }} IS_PR: ${{ github.event.issue.pull_request != null || github.event_name == 'pull_request_review_comment' }} BASE_BRANCH: ${{ steps.prepare.outputs.BASE_BRANCH }} CLAUDE_SUCCESS: ${{ steps.claude-code.outputs.conclusion == 'success' }} OUTPUT_FILE: ${{ steps.claude-code.outputs.execution_file || '' }} TRIGGER_USERNAME: ${{ github.event.comment.user.login || github.event.issue.user.login || github.event.pull_request.user.login || github.event.sender.login || github.triggering_actor || github.actor || '' }} PREPARE_SUCCESS: ${{ steps.prepare.outcome == 'success' }} PREPARE_ERROR: ${{ steps.prepare.outputs.prepare_error || '' }} USE_STICKY_COMMENT: ${{ inputs.use_sticky_comment }} USE_COMMIT_SIGNING: ${{ inputs.use_commit_signing }} - name: Display Claude Code Report if: steps.prepare.outputs.contains_trigger == 'true' && steps.claude-code.outputs.execution_file != '' shell: bash run: | # Try to format the turns, but if it fails, dump the raw JSON if bun run ${{ github.action_path }}/src/entrypoints/format-turns.ts "${{ steps.claude-code.outputs.execution_file }}" >> $GITHUB_STEP_SUMMARY 2>/dev/null; then echo "Successfully formatted Claude Code report" else echo "## Claude Code Report (Raw Output)" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "Failed to format output (please report). Here's the raw JSON:" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '```json' >> $GITHUB_STEP_SUMMARY cat "${{ steps.claude-code.outputs.execution_file }}" >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY fi - name: Revoke app token if: always() && inputs.github_token == '' && steps.prepare.outputs.skipped_due_to_workflow_validation_mismatch != 'true' shell: bash run: | curl -L \ -X DELETE \ -H "Accept: application/vnd.github+json" \ -H "Authorization: Bearer ${{ steps.prepare.outputs.GITHUB_TOKEN }}" \ -H "X-GitHub-Api-Version: 2022-11-28" \ ${GITHUB_API_URL:-https://api.github.com}/installation/token