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

168 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: "Scheduled Tasks Overview"
description: "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."
type: context
domain: scheduled-tasks
tags: [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`)
```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
```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.150.30 per Sonnet run with MCP tools