Skip to main content

Deploy and Test Your Bot

Your bot is built. Now let’s make it run automatically every morning using GitHub Actions.

What Is GitHub Actions?

GitHub Actions is a built-in automation service that runs tasks for you. You tell it when to run (e.g. every weekday at 9 am) and what to do (e.g. run your bot script), and it handles the rest — no server needed.
When you push a workflow file (a YAML file in .github/workflows/), GitHub watches for the trigger you defined. When the trigger fires — a scheduled time, a push, or a manual button press — GitHub spins up a virtual machine, checks out your code, installs dependencies, and runs your commands. It’s like having a free computer in the cloud that does one job and shuts down.

Prompt 7: Create the GitHub Actions Workflow

Ask Claude Code to create the automation:
Your prompt to Claude Code
Create a GitHub Actions workflow file at .github/workflows/daily-report.yml
that:

1. Runs every weekday at 9:00 am NZST (that's around 8 PM or 9 PM UTC
   depending on daylight saving — use 20:00 UTC as a reasonable default)
2. Can also be triggered manually using workflow_dispatch
3. Checks out the repository with full git history (fetch-depth: 0)
4. Sets up Node.js 20
5. Installs dependencies with npm ci
6. Runs the daily report script with these environment variables from
   GitHub secrets: OPENAI_API_KEY, SLACK_WEBHOOK_TEST, SLACK_WEBHOOK_PROD
7. After the script runs, commits and pushes any changes to state.json
   with the message "chore: update commit bank state [skip ci]"
8. The commit should use a bot identity for the git author

Add comments explaining each section of the workflow file.
What happens: Claude Code creates a complete workflow file with the cron schedule, checkout, setup, and run steps.
About cron timing: GitHub Actions cron uses UTC. New Zealand is UTC+12 (or UTC+13 during daylight saving). The schedule 0 20 * * 1-5 means “8 PM UTC, Monday to Friday” which is approximately 9 AM NZST. Cron triggers can be delayed by up to 15 minutes during busy periods — this is normal.
When the bot commits the updated state.json, the commit message includes [skip ci]. This tells GitHub Actions not to trigger another workflow run for that commit — otherwise you’d get an infinite loop of the bot triggering itself.
By default, GitHub Actions checks out only the latest commit (shallow clone). Your bot needs to read the full git history to find recent commits. Setting fetch-depth: 0 ensures the entire history is available.
# .github/workflows/daily-report.yml
name: Daily Report Bot

on:
  schedule:
    # Run at 8 PM UTC (approx 9 AM NZST), Monday to Friday
    - cron: '0 20 * * 1-5'
  workflow_dispatch: # Allow manual triggering

jobs:
  daily-report:
    runs-on: ubuntu-latest

    steps:
      # Check out the full repository history
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          token: ${{ secrets.GITHUB_TOKEN }}

      # Set up Node.js
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      # Install dependencies
      - name: Install dependencies
        run: npm ci

      # Run the daily report bot
      - name: Run daily report
        env:
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
          SLACK_WEBHOOK_TEST: ${{ secrets.SLACK_WEBHOOK_TEST }}
          SLACK_WEBHOOK_PROD: ${{ secrets.SLACK_WEBHOOK_PROD }}
          SLACK_CHANNEL: prod
        run: node src/index.js

      # Commit updated state.json so the commit bank persists
      - name: Commit state changes
        run: |
          git config user.name "daily-report-bot"
          git config user.email "bot@users.noreply.github.com"
          git add state.json
          git diff --staged --quiet || git commit -m "chore: update commit bank state [skip ci]"
          git push

Configure GitHub Secrets

Your bot needs three secrets. Never commit these to your code — store them in GitHub’s encrypted secrets.
Never commit API keys, webhook URLs, or other secrets to your code. Anyone who can see your repository could steal them. GitHub Secrets encrypts them and makes them available only during workflow runs.
If you have the GitHub CLI installed:
gh secret set OPENAI_API_KEY
gh secret set SLACK_WEBHOOK_TEST
gh secret set SLACK_WEBHOOK_PROD
Each command will prompt you to paste the value.

Push and Deploy

1

Stage and commit your code

git add -A
git commit -m "feat: add daily report bot"
2

Push to GitHub

git push origin main
3

Verify on GitHub

Go to your repository on GitHub → Actions tab. You should see the “Daily Report Bot” workflow listed. It will run automatically on the next scheduled time, or you can trigger it manually.

Test the Workflow

1

Dry run (no Slack post)

Trigger the workflow manually with a dry run to check everything works without posting to Slack:
gh workflow run daily-report.yml
Or on the GitHub website: ActionsDaily Report BotRun workflow.Check the logs to see the output. You should see the commit collection, banking, and summary steps complete successfully.
2

Real test (post to test channel)

If the dry run looks good, trigger a real run that posts to your test Slack channel. Check the SLACK_CHANNEL environment variable is set to test in the workflow file, then trigger again.Go to your test Slack channel — you should see a message like this:
Daily Update — Tuesday, 11 March 2026

- Set up the daily report bot project structure and core modules
- Built the commit banking system to distribute updates across the week
- Integrated OpenAI for natural language summaries

Blockers: None
3

Celebrate

Your bot works! It will now run automatically every weekday morning.

Prompt 8: Troubleshoot

Things don’t always work on the first try. Here’s the pattern for debugging with Claude Code:
Your prompt to Claude Code
I'm getting this error when the GitHub Actions workflow runs:

[paste the exact error message here]

The workflow is supposed to collect git commits, summarise them with
OpenAI, and post to Slack. Can you help me figure out what went wrong
and fix it?
Communication skill: Describing errors. Always paste the exact error message. Tell Claude Code what you expected to happen and what actually happened. The more context, the faster the fix.

Common Issues

Possible causes:
  • The workflow file isn’t on the default branch (usually main). Scheduled workflows only run from the default branch.
  • The cron schedule is in UTC, not your local time. Double-check the conversion.
  • GitHub Actions can delay cron triggers by up to 15 minutes during busy periods.
Possible causes:
  • The webhook URL has been revoked or is incorrect. Go to your Slack app settings and check.
  • The secret name in your workflow doesn’t match what you set in GitHub Secrets.
  • You’re using the test webhook URL but the environment variable points to prod (or vice versa).
Possible cause: The git log separator conflicts with shell operators. Using || or && as separators will break because the shell interprets them. Use a safe separator like <SEP> instead.
Possible cause: If someone pushes to the repository at the same time as the bot tries to commit state.json, you’ll get a conflict. The [skip ci] tag prevents cascading runs, but timing conflicts can still happen. This is rare in practice.
Possible causes:
  • The time window is too short. The default is 24 hours, but if the workflow runs at a slightly different time, some commits might fall outside the window.
  • fetch-depth: 0 is missing from the checkout step, so the git history isn’t available.

Switch to Production

Once you’re happy with the test output, switch to the production channel:
  1. In your workflow file (.github/workflows/daily-report.yml), change SLACK_CHANNEL: test to SLACK_CHANNEL: prod
  2. Commit and push
Or ask Claude Code:
Your prompt to Claude Code
Change the default Slack channel in the GitHub Actions workflow from
"test" to "prod" so the daily reports go to the production channel.
That’s it — your bot is live.
Your bot is deployed and running! Head to What’s next for ideas to extend it, lessons learned, and reflection questions.