Background Agents — Scheduled Automation

Lesson 5 · Safe Agentic Workflows · ~10 minutes

So far, every workflow we've built requires you to trigger it — typing a command, opening a PR, or pushing a commit. But the most powerful pattern in agentic workflows is the one that runs while you sleep.

Background agents run on a schedule. They analyze your repository, produce reports, and surface improvements — all without human invocation. You wake up to a ready-to-review issue summarizing what changed, what's stale, and what needs attention.

The Concept

A background agent is a workflow triggered by schedule instead of a human action. It reads your repository, performs analysis, and outputs findings through a safe output — typically creating an issue or posting a comment.

The key insight: the same pattern we use for safety (read-only agent → structured output → separate write job) makes scheduled agents inherently safe. They can't push code or merge PRs unless you explicitly grant those outputs. By default, they just report.

Schedule Syntax

GitHub Agentic Workflows supports human-friendly schedule expressions that are automatically converted to cron. The system uses fuzzy schedules by default — automatically scattering execution times across workflows to prevent load spikes.

Expression When It Runs Type
daily Once per day, scattered time Fuzzy
daily on weekdays Mon–Fri, scattered time Fuzzy
daily around 9am 8am–10am window (±1 hour) Fuzzy
daily around 9am on weekdays Mon–Fri, 8am–10am Fuzzy
daily between 9:00 and 17:00 Business hours window Fuzzy
weekly Scattered day and time Fuzzy
weekly on monday Monday, scattered time Fuzzy
weekly on friday around 5pm Friday 4pm–6pm Fuzzy
every 2h Every 2 hours Fuzzy
bi-weekly Every 14 days Fuzzy
0 9 * * 1-5 Weekdays at 9:00 AM (standard cron) Fixed
Fuzzy vs Fixed

Fuzzy schedules scatter execution times deterministically per-workflow, preventing load spikes when many workflows share the same time. Always prefer fuzzy syntax (daily) over fixed cron (0 9 * * *) unless you need an exact time.

You can also add timezone offsets: daily around 9am utc-5 (EST) or daily around 14:00 utc+9 (JST).

The Background Agent Pattern

Every background agent follows the same structure:

Schedule → Read → Analyze → Report
1 Schedule trigger — fires automatically on cadence
2 Read permissions — agent reads repo contents, issues, PRs
3 Analysis prompt — agent examines the repo against criteria you define
4 Safe output — findings delivered as an issue, comment, or discussion

The safety model is clean: the agent runs with read-only permissions and can only produce output through the declared safe-output channel. It can't modify code, merge PRs, or delete anything.

Example Workflows

1. Daily Repo Status Report

Creates an issue each morning summarizing yesterday's activity — commits, PRs opened/merged, issues filed.

.github/workflows/daily-status.md
---
description: "Daily repository status report"
on:
  schedule: daily around 8am on weekdays
  workflow_dispatch:

permissions:
  contents: read
  issues: read
  pull-requests: read

engine:
  id: copilot
  model: gpt-4.1-mini

max-ai-credits: 500

safe-outputs:
  create-issue:
    title-prefix: "[daily-status] "
    labels: [report, daily]
    close-older-issues: true
    expires: 7
---

Analyze this repository's activity over the past 24 hours.

Create an issue with a status report covering:

1. **Commits** — list commits merged to main, grouped by author
2. **Pull Requests** — PRs opened, PRs merged, PRs with reviews requested
3. **Issues** — new issues filed, issues closed, issues with no response > 48h
4. **Highlights** — anything unusual (large PRs, spikes in activity, stale items)

Keep the report concise and scannable. Use tables where appropriate.

If there was no activity in the past 24 hours, call `noop` with a message
explaining the repository was quiet.

2. Weekly Code Quality Monitoring

Scans for dead code, high-complexity functions, and patterns that commonly lead to bugs.

.github/workflows/code-quality-weekly.md
---
description: "Weekly code quality analysis"
on:
  schedule: weekly on monday around 9am
  workflow_dispatch:

permissions:
  contents: read

engine:
  id: claude
  model: claude-sonnet-4-5

max-ai-credits: 1000

safe-outputs:
  create-issue:
    title-prefix: "[code-quality] "
    labels: [tech-debt, automation]
    close-older-issues: true
    expires: 14
---

Perform a code quality analysis of this repository. Focus on:

1. **Dead code** — functions/methods never called, unreachable branches
2. **Complexity** — functions exceeding 50 lines or 10+ branches
3. **Duplication** — near-identical logic in multiple locations
4. **Outdated patterns** — deprecated API usage, old-style error handling

For each finding, provide:
- File and line number
- What the issue is
- Suggested fix (1-2 sentences)

Prioritize findings by impact. Limit to the top 10 issues.

If the codebase is clean, call `noop` with a congratulatory message.

3. Dependency Freshness Check

.github/workflows/dependency-check.md
---
description: "Weekly dependency freshness report"
on:
  schedule: weekly on friday
  workflow_dispatch:

permissions:
  contents: read

engine:
  id: copilot
  model: gpt-4.1-mini

max-ai-credits: 500

safe-outputs:
  create-issue:
    title-prefix: "[deps] "
    labels: [dependencies, automation]
    close-older-issues: true
    expires: 14
---

Analyze the dependency files in this repository (package.json, requirements.txt,
Cargo.toml, go.mod, or equivalent).

Report:
1. Dependencies more than 2 major versions behind
2. Dependencies with known security advisories
3. Dependencies that haven't been updated in 12+ months
4. Any pinned versions that could be safely bumped

If all dependencies are current, call `noop`.

4. Documentation Staleness Detection

.github/workflows/docs-freshness.md
---
description: "Bi-weekly documentation staleness check"
on:
  schedule: bi-weekly
  workflow_dispatch:

permissions:
  contents: read

engine:
  id: copilot
  model: gpt-4.1-mini

max-ai-credits: 500

safe-outputs:
  create-issue:
    title-prefix: "[docs] "
    labels: [documentation, automation]
    close-older-issues: true
    expires: 21
---

Review the documentation in this repository (README.md, docs/, wiki pages).

Flag documentation that appears stale:
1. References to APIs, functions, or config options that no longer exist in code
2. Setup instructions that reference outdated tool versions
3. Architecture docs that don't match the current file structure
4. Links that point to renamed or deleted files

For each finding, suggest the specific update needed.
If documentation is current, call `noop`.

Key Configuration

close-older-issues: true

When your scheduled workflow creates a new issue, this setting automatically closes previous issues from the same workflow. Without it, you'd accumulate one open issue per day — quickly flooding your issue tracker.

How it works: when the new issue is successfully created, the system searches for open issues containing the same workflow-id marker and closes them as "not planned" with a comment linking to the new issue. Maximum 10 older issues are closed per run.

expires: 7

Auto-closes the issue after 7 days even if no new report replaces it. This prevents orphaned issues from cluttering your tracker if you disable the workflow or it fails repeatedly. Accepts day strings (7d, 2w, 1m) or plain integers (interpreted as days).

max-ai-credits: 500

Sets the AI Credits budget for a single run. Defaults to 1000 if omitted. One AI Credit = $0.01 USD. For a daily workflow, even a modest budget adds up: 500 AIC × 30 days = $150/month. Set this thoughtfully.

⚠️ Cost Awareness

Scheduled agents run on every trigger — that's the point. But it means cost is predictable and relentless. A daily workflow with no budget cap will happily spend 1000 AIC every day ($300/month) whether it finds anything useful or not.

Default guardrails: 1000 AIC per run, 5000 AIC per workflow per day, and a 20-minute timeout. Always set max-ai-credits to the minimum your workflow actually needs. Use a cheaper model (gpt-4.1-mini, claude-haiku-4-5) for routine monitoring tasks.

max-daily-ai-credits

For extra protection, cap total daily spend across all runs of the same workflow:

max-daily-ai-credits: 2000

If the workflow has already consumed 2000 AIC in the past 24 hours (across all runs), subsequent runs are skipped and an issue is created explaining why.

Connection to Your Work

Think about your /status skill — you invoke it manually to get a snapshot of your project. A scheduled workflow produces the same output automatically:

🖐️ Manual (today)
⏰ Scheduled (background agent)

The manual skill and the scheduled workflow can share the same prompt. The only difference is the trigger and the output channel.

Full Example: Daily Status Workflow

Here's a complete workflow file you could drop into any repository:

.github/workflows/morning-briefing.md
---
description: "Morning briefing — summarizes repo activity and open work"
emoji: "☀️"
labels: [automation, monitoring]

on:
  schedule: daily around 8am on weekdays
  workflow_dispatch:

permissions:
  contents: read
  issues: read
  pull-requests: read

engine:
  id: copilot
  model: gpt-4.1-mini

max-ai-credits: 400
max-daily-ai-credits: 2000

safe-outputs:
  create-issue:
    title-prefix: "[morning-briefing] "
    labels: [report, daily-briefing]
    close-older-issues: true
    expires: 3
---

# Morning Briefing

Generate a concise daily briefing for this repository. Today's date is
{{ date }}.

## What to analyze

1. **Yesterday's activity**
   - Commits pushed to main
   - Pull requests opened, reviewed, or merged
   - Issues opened or closed

2. **Attention needed**
   - PRs awaiting review for more than 24 hours
   - Issues with no response for more than 48 hours
   - Failing CI on open PRs

3. **Upcoming**
   - PRs marked as ready for review
   - Issues assigned but not started (no linked branch)

## Format

Use this structure for the issue body:
- Start with a 1-sentence summary ("Busy day: 5 PRs merged" or "Quiet: no changes")
- Use tables for lists of items (PR #, author, status)
- End with "Action items" — the 1-3 things that need human attention today

## Rules

- Keep it under 500 words
- Link to actual PRs and issues using #number format
- If the repo was completely quiet, call `noop` instead of creating an empty report

Practical Exercise

Your turn: Design a scheduled workflow

Pick one recurring task you do manually for your repository and design a scheduled workflow for it. Use this template:

---
description: "___"

on:
  schedule: ___          # How often?
  workflow_dispatch:     # Always include for manual testing

permissions:
  contents: read
  # What else does it need to read?

engine:
  id: copilot
  model: gpt-4.1-mini   # Start cheap

max-ai-credits: ___     # What's the minimum budget?

safe-outputs:
  create-issue:
    title-prefix: "[___] "
    labels: [___]
    close-older-issues: true
    expires: ___         # How long is the report useful?
---

# Your prompt here

What should the agent analyze?
What format should the output take?
When should it call `noop` instead?

Ideas for your first scheduled workflow:

Check Your Understanding

What does close-older-issues: true do in a scheduled workflow?
Correct — it searches for open issues with the same workflow-id marker and closes them as "not planned" with a link to the new issue. This keeps your issue tracker clean by ensuring only the latest report is open.
Not quite. close-older-issues: true specifically closes previous issues from the same workflow when a new one is created. It identifies them by a hidden workflow-id marker in the issue body. This ensures only the latest report is open at any time.
What happens if you omit max-ai-credits from a daily scheduled workflow?
Right — the default is 1000 AIC per run. For a daily workflow, that's $10/day or ~$300/month. There's also a default daily cap of 5000 AIC, but the per-run default alone can be expensive for monitoring workflows that don't need much compute.
The default max-ai-credits is 1000 per run when omitted. For a daily workflow, that's ~$10/day or ~$300/month. It's not unlimited (there's also a default 5000 AIC daily cap), but it's expensive for a simple monitoring task. Always set it explicitly to the minimum your workflow needs.
How do you make a scheduled workflow run only on weekdays (Monday through Friday)?
Exactly — append on weekdays to any daily or hourly schedule. It restricts execution to Monday through Friday. You can also use standard cron (0 9 * * 1-5) but the fuzzy syntax is preferred because it prevents load spikes.
The correct answer is daily on weekdays. The on weekdays modifier can be appended to daily, hourly, or interval schedules. While cron syntax like 0 9 * * 1-5 also works, the fuzzy on weekdays form is preferred because it automatically scatters execution times.

What's Next

You now have the full picture: hooks guard every action, commands structure your workflows, skills inform decisions, and scheduled agents work in the background. The next lesson covers multi-agent orchestration — how to chain workflows together, dispatch sub-agents, and build systems where agents coordinate with each other.

Primary Source

Schedule Syntax Reference — the complete documentation on fuzzy schedules, time constraints, intervals, cron expressions, and timezone support.

Also see: Cost Management and Safe Outputs for the full configuration options.

Questions? Ask me about schedule syntax, cost budgeting, safe output options, or how to adapt any of these examples to your specific repository.
← Back Next →