AGENT SKILL

Scheduler

Cron-style job scheduler. Add, remove, list, and run jobs against a JSON-backed registry.

License 许可
MIT
最近更新
2026-11-07
Stars
★ 1
Forks
0

01 前言 Front Matter

name
Scheduler
description
Cron-style job scheduler. Add, remove, list, and run jobs against a JSON-backed registry.

03 SKILL.md 正文

Scheduler

Time-anchored work — calendar sync, reminders, end-of-day rollups. For loop-style "every N minutes" polling with no calendar component, use the Heartbeat Faculty instead.

Setup

Resolved by the runner from Fitting config:

GARRISON_SCHEDULER_JOBS=...   # default: data/scheduler-jobs.json
GARRISON_SCHEDULER_LOG=...    # default: data/scheduler.log

Both paths are relative to the composition directory.

CLI

The scheduler.mjs CLI runs from the Fitting's installed directory (apm_modules/_local/scheduler/).

node scripts/scheduler.mjs --probe                    # health check
node scripts/scheduler.mjs list                       # JSON list of jobs
node scripts/scheduler.mjs add <id> <cron> <command>  # add or replace
node scripts/scheduler.mjs remove <id>                # remove a job
node scripts/scheduler.mjs run-now <id>               # run once now
node scripts/scheduler.mjs tick                       # process current-minute due jobs
node scripts/scheduler.mjs daemon                     # tick every minute until killed

Cron grammar

5 fields: minute hour day-of-month month day-of-week. Supported:

  • * — any value
  • */N — every N units (modulo arithmetic from field min)
  • M — single value
  • M,N,... — comma-separated list
  • A-B — inclusive range

No @yearly/@daily aliases, no seconds, no named months/days. That covers Phase 2's intended patterns:

  • */5 * * * * — every 5 minutes (calendar sync)
  • 0 8 * * 1-5 — 8am weekdays (morning briefing)
  • 0 18 * * * — 6pm daily (end-of-day rollup)

Tick semantics

A tick runs at most once per minute per job. Each job records last_run_minute (e.g. 2026-5-7T8:0) so a second tick within the same minute is a no-op for that job. Cron matching is against the local time of the tick, not UTC.

Operating principles

  • Time-anchored vs loop-driven. Use Scheduler for "at H:M every weekday." Use Heartbeat for "every 40 minutes, regardless of clock." A heartbeat tick can call scheduler.mjs tick to drive due jobs as a side effect.
  • Job idempotency is the consumer's responsibility. The scheduler doesn't dedupe across daemon restarts; if a job must not fire twice, the job's command must check its own state.
  • Log file grows unbounded. Rotate it externally if retention matters. v1 doesn't ship rotation.

Persistence

jobs.json is a flat array of objects:

[
  {
    "id": "morning-briefing",
    "cron": "0 8 * * 1-5",
    "command": "curl -X POST http://127.0.0.1:24777/jobs -d ...",
    "enabled": true,
    "last_run": "2026-05-07T07:00:00.000Z",
    "last_run_minute": "2026-5-7T8:0"
  }
]

Survives Garrison restart — the scheduler reads jobs.json on every tick. last_run_minute is written before the job is spawned, so a crash mid-run doesn't double-fire on restart.

Cookbook: morning briefing

The daily morning briefing now ships as its own Fitting — fittings/seed/morning-briefing/. Add it to your composition's selections.automations block and garrison up registers the scheduler job for you. See that Fitting's instructions.md for configuration knobs (briefing_time, weekdays_only, GARRISON_BRIEFING_TIME / GARRISON_BRIEFING_WEEKDAYS_ONLY env overrides).

If you want a different scheduled-prompt recipe (e.g. an end-of-day rollup), follow the morning-briefing Fitting's setup.sh as a template — POST {kind, instructions} to http://$GARRISON_GATEWAY_HOST:$GARRISON_GATEWAY_PORT/jobs and the gateway will dispatch it to the session as a synthetic prompt.

How the daemon mode is wired

In Phase 2, the runner does not auto-spawn the scheduler daemon. Three integration paths the consumer can pick from:

  1. Manual: node apm_modules/_local/scheduler/scripts/scheduler.mjs daemon in a tmux pane or under launchctl asuser.
  2. Heartbeat-driven: Phase 2's heartbeat (T4) can run tick once per heartbeat as part of its periodic work. Coarser cadence (40 min vs 1 min) but no separate process.
  3. Host cron: * * * * * cd <composition> && node apm_modules/_local/scheduler/scripts/scheduler.mjs tick in crontab.

A future runtime-SDK milestone may add an explicit x-garrison.daemon declaration so the runner spawns the scheduler daemon at Up time.

04 同仓库更多 Skills