Claude Code GitHub Actions Notification (2026)
Setting up notifications for GitHub Actions when working with Claude Code ensures you stay informed about workflow status, test results, and deployment outcomes. This guide walks you through configuring notifications across multiple channels.
Why Configure GitHub Actions Notifications
When Claude Code executes workflows through skills like the TDD skill or automation pipelines, you need visibility into what happens in your CI/CD environment. Without proper notifications, you might miss failed builds, broken tests, or successful deployments that require your attention.
GitHub Actions provides native notification mechanisms, but extending these to Slack, Discord, email, or custom webhooks gives you flexibility. The setup involves understanding workflow triggers, artifact handling, and notification channels.
Notification strategy also scales with team size. A solo developer might only need GitHub’s built-in email alerts, but a team of fifteen engineers shipping to production multiple times per day needs structured routing: failures go to an on-call channel, deploy confirmations go to a product channel, and weekly summaries get emailed to stakeholders. Claude Code workflows add another dimension because automated AI-driven tasks may run outside business hours, making async notification delivery even more important.
Notification Channel Comparison
Before writing a single line of YAML, choose your notification target based on your team’s actual workflow:
| Channel | Setup Complexity | Real-Time | Rich Formatting | Cost | Best For |
|---|---|---|---|---|---|
| GitHub Email (native) | None | No (batched) | No | Free | Solo devs, simple projects |
| Slack (webhook) | Low | Yes | Yes (blocks) | Free tier available | Team CI alerts |
| Discord (webhook) | Low | Yes | Yes (embeds) | Free | Open-source, community projects |
| Microsoft Teams | Medium | Yes | Yes (cards) | Free with M365 | Enterprise orgs |
| PagerDuty | High | Yes | Limited | Paid | On-call escalation |
| Custom HTTP webhook | Medium | Yes | You control | Free | Internal dashboards |
For most Claude Code users running automated pipelines, Slack or Discord gives the best signal-to-noise ratio with minimal configuration overhead.
Basic GitHub Actions Notification Workflow
The foundation of notification setup starts with your workflow file. Here’s a basic configuration that triggers on workflow completion:
name: Claude Code Build Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Claude Code Task
run: |
# Your Claude Code execution here
claude --print "$(cat CLAUDE.md)"
- name: Run Tests
run: npm test
- name: Upload Results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results
path: test-results/
The if: always() condition ensures artifacts upload regardless of success or failure, which is critical for debugging.
Understanding Job-Level vs Step-Level Notifications
A common mistake is placing notification steps only at the job level and losing granularity. Consider this expanded structure that gives you step-level insight:
jobs:
build:
runs-on: ubuntu-latest
outputs:
test_status: ${{ steps.tests.outcome }}
deploy_status: ${{ steps.deploy.outcome }}
steps:
- uses: actions/checkout@v4
- name: Run Tests
id: tests
run: npm test
- name: Deploy
id: deploy
if: success()
run: ./scripts/deploy.sh
- name: Notify with Step Details
if: always()
uses: 8398a7/action-slack@v3
with:
status: custom
custom_payload: |
{
"text": "Build complete for ${{ github.repository }}",
"attachments": [{
"color": "${{ job.status == 'success' && 'good' || 'danger' }}",
"fields": [
{"title": "Tests", "value": "${{ steps.tests.outcome }}", "short": true},
{"title": "Deploy", "value": "${{ steps.deploy.outcome }}", "short": true},
{"title": "Branch", "value": "${{ github.ref_name }}", "short": true},
{"title": "Triggered by", "value": "${{ github.actor }}", "short": true}
]
}]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
Exposing step-level outcomes via outputs and steps.<id>.outcome means your notification payload carries actionable detail rather than just pass or fail.
Slack Notification Configuration
Slack remains popular for team notifications. Create an incoming webhook in your Slack workspace, then add a notification step:
- name: Notify Slack
if: always()
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
fields: repo,message,commit,author,action
channel: '#ci-notifications'
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
For more detailed notifications, customize message formatting with a raw curl call:
- name: Custom Slack Message
if: failure()
run: |
curl -X POST -H 'Content-type: application/json' \
--data '{"text":"Build failed: ${{ github.repository }} - ${{ github.workflow }}"}' \
${{ secrets.SLACK_WEBHOOK_URL }}
Advanced Slack Block Kit Formatting
Slack’s Block Kit format lets you build visually structured notifications with buttons, dividers, and context sections. This level of detail is especially valuable for Claude Code pipelines that run multi-step AI tasks:
- name: Rich Slack Notification
if: always()
run: |
STATUS_EMOJI="${{ job.status == 'success' && ':white_check_mark:' || ':x:' }}"
STATUS_COLOR="${{ job.status == 'success' && '#36a64f' || '#e01e5a' }}"
RUN_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
curl -X POST -H 'Content-type: application/json' \
--data "{
\"attachments\": [{
\"color\": \"${STATUS_COLOR}\",
\"blocks\": [
{
\"type\": \"header\",
\"text\": {
\"type\": \"plain_text\",
\"text\": \"${STATUS_EMOJI} ${{ github.workflow }}\"
}
},
{
\"type\": \"section\",
\"fields\": [
{\"type\": \"mrkdwn\", \"text\": \"*Repository*\n${{ github.repository }}\"},
{\"type\": \"mrkdwn\", \"text\": \"*Branch*\n${{ github.ref_name }}\"},
{\"type\": \"mrkdwn\", \"text\": \"*Commit*\n\`${{ github.sha }}\`\"},
{\"type\": \"mrkdwn\", \"text\": \"*Triggered by*\n${{ github.actor }}\"}
]
},
{
\"type\": \"actions\",
\"elements\": [{
\"type\": \"button\",
\"text\": {\"type\": \"plain_text\", \"text\": \"View Run\"},
\"url\": \"${RUN_URL}\"
}]
}
]
}]
}" \
${{ secrets.SLACK_WEBHOOK_URL }}
If you use the Slack MCP server with Claude Code, you can further automate response handling when notifications arrive, enabling you to trigger Claude Code actions directly from Slack messages.
Discord Webhook Notifications
Discord offers similar functionality with its webhook system:
- name: Discord Notification
if: always()
run: |
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"content": null,
"embeds": [{
"title": "Workflow ${{ job.status }}",
"description": "${{ github.repository }} - ${{ github.workflow }}",
"color": ${{ job.status == 'success' && 3066993 || 15158332 }},
"fields": [
{"name": "Branch", "value": "${{ github.ref }}", "inline": true},
{"name": "Commit", "value": "${{ github.sha }}", "inline": true}
]
}]
}' \
${{ secrets.DISCORD_WEBHOOK_URL }}
Discord Color Reference
Discord embeds use decimal integer color codes. Here are the most useful values for CI status notifications:
| Status | Hex | Decimal | Use Case |
|---|---|---|---|
| Success | #2ECC71 |
3066993 | Build passed |
| Failure | #E74C3C |
15158332 | Build failed |
| Warning | #F39C12 |
15968802 | Flaky tests, slow build |
| Cancelled | #95A5A6 |
9807322 | Manual cancellation |
| In Progress | #3498DB |
3447003 | Long-running jobs |
Using consistent colors across your Discord server makes it easy to scan notification history at a glance.
Email Notifications with GitHub
For teams preferring email, GitHub’s native notification system works well. Configure branch protection rules to require status checks, then subscribe to workflow run notifications:
- Go to your repository Settings
- Click Notifications
- Enable “Workflow runs” under GitHub Actions
For custom email handling with templates, use a GitHub App or action:
- name: Send Email Notification
if: failure()
uses: dawidd6/action-send-mail@v3
with:
server_address: smtp.gmail.com
server_port: 465
username: ${{ secrets.MAIL_USERNAME }}
password: ${{ secrets.MAIL_PASSWORD }}
subject: "Build Failed: ${{ github.repository }}"
body: |
Workflow ${{ github.workflow }} failed
Branch: ${{ github.ref }}
Commit: ${{ github.sha }}
View logs: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
to: "[email protected]"
from: "CI Notification <[email protected]>"
HTML Email Templates for Richer Context
Plain text emails work but miss an opportunity to pack in structured information. The dawidd6/action-send-mail action supports HTML bodies, letting you send a miniature status dashboard on every failure:
- name: Send HTML Failure Report
if: failure()
uses: dawidd6/action-send-mail@v3
with:
server_address: smtp.gmail.com
server_port: 465
secure: true
username: ${{ secrets.MAIL_USERNAME }}
password: ${{ secrets.MAIL_PASSWORD }}
subject: "[FAILURE] ${{ github.workflow }} on ${{ github.ref_name }}"
html_body: |
<html>
<body style="font-family: Arial, sans-serif; padding: 20px;">
<h2 style="color: #e01e5a;">Build Failure Report</h2>
<table style="border-collapse: collapse; width: 100%;">
<tr style="background: #f5f5f5;">
<td style="padding: 8px; border: 1px solid #ddd;"><strong>Repository</strong></td>
<td style="padding: 8px; border: 1px solid #ddd;">${{ github.repository }}</td>
</tr>
<tr>
<td style="padding: 8px; border: 1px solid #ddd;"><strong>Branch</strong></td>
<td style="padding: 8px; border: 1px solid #ddd;">${{ github.ref_name }}</td>
</tr>
<tr style="background: #f5f5f5;">
<td style="padding: 8px; border: 1px solid #ddd;"><strong>Commit</strong></td>
<td style="padding: 8px; border: 1px solid #ddd;">${{ github.sha }}</td>
</tr>
<tr>
<td style="padding: 8px; border: 1px solid #ddd;"><strong>Author</strong></td>
<td style="padding: 8px; border: 1px solid #ddd;">${{ github.actor }}</td>
</tr>
</table>
<p>
<a href="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
style="background: #0366d6; color: white; padding: 10px 20px; text-decoration: none; border-radius: 4px;">
View Full Logs
</a>
</p>
</body>
</html>
to: "[email protected]"
from: "CI Notifications <[email protected]>"
Conditional Notifications Based on Changes
You can reduce notification noise by filtering based on file changes or authors:
name: Conditional Notifications
on:
push:
paths-ignore:
- '.md'
- 'docs/'
pull_request:
paths-ignore:
- '.md'
jobs:
notify:
runs-on: ubuntu-latest
steps:
- name: Check changed files
id: changes
uses: dorny/paths-filter@v2
with:
filters: |
src:
- 'src/'
- 'lib/'
- '*.js'
- '*.ts'
- name: Notify on source changes
if: steps.changes.outputs.src == 'true'
run: |
echo "Source code changed - notifying team"
Environment-Specific Routing
Production deploys warrant louder notifications than staging pushes. Use environment conditions to route to different channels:
jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ github.ref_name == 'main' && 'production' || 'staging' }}
steps:
- name: Deploy Application
run: ./scripts/deploy.sh
- name: Notify Production Channel
if: github.ref_name == 'main' && success()
run: |
curl -X POST -H 'Content-type: application/json' \
--data '{"text":"Production deploy succeeded for ${{ github.repository }} at commit ${{ github.sha }}"}' \
${{ secrets.SLACK_PROD_WEBHOOK_URL }}
- name: Notify Staging Channel
if: github.ref_name != 'main' && success()
run: |
curl -X POST -H 'Content-type: application/json' \
--data '{"text":"Staging deploy succeeded on branch ${{ github.ref_name }}"}' \
${{ secrets.SLACK_STAGING_WEBHOOK_URL }}
- name: Escalate Production Failure
if: github.ref_name == 'main' && failure()
run: |
# PagerDuty or high-priority channel for production failures
curl -X POST -H 'Content-type: application/json' \
--data '{"text":"<!channel> PRODUCTION DEPLOY FAILED: ${{ github.repository }} - immediate attention required"}' \
${{ secrets.SLACK_ONCALL_WEBHOOK_URL }}
The <!channel> mention in Slack triggers a channel-wide notification, which is appropriate for production failures and should never appear in staging notifications.
Storing and Managing Secrets Properly
Every notification channel requires a credential: a webhook URL, SMTP password, or API token. Mismanaging these is a common source of broken notifications and security exposure.
Add secrets at the repository level via Settings > Secrets and variables > Actions. For organization-wide pipelines, add them at the organization level so repositories can reference them without duplication.
Reference secrets in workflows using this pattern:
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
Never interpolate secrets directly into log-visible strings. This example is wrong:
BAD - the webhook URL will appear in logs
run: echo "Webhook is ${{ secrets.SLACK_WEBHOOK_URL }}"
To audit which secrets a workflow uses, scan your YAML for secrets. references and verify each one exists in your repository settings before the first run.
Integrating with Claude Code Skills
Several Claude skills enhance notification workflows. The supermemory skill can track notification history and patterns, helping you understand which types of failures require immediate attention versus those that can wait.
For frontend projects using the frontend-design skill, you might want notifications specifically about visual regression test failures:
- name: Visual Regression Check
uses: chromaui/action@v1
with:
projectDirectory: .
buildScriptName: test:visual
- name: Notify on Visual Changes
if: failure()
run: |
echo "Visual regression detected - review required"
The pdf skill can attach test reports to notifications. After generating test results, use the /pdf skill in Claude Code to create a formatted report, then attach it as an artifact:
- name: Attach Report to Notification
uses: actions/upload-artifact@v4
with:
name: test-report-pdf
path: report.pdf
Full Reusable Notification Workflow
If your repository contains multiple workflows, each one would otherwise need its own copy-pasted notification steps. Instead, create a reusable notification workflow once and call it from every consumer:
.github/workflows/notify.yml
name: Reusable Notification Dispatcher
on:
workflow_call:
inputs:
status:
required: true
type: string
workflow_name:
required: true
type: string
run_url:
required: true
type: string
secrets:
SLACK_WEBHOOK_URL:
required: true
jobs:
notify:
runs-on: ubuntu-latest
steps:
- name: Send Slack Notification
run: |
COLOR="${{ inputs.status == 'success' && '#36a64f' || '#e01e5a' }}"
curl -X POST -H 'Content-type: application/json' \
--data "{
\"attachments\": [{
\"color\": \"${COLOR}\",
\"text\": \"*${{ inputs.workflow_name }}* completed with status: *${{ inputs.status }}*\",
\"actions\": [{
\"type\": \"button\",
\"text\": \"View Run\",
\"url\": \"${{ inputs.run_url }}\"
}]
}]
}" \
${{ secrets.SLACK_WEBHOOK_URL }}
Then call it from any other workflow with a minimal uses block:
.github/workflows/build.yml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm test
send-notification:
needs: build
if: always()
uses: ./.github/workflows/notify.yml
with:
status: ${{ needs.build.result }}
workflow_name: "Main Build Pipeline"
run_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
secrets:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
This pattern keeps notification logic in one place and makes it easy to change your channel or message format across the entire repository.
Best Practices
-
Use status-specific channels: Send failures to a high-priority channel and successes to a lower-priority one.
-
Include actionable information: Always provide links to logs, run IDs, and direct commits.
-
Filter noise: Use path filters and branch conditions to avoid notifications for documentation-only changes.
-
Secure your secrets: Store webhook URLs and credentials in GitHub Secrets, never in workflow files.
-
Test your notifications: Create a manual workflow dispatch to verify notification delivery before relying on it.
-
Rate-limit awareness: Slack, Discord, and other webhooks enforce rate limits. If your pipeline dispatches many jobs in parallel, throttle notifications to avoid rejected requests. Batch job results into a single summary notification where possible.
-
Use
if: always()on notification steps: Without this condition, a failed upstream step will skip your notification step entirely, leaving the team with no visibility into the failure. -
Cache run metadata early: Steps that compute URLs or format commit messages can fail if they depend on context that’s unavailable in certain trigger types. Set up a dedicated step at the top of the job to export all variables you’ll use in notifications.
Troubleshooting Notification Issues
If notifications aren’t arriving, verify these common issues:
- Check that webhook URLs are correct and not expired
- Ensure secrets are properly configured in repository settings
- Verify the workflow has permission to send notifications
- Review GitHub Actions logs for specific error messages
For Slack, use the Slack API’s test endpoint to confirm connectivity. For Discord, the developer portal provides webhook testing tools.
Diagnosing Silent Failures
Notification steps themselves can silently fail if the curl exit code is non-zero but the step has no error handling. Add explicit error handling to detect and surface these failures:
- name: Notify with Error Handling
if: always()
run: |
HTTP_RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST -H 'Content-type: application/json' \
--data '{"text":"Build finished: ${{ job.status }}"}' \
${{ secrets.SLACK_WEBHOOK_URL }})
if [ "$HTTP_RESPONSE" != "200" ]; then
echo "Notification failed with HTTP $HTTP_RESPONSE"
exit 1
else
echo "Notification delivered successfully"
fi
This approach surfaces HTTP errors (400 bad request from malformed JSON, 410 for expired webhooks, 429 for rate limiting) as visible step failures in your Actions log, making diagnosis straightforward.
A complementary approach is to run a dedicated workflow_dispatch-triggered test workflow that fires a single notification to your test channel. Run it after any changes to your notification configuration to confirm end-to-end delivery before a real failure exposes a broken alert pipeline.
Setting up proper GitHub Actions notifications for Claude Code workflows transforms your CI/CD pipeline from a black box into a transparent, observable system. Teams can respond faster to issues, track deployment success rates, and maintain confidence in their automated workflows.
Related Reading
- Claude Code GitHub Actions Matrix Builds Guide
- Claude Code GitHub Actions Approval Workflows
- Automated Testing Pipeline with Claude TDD Skill 2026
- Workflows Hub
Built by theluckystrike. More at zovo.one
Find the right skill → Browse 155+ skills in our Skill Finder.
See Also
Configure MCP → Build your server config with our MCP Config Generator.
Try it: Paste your error into our Error Diagnostic for an instant fix.