CI Notifications

Send build status updates, deploy alerts, and test summaries to Discord directly from your CI/CD pipeline using discli.

The problem

Your team uses Discord for communication, but deploy notifications live in GitHub, email, or a separate tool. Developers miss failed builds, successful deploys go unnoticed, and nobody knows what is currently running in production.

The solution

Add discli to your CI/CD pipeline as a lightweight notification step. No webhooks to configure, no separate bot infrastructure — just pip install discord-cli-agent and a single discli message send command.

Full working code

Basic deploy notification

name: Deploy and Notify
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to production
run: |
# Your deploy steps here
echo "Deploying..."
- name: Notify Discord (success)
if: success()
env:
DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_BOT_TOKEN }}
run: |
pip install discord-cli-agent
discli message send "#deploys" "Deploy **${{ github.sha }}** to production succeeded. Branch: \`${{ github.ref_name }}\` | Author: ${{ github.actor }} | [View commit](https://github.com/${{ github.repository }}/commit/${{ github.sha }})"
- name: Notify Discord (failure)
if: failure()
env:
DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_BOT_TOKEN }}
run: |
pip install discord-cli-agent
discli message send "#deploys" "Deploy **${{ github.sha }}** FAILED. Branch: \`${{ github.ref_name }}\` | Author: ${{ github.actor }} | [View run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})"

With test summary

name: Test and Notify
on:
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tests
id: tests
run: |
# Run tests and capture summary
python -m pytest --tb=short 2>&1 | tee test-output.txt
echo "result=${PIPESTATUS[0]}" >> $GITHUB_OUTPUT
- name: Notify Discord
if: always()
env:
DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_BOT_TOKEN }}
run: |
pip install discord-cli-agent
# Extract test summary (last 3 lines of pytest output)
SUMMARY=$(tail -3 test-output.txt | tr '\n' ' ')
if [ "${{ steps.tests.outputs.result }}" = "0" ]; then
STATUS="PASSED"
else
STATUS="FAILED"
fi
discli message send "#ci" "**Tests ${STATUS}** for PR #${{ github.event.pull_request.number }}: ${{ github.event.pull_request.title }}
\`\`\`
${SUMMARY}
\`\`\`
[View PR](https://github.com/${{ github.repository }}/pull/${{ github.event.pull_request.number }}) | [View run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})"
stages:
- deploy
- notify
deploy:
stage: deploy
script:
- echo "Deploying..."
notify_success:
stage: notify
when: on_success
variables:
DISCORD_BOT_TOKEN: $DISCORD_BOT_TOKEN
script:
- pip install discord-cli-agent
- discli message send "#deploys" "Deploy ${CI_COMMIT_SHORT_SHA} to production succeeded. Branch: ${CI_COMMIT_REF_NAME} | Author: ${GITLAB_USER_LOGIN}"
notify_failure:
stage: notify
when: on_failure
variables:
DISCORD_BOT_TOKEN: $DISCORD_BOT_TOKEN
script:
- pip install discord-cli-agent
- discli message send "#deploys" "Deploy ${CI_COMMIT_SHORT_SHA} FAILED. Branch: ${CI_COMMIT_REF_NAME} | [View pipeline](${CI_PIPELINE_URL})"
#!/bin/bash
# ci-notify.sh — Reusable CI notification script.
# Usage: ./ci-notify.sh <status> <channel> [details]
STATUS="${1:?Usage: $0 <success|failure> <channel> [details]}"
CHANNEL="${2:?Usage: $0 <status> <channel> [details]}"
DETAILS="${3:-No additional details.}"
COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
AUTHOR=$(git log -1 --format='%an' 2>/dev/null || echo "unknown")
TIMESTAMP=$(date -u +"%Y-%m-%d %H:%M UTC")
if [ "$STATUS" = "success" ]; then
ICON="**[SUCCESS]**"
else
ICON="**[FAILURE]**"
fi
MESSAGE="${ICON} Deploy \`${COMMIT}\` on \`${BRANCH}\` by ${AUTHOR} at ${TIMESTAMP}
${DETAILS}"
discli message send "$CHANNEL" "$MESSAGE"

Use it from any CI system:

Terminal window
# On success
./ci-notify.sh success "#deploys" "All 142 tests passed."
# On failure
./ci-notify.sh failure "#deploys" "3 tests failed in auth module."

Step-by-step explanation

Store your bot token as a CI secret

Add your Discord bot token as a secret in your CI provider:

  • GitHub Actions: Settings > Secrets and variables > Actions > New repository secret. Name it DISCORD_BOT_TOKEN.
  • GitLab CI: Settings > CI/CD > Variables. Name it DISCORD_BOT_TOKEN and mark it as masked.

discli automatically reads the DISCORD_BOT_TOKEN environment variable, so no discli config set step is needed.

Danger

Never hardcode your bot token in workflow files or commit it to your repository. Always use your CI provider’s secrets mechanism.

Install discli in the CI environment

Add a pip install discord-cli-agent step before sending notifications. This installs discli and its dependencies (discord.py, click) in the CI runner.

- run: pip install discord-cli-agent
Tip

To speed up CI runs, cache the pip install or pin a specific version: pip install discord-cli-agent==X.Y.Z.

Send the notification

Use discli message send with a channel name and your message. discli resolves #deploys to the correct channel ID automatically.

Terminal window
discli message send "#deploys" "Deploy abc1234 to production succeeded."

You can include Markdown formatting in the message — Discord renders bold, italic, code blocks, and links.

Handle success and failure separately

Use conditional steps to send different messages based on the build outcome:

# GitHub Actions conditionals
- if: success() # Runs only if previous steps succeeded
- if: failure() # Runs only if a previous step failed
- if: always() # Runs regardless of outcome

This ensures your team gets notified about failures even when the deploy step crashes.

Thread-per-deploy pattern

For high-frequency deploys, create a thread for each deploy to keep the channel organized:

#!/bin/bash
# deploy-thread.sh — Create a thread per deploy with full details.
CHANNEL="#deploys"
COMMIT=$(git rev-parse --short HEAD)
BRANCH=$(git rev-parse --abbrev-ref HEAD)
# Send the initial message
RESULT=$(discli --json message send "$CHANNEL" "Deploying \`${COMMIT}\` from \`${BRANCH}\`...")
MSG_ID=$(echo "$RESULT" | jq -r '.id')
# Create a thread on that message
THREAD=$(discli --json thread create "$CHANNEL" "$MSG_ID" "Deploy ${COMMIT}")
THREAD_ID=$(echo "$THREAD" | jq -r '.id')
# Post detailed info in the thread
discli thread send "$THREAD_ID" "**Commit:** \`${COMMIT}\`
**Branch:** \`${BRANCH}\`
**Author:** $(git log -1 --format='%an')
**Message:** $(git log -1 --format='%s')
**Timestamp:** $(date -u +"%Y-%m-%d %H:%M UTC")"
# ... run deploy ...
# Post result
if deploy_command_here; then
discli thread send "$THREAD_ID" "Deploy **succeeded** in $(elapsed_time)s."
else
discli thread send "$THREAD_ID" "Deploy **failed**. Check the CI logs for details."
fi

Edge cases and pitfalls

Warning

Channel name vs. ID. If your bot is in multiple servers with a channel named #deploys, discli will pick the first match. Use the numeric channel ID (e.g., 1234567890123456789) instead of the name to avoid sending to the wrong server.

Warning

Rate limits in parallel jobs. If you have a matrix build with 10 parallel jobs all notifying the same channel, you will hit Discord’s rate limit. Send a single consolidated notification from a downstream job instead:

notify:
needs: [build-linux, build-mac, build-windows]
if: always()
steps:
- run: discli message send "#ci" "Build matrix complete. Results: ..."
Warning

Message length in CI. Test output and error logs can be long. Discord’s 2000 character limit means you need to truncate. Extract just the summary line or last few lines of output rather than piping the full log.

Warning

CI runner network access. Your CI runner must be able to reach Discord’s API (discord.com on port 443). If you are behind a corporate firewall or using self-hosted runners, ensure this is not blocked.

Extending the pipeline

Rich embeds

Use --embed-title and --embed-desc flags to send formatted embed messages with color-coded status indicators.

Terminal window
discli message send "#deploys" "" \
--embed-title "Deploy Succeeded" \
--embed-desc "Commit abc1234 deployed to prod."

Failure alerts with diff link

Include a link to the diff that caused the failure so developers can jump straight to the problem:

Terminal window
discli message send "#alerts" "Build failed: [view diff](https://github.com/org/repo/compare/abc...def)"

Deployment tracking

Maintain a #deploy-log channel as a persistent record of all deployments. Combine with the Channel Logger to create a searchable deployment history.

Rollback notifications

Add a notification step to your rollback procedure so the team knows when a deploy was reverted and why.