Skip to content
X

Level 9: Infrastructure Operator — 24/7 Background Jobs

Using GitHub Actions’ on.schedule or Vercel/Railway’s cron features, you can run Claude Code automatically 24 hours a day, 365 days a year without human intervention. Here I’ll learn how to design repeating tasks — like PR reviews, security audits, and scheduled report generation — as infrastructure.

Target audience: Anyone who is comfortable with parallel agents and wants to build an always-on automation system.

Estimated learning time: Read 25min + Practice 50min


How Event-driven Execution Works with GitHub Actions

Section titled “How Event-driven Execution Works with GitHub Actions”

GitHub Actions triggers workflows based on events that occur in the repository (PR creation, merge, push, deployment completion, etc.).

on:
  pull_request:
    types: [opened, synchronize]  # On PR creation/update
  push:
    branches: [main]              # On push to main
  deployment_status:              # On deployment status change
  workflow_dispatch:              # Manual trigger

When an event occurs, GitHub’s infrastructure automatically launches the jobs. Claude Code is installed inside those jobs with npm install -g @anthropic-ai/claude-code and then executed.

Scheduled Execution with GitHub Actions cron

Section titled “Scheduled Execution with GitHub Actions cron”

Writing a cron expression in on.schedule enables scheduled execution. Cron expressions use UTC.

on:
  schedule:
    - cron: '0 0 * * *'    # Every day at UTC 0:00
    - cron: '0 1 * * 1'    # Every Monday at UTC 1:00
    - cron: '0 9 1 * *'    # 1st of every month at UTC 9:00

Cron expression format: minute hour day month weekday (* means all)

General-purpose Automated PR Review Workflow

Section titled “General-purpose Automated PR Review Workflow”

Reviews a PR with Claude Code every time it is created or updated, and posts the result as a comment.

name: AI Code Review

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  review:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write

    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

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

      - name: Install Claude Code
        run: npm install -g @anthropic-ai/claude-code

      - name: Run AI Review
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          DIFF=$(git diff origin/main...HEAD)

          if [ -z "$DIFF" ]; then
            echo "No review targets"
            exit 0
          fi

          echo "$DIFF" | claude --print \
            --dangerously-skip-permissions \
            "Please review this diff.
            Check from the perspectives of bugs, security, and performance.
            If there are issues, list them with severity. If not, respond with LGTM." \
            > review_result.txt

      - name: Post Review Comment
        if: github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs')
            const review = fs.readFileSync('review_result.txt', 'utf8')
            await github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `## AI Code Review\n\n${review}\n\n---\n*Automated review by Claude Code*`
            })

General-purpose Daily Report Generation Workflow

Section titled “General-purpose Daily Report Generation Workflow”

Analyzes the codebase daily at a scheduled time, generates a security audit report of dependency packages, and creates it as an Issue.

name: Daily Security Audit

on:
  schedule:
    - cron: '0 0 * * *'  # Every day at UTC 0:00

jobs:
  audit:
    runs-on: ubuntu-latest
    permissions:
      issues: write

    steps:
      - uses: actions/checkout@v4

      - name: Install dependencies
        run: npm ci

      - name: Install Claude Code
        run: npm install -g @anthropic-ai/claude-code

      - name: Run Security Audit
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          AUDIT_RESULT=$(npm audit --json 2>&1 || true)

          ANALYSIS=$(echo "$AUDIT_RESULT" | claude --print --dangerously-skip-permissions "
          The following is the result of npm audit (JSON).
          If there are critical vulnerabilities, report them in this format:
          ## Vulnerability Report
          - Package name: Impact · How to fix
          If there are no critical vulnerabilities, respond with 'No issues.'
          ")

          echo "$ANALYSIS"

          # Create an Issue only if vulnerabilities are detected
          if echo "$ANALYSIS" | grep -q "## Vulnerability Report"; then
            gh issue create \
              --title "Security vulnerabilities detected ($(date +%Y-%m-%d))" \
              --body "$ANALYSIS" \
              --label "security,urgent"
          fi

Node.js Implementation Example with Server-side cron (Vercel / Railway)

Section titled “Node.js Implementation Example with Server-side cron (Vercel / Railway)”

There is also an approach that uses Vercel Cron Functions or Railway’s scheduled execution instead of GitHub Actions.

// api/cron/daily-report.js (Vercel Cron Functions example)
// Set {"crons": [{"path": "/api/cron/daily-report", "schedule": "0 0 * * *"}]} in vercel.json

import Anthropic from "@anthropic-ai/sdk";

export default async function handler(req, res) {
  // Validate the request is from Vercel Cron
  if (req.headers["authorization"] !== `Bearer ${process.env.CRON_SECRET}`) {
    return res.status(401).json({ error: "Unauthorized" });
  }

  const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });

  // Fetch yesterday's logs (in a real implementation, retrieve from a database or storage)
  const logs = await fetchYesterdayLogs();

  const message = await client.messages.create({
    model: "claude-opus-4-6",
    max_tokens: 1024,
    messages: [
      {
        role: "user",
        content: `The following are yesterday's access logs. Please report if there are any abnormal patterns.\n\n${logs}`,
      },
    ],
  });

  const report = message.content[0].text;

  // Send the report via Slack, email, etc.
  await sendReport(report);

  res.status(200).json({ success: true, report });
}

Check the following before running Claude in the background.

  • Do I understand the scope of impact of --dangerously-skip-permissions (which files and commands it can operate on)?
  • Is the API key managed as an environment variable or Secret (not hardcoded)?
  • Is an alert notification configured for when a job fails?
  • Have I set a monthly API cost limit in the Anthropic console?
  • Is there a process for a human to review auto-generated content and changes before they are applied to production?

Q. How do I verify that a cron job is running?

For GitHub Actions, check the workflow execution history from the “Actions” tab. For Vercel, check the execution logs in the “Cron Jobs” section of the dashboard.

Q. Can I use GitHub Actions cron on the free tier?

Public repositories are free. Private repositories have a free tier of 2,000 minutes per month, after which you are billed.


Hands-on tutorial for this level →

I’ve understood how to build always-on automation systems using GitHub Actions and cron. Next, I’ll learn about the swarm architecture where agents themselves design and generate other agents.

Let’s move on to Level 10: Swarm Architect — Agents Building Agents.