From b50808eb8e0fe6a40f6ffa005a8cf40b4ba2a661 Mon Sep 17 00:00:00 2001 From: Cal Corum Date: Wed, 4 Mar 2026 02:04:45 -0600 Subject: [PATCH] docs: add scheduled-tasks documentation and update CLAUDE.md routing (#2) Adds scheduled-tasks/CONTEXT.md documenting the implemented headless Claude scheduled task system: runner.sh framework, custom dispatcher scripts, active tasks, settings reference, auth, monitoring, and cost safety guardrails. Updates CLAUDE.md routing table to load CONTEXT.md alongside the SKILL.md for all scheduled-task-related topics. Co-Authored-By: Claude Sonnet 4.6 --- CLAUDE.md | 2 +- scheduled-tasks/CONTEXT.md | 144 +++++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 scheduled-tasks/CONTEXT.md diff --git a/CLAUDE.md b/CLAUDE.md index d6c6ed6..ecd3d1a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -30,7 +30,7 @@ When a topic comes up, load `{tech}/CONTEXT.md` + `{tech}/troubleshooting.md`. F | backup, restic, snapshot, restore, retention | `backups/` | | workstation, dotfiles, symlink, fish, starship, mangohud, zed, fish config, fish alias, tmux, tmux alias | `workstation/` | | tui testing, mcp-tui-driver, tui automation, terminal ui test | `development/tui-testing.md` | -| scheduled task, claude-scheduled, headless claude, timer, cowork | `~/.claude/skills/create-scheduled-task/SKILL.md` | +| scheduled task, claude-scheduled, headless claude, timer, cowork, issue-poller, issue-worker, pr-reviewer, backlog-triage | `scheduled-tasks/CONTEXT.md` + `~/.claude/skills/create-scheduled-task/SKILL.md` | **Special loads:** - Pi-hole → also `networking/pihole-ha-setup.md` diff --git a/scheduled-tasks/CONTEXT.md b/scheduled-tasks/CONTEXT.md new file mode 100644 index 0000000..e724168 --- /dev/null +++ b/scheduled-tasks/CONTEXT.md @@ -0,0 +1,144 @@ +# 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// # 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@.timer + → claude-scheduled@.service + → runner.sh + reads tasks//{prompt.md,settings.json,mcp.json} + invokes: claude -p --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`) + +```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 + +```bash +# 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.15–0.30 per Sonnet run with MCP tools