claude-home/scheduled-tasks/CONTEXT.md
Cal Corum 4b7eca8a46
All checks were successful
Reindex Knowledge Base / reindex (push) Successful in 3s
docs: add YAML frontmatter to all 151 markdown files
Adds title, description, type, domain, and tags frontmatter to every
doc for improved KB semantic search. The description field is prepended
to every search chunk, and domain/type/tags enable filtered queries.

Type values: context, guide, runbook, reference, troubleshooting
Domain values match directory structure (networking, docker, etc.)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 09:00:44 -05:00

5.9 KiB
Raw Blame History

title description type domain tags
Scheduled Tasks Overview Headless Claude Code sessions triggered by systemd timers using runner.sh template framework and custom dispatcher scripts. Covers task layout, settings reference, cost safety, and monitoring. context scheduled-tasks
claude-code
systemd
timers
automation
headless
runner
issue-poller
pr-reviewer
backlog-triage

Scheduled Tasks — Headless Claude Sessions on a Timer

Headless Claude Code sessions triggered by systemd timers. Runs claude -p with task-specific prompts, tools, and cost limits — no TTY required.

For a guide on creating new tasks, see: ~/.claude/skills/create-scheduled-task/SKILL.md

File Layout

~/.config/claude-scheduled/
├── runner.sh                       # Universal task runner (template-based tasks)
├── disabled                        # Touch to globally pause all template tasks
├── tasks/
│   ├── backlog-triage/             # Example template task
│   │   ├── prompt.md               # What Claude should do
│   │   ├── settings.json           # Model, budget, tools, working dir
│   │   └── mcp.json                # MCP servers (optional)
│   ├── issue-poller/               # Used by issue-poller.sh (not runner.sh)
│   ├── issue-worker/               # Agent instructions + settings
│   └── pr-reviewer/                # Agent instructions + settings
├── issue-poller.sh                 # Custom dispatcher for issue scanning
├── issue-dispatcher.sh             # Dispatches AI agent per issue
├── pr-reviewer-dispatcher.sh       # Dispatches AI reviewer per open PR
└── repos.json                      # Gitea repos to scan

~/.config/systemd/user/
├── claude-scheduled@.service       # Template service (used by runner.sh tasks)
├── claude-scheduled@backlog-triage.timer
├── claude-issue-poller.service/timer   # Every 30 min
├── claude-pr-reviewer.service/timer
├── claude-issue-dispatcher.service
└── claude-daily-report.service/timer

~/.local/share/claude-scheduled/
└── logs/<task-name>/               # Timestamped .log files (last 30 kept)

Source files are in ~/dotfiles/claude-scheduled/ and symlinked into place.

Two Execution Patterns

1. runner.sh (Template Framework)

Used by tasks with only a prompt and settings — no custom logic needed.

claude-scheduled@<task>.timer
    → claude-scheduled@.service
        → runner.sh <task>
            reads tasks/<task>/{prompt.md,settings.json,mcp.json}
            invokes: claude -p <prompt> --model --effort --max-budget-usd
                          --allowedTools --output-format json
            stores result to cognitive-memory
            optionally POSTs to Discord webhook

Kill switch: touch ~/.config/claude-scheduled/disabled pauses all runner.sh tasks.

2. Custom Dispatcher Scripts

Used for tasks that need conditional dispatch, parallel agents, or complex logic.

claude-issue-poller.timer (every 30 min)
    → issue-poller.sh
        → scans repos.json for new open issues
        → calls issue-dispatcher.sh per issue
            → spawns claude -p (issue-worker agent)

claude-pr-reviewer.timer
    → pr-reviewer-dispatcher.sh
        → scans open PRs needing review
        → spawns claude -p (pr-reviewer agent) per PR

claude-daily-report.timer
    → daily-report.py
        → generates summary, posts to Discord

Active Tasks

Task Trigger Type Description
backlog-triage Weekdays 09:15 runner.sh Scan Gitea issues, prioritize, suggest focus
issue-poller Every 30 min custom Find new issues, dispatch AI workers
issue-dispatcher On-demand custom Fix a single issue, open a PR
pr-reviewer On timer custom Review open PRs, post formal reviews
daily-report Daily custom Summarize activity, post to Discord

Settings Reference (settings.json)

{
  "model": "sonnet",
  "effort": "medium",
  "max_budget_usd": 0.75,
  "allowed_tools": "Read(*) Glob(*) Grep(*)",
  "graph": "default",
  "working_dir": "/mnt/NV2/Development/claude-home",
  "timeout_seconds": 300,
  "notify_webhook": "https://discord.com/api/webhooks/..."
}
Field Default Notes
model sonnet Model alias. Use sonnet for cost efficiency.
effort medium low, medium, high — controls reasoning depth
max_budget_usd 0.25 Hard cost ceiling per session
allowed_tools Read(*) Glob(*) Grep(*) Principle of least privilege
graph default Cognitive-memory graph for output storage
working_dir claude-home cd here before running — loads that project's CLAUDE.md
timeout_seconds 300 Hard timeout via timeout(1)
notify_webhook Discord webhook URL for result posting (optional)

Auth and Environment

  • Uses Cal's Claude Max subscription via OAuth (no API key needed)
  • runner.sh unsets CLAUDECODE to allow nested sessions (running from within Claude Code)
  • MCP servers configured per-task via mcp.json + --strict-mcp-config

Monitoring

# List all active timers
systemctl --user list-timers 'claude*'

# Check logs for a task
journalctl --user -u claude-scheduled@backlog-triage.service --since today

# Latest log file for runner.sh task
ls -t ~/.local/share/claude-scheduled/logs/backlog-triage/ | head -1

# Manual test run
~/.config/claude-scheduled/runner.sh backlog-triage

Cost Safety

  • Per-task max_budget_usd cap — runner.sh detects error_max_budget_usd and warns
  • --allowedTools restricts what Claude can do (read-only tasks can't Edit/Write/Bash)
  • timeout_seconds kills hung sessions
  • Global kill switch: touch ~/.config/claude-scheduled/disabled
  • Typical cost: $0.150.30 per Sonnet run with MCP tools