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.
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.
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 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).
Every background agent follows the same structure:
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.
Creates an issue each morning summarizing yesterday's activity — commits, PRs opened/merged, issues filed.
---
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.
Scans for dead code, high-complexity functions, and patterns that commonly lead to bugs.
---
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.
---
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`.
---
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`.
close-older-issues: trueWhen 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: 7Auto-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: 500Sets 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.
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-creditsFor 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.
Think about your /status skill — you invoke it manually to get a snapshot of your project. A scheduled workflow produces the same output automatically:
The manual skill and the scheduled workflow can share the same prompt. The only difference is the trigger and the output channel.
Here's a complete workflow file you could drop into any repository:
---
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
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:
eval(), hardcoded URLs, or unvalidated inputsclose-older-issues: true do in a scheduled workflow?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.max-ai-credits from a daily scheduled workflow?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.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.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.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.
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.