claude-home/scheduled-tasks/CONTEXT.md
Cal Corum fcecde0de4
All checks were successful
Reindex Knowledge Base / reindex (push) Successful in 2s
docs: decommission cognitive memory references from KB
Removed cognitive-memory MCP, timers, and symlink system references.
Replaced with kb-search MCP and /save-doc skill workflow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:02:56 -05:00

6.5 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
sync-kb
sync-config

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-scheduled@sync-config.timer  # Daily 02:00
├── claude-issue-poller.service/timer   # Every 30 min
├── claude-pr-reviewer.service/timer
├── claude-issue-dispatcher.service
├── claude-daily-report.service/timer
├── sync-kb.service/timer               # Every 2 hours (plain bash, no Claude)

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

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

Three 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
            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

3. Plain Bash Scripts

Used for tasks that don't need AI — just shell commands with their own systemd units.

sync-kb.timer (every 2 hours)
    → sync-kb.service
        → tasks/sync-kb/sync-kb.sh
            → git add/commit/push .md files in claude-home
            → push triggers kb-rag webhook reindex via Gitea Actions

Logs go to ~/.local/share/claude-scheduled/logs/sync-kb/ (last 30 kept).

Active Tasks

Task Trigger Type Description
backlog-triage Weekdays 09:15 runner.sh Scan Gitea issues, prioritize, suggest focus
sync-config Daily 02:00 runner.sh Commit and push ~/.claude and ~/dotfiles to Gitea
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
sync-kb Every 2 hours bash script Commit and push claude-home KB changes to Gitea (triggers kb-rag reindex)

Settings Reference (settings.json)

{
  "model": "sonnet",
  "effort": "medium",
  "max_budget_usd": 0.75,
  "allowed_tools": "Read(*) Glob(*) Grep(*)",
  "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
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