Scheduled Tasks: headless Claude sessions on a timer (Cowork-style) #2

Closed
opened 2026-03-01 06:01:46 +00:00 by cal · 1 comment
Owner

Summary

Build a scheduled task system that runs headless Claude Code sessions on a timer, inspired by MacOS Claude Cowork's scheduled tasks feature. Uses systemd timers to trigger claude -p with task-specific prompts, scoped to the appropriate project and cognitive-memory graph.

Motivation

  • We already have systemd timers for cognitive-memory maintenance (decay, embeddings, git-sync) — this extends that pattern to higher-level automated work
  • Multi-graph support landed in cognitive-memory, enabling per-project memory isolation for scheduled tasks
  • Automate recurring tasks that currently require manual Claude sessions: backlog triage, codebase health checks, memory maintenance, daily briefings

Design Decisions Needed

1. Task Definition Format

How do we define scheduled tasks? Options:

  • A) Central config file (e.g. ~/.config/claude-scheduled/tasks.yaml) listing all tasks with schedule, prompt, working dir, graph, limits
  • B) Individual systemd timer/service pairs per task (current pattern for cognitive-memory maintenance)
  • C) Hybrid — central config that generates systemd units via a management CLI

2. Headless Session Requirements

  • Does claude -p work from a systemd unit (no TTY)?
  • API key / OAuth session persistence in headless context
  • Which flags are needed? (--model, --max-turns, --allowedTools, etc.)
  • Should tasks use --allowedTools to restrict what the session can do?

3. Output & Reporting

Where do task results go?

  • Cognitive-memory store (to the appropriate graph)
  • Log files (~/.local/share/claude-scheduled/logs/)
  • Discord notification via Major Domo
  • Structured output (JSON) for downstream processing
  • Some combination of the above

4. Cost & Safety Guardrails

  • Max turns per task
  • Max tokens per task (if supported)
  • Timeout per session
  • Allowlist of tools per task (e.g. read-only tasks shouldn't have Edit/Write/Bash)
  • Kill switch / global disable

5. Working Directory & Context

  • Each task needs to cd into the right project repo so CLAUDE.md loads
  • Task prompts should specify which cognitive-memory graph to use
  • Should tasks have their own CLAUDE.md overrides?

6. Scheduling

  • Systemd calendar expressions (e.g. OnCalendar=*-*-* 08:00:00)
  • Should tasks support dependencies (task B runs after task A completes)?
  • Retry policy on failure?

Example Tasks (Initial Set)

Task Schedule Working Dir Graph Description
Morning Briefing Daily 08:00 claude-home default Summarize overnight changes, open issues across repos, memory decay alerts
Backlog Triage Daily 09:00 per-project per-project Check Gitea issues, prioritize, update labels
Memory Maintenance Weekly Sun 03:00 cognitive-memory all Cross-graph reflection, edge cleanup, archive dormant memories
Codebase Health Weekly Mon 07:00 per-project per-project Check for stale TODOs, dependency updates, test coverage
Documentation Sync Daily 22:00 claude-home default Ensure docs match current state of homelab

Architecture Sketch

~/.config/claude-scheduled/
├── tasks.yaml              # Central task definitions
├── prompts/                # Task-specific prompt templates
│   ├── morning-briefing.md
│   ├── backlog-triage.md
│   └── ...
└── logs/                   # Execution logs (or ~/.local/share/)

systemd units:
├── claude-scheduled@.service    # Template unit
├── claude-scheduled@.timer      # Template timer
└── (instantiated per task)

Potential Blockers

  • Claude Code headless auth: Need to verify claude -p works from systemd without TTY/interactive login
  • Token cost: Unattended sessions need hard limits to prevent runaway spending
  • Permissions: Headless sessions need careful tool restrictions — a scheduled task shouldn't be able to git push --force unattended

Prior Art

  • MacOS Claude Cowork scheduled tasks
  • Existing cognitive-memory systemd timers (decay, embedding refresh, git-sync)
  • N8N + Claude Code server monitoring workflow (similar concept, different trigger)

Next Steps

  1. Validate claude -p works from systemd (quick spike)
  2. Design task definition schema
  3. Build minimal prototype with 1-2 tasks
  4. Iterate on reporting/output format

May become its own repo if scope grows beyond claude-home.

## Summary Build a scheduled task system that runs headless Claude Code sessions on a timer, inspired by MacOS Claude Cowork's scheduled tasks feature. Uses systemd timers to trigger `claude -p` with task-specific prompts, scoped to the appropriate project and cognitive-memory graph. ## Motivation - We already have systemd timers for cognitive-memory maintenance (decay, embeddings, git-sync) — this extends that pattern to higher-level automated work - Multi-graph support landed in cognitive-memory, enabling per-project memory isolation for scheduled tasks - Automate recurring tasks that currently require manual Claude sessions: backlog triage, codebase health checks, memory maintenance, daily briefings ## Design Decisions Needed ### 1. Task Definition Format How do we define scheduled tasks? Options: - **A) Central config file** (e.g. `~/.config/claude-scheduled/tasks.yaml`) listing all tasks with schedule, prompt, working dir, graph, limits - **B) Individual systemd timer/service pairs** per task (current pattern for cognitive-memory maintenance) - **C) Hybrid** — central config that generates systemd units via a management CLI ### 2. Headless Session Requirements - Does `claude -p` work from a systemd unit (no TTY)? - API key / OAuth session persistence in headless context - Which flags are needed? (`--model`, `--max-turns`, `--allowedTools`, etc.) - Should tasks use `--allowedTools` to restrict what the session can do? ### 3. Output & Reporting Where do task results go? - Cognitive-memory store (to the appropriate graph) - Log files (`~/.local/share/claude-scheduled/logs/`) - Discord notification via Major Domo - Structured output (JSON) for downstream processing - Some combination of the above ### 4. Cost & Safety Guardrails - Max turns per task - Max tokens per task (if supported) - Timeout per session - Allowlist of tools per task (e.g. read-only tasks shouldn't have Edit/Write/Bash) - Kill switch / global disable ### 5. Working Directory & Context - Each task needs to `cd` into the right project repo so CLAUDE.md loads - Task prompts should specify which cognitive-memory graph to use - Should tasks have their own CLAUDE.md overrides? ### 6. Scheduling - Systemd calendar expressions (e.g. `OnCalendar=*-*-* 08:00:00`) - Should tasks support dependencies (task B runs after task A completes)? - Retry policy on failure? ## Example Tasks (Initial Set) | Task | Schedule | Working Dir | Graph | Description | |------|----------|-------------|-------|-------------| | Morning Briefing | Daily 08:00 | claude-home | default | Summarize overnight changes, open issues across repos, memory decay alerts | | Backlog Triage | Daily 09:00 | per-project | per-project | Check Gitea issues, prioritize, update labels | | Memory Maintenance | Weekly Sun 03:00 | cognitive-memory | all | Cross-graph reflection, edge cleanup, archive dormant memories | | Codebase Health | Weekly Mon 07:00 | per-project | per-project | Check for stale TODOs, dependency updates, test coverage | | Documentation Sync | Daily 22:00 | claude-home | default | Ensure docs match current state of homelab | ## Architecture Sketch ``` ~/.config/claude-scheduled/ ├── tasks.yaml # Central task definitions ├── prompts/ # Task-specific prompt templates │ ├── morning-briefing.md │ ├── backlog-triage.md │ └── ... └── logs/ # Execution logs (or ~/.local/share/) systemd units: ├── claude-scheduled@.service # Template unit ├── claude-scheduled@.timer # Template timer └── (instantiated per task) ``` ## Potential Blockers - **Claude Code headless auth**: Need to verify `claude -p` works from systemd without TTY/interactive login - **Token cost**: Unattended sessions need hard limits to prevent runaway spending - **Permissions**: Headless sessions need careful tool restrictions — a scheduled task shouldn't be able to `git push --force` unattended ## Prior Art - MacOS Claude Cowork scheduled tasks - Existing cognitive-memory systemd timers (decay, embedding refresh, git-sync) - N8N + Claude Code server monitoring workflow (similar concept, different trigger) ## Next Steps 1. Validate `claude -p` works from systemd (quick spike) 2. Design task definition schema 3. Build minimal prototype with 1-2 tasks 4. Iterate on reporting/output format --- _May become its own repo if scope grows beyond claude-home._
cal added the
ai-working
label 2026-03-04 08:01:14 +00:00
cal removed the
ai-working
label 2026-03-04 08:05:14 +00:00
Author
Owner

The scheduled task system is fully implemented (runner.sh, systemd units, tasks). This PR adds documentation to the claude-home repo:

  • scheduled-tasks/CONTEXT.md — documents both execution patterns (runner.sh template framework + custom dispatcher scripts), all active tasks, settings reference, auth, monitoring, and cost safety
  • CLAUDE.md — updated routing table so the context loads automatically when scheduled-task topics come up

PR: #6

The scheduled task system is fully implemented (runner.sh, systemd units, tasks). This PR adds documentation to the claude-home repo: - **`scheduled-tasks/CONTEXT.md`** — documents both execution patterns (runner.sh template framework + custom dispatcher scripts), all active tasks, settings reference, auth, monitoring, and cost safety - **`CLAUDE.md`** — updated routing table so the context loads automatically when scheduled-task topics come up PR: https://git.manticorum.com/cal/claude-home/pulls/6
cal added the
ai-reviewed
ai-pr-opened
labels 2026-03-04 08:05:34 +00:00
cal closed this issue 2026-03-05 03:55:21 +00:00
Sign in to join this conversation.
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: cal/claude-home#2
No description provided.